Files
2026-08-25 17:30:40 +08:00

699 lines
17 KiB
C

/**
******************************************************************************
* @file OTA.c
* @author
* @version
* @date
* @brief
******************************************************************************
* @attention
*
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "global.h"
#include "string.h"
#include <stdio.h>
#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<dataLen/2;i++)
{
//每2个字符转换成1个字节
sscanf(&data_str[i*2], "%2hhx", &ota_wr_data[i+dataIdx*256]); //8*256=2048
}
}
else if((rev_index == rev_page-1) && (dataLen > 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<dataLen/2;i++)
{
//每2个字符转换成1个字节
sscanf(&data_str[i*2], "%2hhx", &ota_wr_data[i+dataIdx*256]); //8*256=2048
}
}
else if(dataLen > 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,&LTE_OTA_fineFlag);
delay_ms(5);
OTAfine_WrFlg = 0;
}
//更新升级标志为0xBB,IAP标志为0xBB (不需要兼容旧IAP,不用考虑擦除跳转标志)
else if(OTAfine_WrFlg == 0xBB)
{
EEPROM_WrMulByte(EE_OTA_FINE,&LTE_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