/** ****************************************************************************** * @file OTA.c * @author * @version * @date * @brief ****************************************************************************** * @attention * * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "stm32f10x.h" #include "global.h" #include "string.h" #include #if LTE_Conn //【OTA数据范围】 #define DATA_BUF_LEN 256 //每包长度 #define PAGE_LEN 120*(1024/DATA_BUF_LEN) //序号范围 #define SIZE_LEN 120*1024 //总字节长度限制 120K以内 //【Flash存储】 #define INFO_LEN 12 //存储信息限制,信息总长包括反向存储 #define DATA_LEN 2048 //存储数据限制,每扇2K=256Byte*8 #define USER_FW_INFO 0X08020000 //新程序信息地址 #define USER_FW_MIDD 0X08021800 //新程序数据地址 //【云平台通信】 uint8_t LTE_OTA_Flag; //4G升级标志 1:收到升级相关报文 uint8_t LTE_OTA_fineFlag; //4G升级完成上报标志(上线后先上报升级完成) 0xAA:升级成功 0xBB:维持原程序 uint8_t ota_code; //回复标志 0:成功 1:内容有缺 6:升级失败仍运行原程序 uint16_t OTA_ErrCnt; //OTA过程的错误计数 //【流程】 //0xA8.回复OTA升级信息帧 //0xA9.回复OTA升级数据帧 //0xAA.转存完成,设备上线后主动上报OTA升级完成 #define ota_check_sub 0xA7 #define ota_info_pub 0xA8 #define ota_data_pub 0xA9 //【步骤】 //0xA8_201~205[回复OTA升级信息帧] 201:主题长度 202:主题内容 203:属性长度 204:属性内容 205:确认上传 //0xA9_206~210[回复OTA升级数据帧] 206:主题长度 207:主题内容 208:属性长度 209:属性内容 210:确认上传 //0xAA_211~215[主动上报OTA升级成功] 211:主题长度 212:主题内容 213:属性长度 214:属性内容 215:确认上传 #define ota_check_sub_step1 201 #define ota_check_sub_step2 202 #define ota_check_sub_step3 203 #define ota_info_pub_step1 211 #define ota_info_pub_step2 212 #define ota_info_pub_step3 213 #define ota_info_pub_step4 214 #define ota_info_pub_step5 215 #define ota_data_pub_step1 216 #define ota_data_pub_step2 217 #define ota_data_pub_step3 218 #define ota_data_pub_step4 219 #define ota_data_pub_step5 220 uint32_t firmware_size; //总包的大小 uint16_t firmware_crc; //总包的CRC校验码 uint16_t rev_page; //OTA升级一共多少分包 uint16_t rev_index; //当前包序号 0~rev_page-1,用于计算存入的地址 uint16_t rev_crc; //当前包数据的CRC校验码 uint16_t ota_data_crc; //数据帧的CRC校验码 uint8_t ota_wr_info[INFO_LEN]; //存放信息让底层能判断读出 uint8_t ota_wr_data[DATA_LEN]; //保存2K数据后再下载 uint8_t OTAfine_WrFlg; //更新OTA升级成功/失败标志的标志 0xAA:更新到0 0xBB:更新到0xBB uint8_t otaSub_reply_count; uint8_t otaInfo_reply_count; uint8_t otaData_reply_count; uint8_t ota_rx_Buf[2048]; //下发[OTA升级信息]报文的处理 void LTE_OTA_Info(void) { //进入升级模式 LTE_OTA_Flag = 1; //准备订阅主题和发送回复 LTE_status = ota_check_sub; LTE_step = ota_check_sub_step1; //收到并存储信息 //{"page":100,"size":65535,"method":"crc16"} if(strstr(LTE_Rx_Buf, "\"page\"") && strstr(LTE_Rx_Buf, "\"size\"") && strstr(LTE_Rx_Buf, "\"check\"")) { char str[6]; //字符串 0~102400 uint8_t len = 0; //字符串长度 uint32_t temp; //过程量 uint8_t tmpWr[12]; ota_code = 0; //Bin文件最大120KB,对应Page最大PAGE_LEN len = GetStr("\"page\":", ',', ',', LTE_Rx_Buf, str); sscanf(str, "%u", &temp); if((temp > 0) && (temp <= PAGE_LEN) && (len > 0)) { rev_page = temp; } else { ota_code = 2; //内容超出范围 return; } //Bin文件最大120KB,对应size最大120*1024 len = GetStr("\"size\":", ',', ',', LTE_Rx_Buf, str); sscanf(str, "%u", &temp); if((temp > 0) && (temp <= SIZE_LEN) && (len > 0)) { firmware_size = temp; } else { ota_code = 2; //内容超出范围 return; } //整体CRC码 len = GetStr("\"check\":\"", '\"', '\"', LTE_Rx_Buf, str); if(len == 4) { sscanf(str, "%4hx", &firmware_crc); } else { ota_code = 2; //内容超出范围 return; } //序号清零,等待升级 rev_index = 0; //赋值 tmpWr[0] = (firmware_size>> 0) & 0xFF; tmpWr[1] = (firmware_size>> 8) & 0xFF; tmpWr[2] = (firmware_size>>16) & 0xFF; tmpWr[3] = (firmware_size>>24) & 0xFF; tmpWr[4] = (firmware_crc >> 0) & 0xFF; tmpWr[5] = (firmware_crc >> 8) & 0xFF; tmpWr[6] = tmpWr[0] ^ 0xff; tmpWr[7] = tmpWr[1] ^ 0xff; tmpWr[8] = tmpWr[2] ^ 0xff; tmpWr[9] = tmpWr[3] ^ 0xff; tmpWr[10] = tmpWr[4] ^ 0xff; tmpWr[11] = tmpWr[5] ^ 0xff; //把OTA信息存储 FLASH_WrData(USER_FW_INFO, (uint16_t *)&tmpWr[0], INFO_LEN/2); //12/2=6 } else { ota_code = 1; //内容有缺 } } //下发[OTA升级数据]报文的处理 void LTE_OTA_Data(void) { LTE_status = ota_data_pub; LTE_step = ota_data_pub_step1; //收到并存储数据 //{"index":0,"sign":"Hex","data":"HEX..."} if(strstr(LTE_Rx_Buf, "\"index\"") && strstr(LTE_Rx_Buf, "\"data\"") && strstr(LTE_Rx_Buf, "\"check\"")) { char str[6] = {0}; //字符串 0~102400 uint16_t len = 0; //字符串长度 uint32_t temp = 0; //过程量 char data_str[DATA_BUF_LEN*2+4]; //字符串 uint16_t dataLen = 0; //数据长度需要单独拿出参与最后一包的判断 uint8_t dataIdx; //当前包对应2K数组中的位置 0~7 ota_code = 0; //Bin文件最大120KB,对应index最大PAGE_LEN len = GetStr("\"index\":", ',', ',', LTE_Rx_Buf, str); sscanf(str, "%u", &temp); if(len > 0) { if(temp == 0) { rev_index = temp; } else if((temp > 0) && (temp <= PAGE_LEN)) { if(temp == rev_index+1) { rev_index = temp; } else { ota_code = 3; //内容不连续 return; } } else { ota_code = 2; //内容超出范围 return; } } else { ota_code = 1; //内容有缺 } //该包的CRC码 len = GetStr("\"check\":\"", '\"', '\"', LTE_Rx_Buf, str); if(len == 4) { sscanf(str, "%4hx", &rev_crc); } else if(len > 0) { if(rev_index != 0) rev_index--; //该包接收错误,应回退等待下一次发当前包 ota_code = 2; //内容超出范围 return; } else { ota_code = 1; //内容有缺 } //该包的数据字符串放入str数组 char* dataStart = strstr(LTE_Rx_Buf, "\"data\":\""); dataStart += strlen("\"data\":\""); char* dataEnd = strchr(dataStart, '\"'); dataLen = dataEnd - dataStart; strncpy(data_str, dataStart, dataLen); data_str[dataLen] = '\0'; dataIdx = rev_index%8; //2K数组中的位置0~7 (dataIdx=7)或(rev_index == rev_page-1)时执行写入Flash if((rev_index < rev_page-1) && (dataLen == DATA_BUF_LEN*2)) //正常包 { uint16_t i; //转换到ota_wr_data数组 for(i=0;i 0)) //最后一包 { uint16_t i; //清空ota_wr_data的该包对应位置及以后的位置 for(i=dataIdx;i<8;i++) { memset(&ota_wr_data[i*256], 0, DATA_BUF_LEN); } //将最后一包也转换到ota_wr_data数组 for(i=0;i 0) { if(rev_index != 0) rev_index--; //该包接收错误,应回退等待下一次发当前包 ota_code = 2; //内容超出范围 return; } else { ota_code = 1; //内容有缺 } //数据格式都正确,进行校验和写入 //CRC校验码 ota_data_crc = CRC16_FirmtoEE(&ota_wr_data[dataIdx*256], dataLen/2); if(rev_crc == ota_data_crc) { if(rev_index == 0) //对第1包进行合法范围判断 { if((ota_wr_data[6] > 0x01) || (ota_wr_data[7] != 0x08)) //Flash 128KB 0x08000000~0x0801FFFF { if(rev_index != 0) rev_index--; //该包接收错误,应回退等待下一次发当前包 ota_code = 5; //内容不是正规升级文件 return; } } //执行写入Flash else if((dataIdx == 7) || (rev_index == rev_page-1)) { FLASH_WrData(rev_index/8 * DATA_LEN + USER_FW_MIDD, (uint16_t *)&ota_wr_data[0], DATA_LEN/2); //2048/2=1024 delay_ms(2); } } else { if(rev_index != 0) rev_index--; //该包接收错误,应回退等待下一次发当前包 ota_code = 4; //CRC校验错误 return; } } else { ota_code = 1; //内容有缺 } } //处理数据,接收报文识别后执行 void LTE_OTA_IT_Update(void) { if(LTE_status != 0) //收到后,执行回复,才判断OK,>,ERROR { /*收到OK或>或ERROR,认为回复完整,开始分析*/ if((LTE_Rx_BufIndex >= 2) && (strstr(LTE_Rx_Buf, "OK"))) { //0xA7.检查订阅主题 if(LTE_status == ota_check_sub) { //1.检查订阅 if(strstr(LTE_Rx_Buf, "AT+CMQTTSUB?") && (LTE_step == ota_check_sub_step1)) { if(strstr(LTE_Rx_Buf, "/ota/device/firmware/101") == 0) //缺少了OTA数据帧的主题 { LTE_status = ota_check_sub; LTE_step = ota_check_sub_step2; //无订阅,跳转:订阅OTA数据帧的主题 } else { LTE_status = ota_info_pub; LTE_step = ota_info_pub_step1; //有订阅,跳转:发送回复 } } //3.订阅OTA数据帧的主题 else if(LTE_step == ota_check_sub_step3) { otaSub_reply_count = 0; LTE_status = ota_info_pub; LTE_step = ota_info_pub_step1; //订阅成功,进行信息帧的回复 } } //0xA8.回复OTA升级信息帧 if(LTE_status == ota_info_pub) { //2. if(LTE_step == ota_info_pub_step2) { LTE_status = ota_info_pub; LTE_step = ota_info_pub_step3; //主题接收OK,准备下一步 } //4. else if(LTE_step == ota_info_pub_step4) { LTE_status = ota_info_pub; LTE_step = ota_info_pub_step5; //内容接收OK,准备下一步 } //5. else if(strstr(LTE_Rx_Buf, "AT+CMQTTPUB") && (LTE_step == ota_info_pub_step5)) { otaInfo_reply_count = 0; if(ota_code == 0) { //等待数据内容,期间不主动发数据 LTE_status = 0; LTE_step = 0; return; } else { //退出升级流程,正常上报 LTE_OTA_Flag = 0; LTE_status = ask_lbs; LTE_step = ask_lbs_step1; //跳转:正常流程第一步 } } } //0xA9.回复OTA升级数据帧 else if(LTE_status == ota_data_pub) { //2. if(LTE_step == ota_data_pub_step2) { LTE_status = ota_data_pub; LTE_step = ota_data_pub_step3; //主题接收OK,准备下一步 } //4. else if(LTE_step == ota_data_pub_step4) { LTE_status = ota_data_pub; LTE_step = ota_data_pub_step5; //内容接收OK,准备下一步 } //5. else if(strstr(LTE_Rx_Buf, "AT+CMQTTPUB") && (LTE_step == ota_data_pub_step5)) { otaData_reply_count = 0; //未收到全部数据时 if(rev_index < rev_page-1) { //等待数据内容,期间不主动发数据 LTE_status = 0; LTE_step = 0; return; } else { //更新EE_OTA完成标志,先更新失败标志,若底层完成,会改为成功标志 LTE_OTA_fineFlag = 0xBB; OTAfine_WrFlg = 0xBB; } } } } else if((LTE_Rx_BufIndex >= 1) && (strstr(LTE_Rx_Buf, ">"))) { //0xA7.检查订阅 if(LTE_status == ota_check_sub) { //1.订阅OTA数据帧的主题 if(strstr(LTE_Rx_Buf, "AT+CMQTTSUB=0,39,1") && (LTE_step == ota_check_sub_step2)) { LTE_status = ota_check_sub; LTE_step = ota_check_sub_step3; //准备下一步 } } //0xA8.回复OTA升级数据帧 else if(LTE_status == ota_info_pub) { //1. if(strstr(LTE_Rx_Buf, "AT+CMQTTTOPIC") && (LTE_step == ota_info_pub_step1)) { LTE_status = ota_info_pub; LTE_step = ota_info_pub_step2; //准备下一步 } //3. else if(strstr(LTE_Rx_Buf, "AT+CMQTTPAYLOAD") && (LTE_step == ota_info_pub_step3)) { LTE_status = ota_info_pub; LTE_step = ota_info_pub_step4; //准备下一步 } } //0xA9.回复OTA升级信息帧 else if(LTE_status == ota_data_pub) { //1. if(strstr(LTE_Rx_Buf, "AT+CMQTTTOPIC") && (LTE_step == ota_data_pub_step1)) { LTE_status = ota_data_pub; LTE_step = ota_data_pub_step2; //准备下一步 } //3. else if(strstr(LTE_Rx_Buf, "AT+CMQTTPAYLOAD") && (LTE_step == ota_data_pub_step3)) { LTE_status = ota_data_pub; LTE_step = ota_data_pub_step4; //准备下一步 } } } else if((LTE_Rx_BufIndex >= 5) && (strstr(LTE_Rx_Buf, "ERROR"))) { LTE_ResendDelay = ResendTime; OTA_ErrCnt++; if(OTA_ErrCnt > ERR_timeEnd2) //1min { OTA_ErrCnt = 0; //退出升级流程,在正常流程中检查问题 LTE_OTA_Flag = 0; CRESET_flag = 1; //重启 CRESET_step = 0; } } } } //收到下发报文后,在主循环进行处理 void LTE_OTA_IQ_Update(void) { if((LTE_status == 0) && (LTE_step == 0)) //OTA升级,重点是接收下发报文 { /*监控下发报文*/ if(strstr(LTE_Rx_Buf, "+CMQTTRXSTART") && strstr(LTE_Rx_Buf, "+CMQTTRXEND")) //有头有尾 { //OTA信息帧 if(strstr(LTE_Rx_Buf, "/ota/device/upgrade/101")) { LTE_OTA_Info(); } //OTA数据帧 else if(strstr(LTE_Rx_Buf, "/ota/device/firmware/101")) { LTE_OTA_Data(); if(ota_code != 0) { uint16_t i; for(i=0;i<2048;i++) { ota_rx_Buf[i] = LTE_Rx_Buf[i]; } } } } } //更新升级标志归0 if(OTAfine_WrFlg == 0xAA) { EEPROM_WrMulByte(EE_OTA_FINE,<E_OTA_fineFlag); delay_ms(5); OTAfine_WrFlg = 0; } //更新升级标志为0xBB,IAP标志为0xBB (不需要兼容旧IAP,不用考虑擦除跳转标志) else if(OTAfine_WrFlg == 0xBB) { EEPROM_WrMulByte(EE_OTA_FINE,<E_OTA_fineFlag); delay_ms(5); OTAfine_WrFlg = 0; IAP_Run = 0xBB; //表示存在下一版程序 EEPROM_WrMulByte(EE_IAP_NEW1,&IAP_Run); delay_ms(10); EEPROM_WrMulByte(EE_IAP_NEW2,&IAP_Run); delay_ms(10); //执行软件重启 NVIC_SystemReset(); } } //该函数用于发送报文 void LTE_OTA_IQ_Transmit(void) { if(LTE_status != 0) { if((LTE_Rx_BufIndex == 0) && (LTE_WaitRxFlg == 1)) //有发送指令却没有回复 //只执行1次 { LTE_WaitRxFlg = 0; LTE_WaitRxDelay = WaitRxTime; return; } LTE_Rx_BufIndex = 0; memset(LTE_Rx_Buf, 0, LTE_RX_BUF_LEN); //填入前先清空 memset(LTE_Tx_Buf, 0, LTE_TX_BUF_LEN); } //定期查询订阅并重新订阅主题 if(LTE_status == ota_check_sub) { otaSub_reply_count++; //尝试1次重新回复 if(otaSub_reply_count == 10) { LTE_step = ota_check_sub_step1; } //仍然失败退出回复 else if(otaSub_reply_count >= 20) { LTE_OTA_Flag = 0; LTE_status = ask_lbs; LTE_step = ask_lbs_step1; //回复OTA升级信息一直失败,跳转:正常流程第一步 otaSub_reply_count = 0; } switch(LTE_step) //ota_info_pub_step1~ota_info_pub_step5 { case ota_check_sub_step1: LTE_Send("AT+CMQTTSUB?\r\n"); //查询订阅 break; case ota_check_sub_step2: LTE_Send("AT+CMQTTSUB=0,39,1\r\n"); //订阅主题长度 "/ota/device/firmware/101/030200001/post"=39Byte //订阅OTA升级数据 break; case ota_check_sub_step3: LTE_Send("/ota/device/firmware/101/%s/post", BMS_SN); //订阅的主题 (只有这个不用换新行) break; default: break; } } //0xA8.回复OTA升级信息帧 else if(LTE_status == ota_info_pub) { otaInfo_reply_count++; //尝试1次重新回复 if(otaInfo_reply_count == 10) { LTE_step = ota_info_pub_step1; } //仍然失败退出回复 else if(otaInfo_reply_count >= 20) { LTE_OTA_Flag = 0; LTE_status = ask_lbs; LTE_step = ask_lbs_step1; //回复OTA升级信息一直失败,跳转:正常流程第一步 otaInfo_reply_count = 0; } switch(LTE_step) //ota_info_pub_step1~ota_info_pub_step5 { case ota_info_pub_step1: LTE_Send("AT+CMQTTTOPIC=0,39\r\n"); //上报主题长度 24+9+6=39Byte break; case ota_info_pub_step2: LTE_Send("/ota/device/upgrade/101/%s/reply", BMS_SN); //上报的主题 (只有这个不用换新行) break; case ota_info_pub_step3: LTE_Send("AT+CMQTTPAYLOAD=0,%hu\r\n", 11+uint_str_len(ota_code)); //上报内容长度 = 数据长度+固定字符长度+回车 break; case ota_info_pub_step4: LTE_Send("{\"code\":%hu}\r\n", ota_code); break; case ota_info_pub_step5: LTE_Send("AT+CMQTTPUB=0,1,30\r\n"); //至少上报1次+30s内等待服务器回复 break; default: break; } } //0xA9.回复OTA升级数据帧 else if(LTE_status == ota_data_pub) { otaData_reply_count++; //尝试1次重新回复(数据帧比较特殊,如果后续序号不对就失败了,故增加次数) if(otaData_reply_count == 20) { LTE_step = ota_data_pub_step1; } //仍然失败退出回复 else if(otaData_reply_count >= 30) { LTE_status = 0; LTE_step = 0; otaData_reply_count = 0; } switch(LTE_step) //ota_data_pub_step1~ota_data_pub_step5 { case ota_data_pub_step1: LTE_Send("AT+CMQTTTOPIC=0,40\r\n"); //上报主题长度 25+9+6=40Byte break; case ota_data_pub_step2: LTE_Send("/ota/device/firmware/101/%s/reply", BMS_SN); //上报的主题 (只有这个不用换新行) break; case ota_data_pub_step3: LTE_Send("AT+CMQTTPAYLOAD=0,%hu\r\n", 11+uint_str_len(ota_code)); //上报内容长度 = 数据长度+固定字符长度+回车 break; case ota_data_pub_step4: LTE_Send("{\"code\":%hu}\r\n", ota_code); break; case ota_data_pub_step5: LTE_Send("AT+CMQTTPUB=0,1,30\r\n"); //至少上报1次+30s内等待服务器回复 break; default: break; } } } #endif