/*----------------------------------------------* * 包含头文件 * *----------------------------------------------*/ #include "FreeRTOS.h" #include "task.h" #include "timers.h" #include "am_util_debug.h" #include "amotas_api.h" #include "sys_config.h" #include "ble_ota_execute.h" #include "ble_data_transmission.h" #include "ble_ota_server.h" #include "ble_management_server.h" #include "task_ble.h" //#include "task_ui.h" #define ENABLE_STATIC_PRINT false extern uint32_t am_util_stdio_printf(const char *pcFmt, ...); #define static_print_remind(...) am_util_stdio_printf(__VA_ARGS__) #if ENABLE_STATIC_PRINT #define static_print_info(...) am_util_stdio_printf(__VA_ARGS__) #else #define static_print_info(...) #endif #define VERIFY_SUCCESS 0 #define VERIFY_FAIL 1 #define APP_STARTOTA 0 #define DEVICE_STARTOTA 1 /*----------------------------------------------* * 模块级变量 * *----------------------------------------------*/ ota_fw_info_t g_ota_fw_info; // 固件实时信息 extern void close_low_power_conn_timer(void); extern void amotas_send_data(uint8_t *buf, uint16_t len); extern void user_update_percent_show(uint8_t percent); void DeviceRequestOTAFileData(uint32_t offset,uint16_t DataLen,uint32_t TotalFileSise,uint32_t ReceivedFileSize); void DeviceNoticeOTAFileReceivedSuccess(void); void DeviceNoticeOTAProcessUpdate(uint8_t FileVerifyResult,uint8_t OTAStartMode); void DeviceOTAErrReport(uint16_t OtaErrorResult); /***************************************************************************** 4.12.1 询问是否可以进入OTA 模式 *****************************************************************************/ void UserCheckIFOtaMode(uint8_t *in_data,uint16_t in_len,uint8_t *out_data,uint16_t *out_len) { uint16_t CurrentMTUSize; uint16_t write_idx = 0; uint8_t otaStatus = 1; protocol_data_info_t data_info = {0}; if(OtaIsStarted()) return; data_info.error = FENDA_SUCCESS; do { user_get_data_info(&data_info,&in_data,&in_len); switch((data_info.type & 0x7F)) { case PackageVersionType: if(data_info.len <= FILE_NAME_LENGTH_MAX) { memcpy(g_ota_fw_info.OtaFileName, data_info.p_data, data_info.len); static_print_remind("OTA Received PackageFileName:%s.\r\n",g_ota_fw_info.OtaFileName); } else { data_info.error = DEVICE_FW_OTA_ERROR; } break; case FileLenghtType: if(data_info.len==4) { g_ota_fw_info.OtaFlieLenFromAPP |= (*data_info.p_data++)<<24; // APP下发的固件数据长度 g_ota_fw_info.OtaFlieLenFromAPP |= (*data_info.p_data++)<<16; g_ota_fw_info.OtaFlieLenFromAPP |= (*data_info.p_data++)<<8; g_ota_fw_info.OtaFlieLenFromAPP |= *data_info.p_data++; static_print_remind("OTA Received File Length:%x.\r\n",g_ota_fw_info.OtaFlieLenFromAPP); } break; case OtaModelType: if(data_info.len==1) { g_ota_fw_info.OtaWorkMode = *data_info.p_data++; if(g_ota_fw_info.OtaWorkMode) {//只支持前台模式 data_info.error = DEVICE_FORBIT_OTA_ERROR; } } break; default: // data_info.error=PARAM_ERROR; // in_len=0; break; } in_data+=(data_info.len); in_len-=(2+data_info.len); if(in_len>FRAM_MAX_SIZ) { in_len=0; } } while(in_len); otaStatus = OtaRequest(g_ota_fw_info.OtaFlieLenFromAPP); if(data_info.error) { write_idx=user_set_protocol_error(out_data,OTA_SERVER,data_info.error); } else { out_data[write_idx++]=3; out_data[write_idx++]=OtaStatusType; out_data[write_idx++]=otaStatus; out_data[write_idx++]=3; out_data[write_idx++]=BatteryThresholdType; out_data[write_idx++]=OTA_BATT_THRESHOLD; out_data[write_idx++]=4; out_data[write_idx++]=AppWaitTimeOutType; out_data[write_idx++]=APP_WAIT_TIME_MAX/0x100; out_data[write_idx++]=APP_WAIT_TIME_MAX%0x100; out_data[write_idx++]=4; out_data[write_idx++]=OtaMTUSizeType; CurrentMTUSize = user_app_mtu_get(); out_data[write_idx++]=CurrentMTUSize/0x100; out_data[write_idx++]=CurrentMTUSize%0x100; } *out_len=write_idx; } /***************************************************************************** 4.12.2 APP 通知设备升级状态 *****************************************************************************/ void UserNoticOtaStatus(uint8_t *in_data,uint16_t in_len,uint8_t *out_data,uint16_t *out_len) { uint16_t write_idx=0; protocol_data_info_t data_info = {0}; OtaTimeoutReset(); if(in_len) { do { user_get_data_info(&data_info,&in_data,&in_len); switch((data_info.type & 0x7F)) { case AppOtaStatusType: g_ota_fw_info.AppOtaStatus = *data_info.p_data; break; default: // data_info.error=PARAM_ERROR; // in_len=0; break; } in_data= data_info.p_data; in_data+=(data_info.len); in_len-=(2+data_info.len); if(in_len>FRAM_MAX_SIZ) { in_len=0; } } while(in_len); } if((g_ota_fw_info.AppOtaStatus==0) && (g_ota_fw_info.DeviceOtaStatus==0)) { //开始正式升级 static_print_remind("OTA start\n"); OtaStart(); close_low_power_conn_timer(); change_ble_task_priority(); amota_conn_param_update(CONN_PARAM_OTA); // 使用OTA连接参数 /* 由于此时还未申请固件信息,使用APP下发的固件数据长度 */ DeviceRequestOTAFileData(0, FW_HEAD_INFO_IEN, g_ota_fw_info.OtaFlieLenFromAPP, 0); } *out_len=write_idx; } /***************************************************************************** 4.12.3 设备根据文件信息分帧请求文件内容 *****************************************************************************/ void DeviceRequestOTAFileData(uint32_t offset,uint16_t DataLen,uint32_t TotalFileSise,uint32_t ReceivedFileSize) { Ltv_t ltvArray[4] = {0}; FrameInfo_t frameInfo; ltvArray[0].len = 6; ltvArray[0].type = OtaFileOffsetType; ltvArray[0].value = offset; ltvArray[1].len = 4; ltvArray[1].type = OtaRequestDataLenType; ltvArray[1].value = DataLen; ltvArray[2].len = 6; ltvArray[2].type = OtaTotalFileSizeType; ltvArray[2].value = TotalFileSise; ltvArray[3].len = 6; ltvArray[3].type = OtaReceivedFileLenType; ltvArray[3].value = ReceivedFileSize; frameInfo.serviceId = OTA_SERVER; frameInfo.commandId = RequestOTAFileDataID; frameInfo.frameType.value = 0; BLE_SendLtvArray(&frameInfo, ltvArray, 4); // uint16_t write_idx = 0; // uint8_t buf_temp[30] = {0}; // uint32_t Value32; // buf_temp[write_idx++] = 0x06; // buf_temp[write_idx++] = OtaFileOffsetType; // buf_temp[write_idx++] = offset/0x1000000; // Value32 =offset%0x1000000; // buf_temp[write_idx++] = Value32/0x10000; // Value32 =offset%0x10000; // buf_temp[write_idx++] = Value32/0x100; // buf_temp[write_idx++] = offset%0x100; // buf_temp[write_idx++] = 0x04; // buf_temp[write_idx++] = OtaRequestDataLenType; // buf_temp[write_idx++] = DataLen/0x100; // buf_temp[write_idx++] = DataLen%0x100; // buf_temp[write_idx++] = 0x06; // buf_temp[write_idx++] = OtaTotalFileSizeType; // buf_temp[write_idx++] = TotalFileSise/0x1000000; // Value32 =TotalFileSise%0x1000000; // buf_temp[write_idx++] = Value32/0x10000; // Value32 =TotalFileSise%0x10000; // buf_temp[write_idx++] = Value32/0x100; // buf_temp[write_idx++] = TotalFileSise%0x100; // buf_temp[write_idx++] = 0x06; // buf_temp[write_idx++] = OtaReceivedFileLenType; // buf_temp[write_idx++] = ReceivedFileSize/0x1000000; // Value32 =ReceivedFileSize%0x1000000; // buf_temp[write_idx++] = Value32/0x10000; // Value32 =ReceivedFileSize%0x10000; // buf_temp[write_idx++] = Value32/0x100; // buf_temp[write_idx++] = ReceivedFileSize%0x100; // BLE_SendFrameById(OTA_SERVER,RequestOTAFileDataID,buf_temp,write_idx); } /***************************************************************************** 4.12.4 APP 根据设备的分帧请求返回文件内容 *****************************************************************************/ void UserReceiveOTAFileData(uint8_t *in_data,uint16_t in_len,uint8_t *out_data,uint16_t *out_len) { uint16_t write_idx=0; protocol_data_info_t data_info = {0}; OtaCtrlBlock_t ctrlBlock; uint32_t rcvFileOffset; uint16_t dataLen = in_len; static uint8_t otaProtocolVersion = 0; if(!OtaIsStarted()) return; OtaTimeoutReset(); rcvFileOffset = ((uint32_t)in_data[0] << 24) + \ ((uint32_t)in_data[1] << 16) + \ ((uint32_t)in_data[2] << 8) + \ ((uint32_t)in_data[3]); static_print_info("in_len=%d,rcvFileOffset=%d,pkt.offset=%d,pkt.FileSize=%d\n",in_len,rcvFileOffset,ctrlBlock.pkt.offset,ctrlBlock.pkt.FileSize); GetOtaCtrlBlock(&ctrlBlock); if(ctrlBlock.pkt.offset== 0) { if(in_len == 4 + FW_HEAD_INFO_IEN) { otaProtocolVersion = 1; //V0.0.2.9协议,新增文件偏移 } else { otaProtocolVersion = 0; //老协议,纯数据 } static_print_info("otaProtocolVersion=%d\r\n", otaProtocolVersion); } if(otaProtocolVersion > 0) { // OtaFrameResendTimerLoad(); // 目前不使用超时未收到数据再次请求机制 if(rcvFileOffset != ctrlBlock.pkt.offset) { static_print_remind("rcvFileOffset=0x%x,ctrlBlock.offset=0x%x\r\n", rcvFileOffset, ctrlBlock.pkt.offset); return; } in_data += 4; dataLen = in_len - 4; } // 为提高OTA速度,提前申请固件数据再将数据写入Flash if(ctrlBlock.ota_status == OTA_STATE_FW_DATA) { ctrlBlock.pkt.offset += dataLen; if(ctrlBlock.pkt.FileSize > ctrlBlock.pkt.offset) { ctrlBlock.pkt.ApplyLen = ctrlBlock.pkt.FileSize - ctrlBlock.pkt.offset; ctrlBlock.pkt.ApplyLen = ctrlBlock.pkt.ApplyLen > APPLY_FW_DATA_LEN ? APPLY_FW_DATA_LEN : ctrlBlock.pkt.ApplyLen; DeviceRequestOTAFileData(ctrlBlock.pkt.offset, ctrlBlock.pkt.ApplyLen, ctrlBlock.pkt.FileSize, ctrlBlock.pkt.offset); } } data_info.error = OtaPacketHandler(dataLen, in_data); if(data_info.error != FENDA_SUCCESS) { DeviceOTAErrReport(data_info.error); OtaFailed(data_info.error); } else { GetOtaCtrlBlock(&ctrlBlock); // if(ctrlBlock.ota_status == OTA_STATE_FW_DATA) // { // if(otaProtocolVersion > 0) // { // //OtaFrameResendTimerLoad(); // } // //static_print_info("\n ApplyLen = %x, offset = %x, FileSize = %x \n", // // ctrlBlock.pkt.ApplyLen,ctrlBlock.pkt.offset, ctrlBlock.pkt.FileSize); // DeviceRequestOTAFileData(ctrlBlock.pkt.offset, ctrlBlock.pkt.ApplyLen, // ctrlBlock.pkt.FileSize, ctrlBlock.pkt.offset); // } // else if(ctrlBlock.ota_status == OTA_STATE_FW_RESET) if(ctrlBlock.ota_status == OTA_STATE_FW_RESET) {// 收完最后一包数据 DeviceNoticeOTAFileReceivedSuccess(); if(ctrlBlock.crc_verify) { static_print_remind("\n***** Verification succeeded. *****\n "); DeviceNoticeOTAProcessUpdate(VERIFY_SUCCESS, DEVICE_STARTOTA); OtaSucceed(); } else { static_print_remind("\n***** Verification fail. *****\n "); DeviceNoticeOTAProcessUpdate(VERIFY_FAIL, DEVICE_STARTOTA); OtaFailed(DATA_CRC_OTA_ERROR); } } } *out_len=write_idx; } /***************************************************************************** 4.12.5 设备通知APP 升级包接收完 *****************************************************************************/ void DeviceNoticeOTAFileReceivedSuccess(void) { uint16_t write_idx = 0; uint8_t buf_temp[2] = {0}; buf_temp[write_idx++] = 0x02; buf_temp[write_idx++] = PkgValidityType; BLE_SendFrameById(OTA_SERVER,NoticeReceiveOTAFileSuccessID,buf_temp,write_idx); } /***************************************************************************** 4.12.6 设备回复手机文件接收完毕校验,并指定由谁开启OTA 流程 *****************************************************************************/ void DeviceNoticeOTAProcessUpdate(uint8_t FileVerifyResult,uint8_t OTAStartMode) { uint16_t write_idx = 0; uint8_t buf_temp[6] = {0}; buf_temp[write_idx++] = 0x03; buf_temp[write_idx++] = PkgValidityType; buf_temp[write_idx++] = FileVerifyResult; buf_temp[write_idx++] = 0x03; buf_temp[write_idx++] = WhichStartOtaType; buf_temp[write_idx++] = OTAStartMode; BLE_SendFrameById(OTA_SERVER,NoticeOTAUpdateTypeID,buf_temp,write_idx); } /***************************************************************************** 4.12.6 APP回复设备升级完成。 (事实上FD186 APP没有这一步操作,我们是在4.12.4开启定时器重启) *****************************************************************************/ void NoticeOTAUpdateResultACK(uint8_t *in_data,uint16_t in_len,uint8_t *out_data,uint16_t *out_len) { protocol_data_info_t data_info = {0}; do { user_get_data_info(&data_info,&in_data,&in_len); switch((data_info.type & 0x7F)) { case AppStartOtaType: if(data_info.len==1) { if(*data_info.p_data) { static_print_remind("\n***** Verification succeeded. Device Reset*****\n "); } } break; default: // data_info.error=PARAM_ERROR; // in_len=0; break; } in_data+=(data_info.len); in_len-=(2+data_info.len); if(in_len>FRAM_MAX_SIZ) { in_len=0; } } while(in_len); } /***************************************************************************** 4.12.7 设备端OTA状态上报 *****************************************************************************/ void DeviceOTAErrReport(uint16_t OtaErrorResult) { uint16_t write_idx = 0; uint8_t buf_temp[TEMP_NUM_MAX] = {0}; buf_temp[write_idx++] = 0x04; buf_temp[write_idx++] = 0xff; buf_temp[write_idx++] = OtaErrorResult / 0x100; buf_temp[write_idx++] = OtaErrorResult % 0x100; BLE_SendFrameById(OTA_SERVER, DeviceOTAErrReportID, buf_temp, write_idx); } void UserCancleOta(uint8_t *in_data,uint16_t in_len,uint8_t *out_data,uint16_t *out_len) { protocol_data_info_t data_info = {0}; if(!OtaIsStarted()) return; static_print_info("UserCancleOta\n"); do { user_get_data_info(&data_info,&in_data,&in_len); switch((data_info.type & 0x7F)) { case CancelOtaType: OtaFailed(USER_CANCEL_OTA); break; default: // data_info.error=PARAM_ERROR; // in_len=0; break; } in_data+=(data_info.len); in_len-=(2+data_info.len); if(in_len>FRAM_MAX_SIZ) { in_len=0; } } while(in_len); } const p_func_t user_Ota_server_func[Ota_server_max_ID]= { user_null_func, UserCheckIFOtaMode, //4.12.1 UserNoticOtaStatus, //4.12.2 user_null_func, //4.12.3 UserReceiveOTAFileData, //4.12.4 user_null_func, NoticeOTAUpdateResultACK, //5.9.6 user_null_func,//user_notify_ota_status, //5.9.7 UserCancleOta, //5.9.8 };