/** **************************************************************************************** * @brief Handles GAPC command completion events. * * @param[in] msgid Id of the message received. * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (TASK_GAP). * @param[in] src_id ID of the sending task instance. * * @return If the message was consumed or not. **************************************************************************************** */ int gapc_cmp_evt_handler(ke_msg_id_t msgid, struct gapc_cmp_evt *param, ke_task_id_t dest_id, ke_task_id_t src_id) { switch (param->operation) { case GAPC_ENCRYPT: if (param->status != CO_ERROR_NO_ERROR) { app_env.peer_device.bonded = 0; app_disconnect(); } break; case GAPC_DISCONNECT: if (app_env.state == APP_DISCONNECTING) { printf("app_exit() after GAPC_DISCONNECT_CMD completion\n"); app_exit(); } default: break; } return 0; }
/** **************************************************************************************** * @brief Handle Bond indication. * * @param[in] msgid Id of the message received. * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (TASK_GAP). * @param[in] src_id ID of the sending task instance. * * @return If the message was consumed or not. **************************************************************************************** */ int gap_bond_ind_handler(ke_msg_id_t msgid, struct gapc_bond_ind *param, ke_task_id_t dest_id, ke_task_id_t src_id) { switch (param->info) { case GAPC_PAIRING_SUCCEED: if (param->data.auth | GAP_AUTH_BOND) app_env.peer_device.bonded = 1; // discover spota service app_env.peer_device.spota.svc_found = 0; app_env.peer_device.spota.svc_start_handle = 0; app_env.peer_device.spota.svc_end_handle = 0; app_env.peer_device.spota.mem_dev_handle = 0; app_env.peer_device.spota.gpio_map_handle = 0; app_env.peer_device.spota.mem_info_handle = 0; app_env.peer_device.spota.patch_len_handle = 0; app_env.peer_device.spota.patch_data_handle = 0; app_env.peer_device.spota.serv_status_handle = 0; app_env.peer_device.spota.serv_status_cli_char_cfg_desc_handle = 0; app_discover_svc_by_uuid_16(app_env.peer_device.device.conidx, SPOTA_PRIMARY_SERVICE_UUID); break; case GAPC_IRK_EXCH: memcpy (app_env.peer_device.irk.irk.key, param->data.irk.irk.key, KEY_LEN); memcpy (app_env.peer_device.irk.addr.addr.addr, param->data.irk.addr.addr.addr, KEY_LEN); app_env.peer_device.irk.addr.addr_type = param->data.irk.addr.addr_type; break; case GAPC_LTK_EXCH: app_env.peer_device.ediv = param->data.ltk.ediv; memcpy (app_env.peer_device.rand_nb, param->data.ltk.randnb.nb, RAND_NB_LEN); app_env.peer_device.ltk.key_size = param->data.ltk.key_size; memcpy (app_env.peer_device.ltk.ltk.key, param->data.ltk.ltk.key, param->data.ltk.key_size); app_env.peer_device.ltk.ediv = param->data.ltk.ediv; memcpy (app_env.peer_device.ltk.randnb.nb, param->data.ltk.randnb.nb, RAND_NB_LEN); break; case GAPC_PAIRING_FAILED: printf("Pairing failed. Aborting...\n"); app_env.peer_device.bonded = 0; app_disconnect(); break; } return 0; }
int streamdatah_enable_cfm_handler(ke_msg_id_t const msgid, struct streamdatah_enable_cfm const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { if (param->status != PRF_ERR_OK) app_disconnect(); min_hdl = param->streamdatah.chars[STREAMDATAH_D0_CHAR].val_hdl; max_hdl = param->streamdatah.chars[STREAMDATAH_D9_CHAR].val_hdl; return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of encrypt request command * * @param[in] msgid Id of the message received. * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (TASK_GAP). * @param[in] src_id ID of the sending task instance. * * @return If the message was consumed or not. **************************************************************************************** */ int gapc_encrypt_req_ind_handler(ke_msg_id_t const msgid, struct gapc_encrypt_req_ind *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { struct gapc_encrypt_cfm* cfm = KE_MSG_ALLOC(GAPC_ENCRYPT_CFM, src_id, dest_id, gapc_encrypt_cfm); if (!app_validate_encrypt_req_func(param)) { cfm->found = false; } else { if(((app_sec_env.auth & GAP_AUTH_BOND) != 0) && (memcmp(&(app_sec_env.rand_nb), &(param->rand_nb), RAND_NB_LEN) == 0) && (app_sec_env.ediv == param->ediv)) { cfm->found = true; cfm->key_size = app_sec_env.key_size; memcpy(&(cfm->ltk), &(app_sec_env.ltk), KEY_LEN); // update connection auth app_connect_confirm(app_sec_env.auth); app_sec_encrypt_complete_func(); } else { cfm->found = false; } } ke_msg_send(cfm); if (cfm->found == false) app_disconnect(); return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles reception of bond indication * * @param[in] msgid Id of the message received. * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (TASK_GAP). * @param[in] src_id ID of the sending task instance. * * @return If the message was consumed or not. **************************************************************************************** */ int gapc_bond_ind_handler(ke_msg_id_t const msgid, struct gapc_bond_ind *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { switch(param->info) { // Bond Pairing request case GAPC_PAIRING_SUCCEED: { // Save Authentication level app_sec_env.auth = param->data.auth; if (app_sec_env.auth & GAP_AUTH_BOND) { app_sec_env.peer_addr_type = app_env.peer_addr_type; memcpy(app_sec_env.peer_addr.addr, app_env.peer_addr.addr, BD_ADDR_LEN); } app_paired_func(); } break; case GAPC_PAIRING_FAILED: { // disconnect app_disconnect(); // clear bond data. app_sec_env.auth = 0; } break; case (GAPC_LTK_EXCH): { // app_store_ltk_func(); } break; case (GAPC_IRK_EXCH): { // app_store_irk_func(); } break; case (GAPC_CSRK_EXCH): { // app_store_csrk_func(); } break; default: { ASSERT_ERR(0); } break; } return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Handles GATTC command completion event. * * @param[in] msgid Id of the message received. * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (TASK_GAP). * @param[in] src_id ID of the sending task instance. * * @return If the message was consumed or not. **************************************************************************************** */ int gattc_cmp_evt_handler(ke_msg_id_t msgid, struct gattc_cmp_evt *param, ke_task_id_t dest_id, ke_task_id_t src_id) { switch(param->req_type) { case GATTC_DISC_BY_UUID_SVC: if(param->status != CO_ERROR_NO_ERROR && param->status != ATT_ERR_ATTRIBUTE_NOT_FOUND ) { printf("Error while trying to discover SPOTA service by UUID (status = 0x%02X) \n", param->status); // disconnect app_env.state = APP_DISCONNECTING; app_disconnect(); } else { if (app_env.peer_device.spota.svc_found != 1) { printf("Peer device does not support the SPOTA service \n"); // disconnect app_env.state = APP_DISCONNECTING; app_disconnect(); } else { // SPOTA service was discovered. Now discover SPOTA characteristics. app_discover_all_char( KE_IDX_GET(src_id), app_env.peer_device.spota.svc_start_handle, app_env.peer_device.spota.svc_end_handle); } }; break; case GATTC_DISC_ALL_CHAR: if(param->status != CO_ERROR_NO_ERROR && param->status != ATT_ERR_ATTRIBUTE_NOT_FOUND ) { printf("Error while trying to discover SPOTA service characteristics (status = 0x%02X) \n", param->status); // disconnect app_env.state = APP_DISCONNECTING; app_disconnect(); } else if ( app_env.peer_device.spota.mem_dev_handle == 0 || app_env.peer_device.spota.gpio_map_handle == 0 || app_env.peer_device.spota.mem_info_handle == 0 || app_env.peer_device.spota.patch_len_handle == 0 || app_env.peer_device.spota.patch_data_handle == 0 || app_env.peer_device.spota.serv_status_handle == 0 ) { printf("Error: Missing characteristics in peer device's SPOTA service.\n"); // disconnect app_env.state = APP_DISCONNECTING; app_disconnect(); } else { // trigger next step - discover SPOTA_SERV_STATUS Client char descriptor app_discover_char_desc(KE_IDX_GET(src_id), app_env.peer_device.spota.serv_status_handle, app_env.peer_device.spota.svc_end_handle); } break; case GATTC_DISC_DESC_CHAR: if(param->status != CO_ERROR_NO_ERROR && param->status != ATT_ERR_ATTRIBUTE_NOT_FOUND ) { printf("Error while trying to discover SPOTA_SERV_STATUS characteristic descriptors (status = 0x%02X) \n", param->status); // disconnect app_env.state = APP_DISCONNECTING; app_disconnect(); } else if ( app_env.peer_device.spota.serv_status_cli_char_cfg_desc_handle == 0 ) { printf("Error: Missing Client Char. Conf. descriptor for SPOTA_SERV_STATUS characteristic.\n"); // disconnect app_env.state = APP_DISCONNECTING; app_disconnect(); } else { // trigger next step - enable SPOTA_SERV_STATUS notifications uint8_t v[2]; app_env.state = APP_EN_SERV_STATUS_NOTIFICATIONS; v[1] = 0x00; v[0] = 0x01; app_characteristic_write(KE_IDX_GET(src_id), app_env.peer_device.spota.serv_status_cli_char_cfg_desc_handle, v, 2); } break; case GATTC_WRITE: case GATTC_WRITE_NO_RESPONSE: if(param->status != CO_ERROR_NO_ERROR) // write characteristic command failed { printf("error: failed to write a characteristic (status=0x%02X). Aborting... \n", param->status); // disconnect app_env.state = APP_DISCONNECTING; app_disconnect(); } else if (app_env.state == APP_EN_SERV_STATUS_NOTIFICATIONS) // write to SPOTA_SERV_STATUS Client Char. Conf. descriptor completed successfully { // trigger next step - write to SPOTA_MEM_DEV app_suota_write_mem_dev(); } else if (app_env.state == APP_WR_MEM_DEV) // write SPOTA_MEM_DEV completed successfully { // nothing to do - wait for notification on SPOTA_SERV_STATUS } else if (app_env.state == APP_WR_GPIO_MAP) // write SPOTA_GPIO_MAP completed successfully { // trigger next step - read spota_mem_info operation app_env.state = APP_RD_MEM_INFO; app_characteristic_read(KE_IDX_GET(src_id), app_env.peer_device.spota.mem_info_handle); } else if (app_env.state == APP_WR_PATCH_LEN) // write SPOTA_PATCH_LEN completed successfully { // init 1st chunk of block patch_chunck_offset = 0; // offset in block patch_chunck_length = (block_length - patch_chunck_offset) > 20 ? 20: (block_length - patch_chunck_offset); // // trigger next step - write SPOTA_PATCH_DATA // app_suota_write_chunks(); } else if (app_env.state == APP_WR_PATCH_DATA) // write SPOTA_PATCH_DATA completed successfully { // sanity check - should necer happen if (expected_write_completion_events_counter <= 0 ) { printf("Fatal error. Unexpected write completion \n"); // disconnect app_env.state = APP_DISCONNECTING; app_disconnect(); return 0; } --expected_write_completion_events_counter; // decrement expected write completions } case GATTC_READ: if(param->status != CO_ERROR_NO_ERROR) // read characteristic command failed { printf("error: failed to read a characteristic. Aborting... \n"); // disconnect app_env.state = APP_DISCONNECTING; app_disconnect(); } else if (app_env.state == APP_RD_MEM_INFO) // read SPOTA_MEM_INFO completed successfully { uint32_t mem_info = (app_env.peer_device.spota.mem_info_value[3] << 24) | (app_env.peer_device.spota.mem_info_value[2] << 16) | (app_env.peer_device.spota.mem_info_value[1] << 8) | (app_env.peer_device.spota.mem_info_value[0]) ; printf("Memory Information: 0x%08X \n", mem_info); // // trigger next step - write SPOTA_PATCH_LEN of 1st block // // initialize block offset to point to the start of image block_offset = 0; block_length = (patch_length - block_offset) > suota_block_size ? suota_block_size : (patch_length - block_offset); app_suota_write_patch_len(block_length); print_time(); } else if (app_env.state == APP_RD_MEM_INFO_2) // read SPOTA_MEM_INFO completed successfully { uint32_t mem_info = (app_env.peer_device.spota.mem_info_value[3] << 24) | (app_env.peer_device.spota.mem_info_value[2] << 16) | (app_env.peer_device.spota.mem_info_value[1] << 8) | (app_env.peer_device.spota.mem_info_value[0]) ; printf("Memory Information: 0x%08X \n", mem_info); // // trigger next step - send END OF SUOTA // app_suota_end(); } break; default: break; } return 0; }
/** **************************************************************************************** * @brief Handles GATTC_EVENT_IND event. * * @param[in] msgid Id of the message received. * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (TASK_GAP). * @param[in] src_id ID of the sending task instance. * * @return If the message was consumed or not. **************************************************************************************** */ int gattc_event_ind_handler(ke_msg_id_t msgid, struct gattc_event_ind *param, ke_task_id_t dest_id, ke_task_id_t src_id) { // handle notifications from SPOTA_SERV_STATUS only if(param->handle != app_env.peer_device.spota.serv_status_handle) { return 0; } // retrieve notification value app_env.peer_device.spota.serv_status_value = param->value[0]; if (app_env.state == APP_WR_MEM_DEV) { // check if write SPOTA_MEM_DEV completed successfully if (app_env.peer_device.spota.serv_status_value != SPOTA_STATUS_IMG_STARTED) { printf("error: SPOTA_SERV_STATUS = 0x%02X after writing to SPOTA_MEM_DEV\n", app_env.peer_device.spota.serv_status_value); // disconnect app_env.state = APP_DISCONNECTING; app_disconnect(); return 0; // in order to exit this function immediately } // trigger next step - write SPOTA_GPIO_MAP app_suota_write_gpio_map(); } else if (app_env.state == APP_WR_PATCH_DATA) // handle the notification only after the last chunk has been written { // check SPOTA_SERV_STATUS if (app_env.peer_device.spota.serv_status_value != SPOTA_STATUS_CMP_OK) { printf("Error: SPOTA_SERV_STATUS = 0x%02X after writing block \n", app_env.peer_device.spota.serv_status_value); // disconnect app_env.state = APP_DISCONNECTING; app_disconnect(); return 0; // in order to exit this function immediately } if(is_last_block()) { // no more blocks to write // trigger next step - read SPOTA_MEM_INFO (the 2nd time) app_env.state = APP_RD_MEM_INFO_2; app_characteristic_read(KE_IDX_GET(src_id), app_env.peer_device.spota.mem_info_handle); } else { // advance to the next block next_block(); if( is_last_block() ) // we may need a different block length for the last block { // trigger next step - write SPOTA_PATCH_LEN for last block app_suota_write_patch_len(block_length); } else { // trigger next step - start writing the block chunks app_suota_write_chunks(); } } } else if (app_env.state == APP_WR_END_OF_SUOTA) // handle the notification after the end of SUOTA command has been issued { // check SPOTA_SERV_STATUS if (app_env.peer_device.spota.serv_status_value != SPOTA_STATUS_CMP_OK) { printf("error: SPOTA_SERV_STATUS = 0x%02X after sending END OF SUOTA \n", app_env.peer_device.spota.serv_status_value); // disconnect app_env.state = APP_DISCONNECTING; app_disconnect(); return 0; // in order to exit this function immediately } // no more blocks to write - SUOTA procedure completed successfully printf("\nSUOTA procedure completed successfully \n\n"); print_time(); // send boot command - the receiver will reboot when it receives this command // the connection is expected to be lost { void app_suota_reboot(void); app_suota_reboot(); } // trigger next step - disconnect app_env.state = APP_DISCONNECTING; app_disconnect(); } else { // no handling of notifications in the rest of the states /// printf(" SPOTA_SERV_STATUS = 0x%02X app_env.state = %d\n", app_env.peer_device.spota.serv_status_value, app_env.state ); } return 0; }