uint32_t dfu_image_validate(uint16_t crc_seed) { uint32_t err_code; switch (m_dfu_state) { case DFU_STATE_RX_DATA_PKT: m_dfu_state = DFU_STATE_VALIDATE; // Check if the application image write has finished. if (m_data_received != m_image_size) { // Image not yet fully transfered by the peer or the peer has attempted to write // too much data. Hence the validation should fail. err_code = NRF_ERROR_INVALID_STATE; } else { // Valid peer activity detected. Hence restart the DFU timer. err_code = dfu_timer_restart(); if (err_code == NRF_SUCCESS) { if(crc_crc16_update(crc_seed, (uint32_t*)dfu_storage_start_address_get(), m_image_size) == 0) { m_dfu_state = DFU_STATE_WAIT_4_ACTIVATE; err_code = NRF_SUCCESS; } else { err_code = NRF_ERROR_INTERNAL; } } } break; default: err_code = NRF_ERROR_INVALID_STATE; break; } return err_code; }
/**@brief Function for processing ANTFS upload data event. * * @param[in] p_event The event extracted from the queue to be processed. */ static void antfs_event_upload_data_handle(const antfs_event_return_t * p_event) { static uint8_t * p_rxd_data; static uint32_t rxd_data_size; uint32_t err_code = NRF_SUCCESS; ota_image_header_t * p_ota_image_header; // Allocate a memory pool for upload buffering. if (m_data_buffered == 0) { // Check which pool is empty. if (m_mem_pool_1.size == 0) { mp_buffering_handle = &m_mem_pool_1; } else if (m_mem_pool_2.size == 0) { mp_buffering_handle = &m_mem_pool_2; } else { // something is wrong. dfu_error_notify(err_code, 6); } mp_rx_buffer = &mp_buffering_handle->a_mem_pool[0]; } if ((p_event->bytes + m_data_buffered) < ANTFS_UPLOAD_DATA_BUFFER_MAX_SIZE) { // Copy over the buffer the rx'd 8 byte data memcpy(mp_rx_buffer + m_data_buffered, p_event->data, p_event->bytes); // Advance buffered count m_data_buffered += p_event->bytes; // Advance current over all data count. } else { // something is wrong. dfu_error_notify(err_code, 7); } if ((m_data_buffered >= ANTFS_UPLOAD_DATA_BUFFER_MIN_SIZE) || ((m_pending_offset + m_data_buffered) >= m_current_file_size)) { /* If any of the pool is still pending process and we are running out of space * The ANTFS_UPLOAD_DATA_BUFFER_MIN_SIZE should be enough delay to get the previous buffer be processed, including flashing*/ if (((m_mem_pool_1.size != 0) || (m_mem_pool_2.size != 0)) && ((m_pending_offset + m_data_buffered) < m_current_file_size)) { if (m_data_buffered < ANTFS_UPLOAD_DATA_BUFFER_MAX_SIZE) { // We can wait for a bit. return; } else { // Something is wrong. the device is not flashing. upload_data_response_fail_reset(); return; } } mp_buffering_handle->size = m_data_buffered; // Set the size and consider this pool closed and ready for processing. m_data_buffered = 0; // Reset buffered data count // Decide what to do with the data in the buffer. switch (m_current_file_index) { case ANTFS_FILE_INDEX_UPDATE_STACK: case ANTFS_FILE_INDEX_UPDATE_BOOTLOADER: case ANTFS_FILE_INDEX_UPDATE_APPLICATION: case ANTFS_FILE_INDEX_UPDATE_STACK_BOOTLOADER: // Not in the right state if (m_antfs_dfu_state != ANTFS_DFU_STATE_READY) { // Throw it away. mp_buffering_handle->size = 0; mp_buffering_handle = NULL; upload_data_response_fail_reset(); return; } p_rxd_data = mp_buffering_handle->a_mem_pool; rxd_data_size = mp_buffering_handle->size; // pre calculate pending offset m_pending_offset = m_pending_offset + rxd_data_size; /*********** * Header Section */ if (!m_ota_image_header_parsed) { // Parse the Header if (antfs_ota_image_header_parsing(&p_rxd_data, &rxd_data_size)) { m_ota_image_header_parsed = true; p_ota_image_header = antfs_ota_image_header_get(); } else { return; // Get more } if ((p_ota_image_header == NULL) || // Make sure it is a valid header (p_ota_image_header->architecture_identifier != OTA_IMAGE_ARCH_IDENTIFIER_ST_BL_AP) || // Make sure it is SD BL and AP arch (p_ota_image_header->image_format != OTA_IMAGE_IMAGE_FORMAT_BINARY)) // Make sure it is in Binary format { // Invalid header, fail now. upload_data_response_fail_reset(); return; } // Fill in DFU parameters m_dfu_pkt.params.start_packet.dfu_update_mode = m_update_mode; m_dfu_pkt.params.start_packet.sd_image_size = p_ota_image_header->wireless_stack_size; m_dfu_pkt.params.start_packet.bl_image_size = p_ota_image_header->bootloader_size; m_dfu_pkt.params.start_packet.app_image_size = p_ota_image_header->application_size; m_dfu_pkt.params.start_packet.info_bytes_size = OTA_IMAGE_CRC_SIZE_MAX; err_code = dfu_start_pkt_handle(&m_dfu_pkt); // reinitializing dfu pkt if (err_code) { upload_data_response_fail_reset(); return; } m_image_data_max = p_ota_image_header->wireless_stack_size + p_ota_image_header->bootloader_size + p_ota_image_header->application_size + OTA_IMAGE_CRC_SIZE_MAX; m_header_crc_seed = antfs_ota_image_header_crc_get(); m_current_crc = m_header_crc_seed; m_current_offset = p_ota_image_header->header_size; } /*********** * Image Section */ if (!m_image_data_complete) { m_upload_swap_space_prepared = false; m_dfu_pkt.params.data_packet.p_data_packet = (uint32_t*) p_rxd_data; m_dfu_pkt.params.data_packet.packet_length = rxd_data_size / sizeof(uint32_t); // store flushed information for flash write verification. mp_buffering_handle->size = rxd_data_size; mp_buffering_handle->crc = crc_crc16_update(0, p_rxd_data, rxd_data_size); // Pass the image to dfu. m_dfu_pkt.packet_type = DATA_PACKET; err_code = dfu_data_pkt_handle(&m_dfu_pkt); if (err_code == NRF_SUCCESS) { // All the expected firmware image has been received and processed successfully. m_image_data_complete = true; } else if (err_code == NRF_ERROR_INVALID_LENGTH) { // The image is still partially completed. We need more. //do nothing; } // Unmanaged return code. Something is wrong need to abort. else { //TODO Need to figure out what to do on unmanaged returns. Maybe reset dfu_error_notify(err_code, 9); } } m_antfs_dfu_state = ANTFS_DFU_STATE_READY; break; default: mp_buffering_handle->size = 0; break; } } }
/* * NOTE: This callback is only called by the following * - Storing done operation by dfu_data_pkt_handle * - And all clearing done operation. */ static void dfu_cb_handler(uint32_t result, uint8_t * p_data) { uint32_t err_code; uint16_t rxd_buffer_len = 0; uint16_t ram_crc = 0; uint16_t flash_crc = 0; #if defined (DBG_DFU_UART_OUT_PIN) DEBUG_UART_OUT(0xFF); DEBUG_UART_OUT(m_antfs_dfu_state); #endif switch (m_antfs_dfu_state) { case ANTFS_DFU_STATE_INIT_DELAYED: // This is when upon initialization, a pre-erase operation have occured i.e. bank1 pre clearing. services_init(); break; case ANTFS_DFU_STATE_FLASH_ERASE: // Handles upload and download request response delay when there is ongoing flash activities // Generally we need to avoid flash activities and burst activities to happen at the same time. // ANTFS request response are delayed and when flash is done response are handled here. if (m_upload_request_in_progress) { m_upload_request_in_progress = false; // Make sure we got all the latest values. m_response_info.file_size.data = m_current_offset; m_response_info.file_crc = m_current_crc; if (result == NRF_SUCCESS) { m_upload_swap_space_prepared = true; UNUSED_VARIABLE(antfs_upload_req_resp_transmit(RESPONSE_MESSAGE_OK, &m_response_info)); } else { /* Not ready */ UNUSED_VARIABLE(antfs_upload_req_resp_transmit(RESPONSE_MESSAGE_UPLOAD_NOT_READY, &m_response_info)); } } if (m_download_request_in_progress) { m_download_request_in_progress = false; UNUSED_VARIABLE(antfs_download_req_resp_prepare(RESPONSE_MESSAGE_OK, &m_response_info)); } m_antfs_dfu_state = ANTFS_DFU_STATE_READY; break; case ANTFS_DFU_STATE_FLASH_PENDING: case ANTFS_DFU_STATE_READY: // Handles Flash write call back queued by Upload Data. if (result != NRF_SUCCESS) { upload_data_response_fail_reset(); return; } if ((m_mem_pool_1.a_mem_pool <= p_data) && (p_data <= (m_mem_pool_1.a_mem_pool + ANTFS_UPLOAD_DATA_BUFFER_MAX_SIZE))) { rxd_buffer_len = m_mem_pool_1.size; ram_crc = m_mem_pool_1.crc; m_mem_pool_1.size = 0; } else if ((m_mem_pool_2.a_mem_pool <= p_data) && (p_data <= (m_mem_pool_2.a_mem_pool + ANTFS_UPLOAD_DATA_BUFFER_MAX_SIZE))) { rxd_buffer_len = m_mem_pool_2.size; ram_crc = m_mem_pool_2.crc; m_mem_pool_2.size = 0; } else { upload_data_response_fail_reset(); return; } // Verify the data written to flash. flash_crc = crc_crc16_update(0, (uint8_t*)(dfu_storage_start_address_get() + m_image_data_offset), rxd_buffer_len); if (flash_crc != ram_crc) { upload_data_response_fail_reset(); return; } //update current offsets and crc m_current_offset += rxd_buffer_len; m_current_crc = crc_crc16_update(m_current_crc, (uint8_t*)(dfu_storage_start_address_get() + m_image_data_offset), rxd_buffer_len); m_image_data_offset += rxd_buffer_len; if (m_antfs_dfu_state == ANTFS_DFU_STATE_FLASH_PENDING) { m_antfs_dfu_state = ANTFS_DFU_STATE_READY; // Update it with the latest values; m_response_info.file_size.data = m_current_offset; m_response_info.file_crc = m_current_crc; if (m_upload_request_in_progress) { m_upload_request_in_progress = false; UNUSED_VARIABLE(antfs_upload_req_resp_transmit(RESPONSE_MESSAGE_OK, &m_response_info)); } else // data response { if (m_image_data_complete == true) { if (m_image_data_max == m_image_data_offset) { err_code = dfu_image_validate(m_header_crc_seed); if (err_code == NRF_SUCCESS) { UNUSED_VARIABLE(antfs_upload_data_resp_transmit(true)); m_antfs_dfu_state = ANTFS_DFU_STATE_VALIDATED; return; } else { upload_data_response_fail_reset(); } } if ((m_mem_pool_1.size != 0) || (m_mem_pool_2.size != 0)) { m_antfs_dfu_state = ANTFS_DFU_STATE_FLASH_PENDING; } } else //m_image_data_complete == false { if ((m_mem_pool_1.size == 0) && (m_mem_pool_2.size == 0)) { UNUSED_VARIABLE(antfs_upload_data_resp_transmit(true)); // Handles block transfers } else { m_antfs_dfu_state = ANTFS_DFU_STATE_FLASH_PENDING; } } } } break; default: break; } }
uint16_t antfs_ota_image_header_crc_get (void) { return crc_crc16_update(HEADER_CRC_SEED, m_ota_image_header, m_ota_image_header_count); }