/**@brief Function for notifying a DFU Controller about error conditions in the DFU module. * This function also ensures that an error is translated from nrf_errors to DFU Response * Value. * * @param[in] p_dfu DFU Service Structure. * @param[in] err_code Nrf error code that should be translated and send to the DFU Controller. */ static void dfu_error_notify(ble_dfu_t * p_dfu, uint32_t err_code) { // An error has occurred. Notify the DFU Controller about this error condition. // Translate the err_code returned to DFU Response Value. ble_dfu_resp_val_t resp_val; resp_val = nrf_err_code_translate(err_code, BLE_DFU_RECEIVE_APP_PROCEDURE); err_code = ble_dfu_response_send(p_dfu, BLE_DFU_RECEIVE_APP_PROCEDURE, resp_val); APP_ERROR_CHECK(err_code); }
/**@brief Function for handling the callback events from the dfu module. * Callbacks are expected when \ref dfu_data_pkt_handle has been executed. * * @param[in] packet Packet type for which this callback is related. * @param[in] result Operation result code. NRF_SUCCESS when a queued operation was successful. * @param[in] p_data Pointer to the data to which the operation is related. */ static void dfu_cb_handler(uint32_t packet, uint32_t result, uint8_t * p_data) { switch (packet) { ble_dfu_resp_val_t resp_val; uint32_t err_code; case DATA_PACKET: if (result != NRF_SUCCESS) { // Disconnect from peer. if (IS_CONNECTED()) { err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); APP_ERROR_CHECK(err_code); } } else { err_code = hci_mem_pool_rx_consume(p_data); APP_ERROR_CHECK(err_code); // If the callback matches final data packet received then the peer is notified. if (mp_final_packet == p_data) { // Notify the DFU Controller about the success of the procedure. err_code = ble_dfu_response_send(&m_dfu, BLE_DFU_RECEIVE_APP_PROCEDURE, BLE_DFU_RESP_VAL_SUCCESS); APP_ERROR_CHECK(err_code); } } break; case START_PACKET: // Translate the err_code returned by the above function to DFU Response Value. resp_val = nrf_err_code_translate(result, BLE_DFU_START_PROCEDURE); err_code = ble_dfu_response_send(&m_dfu, BLE_DFU_START_PROCEDURE, resp_val); APP_ERROR_CHECK(err_code); break; default: // ignore. break; } }
/**@brief Function for handling the callback events from the dfu module. * Callbacks are expected when \ref dfu_data_pkt_handle has been executed. * * @param[in] packet Packet type for which this callback is related. * @param[in] result Operation result code. NRF_SUCCESS when a queued operation was successful. * @param[in] p_data Pointer to the data to which the operation is related. */ static void dfu_cb_handler(uint32_t packet, uint32_t result, uint8_t * p_data) { switch (packet) { ble_dfu_resp_val_t resp_val; uint32_t err_code; case DATA_PACKET: if (result != NRF_SUCCESS) { // Disconnect from peer. if (IS_CONNECTED()) { err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); APP_ERROR_CHECK(err_code); } } else { err_code = hci_mem_pool_rx_consume(p_data); APP_ERROR_CHECK(err_code); } break; case START_PACKET: // Translate the err_code returned by the above function to DFU Response Value. resp_val = nrf_err_code_translate(result, BLE_DFU_START_PROCEDURE); err_code = ble_dfu_response_send(&m_dfu, BLE_DFU_START_PROCEDURE, resp_val); APP_ERROR_CHECK(err_code); break; default: // ignore. break; } }
/**@brief Function for the Device Firmware Update Service event handler. * * @details This function will be called for all Device Firmware Update Service events which * are passed to the application. * * @param[in] p_dfu Device Firmware Update Service structure. * @param[in] p_evt Event received from the Device Firmware Update Service. */ static void on_dfu_evt(ble_dfu_t * p_dfu, ble_dfu_evt_t * p_evt) { uint32_t err_code; switch (p_evt->ble_dfu_evt_type) { case BLE_DFU_VALIDATE: err_code = dfu_image_validate(); // Translate the err_code returned by the above function to DFU Response Value. ble_dfu_resp_val_t resp_val; resp_val = nrf_err_code_translate(err_code, BLE_DFU_VALIDATE_PROCEDURE); err_code = ble_dfu_response_send(p_dfu, BLE_DFU_VALIDATE_PROCEDURE, resp_val); APP_ERROR_CHECK(err_code); break; case BLE_DFU_ACTIVATE_N_RESET: err_code = dfu_transport_close(); APP_ERROR_CHECK(err_code); // With the S110 Flash API it is safe to initiate the activate before connection is // fully closed. err_code = dfu_image_activate(); if (err_code != NRF_SUCCESS) { dfu_reset(); } break; case BLE_DFU_SYS_RESET: err_code = dfu_transport_close(); APP_ERROR_CHECK(err_code); dfu_reset(); break; case BLE_DFU_START: m_pkt_type = PKT_TYPE_START; if (p_evt->evt.ble_dfu_pkt_write.len == 0) { m_update_mode = DFU_UPDATE_APP; } else { m_update_mode = (uint8_t)p_evt->evt.ble_dfu_pkt_write.p_data[0]; } break; case BLE_DFU_RECEIVE_INIT_DATA: m_pkt_type = PKT_TYPE_INIT; break; case BLE_DFU_RECEIVE_APP_DATA: m_pkt_type = PKT_TYPE_FIRMWARE_DATA; break; case BLE_DFU_PACKET_WRITE: on_dfu_pkt_write(p_dfu, p_evt); break; case BLE_DFU_PKT_RCPT_NOTIF_ENABLED: m_pkt_rcpt_notif_enabled = true; m_pkt_notif_target = p_evt->evt.pkt_rcpt_notif_req.num_of_pkts; m_pkt_notif_target_cnt = p_evt->evt.pkt_rcpt_notif_req.num_of_pkts; break; case BLE_DFU_PKT_RCPT_NOTIF_DISABLED: m_pkt_rcpt_notif_enabled = false; m_pkt_notif_target = 0; break; case BLE_DFU_BYTES_RECEIVED_SEND: err_code = ble_dfu_bytes_rcvd_report(p_dfu, m_num_of_firmware_bytes_rcvd); APP_ERROR_CHECK(err_code); break; default: // Unsupported event received from DFU Service. Ignore. break; } }
/**@brief Function for processing start data written by the peer to the DFU Packet * Characteristic. * * @param[in] p_dfu DFU Service Structure. * @param[in] p_evt Pointer to the event received from the S110 SoftDevice. */ static void start_data_process(ble_dfu_t * p_dfu, ble_dfu_evt_t * p_evt) { uint32_t err_code; dfu_start_packet_t start_packet = {.dfu_update_mode = m_update_mode}; dfu_update_packet_t update_packet = { .packet_type = START_PACKET, .params.start_packet = &start_packet }; uint32_t length = p_evt->evt.ble_dfu_pkt_write.len; // Verify that the data is exactly three * four bytes (three words) long. // Or a single word to support backwards compatibility of application image transfer. if ((length != (3 * sizeof(uint32_t))) && (length != sizeof(uint32_t))) { err_code = ble_dfu_response_send(p_dfu, BLE_DFU_START_PROCEDURE, BLE_DFU_RESP_VAL_NOT_SUPPORTED); APP_ERROR_CHECK(err_code); } else { // Extract the size of from the DFU Packet Characteristic. uint8_t * length_data = p_evt->evt.ble_dfu_pkt_write.p_data; if (length == sizeof(uint32_t)) { // Legacy update. start_packet.sd_image_size = 0; start_packet.bl_image_size = 0; start_packet.app_image_size = uint32_decode(length_data); } else { start_packet.sd_image_size = uint32_decode(length_data); start_packet.bl_image_size = uint32_decode(length_data + 4); start_packet.app_image_size = uint32_decode(length_data + 8); } err_code = dfu_start_pkt_handle(&update_packet); if (err_code != NRF_SUCCESS) { // Translate the err_code returned by the above function to DFU Response Value. ble_dfu_resp_val_t resp_val; resp_val = nrf_err_code_translate(err_code, BLE_DFU_START_PROCEDURE); err_code = ble_dfu_response_send(p_dfu, BLE_DFU_START_PROCEDURE, resp_val); } APP_ERROR_CHECK(err_code); } } /**@brief Function for processing initialization data written by the peer to the DFU Packet * Characteristic. * * @param[in] p_dfu DFU Service Structure. * @param[in] p_evt Pointer to the event received from the S110 SoftDevice. */ static void init_data_process(ble_dfu_t * p_dfu, ble_dfu_evt_t * p_evt) { uint32_t err_code; dfu_update_packet_t dfu_pkt; uint8_t num_of_padding_bytes = 0; dfu_pkt.packet_type = INIT_PACKET; dfu_pkt.params.data_packet.p_data_packet = (uint32_t *)p_evt->evt.ble_dfu_pkt_write.p_data; // The DFU module accepts the dfu_pkt.packet_length to be in 'number of words'. And so if the // received data does not have a size which is a multiple of four, it should be padded with // zeros and the packet_length should be incremented accordingly before calling // dfu_init_pkt_handle. if ((p_evt->evt.ble_dfu_pkt_write.len & (sizeof(uint32_t) - 1)) != 0) { // Find out the number of bytes to be padded. num_of_padding_bytes = sizeof(uint32_t) - (p_evt->evt.ble_dfu_pkt_write.len & (sizeof(uint32_t) - 1)); uint32_t i; for (i = 0; i < num_of_padding_bytes; i++) { dfu_pkt.params.data_packet.p_data_packet[p_evt->evt.ble_dfu_pkt_write.len + i] = 0; } } dfu_pkt.params.data_packet.packet_length = (p_evt->evt.ble_dfu_pkt_write.len + num_of_padding_bytes) / sizeof(uint32_t); err_code = dfu_init_pkt_handle(&dfu_pkt); // Translate the err_code returned by the above function to DFU Response Value. ble_dfu_resp_val_t resp_val; resp_val = nrf_err_code_translate(err_code, BLE_DFU_INIT_PROCEDURE); err_code = ble_dfu_response_send(p_dfu, BLE_DFU_INIT_PROCEDURE, resp_val); APP_ERROR_CHECK(err_code); }