static void uart_event_handle(app_uart_evt_t * p_event) { static uint8_t data_array[BLE_NUS_MAX_DATA_LEN]; static uint8_t index = 0; uint32_t err_code; //uint8_t dbg_idx = 0; //uint8_t nDataLen = 0; switch (p_event->evt_type) { case APP_UART_DATA_READY: UNUSED_VARIABLE(app_uart_get(&data_array[index])); //log_print("0x%02x ", data_array[index]); index++; if ((data_array[index - 1] == 0x03/*'\n'*/) || (index >= (BLE_NUS_MAX_DATA_LEN))) { //err_code = ble_nus_string_send(&m_nus, data_array, index); err_code = ble_uart_send_data(data_array, index); if (err_code != NRF_ERROR_INVALID_STATE) { APP_ERROR_CHECK(err_code); } index = 0; //nrf_delay_ms(10); } //nDataLen = sizeof(json); #if 0 do { if (nDataLen < BLE_NUS_MAX_DATA_LEN) { ble_uart_send_data((uint8_t *)json+dbg_idx, nDataLen); dbg_idx += nDataLen; nDataLen = 0; } else { ble_uart_send_data((uint8_t *)json+dbg_idx, BLE_NUS_MAX_DATA_LEN); dbg_idx += BLE_NUS_MAX_DATA_LEN; nDataLen -= BLE_NUS_MAX_DATA_LEN; } nrf_delay_ms(10); } while(nDataLen > 0); #endif break; case APP_UART_COMMUNICATION_ERROR: APP_ERROR_HANDLER(p_event->data.error_communication); break; case APP_UART_FIFO_ERROR: APP_ERROR_HANDLER(p_event->data.error_code); break; default: break; } }
/** @brief Function for main application entry. */ int main(void) { TaskHandle_t compress_task_handle; TimerHandle_t spi_timer_handle; uint32_t err_code; static int intan_convert_channel = 0; err_code = nrf_drv_clock_init(); APP_ERROR_CHECK(err_code); // Setup bsp module. //bsp_configuration(); //uart initialization const app_uart_comm_params_t comm_params = { RX_PIN_NUMBER, TX_PIN_NUMBER, RTS_PIN_NUMBER, CTS_PIN_NUMBER, APP_UART_FLOW_CONTROL_ENABLED, false, UART_BAUDRATE_BAUDRATE_Baud38400 }; APP_UART_FIFO_INIT(&comm_params, UART_RX_BUF_SIZE, UART_TX_BUF_SIZE, uart_error_handle, APP_IRQ_PRIORITY_LOW, err_code); APP_ERROR_CHECK(err_code); //while(app_uart_put(65) != NRF_SUCCESS); //printf("1 ms = %d\n", pdMS_TO_TICKS(1)); intan_setup(); while(app_uart_put(65) != NRF_SUCCESS); compression_init(); while(app_uart_put(66) != NRF_SUCCESS); //printf("yo\n"); UNUSED_VARIABLE(xTaskCreate(compress_task, "c_task", configMINIMAL_STACK_SIZE + 200, NULL, 2, &compress_task_handle)); if(compress_task_handle == NULL) { printf("compression task init messed up\r\n"); } while(app_uart_put(67) != NRF_SUCCESS); spi_timer_handle = xTimerCreate("s_timer", 1000, pdTRUE, NULL, spi_data_collection_evt_handler); // LED1 timer creation if(spi_timer_handle == NULL) { printf("SPI timer init messed up\r\n"); } while(app_uart_put(68) != NRF_SUCCESS); if(xTimerStart(spi_timer_handle, 0) != pdPASS) { printf("Timer could not be started\r\n"); } while(app_uart_put(69) != NRF_SUCCESS); /* Activate deep sleep mode */ SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; // Start FreeRTOS scheduler. vTaskStartScheduler(); //timers_init(); //while(app_uart_put(67) != NRF_SUCCESS); //data_collection_timers_start(); //while(app_uart_put(68) != NRF_SUCCESS); for (;;) { printf("Messed up\r\n"); //power_manage(); /*if (m_transfer_completed) { //while(app_uart_put(72) != NRF_SUCCESS); m_transfer_completed = false; intan_convert(m_tx_data_spi, m_rx_data_spi,intan_convert_channel); //while(app_uart_put(73) != NRF_SUCCESS); intan_convert_channel ++; intan_convert_channel = intan_convert_channel % 32; //print m_rx_data_spi results switch_state(); //while(app_uart_put(74) != NRF_SUCCESS); //for (int i; i< RX_MSG_LENGTH; i++){ // while(app_uart_put(m_rx_data_spi[i]) != NRF_SUCCESS); //} nrf_delay_ms(DELAY_MS); //while(app_uart_put(75) != NRF_SUCCESS); }*/ //while(app_uart_put(76) != NRF_SUCCESS); } }
/**@brief Function for TX state machine event processing in a state centric manner. * * @param[in] event Type of event occurred. */ static void tx_sm_event_handle(tx_event_t event) { uint32_t err_code; switch (m_tx_state) { case TX_STATE_IDLE: if (event == TX_EVENT_STATE_ENTRY) { err_code = app_timer_stop(m_app_timer_id); APP_ERROR_CHECK(err_code); // Send TX-done event if registered handler exists. if (m_transport_tx_done_handle != NULL) { m_transport_tx_done_handle(m_tx_done_result_code); } } break; case TX_STATE_PENDING: if (event == TX_EVENT_SLIP_TX_DONE) { // @note: this call should always succeed as called from HCI_SLIP_TX_DONE context // and error cases are managed by dedicated error event from the slip layer. err_code = hci_slip_write(mp_tx_buffer, (m_tx_buffer_length + PKT_HDR_SIZE + PKT_CRC_SIZE)); APP_ERROR_CHECK(err_code); tx_sm_state_change(TX_STATE_ACTIVE); } break; case TX_STATE_ACTIVE: switch (event) { case TX_EVENT_VALID_RX_ACK: // Tx sequence number counter incremented as packet transmission // acknowledged by peer transport entity. packet_number_tx_inc(); tx_sm_state_change(TX_STATE_IDLE); break; case TX_EVENT_STATE_ENTRY: m_tx_retry_counter = 0; err_code = app_timer_start(m_app_timer_id, RETRANSMISSION_TIMEOUT_IN_TICKS, NULL); APP_ERROR_CHECK(err_code); break; case TX_EVENT_TIMEOUT: if (m_tx_retry_counter != MAX_RETRY_COUNT) { ++m_tx_retry_counter; // @note: no return value check done for hci_slip_write(...) call as current // system design allows use case where retransmission is not accepted by the // slip layer due to existing acknowledgement packet transmission in the // slip layer. UNUSED_VARIABLE(hci_slip_write(mp_tx_buffer, (m_tx_buffer_length + PKT_HDR_SIZE + PKT_CRC_SIZE))); } else { // Application packet retransmission count reached: // - set correct TX done event callback function result code // - execute state change // @note: m_tx_retry_counter is reset in TX_STATE_ACTIVE state entry. m_tx_done_result_code = HCI_TRANSPORT_TX_DONE_FAILURE; tx_sm_state_change(TX_STATE_IDLE); } break; default: break; } break; default: break; } }
/**@brief Function for processing ANTFS upload request data event. * * @param[in] p_event The event extracted from the queue to be processed. */ static void event_upload_request_handle(const antfs_event_return_t * p_event) { uint8_t response = RESPONSE_MESSAGE_OK; if ((p_event->offset == MAX_ULONG)) { // Requesting to resume an upload. if (m_file_index != p_event->file_index) { // We do not have a save point for this file. m_file_offset = 0; m_current_crc = 0; } } else { // This is a new upload. // Use requested offset and reset CRC. m_file_offset = p_event->offset; m_current_crc = 0; } m_file_index = p_event->file_index; // Read file information from directory. if (mem_file_info_get(m_file_index, &m_temp_dir_structure)) { // Check permissions. if (!(m_temp_dir_structure.general_flags & ANTFS_DIR_WRITE_MASK)) { response = RESPONSE_MESSAGE_NOT_AVAILABLE; printf("Upload request denied: file n/a for writing\n"); } // Set response parameters. m_response_info.file_index.data = m_file_index; // Current valid file size is the last offset written to the file. m_response_info.file_size.data = m_file_offset; // Space available for writing is the file size, as specified on directory. m_response_info.max_file_size = m_temp_dir_structure.file_size_in_bytes; // Get the entire file in a single burst if possible. m_response_info.max_burst_block_size.data = m_temp_dir_structure.file_size_in_bytes; // Last valid CRC. m_response_info.file_crc = m_current_crc; } else { // Index not found. response = RESPONSE_MESSAGE_NOT_EXIST; m_response_info.file_index.data = m_file_index; m_response_info.file_size.data = 0; m_response_info.max_file_size = 0; m_response_info.max_burst_block_size.data = 0; m_response_info.file_crc = 0; printf("Upload request denied: file does not exist\n"); } m_upload_success = true; // @note: Suppress return value as no use case for handling it exists. UNUSED_VARIABLE(antfs_upload_req_resp_transmit(response, &m_response_info)); }
/**@brief Function for processing a single ANTFS event. * * @param[in] p_event The event extracted from the queue to be processed. */ static void antfs_event_process(const antfs_event_return_t * p_event) { switch (p_event->event) { case ANTFS_EVENT_OPEN_COMPLETE: printf("ANTFS_EVENT_OPEN_COMPLETE\n"); break; case ANTFS_EVENT_CLOSE_COMPLETE: printf("ANTFS_EVENT_CLOSE_COMPLETE\n"); break; case ANTFS_EVENT_LINK: printf("ANTFS_EVENT_LINK\n"); break; case ANTFS_EVENT_AUTH: printf("ANTFS_EVENT_AUTH\n"); break; case ANTFS_EVENT_TRANS: printf("ANTFS_EVENT_TRANS\n"); break; case ANTFS_EVENT_PAIRING_REQUEST: printf("ANTFS_EVENT_PAIRING_REQUEST\n"); event_pairing_request_handle(); break; case ANTFS_EVENT_PAIRING_TIMEOUT: printf("ANTFS_EVENT_PAIRING_TIMEOUT\n"); break; case ANTFS_EVENT_DOWNLOAD_REQUEST: printf("ANTFS_EVENT_DOWNLOAD_REQUEST\n"); event_download_request_handle(p_event); break; case ANTFS_EVENT_DOWNLOAD_START: printf("ANTFS_EVENT_DOWNLOAD_START\n"); break; case ANTFS_EVENT_DOWNLOAD_REQUEST_DATA: event_download_data_handle(p_event); break; case ANTFS_EVENT_DOWNLOAD_COMPLETE: printf("ANTFS_EVENT_DOWNLOAD_COMPLETE\n"); break; case ANTFS_EVENT_DOWNLOAD_FAIL: printf("ANTFS_EVENT_DOWNLOAD_FAIL\n"); break; case ANTFS_EVENT_UPLOAD_REQUEST: printf("ANTFS_EVENT_UPLOAD_REQUEST\n"); event_upload_request_handle(p_event); break; case ANTFS_EVENT_UPLOAD_START: printf("ANTFS_EVENT_UPLOAD_START\n"); break; case ANTFS_EVENT_UPLOAD_DATA: event_upload_data_handle(p_event); break; case ANTFS_EVENT_UPLOAD_FAIL: printf("ANTFS_EVENT_UPLOAD_FAIL\n"); // @note: Suppress return value as no use case for handling it exists. UNUSED_VARIABLE(antfs_upload_data_resp_transmit(false)); break; case ANTFS_EVENT_UPLOAD_COMPLETE: printf("ANTFS_EVENT_UPLOAD_COMPLETE\n"); event_upload_complete_handle(); break; case ANTFS_EVENT_ERASE_REQUEST: printf("ANTFS_EVENT_ERASE_REQUEST\n"); event_erase_request_handle(p_event); break; default: break; } }
/**@brief Function for decoding a command packet with RPC_SD_BLE_GATTS_HVX opcode. * * This function will decode the command, call the BLE Stack API, and also send command response * to the peer through the the transport layer. * * @param[in] p_command The encoded structure that needs to be decoded and passed on * to the BLE Stack API. * @param[in] command_len The length of the encoded command read from transport layer. * * @retval NRF_SUCCESS If the decoding of the command was successful, the SoftDevice * API was called, and the command response was sent to peer, * otherwise an error code. * @retval NRF_ERROR_INVALID_LENGTH If the content length of the packet is not conforming to the * codec specification. */ static uint32_t gatts_hvx_handle(uint8_t * const p_command, uint32_t command_len) { uint32_t err_code; uint16_t conn_handle; ble_gatts_hvx_params_t hvx_params; uint8_t resp_data[sizeof(uint16_t)]; uint16_t hvx_params_data_length = 0; uint32_t index = 0; ble_gatts_hvx_params_t * p_hvx_params = NULL; conn_handle = uint16_decode(&p_command[index]); index += sizeof(uint16_t); RPC_DECODER_LENGTH_CHECK(command_len, index, SD_BLE_GATTS_HVX); if (p_command[index++] == RPC_BLE_FIELD_PRESENT) { hvx_params.handle = uint16_decode(&p_command[index]); index += sizeof(uint16_t); hvx_params.type = p_command[index++]; hvx_params.offset = uint16_decode(&p_command[index]); index += sizeof(uint16_t); RPC_DECODER_LENGTH_CHECK(command_len, index, SD_BLE_GATTS_HVX); if (p_command[index++] == RPC_BLE_FIELD_PRESENT) { hvx_params_data_length = uint16_decode(&p_command[index]); index += sizeof(uint16_t); hvx_params.p_len = &hvx_params_data_length; } else { hvx_params.p_len = NULL; } RPC_DECODER_LENGTH_CHECK(command_len, (index + hvx_params_data_length), SD_BLE_GATTS_HVX); if (p_command[index++] == RPC_BLE_FIELD_PRESENT) { hvx_params.p_data = &(p_command[index]); } else { hvx_params.p_data = NULL; } p_hvx_params = &hvx_params; } RPC_DECODER_LENGTH_CHECK(command_len, index, SD_BLE_GATTS_HVX); err_code = sd_ble_gatts_hvx(conn_handle, p_hvx_params); if (err_code == NRF_SUCCESS) { if (p_hvx_params != NULL && p_hvx_params->p_len != NULL) { UNUSED_VARIABLE(uint16_encode(*(p_hvx_params->p_len), resp_data)); return ble_rpc_cmd_resp_data_send(SD_BLE_GATTS_HVX, err_code, resp_data, sizeof(resp_data)); } } return ble_rpc_cmd_resp_send(SD_BLE_GATTS_HVX, err_code); }
void BLEonAdvReport(ble_gap_evt_adv_report_t* advReport) { //debug_log("BLECH\r\n"); signed char rssi = advReport->rssi; if (rssi < MINIMUM_RSSI) { return; // ignore signals that are too weak. } unsigned char dataLength = advReport->dlen; unsigned char* data = (unsigned char*)advReport->data; unsigned char index = 0; unsigned char* namePtr = NULL; //unsigned char nameLen = 0; unsigned char* manufDataPtr = NULL; unsigned char manufDataLen = 0; unsigned char group = BAD_GROUP; unsigned short ID = BAD_ID; while ((namePtr == NULL || manufDataPtr == NULL) && index < dataLength) { unsigned char fieldLen = data[index]; index++; unsigned char fieldType = data[index]; if (fieldType == BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME || fieldType == BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME) { namePtr = &data[index + 1]; // skip field type byte //nameLen = fieldLen - 1; } else if (fieldType == BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA) { manufDataPtr = &data[index + 1]; // skip field type byte manufDataLen = fieldLen - 1; } index += fieldLen; } if (manufDataLen == BADGE_MANUF_DATA_LEN) { if (namePtr != NULL && memcmp(namePtr,(const uint8_t *)DEVICE_NAME,strlen(DEVICE_NAME)) == 0) { custom_adv_data_t badgeAdvData; memcpy(&badgeAdvData,&manufDataPtr[2],CUSTOM_ADV_DATA_LEN); // skip past company ID; ensure data is properly aligned ID = badgeAdvData.ID; group = badgeAdvData.group; debug_log("---Badge seen: group %d, ID %.4X, rssi %d.\r\n",(int)group,(int)ID,(int)rssi); } } else if (manufDataLen == IBEACON_MANUF_DATA_LEN) { iBeacon_data_t iBeaconData; memcpy(&iBeaconData,manufDataPtr,IBEACON_MANUF_DATA_LEN); // ensure data is properly aligned if (iBeaconData.companyID == COMPANY_ID_APPLE && iBeaconData.type == IBEACON_TYPE_PROXIMITY) { // major/minor values are big-endian unsigned short major = ((unsigned short)iBeaconData.major[0] * 256) + iBeaconData.major[1]; UNUSED_VARIABLE(major); unsigned short minor = ((unsigned short)iBeaconData.minor[0] * 256) + iBeaconData.minor[1]; debug_log("---iBeacon seen: major %d, minor %d, rssi %d.\r\n",(int)major,minor,(int)rssi); group = iBeaconData.major[1]; // take only lower byte of major value ID = minor; } } if (ID != BAD_ID && group == badgeAssignment.group && scan.num < MAX_SCAN_RESULTS) { bool prevSeen = false; for(int i=0; i<scan.num; i++) { // check through list of already seen badges if(ID == scan.IDs[i]) { scan.rssiSums[i] += rssi; scan.counts[i]++; prevSeen = true; break; } } if(!prevSeen) { // is it a new badge scan.IDs[scan.num] = ID; scan.rssiSums[scan.num] = rssi; scan.counts[scan.num] = 1; scan.num++; } } /* // Parse the broadcast packet. (find+check name, find custom data if present) while ((name == NULL || gotPayload == false) && index < dataLength) { unsigned char fieldLen = data[index]; index++; unsigned char fieldType = data[index]; if (fieldType == BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME || fieldType == BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME) { name = &data[index + 1]; if (memcmp(name,(const uint8_t *)DEVICE_NAME,strlen(DEVICE_NAME)) == 0) { // name checks out } else if (name != NULL && memcmp(name,(const uint8_t *)BEACON_NAME,strlen(BEACON_NAME)) == 0) { payload.group = BEACON_GROUP; // our beacons are named "[BEACON_NAME]XXXX", where XXXX is a hex ID number. payload.ID = hexStringToShort(&name[strlen(BEACON_NAME)]); if (payload.ID != 0xffff) { // was there a valid ID in name? gotPayload = true; } } else { gotPayload = false; break; // if name doesn't match, stop parsing broadcast packet } } else if(fieldType == BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA) { int payloadLen = fieldLen - 3; // length of field minus field type byte and manuf ID word if(payloadLen == CUSTOM_DATA_LEN) { // Need to copy payload data so it is properly aligned. memcpy(&payload,&data[index+3],CUSTOM_DATA_LEN); // skip past field type byte, manuf ID word gotPayload = true; } } index += fieldLen; } if(gotPayload) { // did we see a valid device, and retrieve relevant data? debug_log("---Badge seen: group %d, ID %hX, rssi %d.\r\n",(int)payload.group,payload.ID,(int)rssi); if(payload.group == badgeAssignment.group || payload.group == BEACON_GROUP) { bool prevSeen = false; for(int i=0; i<scan.num; i++) { // check through list of already seen badges if(payload.ID == scan.IDs[i]) { scan.rssiSums[i] += rssi; scan.counts[i]++; prevSeen = true; break; } } if(!prevSeen) { // is it a new badge scan.IDs[scan.num] = payload.ID; scan.rssiSums[scan.num] = rssi; scan.counts[scan.num] = 1; scan.num++; } } } */ /* // step through data until we find both the name and custom data, or have reached the end of the data while ((gotPayload == false || name == NULL) && index < dataLength) { unsigned char fieldLen = data[index]; index++; unsigned char fieldType = data[index]; if(fieldType == BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME || fieldType == BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME) { name = &data[index+1]; } else if(fieldType == BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA) { payloadLen = fieldLen - 3; // length of field minus field type byte and manuf ID word if(payloadLen == CUSTOM_DATA_LEN) { // Need to copy payload data so it is properly aligned. memcpy(&payload,&data[index+3],CUSTOM_DATA_LEN); // skip past field type byte, manuf ID word gotPayload = true; } } index += fieldLen; } if(name != NULL && memcmp(name,(const uint8_t *)DEVICE_NAME,strlen(DEVICE_NAME)) == 0) { // is it a badge? if(gotPayload) { // is there custom data, and the correct amount? //debug_log("Badge seen: group %d, ID %hX, rssi %d.\r\n",(int)payload.group,payload.ID,(int)rssi); if(payload.group == badgeAssignment.group) { bool prevSeen = false; for(int i=0; i<scan.num; i++) { // check through list of already seen badges if(payload.ID == scan.IDs[i]) { scan.rssiSums[i] += rssi; scan.counts[i]++; prevSeen = true; break; } } if(!prevSeen) { // is it a new badge scan.IDs[scan.num] = payload.ID; scan.rssiSums[scan.num] = rssi; scan.counts[scan.num] = 1; scan.num++; } } } else { //debug_log("Badge seen, rssi %d, but wrong/missing adv data, len %d?\r\n",(int)rssi,payloadLen); } } else if (name != NULL && memcmp(name,(const uint8_t *)BEACON_NAME,strlen(BEACON_NAME)) == 0) { // beacons are named [BEACON_NAME]XXXX, where XXXX is a hex ID number. unsigned short beaconID = hexStringToShort(&name[strlen(BEACON_NAME)]); } else { //debug_log("Unknown device seen, name %.5s, rssi %d.\r\n",name,(int)rssi); } */ }
/* * 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; } }
/**@brief Function for processing ANTFS upload request data event. * * @param[in] p_event The event extracted from the queue to be processed. */ static void antfs_event_upload_request_handle(const antfs_event_return_t * p_event) { uint32_t err_code = RESPONSE_MESSAGE_OK; uint8_t new_request = false; if ((m_antfs_dfu_state == ANTFS_DFU_STATE_FLASH_ERASE) || (m_antfs_dfu_state == ANTFS_DFU_STATE_FLASH_PENDING)) { return; } /*reset*/ m_response_info.file_index.data = p_event->file_index; m_response_info.max_burst_block_size.data = 0; m_response_info.max_file_size = 0; m_response_info.file_size.data = 0; m_response_info.file_crc = 0; // Evaluate File Index first if (m_current_file_index != p_event->file_index ) { m_current_file_index = p_event->file_index; m_current_offset = 0; m_current_crc = 0; } if (p_event->offset == MAX_ULONG) { // This is a request to continue upload. } else if (p_event->offset == 0x00) { new_request = true; } else if(p_event->offset != m_current_offset) { // Something is wrong. UNUSED_VARIABLE(antfs_upload_req_resp_transmit(RESPONSE_INVALID_OPERATION, &m_response_info)); m_antfs_dfu_state = ANTFS_DFU_STATE_STALL; } else { // no implementation. } switch (m_current_file_index) { #if !defined (S210_V3_STACK) case ANTFS_FILE_INDEX_UPDATE_STACK: case ANTFS_FILE_INDEX_UPDATE_BOOTLOADER: case ANTFS_FILE_INDEX_UPDATE_STACK_BOOTLOADER: #endif // S210_V3_STACK case ANTFS_FILE_INDEX_UPDATE_APPLICATION: { // Current valid file size is the last offset written to the file. m_response_info.file_size.data = m_current_offset; // Intentionally report maximum allowed upload file size as max writeable file size + header and crc. // Writeable size check will be performed by dfu_start_pkt_handle() after parsing uploaded header m_response_info.max_file_size = ANTFS_FILE_SIZE_MAX_DFU_IMAGE + OTA_IMAGE_HEADER_SIZE_MAX; // Maximum burst block should be maximum allowable downloadable file size. m_response_info.max_burst_block_size.data = ANTFS_FILE_SIZE_MAX_DFU_IMAGE + OTA_IMAGE_HEADER_SIZE_MAX; // Last valid CRC. m_response_info.file_crc = m_current_crc; // Will only handle upload request while at ANTFS_DFU_STATE_READY if (m_antfs_dfu_state == ANTFS_DFU_STATE_VALIDATED) { if (new_request) { UNUSED_VARIABLE(antfs_upload_req_resp_transmit(RESPONSE_MESSAGE_NOT_AVAILABLE, &m_response_info)); } else { UNUSED_VARIABLE(antfs_upload_req_resp_transmit(RESPONSE_MESSAGE_OK, &m_response_info)); // To handle resume at end of data. } return; } else if (m_antfs_dfu_state != ANTFS_DFU_STATE_READY) { UNUSED_VARIABLE(antfs_upload_req_resp_transmit(RESPONSE_MESSAGE_NOT_AVAILABLE, &m_response_info)); return; } // Check File Size if it can still fit. Uploaded file size may be larger than the total writeable space because it includes header // and CRC that do not get written to flash. Writeable size check will be performed by dfu_start_pk_handle() after // parsing uploaded header if ((p_event->offset + p_event->bytes) > (ANTFS_FILE_SIZE_MAX_DFU_IMAGE + OTA_IMAGE_HEADER_SIZE_MAX + OTA_IMAGE_CRC_SIZE_MAX)) { UNUSED_VARIABLE(antfs_upload_req_resp_transmit(RESPONSE_MESSAGE_NOT_ENOUGH_SPACE, &m_response_info)); return; } m_data_buffered = 0; if (new_request) { m_current_offset = 0; m_current_crc = 0; m_pending_offset = 0; antfs_ota_init(); // Only supports offset starting at 0; if (p_event->offset != 0) { UNUSED_VARIABLE(antfs_upload_req_resp_transmit(RESPONSE_MESSAGE_FAIL, &m_response_info)); return; } // boot_return_set(PARAM_RETURN_BOOT_STATUS_Entered); // Store file size, m_current_file_size = p_event->bytes; if (m_current_file_index == ANTFS_FILE_INDEX_UPDATE_STACK) { m_update_mode = DFU_UPDATE_SD; } else if (m_current_file_index == ANTFS_FILE_INDEX_UPDATE_BOOTLOADER) { m_update_mode = DFU_UPDATE_BL; } else if (m_current_file_index == ANTFS_FILE_INDEX_UPDATE_APPLICATION) { m_update_mode = DFU_UPDATE_APP; } else if (m_current_file_index == ANTFS_FILE_INDEX_UPDATE_STACK_BOOTLOADER) { m_update_mode = DFU_UPDATE_SD; m_update_mode |= DFU_UPDATE_BL;//lint !e655 suppress Lint Warning 655: Bit-wise operations } m_dfu_pkt.packet_type = INIT_PACKET; if ((*ANT_BOOT_APP_SIZE > DFU_IMAGE_MAX_SIZE_BANKED) || (*ANT_BOOT_APP_SIZE == 0xFFFFFFFF) || (*ANT_BOOT_APP_SIZE == 0x00000000) || (m_update_mode & DFU_UPDATE_SD))/*lint !e655 suppress Lint Warning 655: Bit-wise operations*/ { m_dfu_pkt.params.init_packet.total_image_size = DFU_IMAGE_MAX_SIZE_FULL; } else { m_dfu_pkt.params.init_packet.total_image_size = m_current_file_size; } if (m_upload_swap_space_prepared == true) { // Prepare no flash, except the states m_dfu_pkt.params.init_packet.total_image_size = 0; } err_code = dfu_init_pkt_handle(&m_dfu_pkt); if (err_code) { if (err_code == NRF_ERROR_INVALID_STATE) { UNUSED_VARIABLE(antfs_upload_req_resp_transmit(RESPONSE_INVALID_OPERATION, &m_response_info)); } else { UNUSED_VARIABLE(antfs_upload_req_resp_transmit(RESPONSE_MESSAGE_FAIL, &m_response_info)); } return; } m_ota_image_header_parsed = false; m_image_data_complete = false; m_image_data_offset = 0; m_data_buffered = 0; // A flash erase is expected at this time. postpone response if there is. if (flash_busy()) { m_upload_request_in_progress = true; m_antfs_dfu_state = ANTFS_DFU_STATE_FLASH_ERASE; return; } } else { // Check if there are still pending writes scheduled in Flash. if (flash_busy()) { m_upload_request_in_progress = true; m_antfs_dfu_state = ANTFS_DFU_STATE_FLASH_PENDING; return; } } m_antfs_dfu_state = ANTFS_DFU_STATE_READY; UNUSED_VARIABLE(antfs_upload_req_resp_transmit(RESPONSE_MESSAGE_OK, &m_response_info)); } break; default: m_antfs_dfu_state = ANTFS_DFU_STATE_READY; UNUSED_VARIABLE(antfs_upload_req_resp_transmit(RESPONSE_MESSAGE_NOT_EXIST, &m_response_info)); } }
static void upload_data_response_fail_reset(void) { UNUSED_VARIABLE(antfs_upload_data_resp_transmit(false)); m_antfs_dfu_state = ANTFS_DFU_STATE_STALL; }
/**@brief Function for updating the wall clock of the IoT Timer module. */ static void iot_timer_tick_callback(void * p_context) { UNUSED_VARIABLE(p_context); uint32_t err_code = iot_timer_update(); APP_ERROR_CHECK(err_code); }
void storer_init() { storerMode = STORER_INIT; store.from = 0; store.to = 0; debug_log("-storer initialization-\r\n"); unsigned long lastStoredTime = MODERN_TIME; for (int c = 0; c <= LAST_FLASH_CHUNK; c++) { mic_chunk_t* chunkPtr = (mic_chunk_t*)ADDRESS_OF_CHUNK(c); unsigned long timestamp = chunkPtr->timestamp; unsigned long check = chunkPtr->check; //is the timestamp possibly valid? if (timestamp < FUTURE_TIME && timestamp > MODERN_TIME) { //is it a completely stored chunk? if (timestamp == check || check == CHECK_TRUNC) { //is it later than the latest stored one found so far? if (timestamp > lastStoredTime) { store.to = c; //keep track of latest stored chunk lastStoredTime = timestamp; } } } } if (lastStoredTime == MODERN_TIME) { // no valid chunk found debug_log(" No stored chunks found. Will start from chunk 0.\r\n"); store.to = LAST_FLASH_CHUNK; // will advance to chunk 0 below. } else { debug_log(" Last stored chunk: %d at time: 0x%lX\r\n", store.to, lastStoredTime); //printStorerChunk(store.to); } debug_log(" Initializing FLASH for storage...\r\n"); int newChunk = (store.to < LAST_FLASH_CHUNK) ? store.to+1 : 0; // next chunk in FLASH (first unused chunk) unsigned char oldPage = PAGE_OF_CHUNK(store.to); unsigned char newPage = PAGE_OF_CHUNK(newChunk); // If new chunk is on a new page, we can just erase the whole page. if (oldPage != newPage) { debug_log(" erase pg%d.\r\n",(int)newPage); nrf_delay_ms(20); erasePageOfFlash(newPage); while(flashWorking); } // If new chunk is on same page as old data, we need to erase while preserving the old data else { uint32_t* oldChunkAddr = ADDRESS_OF_CHUNK(store.to); // address of latest stored data uint32_t* pageAddr = ADDRESS_OF_PAGE(newPage); // address of beginning of current page int bytesToErase = (int)(oldChunkAddr) - (int)(pageAddr); // how many bytes of current page we need to erase int chunksToSave = (BYTES_PER_PAGE - bytesToErase)/CHUNK_SIZE; // how many old chunks are in this page UNUSED_VARIABLE(chunksToSave); debug_log(" pg%d (%d chunks)-->RAM...", newPage, chunksToSave); uint32_t temp[WORDS_PER_PAGE]; // temporary buffer for page memcpy(temp, pageAddr, BYTES_PER_PAGE); // copy old data to buffer debug_log("clear %dbytes...", bytesToErase); memset(temp, 0xff, bytesToErase); // clear unused portion of page in buffer debug_log("erase pg%d...",(int)newPage); nrf_delay_ms(20); erasePageOfFlash(newPage); // erase page while(flashWorking); debug_log("restore data...\r\n"); nrf_delay_ms(10); writeBlockToFlash(pageAddr, temp, WORDS_PER_PAGE); // replace data from buffer while(flashWorking); } store.to = newChunk; debug_log(" Ready to store to chunk %d.\r\n",newChunk); store.extFrom = 0; // We need to find the most recent stored chunk, to start storing after it scan_header_t header; scan_tail_t tail; ext_eeprom_wait(); store.extTo = EXT_FIRST_DATA_CHUNK; unsigned long lastStoredTimestamp = 0; for (int i = EXT_FIRST_DATA_CHUNK; i <= EXT_LAST_CHUNK; i++) { unsigned int addr = EXT_ADDRESS_OF_CHUNK(i); ext_eeprom_read(addr,header.buf,sizeof(header.buf)); // Beginning of the chunk ext_eeprom_wait(); ext_eeprom_read(addr+EXT_CHUNK_SIZE-4,tail.buf,sizeof(tail.buf)); // End of the chunk ext_eeprom_wait(); // Print all written chunks /*if(header.timestamp != 0xFFFFFFFFUL) { debug_log("CH: %d,TS: %X\r\n",i,(int)header.timestamp); nrf_delay_ms(2); } */ // is it a completely stored scan result chunk? if (header.timestamp > MODERN_TIME && header.timestamp < FUTURE_TIME) { if (tail.check == header.timestamp || tail.check == CHECK_TRUNC || tail.check == CHECK_CONTINUE) { // is it the most recent one found yet? if (header.timestamp >= lastStoredTimestamp) { lastStoredTimestamp = header.timestamp; store.extTo = i; } } } } if (lastStoredTimestamp == 0) { debug_log(" No stored scans found.\r\n"); } else { debug_log(" Last stored scan in chunk %d, timestamp %X.\r\n",(int)store.extTo,(int)lastStoredTimestamp); } store.extTo = (store.extTo < EXT_LAST_CHUNK) ? store.extTo+1 : EXT_FIRST_DATA_CHUNK; //store.extFrom = 0; //store.extTo = EXT_FIRST_DATA_CHUNK; ext_eeprom_global_unprotect(); ext_eeprom_wait(); storerMode = STORER_IDLE; }
double StairSpiked::GetHumanStep(int nHumanDirection) { UNUSED_VARIABLE(nHumanDirection); return 1; }
/**@brief Timer callback used for periodic servicing of LwIP protocol timers. * This trigger is also used in the example to trigger sending UDP packets on the port. * * @details Timer callback used for periodic servicing of LwIP protocol timers. * * @param[in] p_context Pointer used for passing context. No context used in this application. */ static void system_timer_callback(iot_timer_time_in_ms_t wall_clock_value) { UNUSED_VARIABLE(wall_clock_value); sys_check_timeouts(); }