|
|
|
@@ -1,446 +1,460 @@
|
|
|
|
|
#include "Update.h"
|
|
|
|
|
#include "DebugCmd.h"
|
|
|
|
|
#include "main.h"
|
|
|
|
|
#include "bsp.h"
|
|
|
|
|
#include "spiflash.h"
|
|
|
|
|
#include <rthw.h> /*rt_hw_interrupt_disable/enable: TX queue critical section*/
|
|
|
|
|
|
|
|
|
|
extern GateWayPara_t GateWay;
|
|
|
|
|
static void NetUpgradeSavePkg(uint32_t PkgCnt); /*fwd decl: Update() calls it before its definition*/
|
|
|
|
|
|
|
|
|
|
#include "Update.h"
|
|
|
|
|
#include "DebugCmd.h"
|
|
|
|
|
#include "main.h"
|
|
|
|
|
#include "bsp.h"
|
|
|
|
|
#include "spiflash.h"
|
|
|
|
|
#include <rthw.h> /*rt_hw_interrupt_disable/enable: TX queue critical section*/
|
|
|
|
|
|
|
|
|
|
extern GateWayPara_t GateWay;
|
|
|
|
|
static void NetUpgradeSavePkg(uint32_t PkgCnt); /*fwd decl: Update() calls it before its definition*/
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************************
|
|
|
|
|
* 函数名称: Update
|
|
|
|
|
* 功能描述: 固件升级,此函数在解析到升级指令时调用
|
|
|
|
|
* 参 数: PayLoad 协议负载,需去除帧头等信息,只传负载数据
|
|
|
|
|
* 返 回 值: 无
|
|
|
|
|
*****************************************************************************************/
|
|
|
|
|
void Update(uint8_t *PayLoad)
|
|
|
|
|
{
|
|
|
|
|
UpDataRequset_t Req;
|
|
|
|
|
boot_para_t cfg = {0};
|
|
|
|
|
|
|
|
|
|
memcpy(&Req, PayLoad, sizeof(UpDataRequset_t));
|
|
|
|
|
|
|
|
|
|
/*固件大小校验: 为0或超出B区容量时拒绝升级, 不置标志不复位*/
|
|
|
|
|
if(Req.AppSize == 0 || Req.AppSize > FLASH_APPB_SIZE) {
|
|
|
|
|
U_DBG_LOG("AppSize invalid: %d (max %d)\r\n", (int)Req.AppSize, (int)FLASH_APPB_SIZE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*读回现有boot参数,保留FirstRunFlag等字段*/
|
|
|
|
|
dev_boot_read_param(&cfg);
|
|
|
|
|
cfg.AppSize = Req.AppSize;
|
|
|
|
|
cfg.Crc32Check = Req.AppCrc32;
|
|
|
|
|
cfg.PackageCnt = Req.PackageNum;
|
|
|
|
|
cfg.AppFlag = 0;
|
|
|
|
|
cfg.UpdateFlag = APP_UPDATE_FLAG;
|
|
|
|
|
memcpy(cfg.GwMac, GateWay.ConfigPara.GwMac, 6);
|
|
|
|
|
|
|
|
|
|
U_DBG_LOG("Receive upgrade command:\r\n");
|
|
|
|
|
U_DBG_LOG("PackageNum: %d\r\n", cfg.PackageCnt);
|
|
|
|
|
U_DBG_LOG("AppSize: %d\r\n", cfg.AppSize);
|
|
|
|
|
U_DBG_LOG("AppCrc32: 0x%08x\r\n", cfg.Crc32Check);
|
|
|
|
|
U_DBG_LOG("System Reset!\r\n");
|
|
|
|
|
|
|
|
|
|
NetUpgradeSavePkg(0);
|
|
|
|
|
SAVE_BOOT_PARA(&cfg);
|
|
|
|
|
U_DELAY_MS(200);
|
|
|
|
|
U_SYSTEM_TESET();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************************
|
|
|
|
|
* 函数名称: UpdateInit
|
|
|
|
|
* 功能描述: 升级参数初始化,需要在程序启动,外设初始化完后调用
|
|
|
|
|
* 参 数: 无
|
|
|
|
|
* 返 回 值: 无
|
|
|
|
|
*****************************************************************************************/
|
|
|
|
|
void UpdateInit(void)
|
|
|
|
|
{
|
|
|
|
|
boot_para_t cfg;
|
|
|
|
|
|
|
|
|
|
READ_BOOT_PARA(&cfg);
|
|
|
|
|
/*参照hc32l170_app: 仅确保AppFlag=APP_START_FLAG, 使Boot下次直接跳转App
|
|
|
|
|
(网关MAC/服务器/Lora配置从BootPara_t获取, 由Boot配置)*/
|
|
|
|
|
if(cfg.AppFlag != APP_START_FLAG) {
|
|
|
|
|
cfg.AppFlag = APP_START_FLAG;
|
|
|
|
|
SAVE_BOOT_PARA(&cfg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************************
|
|
|
|
|
* Cat1远程升级模块(0x7D帧, 与Boot RS485升级协议一致)
|
|
|
|
|
* 服务器(升级主机) --TCP--> Cat1模组 --USART1--> 本模块:
|
|
|
|
|
* 收0x81升级请求(校验/擦暂存区/断点续传判定) → 0x82分包顺序写入外部SPI Flash暂存区
|
|
|
|
|
* → 每收NUP_WINDOW包回0x02请求帧(服务端窗口流控) → 收完CRC32校验通过后置
|
|
|
|
|
* APP_UPDATE_SPI_FLAG复位, 由Boot完成"外部Flash→B区→A区"搬运
|
|
|
|
|
* 协议帧: 0x7D + DevMac(6) + Cmd + Len + Payload + CRC16(Modbus), 命令0x81/0x82/0x01/0x02
|
|
|
|
|
*****************************************************************************************/
|
|
|
|
|
#define NUP_PACKET_DATA 200 //每包数据长度(与服务端/Boot一致)
|
|
|
|
|
#define NUP_STASH_PROG_MAGIC 0xA5A5C35A //升级进度记录魔数
|
|
|
|
|
#define NUP_WINDOW 8 //每收W包回一次请求帧
|
|
|
|
|
#define NUP_TIMEOUT_MS 3000 //等包超时(Cat1延迟大)
|
|
|
|
|
#define NUP_TIMEOUT_MAX 5 //连续超时次数上限
|
|
|
|
|
#define NUP_IDLE_TIMEOUT_MS 1800000UL //整体无进展超时(30分钟)
|
|
|
|
|
#define NUP_FRAME_BUF_MAX 3072 //0x7D组帧缓冲上限(容纳URC单次喂入的多帧拼接)
|
|
|
|
|
#define NUP_APP_MAX (232 * 1024) //A区容量上限
|
|
|
|
|
|
|
|
|
|
/*升级进度记录(存外部Flash扇区4037): 断电/断连后据此判定断点续传*/
|
|
|
|
|
typedef struct {
|
|
|
|
|
uint32_t Magic; //NUP_STASH_PROG_MAGIC
|
|
|
|
|
uint32_t AppSize; //固件大小
|
|
|
|
|
uint32_t Crc32; //固件CRC32
|
|
|
|
|
uint32_t PkgCnt; //已连续收到的包数
|
|
|
|
|
}FwStashProg_t;
|
|
|
|
|
|
|
|
|
|
static struct {
|
|
|
|
|
bool Active; //升级会话进行中
|
|
|
|
|
uint16_t PkgCnt; //总包数
|
|
|
|
|
uint32_t AppSize; //固件大小
|
|
|
|
|
uint32_t Crc32; //固件CRC32
|
|
|
|
|
uint16_t ExpectIdx; //期望接收的包序号
|
|
|
|
|
uint16_t LastAckIdx; //最近一次0x02应答的包序号(窗口流控基准)
|
|
|
|
|
uint32_t LastTick; //最近收包时刻(rt_tick, 1ms)
|
|
|
|
|
uint32_t ErrCnt; //连续超时次数
|
|
|
|
|
uint8_t TxQ[4][40]; //应答帧队列(0x01/0x02连发互不挤占)
|
|
|
|
|
uint8_t TxQLen[4];
|
|
|
|
|
uint8_t TxHead;
|
|
|
|
|
uint8_t TxChan[4]; /*每帧来源通道: ACK从收到0x81的通道原路返回*/
|
|
|
|
|
uint8_t CurCh; /*当前会话通道: Feed进入时记录*/ //队首索引(出队)
|
|
|
|
|
uint8_t TxCnt; //队列帧数
|
|
|
|
|
}Nup;
|
|
|
|
|
|
|
|
|
|
static uint8_t NupFrameBuf[NUP_FRAME_BUF_MAX]; //0x7D组帧缓冲(TCP分片跨URC拼接)
|
|
|
|
|
static uint16_t NupFrameLen = 0;
|
|
|
|
|
static uint64_t NupErasedMap = 0; /*bit i: stash sector i erased this session (NOR writes only 1->0, erase-before-write required)*/
|
|
|
|
|
|
|
|
|
|
/*软件CRC32: 与Boot GetCrc32/服务端zlib.crc32同算法(0xEDB88320反射, 初末值0xFFFFFFFF)*/
|
|
|
|
|
static uint32_t NetUpgradeCrc32Stash(uint32_t Len)
|
|
|
|
|
{
|
|
|
|
|
uint32_t Crc = 0xFFFFFFFF;
|
|
|
|
|
uint32_t Done = 0;
|
|
|
|
|
uint8_t Buf[256];
|
|
|
|
|
while(Done < Len) {
|
|
|
|
|
uint16_t n = (Len - Done > sizeof(Buf)) ? sizeof(Buf) : (uint16_t)(Len - Done);
|
|
|
|
|
FwStashRead(Buf, Done, n);
|
|
|
|
|
for(uint16_t i = 0; i < n; i++) {
|
|
|
|
|
Crc ^= Buf[i];
|
|
|
|
|
for(int b = 0; b < 8; b++) {
|
|
|
|
|
Crc = (Crc & 1) ? (Crc >> 1) ^ 0xEDB88320 : (Crc >> 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Done += n;
|
|
|
|
|
}
|
|
|
|
|
return ~Crc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*进度记录持久化(扇区4037): PkgCnt=0表示清除*/
|
|
|
|
|
static void NetUpgradeSavePkg(uint32_t PkgCnt)
|
|
|
|
|
{
|
|
|
|
|
FwStashProg_t Prog;
|
|
|
|
|
Prog.Magic = (PkgCnt > 0) ? NUP_STASH_PROG_MAGIC : 0;
|
|
|
|
|
Prog.AppSize = Nup.AppSize;
|
|
|
|
|
Prog.Crc32 = Nup.Crc32;
|
|
|
|
|
Prog.PkgCnt = PkgCnt;
|
|
|
|
|
FwStashProgWrite((uint8_t *)&Prog, sizeof(Prog));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*待发帧入队(0x7D原始帧, 由CatOne主循环经AT+LIPSEND直发, 绕过0x7A打包)*/
|
|
|
|
|
static void NetUpgradePushTx(uint8_t Cmd, uint8_t *Payload, uint8_t Len)
|
|
|
|
|
{
|
|
|
|
|
uint16_t crc;
|
|
|
|
|
rt_base_t level = rt_hw_interrupt_disable();
|
|
|
|
|
if(Nup.TxCnt >= 4) {
|
|
|
|
|
rt_hw_interrupt_enable(level);
|
|
|
|
|
return; /*queue full: drop*/
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
uint8_t Tail = (Nup.TxHead + Nup.TxCnt) % 4;
|
|
|
|
|
Nup.TxQ[Tail][0] = 0x7D;
|
|
|
|
|
memcpy(&Nup.TxQ[Tail][1], GateWay.ConfigPara.GwMac, 6);
|
|
|
|
|
Nup.TxQ[Tail][7] = Cmd;
|
|
|
|
|
Nup.TxQ[Tail][8] = Len;
|
|
|
|
|
memcpy(&Nup.TxQ[Tail][9], Payload, Len);
|
|
|
|
|
crc = CRC_Modbus(CRC16_BASE, Nup.TxQ[Tail], 9 + Len);
|
|
|
|
|
Nup.TxQ[Tail][9 + Len] = crc & 0xFF;
|
|
|
|
|
Nup.TxQ[Tail][10 + Len] = (crc >> 8) & 0xFF;
|
|
|
|
|
Nup.TxQLen[Tail] = 11 + Len;
|
|
|
|
|
Nup.TxChan[Tail] = Nup.CurCh; /*绑定来源通道*/
|
|
|
|
|
Nup.TxCnt++;
|
|
|
|
|
}
|
|
|
|
|
rt_hw_interrupt_enable(level);
|
|
|
|
|
U_DBG_LOG("NetUpgrade push: cmd=0x%02x cnt=%d\r\n", Cmd, Nup.TxCnt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void NetUpgradeSendAck(uint8_t Status, uint16_t Resumed)
|
|
|
|
|
{
|
|
|
|
|
uint8_t p[3];
|
|
|
|
|
p[0] = Status;
|
|
|
|
|
p[1] = Resumed & 0xFF;
|
|
|
|
|
p[2] = (Resumed >> 8) & 0xFF;
|
|
|
|
|
NetUpgradePushTx(0x01, p, 3); //0x20全新/0x21续传/0x32拒绝
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void NetUpgradeSendReq(uint16_t Idx)
|
|
|
|
|
{
|
|
|
|
|
uint8_t p[4];
|
|
|
|
|
p[0] = Idx & 0xFF;
|
|
|
|
|
p[1] = (Idx >> 8) & 0xFF;
|
|
|
|
|
p[2] = Nup.PkgCnt & 0xFF;
|
|
|
|
|
p[3] = (Nup.PkgCnt >> 8) & 0xFF;
|
|
|
|
|
NetUpgradePushTx(0x02, p, 4); //请求从Idx起的下一批(收满PkgCnt视为完成)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*0x81升级请求: 合法性检查/回ACK并启动下载*/
|
|
|
|
|
static void NetUpgradeOnReq(uint8_t *Payload, uint8_t Len)
|
|
|
|
|
{
|
|
|
|
|
UpDataRequset_t Req;
|
|
|
|
|
if(Len < sizeof(Req)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
memcpy(&Req, Payload, sizeof(Req));
|
|
|
|
|
if(Req.AppSize == 0 || Req.AppSize > NUP_APP_MAX) {
|
|
|
|
|
NetUpgradeSendAck(0x32, 0);
|
|
|
|
|
U_DBG_LOG("NetUpgrade reject: AppSize=%d\r\n", Req.AppSize);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/*断点续传已取消: 每次点击升级均从0%全新下载*/
|
|
|
|
|
NetUpgradeSavePkg(0);
|
|
|
|
|
NupErasedMap = 0;
|
|
|
|
|
Nup.Active = true;
|
|
|
|
|
Nup.PkgCnt = Req.PackageNum;
|
|
|
|
|
Nup.AppSize = Req.AppSize;
|
|
|
|
|
Nup.Crc32 = Req.AppCrc32;
|
|
|
|
|
Nup.ExpectIdx = 0;
|
|
|
|
|
Nup.ErrCnt = 0;
|
|
|
|
|
Nup.LastTick = rt_tick_get();
|
|
|
|
|
Nup.LastAckIdx = 0;
|
|
|
|
|
U_DBG_LOG("NetUpgrade req: Pkg=%d Size=%d Crc=0x%08x Resumed=0\r\n",
|
|
|
|
|
Nup.PkgCnt, Nup.AppSize, Nup.Crc32);
|
|
|
|
|
NetUpgradeSendAck(0x20, 0);
|
|
|
|
|
NetUpgradeSendReq(0); //请求首包, 服务端收到0x02才开始发包
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*0x82升级数据: 严格按期望包号顺序写暂存区, 收满窗口回请求帧, 收完CRC校验*/
|
|
|
|
|
static void NetUpgradeOnData(uint8_t *Payload, uint8_t Len)
|
|
|
|
|
{
|
|
|
|
|
uint16_t Idx, Total;
|
|
|
|
|
uint8_t DataLen;
|
|
|
|
|
uint32_t WriteLen;
|
|
|
|
|
if(!Nup.Active || Len < 5) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
Idx = Payload[0] | (Payload[1] << 8);
|
|
|
|
|
Total = Payload[2] | (Payload[3] << 8);
|
|
|
|
|
DataLen = Payload[4];
|
|
|
|
|
if(Total != Nup.PkgCnt) {
|
|
|
|
|
return; //会话不匹配
|
|
|
|
|
}
|
|
|
|
|
if(Idx != Nup.ExpectIdx) {
|
|
|
|
|
return; //重复/乱序包: 丢弃(服务端按期望包号重发)
|
|
|
|
|
}
|
|
|
|
|
if(Idx == Nup.PkgCnt - 1) {
|
|
|
|
|
WriteLen = Nup.AppSize - (uint32_t)Idx * NUP_PACKET_DATA; //尾包实长
|
|
|
|
|
if(DataLen < WriteLen) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if(DataLen < NUP_PACKET_DATA) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
WriteLen = NUP_PACKET_DATA;
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
/*NOR only writes 1->0: erase touched stash sectors before write (one erase per sector per session), fixes stale-bit corruption on 2nd upgrade*/
|
|
|
|
|
uint32_t Sec0 = (uint32_t)Idx * NUP_PACKET_DATA / SPIFLASH_SECTORSIZE;
|
|
|
|
|
uint32_t Sec1 = ((uint32_t)Idx * NUP_PACKET_DATA + WriteLen - 1) / SPIFLASH_SECTORSIZE;
|
|
|
|
|
for(uint32_t s = Sec0; s <= Sec1; s++) {
|
|
|
|
|
if((NupErasedMap & ((uint64_t)1 << s)) == 0) {
|
|
|
|
|
FwStashEraseSector(s);
|
|
|
|
|
NupErasedMap |= (uint64_t)1 << s;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
FwStashWrite(&Payload[5], (uint32_t)Idx * NUP_PACKET_DATA, WriteLen);
|
|
|
|
|
Nup.ExpectIdx++;
|
|
|
|
|
Nup.LastTick = rt_tick_get();
|
|
|
|
|
Nup.ErrCnt = 0;
|
|
|
|
|
if(Nup.ExpectIdx >= Nup.PkgCnt) {
|
|
|
|
|
if(NetUpgradeCrc32Stash(Nup.AppSize) == Nup.Crc32) {
|
|
|
|
|
U_DBG_LOG("NetUpgrade stash verified, reboot to bootloader\r\n");
|
|
|
|
|
UpdateFromStash(Nup.AppSize, Nup.Crc32); //置APP_UPDATE_SPI_FLAG并复位
|
|
|
|
|
}
|
|
|
|
|
U_DBG_LOG("NetUpgrade stash CRC failed, restart download\r\n");
|
|
|
|
|
//校验失败: 从0重下(写前按需擦除保证暂存区干净)
|
|
|
|
|
NetUpgradeSavePkg(0);
|
|
|
|
|
NupErasedMap = 0;
|
|
|
|
|
Nup.ExpectIdx = 0;
|
|
|
|
|
NetUpgradeSendReq(0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(Nup.ExpectIdx - Nup.LastAckIdx >= NUP_WINDOW) {
|
|
|
|
|
NetUpgradeSendReq(Nup.ExpectIdx); //收满窗口, 请求下一批(与断点起点无关)
|
|
|
|
|
Nup.LastAckIdx = Nup.ExpectIdx;
|
|
|
|
|
}
|
|
|
|
|
if(Nup.ExpectIdx % (NUP_WINDOW * 4) == 0) {
|
|
|
|
|
NetUpgradeSavePkg(Nup.ExpectIdx); //定期持久化进度(32包一次)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void NetUpgradeFrameHandler(uint8_t Cmd, uint8_t *Payload, uint8_t Len)
|
|
|
|
|
{
|
|
|
|
|
U_DBG_LOG("NetUpgrade frame: cmd=0x%02x len=%d\r\n", Cmd, Len);
|
|
|
|
|
switch(Cmd) {
|
|
|
|
|
case 0x81:
|
|
|
|
|
NetUpgradeOnReq(Payload, Len);
|
|
|
|
|
break;
|
|
|
|
|
case 0x82:
|
|
|
|
|
NetUpgradeOnData(Payload, Len);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************************
|
|
|
|
|
* 函数名称: NetUpgradeFeed
|
|
|
|
|
* 功能描述: 喂入Cat1下行数据片段(+LIPURC二进制), 流式拼接提取完整0x7D升级帧
|
|
|
|
|
* 参 数: data/len, 二进制数据片段(TCP分片有序)
|
|
|
|
|
* 返 回 值: true=数据已被升级模块消费(帧头0x7D); false=非0x7D流, 调用方交还原0x7A路径
|
|
|
|
|
*****************************************************************************************/
|
|
|
|
|
bool NetUpgradeFeed(uint8_t *data, uint16_t len, uint8_t ch)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
Nup.CurCh = ch; /*记录会话通道*/
|
|
|
|
|
if(NupFrameLen == 0) {
|
|
|
|
|
uint16_t skip = 0;
|
|
|
|
|
while(skip < len && data[skip] != 0x7D) {
|
|
|
|
|
skip++;
|
|
|
|
|
}
|
|
|
|
|
if(skip >= len) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
data += skip;
|
|
|
|
|
len -= skip;
|
|
|
|
|
}
|
|
|
|
|
if(NupFrameLen + len > NUP_FRAME_BUF_MAX) {
|
|
|
|
|
NupFrameLen = 0; //溢出保护, 重新同步
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
memcpy(&NupFrameBuf[NupFrameLen], data, len);
|
|
|
|
|
NupFrameLen += len;
|
|
|
|
|
while(NupFrameLen >= 11) {
|
|
|
|
|
if(NupFrameBuf[0] != 0x7D) {
|
|
|
|
|
uint16_t i;
|
|
|
|
|
for(i = 1; i < NupFrameLen; i++) {
|
|
|
|
|
if(NupFrameBuf[i] == 0x7D) break;
|
|
|
|
|
}
|
|
|
|
|
if(i >= NupFrameLen) {
|
|
|
|
|
NupFrameLen = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
memmove(NupFrameBuf, &NupFrameBuf[i], NupFrameLen - i);
|
|
|
|
|
NupFrameLen -= i;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
uint16_t total = 11 + NupFrameBuf[8];
|
|
|
|
|
if(NupFrameLen < total) {
|
|
|
|
|
break; //帧未收齐, 等下一分片
|
|
|
|
|
}
|
|
|
|
|
uint16_t calc = CRC_Modbus(CRC16_BASE, NupFrameBuf, total - 2);
|
|
|
|
|
uint16_t recv = NupFrameBuf[total - 2] | (NupFrameBuf[total - 1] << 8);
|
|
|
|
|
if(calc == recv) {
|
|
|
|
|
/*MAC filter: only the device whose own GwMac matches the 0x7D frame header handles the frame,
|
|
|
|
|
broadcast 0x81 is answered by the target device only, other devices drop it silently*/
|
|
|
|
|
if(memcmp(&NupFrameBuf[1], GateWay.ConfigPara.GwMac, 6) == 0) {
|
|
|
|
|
NetUpgradeFrameHandler(NupFrameBuf[7], &NupFrameBuf[9], NupFrameBuf[8]);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
U_DBG_LOG("NetUpgrade MAC mismatch, check upgrade dialog MAC\r\n");
|
|
|
|
|
}
|
|
|
|
|
memmove(NupFrameBuf, &NupFrameBuf[total], NupFrameLen - total);
|
|
|
|
|
NupFrameLen -= total;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
memmove(NupFrameBuf, &NupFrameBuf[1], NupFrameLen - 1);
|
|
|
|
|
NupFrameLen -= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
* 函数名称: Update
|
|
|
|
|
* 功能描述: 固件升级,此函数在解析到升级指令时调用
|
|
|
|
|
* 参 数: PayLoad 协议负载,需去除帧头等信息,只传负载数据
|
|
|
|
|
* 返 回 值: 无
|
|
|
|
|
/*****************************************************************************************
|
|
|
|
|
* 函 数 名: NetUpgradePopTx
|
|
|
|
|
* 功 能: 取出本通道应答帧(0x01 ACK/0x02请求), 供CatOne主循环/EthTask经AT+LIPSEND直发
|
|
|
|
|
void Update(uint8_t *PayLoad)
|
|
|
|
|
{
|
|
|
|
|
UpDataRequset_t Req;
|
|
|
|
|
boot_para_t cfg = {0};
|
|
|
|
|
|
|
|
|
|
memcpy(&Req, PayLoad, sizeof(UpDataRequset_t));
|
|
|
|
|
|
|
|
|
|
/*固件大小校验: 为0或超出B区容量时拒绝升级, 不置标志不复位*/
|
|
|
|
|
if(Req.AppSize == 0 || Req.AppSize > FLASH_APPB_SIZE) {
|
|
|
|
|
U_DBG_LOG("AppSize invalid: %d (max %d)\r\n", (int)Req.AppSize, (int)FLASH_APPB_SIZE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*读回现有boot参数,保留FirstRunFlag等字段*/
|
|
|
|
|
dev_boot_read_param(&cfg);
|
|
|
|
|
cfg.AppSize = Req.AppSize;
|
|
|
|
|
cfg.Crc32Check = Req.AppCrc32;
|
|
|
|
|
cfg.PackageCnt = Req.PackageNum;
|
|
|
|
|
cfg.AppFlag = 0;
|
|
|
|
|
cfg.UpdateFlag = APP_UPDATE_FLAG;
|
|
|
|
|
memcpy(cfg.GwMac, GateWay.ConfigPara.GwMac, 6);
|
|
|
|
|
|
|
|
|
|
U_DBG_LOG("Receive upgrade command:\r\n");
|
|
|
|
|
U_DBG_LOG("PackageNum: %d\r\n", cfg.PackageCnt);
|
|
|
|
|
U_DBG_LOG("AppSize: %d\r\n", cfg.AppSize);
|
|
|
|
|
U_DBG_LOG("AppCrc32: 0x%08x\r\n", cfg.Crc32Check);
|
|
|
|
|
U_DBG_LOG("System Reset!\r\n");
|
|
|
|
|
|
|
|
|
|
NetUpgradeSavePkg(0);
|
|
|
|
|
SAVE_BOOT_PARA(&cfg);
|
|
|
|
|
U_DELAY_MS(200);
|
|
|
|
|
U_SYSTEM_TESET();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************************
|
|
|
|
|
* 函数名称: UpdateInit
|
|
|
|
|
* 功能描述: 升级参数初始化,需要在程序启动,外设初始化完后调用
|
|
|
|
|
* 参 数: 无
|
|
|
|
|
* 返 回 值: 无
|
|
|
|
|
*****************************************************************************************/
|
|
|
|
|
void UpdateInit(void)
|
|
|
|
|
{
|
|
|
|
|
boot_para_t cfg;
|
|
|
|
|
|
|
|
|
|
READ_BOOT_PARA(&cfg);
|
|
|
|
|
/*参照hc32l170_app: 仅确保AppFlag=APP_START_FLAG, 使Boot下次直接跳转App
|
|
|
|
|
(网关MAC/服务器/Lora配置从BootPara_t获取, 由Boot配置)*/
|
|
|
|
|
if(cfg.AppFlag != APP_START_FLAG) {
|
|
|
|
|
cfg.AppFlag = APP_START_FLAG;
|
|
|
|
|
SAVE_BOOT_PARA(&cfg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************************
|
|
|
|
|
* Cat1远程升级模块(0x7D帧, 与Boot RS485升级协议一致)
|
|
|
|
|
* 服务器(升级主机) --TCP--> Cat1模组 --USART1--> 本模块:
|
|
|
|
|
* 收0x81升级请求(校验/擦暂存区/断点续传判定) → 0x82分包顺序写入外部SPI Flash暂存区
|
|
|
|
|
* → 每收NUP_WINDOW包回0x02请求帧(服务端窗口流控) → 收完CRC32校验通过后置
|
|
|
|
|
* APP_UPDATE_SPI_FLAG复位, 由Boot完成"外部Flash→B区→A区"搬运
|
|
|
|
|
* 协议帧: 0x7D + DevMac(6) + Cmd + Len + Payload + CRC16(Modbus), 命令0x81/0x82/0x01/0x02
|
|
|
|
|
*****************************************************************************************/
|
|
|
|
|
#define NUP_PACKET_DATA 200 //每包数据长度(与服务端/Boot一致)
|
|
|
|
|
#define NUP_STASH_PROG_MAGIC 0xA5A5C35A //升级进度记录魔数
|
|
|
|
|
#define NUP_WINDOW 8 //每收W包回一次请求帧
|
|
|
|
|
#define NUP_TIMEOUT_MS 3000 //等包超时(Cat1延迟大)
|
|
|
|
|
#define NUP_TIMEOUT_MAX 5 //连续超时次数上限
|
|
|
|
|
#define NUP_IDLE_TIMEOUT_MS 1800000UL //整体无进展超时(30分钟)
|
|
|
|
|
#define NUP_FRAME_BUF_MAX 3072 //0x7D组帧缓冲上限(容纳URC单次喂入的多帧拼接)
|
|
|
|
|
#define NUP_APP_MAX (232 * 1024) //A区容量上限
|
|
|
|
|
|
|
|
|
|
/*升级进度记录(存外部Flash扇区4037): 断电/断连后据此判定断点续传*/
|
|
|
|
|
typedef struct {
|
|
|
|
|
uint32_t Magic; //NUP_STASH_PROG_MAGIC
|
|
|
|
|
uint32_t AppSize; //固件大小
|
|
|
|
|
uint32_t Crc32; //固件CRC32
|
|
|
|
|
uint32_t PkgCnt; //已连续收到的包数
|
|
|
|
|
}FwStashProg_t;
|
|
|
|
|
|
|
|
|
|
static struct {
|
|
|
|
|
bool Active; //升级会话进行中
|
|
|
|
|
uint16_t PkgCnt; //总包数
|
|
|
|
|
uint32_t AppSize; //固件大小
|
|
|
|
|
uint32_t Crc32; //固件CRC32
|
|
|
|
|
uint16_t ExpectIdx; //期望接收的包序号
|
|
|
|
|
uint16_t LastAckIdx; //最近一次0x02应答的包序号(窗口流控基准)
|
|
|
|
|
uint32_t LastTick; //最近收包时刻(rt_tick, 1ms)
|
|
|
|
|
uint32_t ErrCnt; //连续超时次数
|
|
|
|
|
uint8_t TxQ[4][40]; //应答帧队列(0x01/0x02连发互不挤占)
|
|
|
|
|
uint8_t TxQLen[4];
|
|
|
|
|
uint8_t TxHead; //队首索引(出队)
|
|
|
|
|
uint8_t TxCnt; //队列帧数
|
|
|
|
|
}Nup;
|
|
|
|
|
|
|
|
|
|
static uint8_t NupFrameBuf[NUP_FRAME_BUF_MAX]; //0x7D组帧缓冲(TCP分片跨URC拼接)
|
|
|
|
|
static uint16_t NupFrameLen = 0;
|
|
|
|
|
static uint64_t NupErasedMap = 0; /*bit i: stash sector i erased this session (NOR writes only 1->0, erase-before-write required)*/
|
|
|
|
|
|
|
|
|
|
/*软件CRC32: 与Boot GetCrc32/服务端zlib.crc32同算法(0xEDB88320反射, 初末值0xFFFFFFFF)*/
|
|
|
|
|
static uint32_t NetUpgradeCrc32Stash(uint32_t Len)
|
|
|
|
|
{
|
|
|
|
|
uint32_t Crc = 0xFFFFFFFF;
|
|
|
|
|
uint32_t Done = 0;
|
|
|
|
|
uint8_t Buf[256];
|
|
|
|
|
while(Done < Len) {
|
|
|
|
|
uint16_t n = (Len - Done > sizeof(Buf)) ? sizeof(Buf) : (uint16_t)(Len - Done);
|
|
|
|
|
FwStashRead(Buf, Done, n);
|
|
|
|
|
for(uint16_t i = 0; i < n; i++) {
|
|
|
|
|
Crc ^= Buf[i];
|
|
|
|
|
for(int b = 0; b < 8; b++) {
|
|
|
|
|
Crc = (Crc & 1) ? (Crc >> 1) ^ 0xEDB88320 : (Crc >> 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Done += n;
|
|
|
|
|
}
|
|
|
|
|
return ~Crc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*进度记录持久化(扇区4037): PkgCnt=0表示清除*/
|
|
|
|
|
static void NetUpgradeSavePkg(uint32_t PkgCnt)
|
|
|
|
|
{
|
|
|
|
|
FwStashProg_t Prog;
|
|
|
|
|
Prog.Magic = (PkgCnt > 0) ? NUP_STASH_PROG_MAGIC : 0;
|
|
|
|
|
Prog.AppSize = Nup.AppSize;
|
|
|
|
|
Prog.Crc32 = Nup.Crc32;
|
|
|
|
|
Prog.PkgCnt = PkgCnt;
|
|
|
|
|
FwStashProgWrite((uint8_t *)&Prog, sizeof(Prog));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*待发帧入队(0x7D原始帧, 由CatOne主循环经AT+LIPSEND直发, 绕过0x7A打包)*/
|
|
|
|
|
static void NetUpgradePushTx(uint8_t Cmd, uint8_t *Payload, uint8_t Len)
|
|
|
|
|
{
|
|
|
|
|
uint16_t crc;
|
|
|
|
|
rt_base_t level = rt_hw_interrupt_disable();
|
|
|
|
|
if(Nup.TxCnt >= 4) {
|
|
|
|
|
rt_hw_interrupt_enable(level);
|
|
|
|
|
return; /*queue full: drop*/
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
uint8_t Tail = (Nup.TxHead + Nup.TxCnt) % 4;
|
|
|
|
|
Nup.TxQ[Tail][0] = 0x7D;
|
|
|
|
|
memcpy(&Nup.TxQ[Tail][1], GateWay.ConfigPara.GwMac, 6);
|
|
|
|
|
Nup.TxQ[Tail][7] = Cmd;
|
|
|
|
|
Nup.TxQ[Tail][8] = Len;
|
|
|
|
|
memcpy(&Nup.TxQ[Tail][9], Payload, Len);
|
|
|
|
|
crc = CRC_Modbus(CRC16_BASE, Nup.TxQ[Tail], 9 + Len);
|
|
|
|
|
Nup.TxQ[Tail][9 + Len] = crc & 0xFF;
|
|
|
|
|
Nup.TxQ[Tail][10 + Len] = (crc >> 8) & 0xFF;
|
|
|
|
|
Nup.TxQLen[Tail] = 11 + Len;
|
|
|
|
|
Nup.TxCnt++;
|
|
|
|
|
}
|
|
|
|
|
rt_hw_interrupt_enable(level);
|
|
|
|
|
U_DBG_LOG("NetUpgrade push: cmd=0x%02x cnt=%d\r\n", Cmd, Nup.TxCnt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void NetUpgradeSendAck(uint8_t Status, uint16_t Resumed)
|
|
|
|
|
{
|
|
|
|
|
uint8_t p[3];
|
|
|
|
|
p[0] = Status;
|
|
|
|
|
p[1] = Resumed & 0xFF;
|
|
|
|
|
p[2] = (Resumed >> 8) & 0xFF;
|
|
|
|
|
NetUpgradePushTx(0x01, p, 3); //0x20全新/0x21续传/0x32拒绝
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void NetUpgradeSendReq(uint16_t Idx)
|
|
|
|
|
{
|
|
|
|
|
uint8_t p[4];
|
|
|
|
|
p[0] = Idx & 0xFF;
|
|
|
|
|
p[1] = (Idx >> 8) & 0xFF;
|
|
|
|
|
p[2] = Nup.PkgCnt & 0xFF;
|
|
|
|
|
p[3] = (Nup.PkgCnt >> 8) & 0xFF;
|
|
|
|
|
NetUpgradePushTx(0x02, p, 4); //请求从Idx起的下一批(收满PkgCnt视为完成)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*0x81升级请求: 合法性检查/回ACK并启动下载*/
|
|
|
|
|
static void NetUpgradeOnReq(uint8_t *Payload, uint8_t Len)
|
|
|
|
|
{
|
|
|
|
|
UpDataRequset_t Req;
|
|
|
|
|
if(Len < sizeof(Req)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
memcpy(&Req, Payload, sizeof(Req));
|
|
|
|
|
if(Req.AppSize == 0 || Req.AppSize > NUP_APP_MAX) {
|
|
|
|
|
NetUpgradeSendAck(0x32, 0);
|
|
|
|
|
U_DBG_LOG("NetUpgrade reject: AppSize=%d\r\n", Req.AppSize);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/*断点续传已取消: 每次点击升级均从0%全新下载*/
|
|
|
|
|
NetUpgradeSavePkg(0);
|
|
|
|
|
NupErasedMap = 0;
|
|
|
|
|
Nup.Active = true;
|
|
|
|
|
Nup.PkgCnt = Req.PackageNum;
|
|
|
|
|
Nup.AppSize = Req.AppSize;
|
|
|
|
|
Nup.Crc32 = Req.AppCrc32;
|
|
|
|
|
Nup.ExpectIdx = 0;
|
|
|
|
|
Nup.ErrCnt = 0;
|
|
|
|
|
Nup.LastTick = rt_tick_get();
|
|
|
|
|
Nup.LastAckIdx = 0;
|
|
|
|
|
U_DBG_LOG("NetUpgrade req: Pkg=%d Size=%d Crc=0x%08x Resumed=0\r\n",
|
|
|
|
|
Nup.PkgCnt, Nup.AppSize, Nup.Crc32);
|
|
|
|
|
NetUpgradeSendAck(0x20, 0);
|
|
|
|
|
NetUpgradeSendReq(0); //请求首包, 服务端收到0x02才开始发包
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*0x82升级数据: 严格按期望包号顺序写暂存区, 收满窗口回请求帧, 收完CRC校验*/
|
|
|
|
|
static void NetUpgradeOnData(uint8_t *Payload, uint8_t Len)
|
|
|
|
|
{
|
|
|
|
|
uint16_t Idx, Total;
|
|
|
|
|
uint8_t DataLen;
|
|
|
|
|
uint32_t WriteLen;
|
|
|
|
|
if(!Nup.Active || Len < 5) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
Idx = Payload[0] | (Payload[1] << 8);
|
|
|
|
|
Total = Payload[2] | (Payload[3] << 8);
|
|
|
|
|
DataLen = Payload[4];
|
|
|
|
|
if(Total != Nup.PkgCnt) {
|
|
|
|
|
return; //会话不匹配
|
|
|
|
|
}
|
|
|
|
|
if(Idx != Nup.ExpectIdx) {
|
|
|
|
|
return; //重复/乱序包: 丢弃(服务端按期望包号重发)
|
|
|
|
|
}
|
|
|
|
|
if(Idx == Nup.PkgCnt - 1) {
|
|
|
|
|
WriteLen = Nup.AppSize - (uint32_t)Idx * NUP_PACKET_DATA; //尾包实长
|
|
|
|
|
if(DataLen < WriteLen) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if(DataLen < NUP_PACKET_DATA) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
WriteLen = NUP_PACKET_DATA;
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
/*NOR only writes 1->0: erase touched stash sectors before write (one erase per sector per session), fixes stale-bit corruption on 2nd upgrade*/
|
|
|
|
|
uint32_t Sec0 = (uint32_t)Idx * NUP_PACKET_DATA / SPIFLASH_SECTORSIZE;
|
|
|
|
|
uint32_t Sec1 = ((uint32_t)Idx * NUP_PACKET_DATA + WriteLen - 1) / SPIFLASH_SECTORSIZE;
|
|
|
|
|
for(uint32_t s = Sec0; s <= Sec1; s++) {
|
|
|
|
|
if((NupErasedMap & ((uint64_t)1 << s)) == 0) {
|
|
|
|
|
FwStashEraseSector(s);
|
|
|
|
|
NupErasedMap |= (uint64_t)1 << s;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
FwStashWrite(&Payload[5], (uint32_t)Idx * NUP_PACKET_DATA, WriteLen);
|
|
|
|
|
Nup.ExpectIdx++;
|
|
|
|
|
Nup.LastTick = rt_tick_get();
|
|
|
|
|
Nup.ErrCnt = 0;
|
|
|
|
|
if(Nup.ExpectIdx >= Nup.PkgCnt) {
|
|
|
|
|
if(NetUpgradeCrc32Stash(Nup.AppSize) == Nup.Crc32) {
|
|
|
|
|
U_DBG_LOG("NetUpgrade stash verified, reboot to bootloader\r\n");
|
|
|
|
|
UpdateFromStash(Nup.AppSize, Nup.Crc32); //置APP_UPDATE_SPI_FLAG并复位
|
|
|
|
|
}
|
|
|
|
|
U_DBG_LOG("NetUpgrade stash CRC failed, restart download\r\n");
|
|
|
|
|
//校验失败: 从0重下(写前按需擦除保证暂存区干净)
|
|
|
|
|
NetUpgradeSavePkg(0);
|
|
|
|
|
NupErasedMap = 0;
|
|
|
|
|
Nup.ExpectIdx = 0;
|
|
|
|
|
NetUpgradeSendReq(0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(Nup.ExpectIdx - Nup.LastAckIdx >= NUP_WINDOW) {
|
|
|
|
|
NetUpgradeSendReq(Nup.ExpectIdx); //收满窗口, 请求下一批(与断点起点无关)
|
|
|
|
|
Nup.LastAckIdx = Nup.ExpectIdx;
|
|
|
|
|
}
|
|
|
|
|
if(Nup.ExpectIdx % (NUP_WINDOW * 4) == 0) {
|
|
|
|
|
NetUpgradeSavePkg(Nup.ExpectIdx); //定期持久化进度(32包一次)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void NetUpgradeFrameHandler(uint8_t Cmd, uint8_t *Payload, uint8_t Len)
|
|
|
|
|
{
|
|
|
|
|
U_DBG_LOG("NetUpgrade frame: cmd=0x%02x len=%d\r\n", Cmd, Len);
|
|
|
|
|
switch(Cmd) {
|
|
|
|
|
case 0x81:
|
|
|
|
|
NetUpgradeOnReq(Payload, Len);
|
|
|
|
|
break;
|
|
|
|
|
case 0x82:
|
|
|
|
|
NetUpgradeOnData(Payload, Len);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************************
|
|
|
|
|
* 函数名称: NetUpgradeFeed
|
|
|
|
|
* 功能描述: 喂入Cat1下行数据片段(+LIPURC二进制), 流式拼接提取完整0x7D升级帧
|
|
|
|
|
* 参 数: data/len, 二进制数据片段(TCP分片有序)
|
|
|
|
|
* 返 回 值: true=数据已被升级模块消费(帧头0x7D); false=非0x7D流, 调用方交还原0x7A路径
|
|
|
|
|
*****************************************************************************************/
|
|
|
|
|
bool NetUpgradeFeed(uint8_t *data, uint16_t len)
|
|
|
|
|
{
|
|
|
|
|
if(NupFrameLen == 0) {
|
|
|
|
|
uint16_t skip = 0;
|
|
|
|
|
while(skip < len && data[skip] != 0x7D) {
|
|
|
|
|
skip++;
|
|
|
|
|
}
|
|
|
|
|
if(skip >= len) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
data += skip;
|
|
|
|
|
len -= skip;
|
|
|
|
|
}
|
|
|
|
|
if(NupFrameLen + len > NUP_FRAME_BUF_MAX) {
|
|
|
|
|
NupFrameLen = 0; //溢出保护, 重新同步
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
memcpy(&NupFrameBuf[NupFrameLen], data, len);
|
|
|
|
|
NupFrameLen += len;
|
|
|
|
|
while(NupFrameLen >= 11) {
|
|
|
|
|
if(NupFrameBuf[0] != 0x7D) {
|
|
|
|
|
uint16_t i;
|
|
|
|
|
for(i = 1; i < NupFrameLen; i++) {
|
|
|
|
|
if(NupFrameBuf[i] == 0x7D) break;
|
|
|
|
|
}
|
|
|
|
|
if(i >= NupFrameLen) {
|
|
|
|
|
NupFrameLen = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
memmove(NupFrameBuf, &NupFrameBuf[i], NupFrameLen - i);
|
|
|
|
|
NupFrameLen -= i;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
uint16_t total = 11 + NupFrameBuf[8];
|
|
|
|
|
if(NupFrameLen < total) {
|
|
|
|
|
break; //帧未收齐, 等下一分片
|
|
|
|
|
}
|
|
|
|
|
uint16_t calc = CRC_Modbus(CRC16_BASE, NupFrameBuf, total - 2);
|
|
|
|
|
uint16_t recv = NupFrameBuf[total - 2] | (NupFrameBuf[total - 1] << 8);
|
|
|
|
|
if(calc == recv) {
|
|
|
|
|
/*MAC filter: only the device whose own GwMac matches the 0x7D frame header handles the frame,
|
|
|
|
|
broadcast 0x81 is answered by the target device only, other devices drop it silently*/
|
|
|
|
|
if(memcmp(&NupFrameBuf[1], GateWay.ConfigPara.GwMac, 6) == 0) {
|
|
|
|
|
NetUpgradeFrameHandler(NupFrameBuf[7], &NupFrameBuf[9], NupFrameBuf[8]);
|
|
|
|
|
}
|
|
|
|
|
memmove(NupFrameBuf, &NupFrameBuf[total], NupFrameLen - total);
|
|
|
|
|
NupFrameLen -= total;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
memmove(NupFrameBuf, &NupFrameBuf[1], NupFrameLen - 1);
|
|
|
|
|
NupFrameLen -= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************************
|
|
|
|
|
* 函数名称: NetUpgradePopTx
|
|
|
|
|
* 功能描述: 取待发应答帧(0x01 ACK/0x02请求), 由CatOne主循环经AT+LIPSEND直发
|
|
|
|
|
*****************************************************************************************/
|
|
|
|
|
bool NetUpgradePopTx(uint8_t *Out, uint16_t *OutLen)
|
|
|
|
|
*****************************************************************************************/
|
|
|
|
|
bool NetUpgradePopTx(uint8_t *Out, uint16_t *OutLen, uint8_t ch)
|
|
|
|
|
{
|
|
|
|
|
uint8_t cmdLog = 0;
|
|
|
|
|
bool ret = false;
|
|
|
|
|
if(Nup.TxCnt > 0) {
|
|
|
|
|
cmdLog = Nup.TxQ[Nup.TxHead][7];
|
|
|
|
|
memcpy(Out, Nup.TxQ[Nup.TxHead], Nup.TxQLen[Nup.TxHead]);
|
|
|
|
|
*OutLen = Nup.TxQLen[Nup.TxHead];
|
|
|
|
|
Nup.TxHead = (Nup.TxHead + 1) % 4;
|
|
|
|
|
rt_base_t level = rt_hw_interrupt_disable();
|
|
|
|
|
for(uint8_t idx = 0; idx < Nup.TxCnt; idx++) {
|
|
|
|
|
uint8_t slot = (Nup.TxHead + idx) % 4;
|
|
|
|
|
if(Nup.TxChan[slot] != ch) continue; /*跳过其他通道的帧(Cat1/ETH各自取自己的ACK)*/
|
|
|
|
|
memcpy(Out, Nup.TxQ[slot], Nup.TxQLen[slot]);
|
|
|
|
|
*OutLen = Nup.TxQLen[slot];
|
|
|
|
|
uint8_t keep = Nup.TxCnt - idx - 1; /*slot之后的帧数: 依次前移紧凑*/
|
|
|
|
|
for(uint8_t m2 = 0; m2 < keep; m2++) {
|
|
|
|
|
uint8_t curSlot = (slot + m2) % 4;
|
|
|
|
|
uint8_t nxt = (slot + m2 + 1) % 4;
|
|
|
|
|
memcpy(Nup.TxQ[curSlot], Nup.TxQ[nxt], 40);
|
|
|
|
|
Nup.TxChan[curSlot] = Nup.TxChan[nxt];
|
|
|
|
|
Nup.TxQLen[curSlot] = Nup.TxQLen[nxt];
|
|
|
|
|
}
|
|
|
|
|
Nup.TxCnt--;
|
|
|
|
|
ret = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if(ret) {
|
|
|
|
|
U_DBG_LOG("NetUpgrade pop: cmd=0x%02x\r\n", cmdLog);
|
|
|
|
|
}
|
|
|
|
|
rt_hw_interrupt_enable(level);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool NetUpgradeActive(void)
|
|
|
|
|
{
|
|
|
|
|
return Nup.Active;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************************
|
|
|
|
|
* 函数名称: NetUpgradeTick
|
|
|
|
|
* 功能描述: 1ms轮询(CatOne主循环调用): 等包超时催发请求, 长期无进展放弃会话
|
|
|
|
|
*****************************************************************************************/
|
|
|
|
|
void NetUpgradeTick(void)
|
|
|
|
|
{
|
|
|
|
|
if(!Nup.Active) {
|
|
|
|
|
if(NupFrameLen > 0) {
|
|
|
|
|
NupFrameLen = 0; /*非会话期清理残片, 防止后续0x7A业务流被组帧器吞掉*/
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
uint32_t Now = rt_tick_get();
|
|
|
|
|
if(Now - Nup.LastTick > NUP_IDLE_TIMEOUT_MS) {
|
|
|
|
|
Nup.Active = false;
|
|
|
|
|
NupFrameLen = 0;
|
|
|
|
|
U_DBG_LOG("NetUpgrade idle timeout(30min), abort session\r\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(Now - Nup.LastTick > NUP_TIMEOUT_MS) {
|
|
|
|
|
Nup.LastTick = Now;
|
|
|
|
|
NupFrameLen = 0; /*等包超时: 残片必为损坏流, 清掉重同步*/
|
|
|
|
|
Nup.ErrCnt++;
|
|
|
|
|
if(Nup.ErrCnt > NUP_TIMEOUT_MAX) {
|
|
|
|
|
Nup.Active = false; //放弃会话(不复位), 服务器可重新0x81发起
|
|
|
|
|
NupFrameLen = 0;
|
|
|
|
|
U_DBG_LOG("NetUpgrade timeout, abort session\r\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
NetUpgradeSendReq(Nup.ExpectIdx); //催发: 服务端重发当前批次
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************************
|
|
|
|
|
* 函数名称: UpdateFromStash
|
|
|
|
|
* 功能描述: 暂存区校验通过后, 置APP_UPDATE_SPI_FLAG并复位, Boot从外部Flash搬运升级
|
|
|
|
|
*****************************************************************************************/
|
|
|
|
|
void UpdateFromStash(uint32_t AppSize, uint32_t Crc32)
|
|
|
|
|
{
|
|
|
|
|
boot_para_t cfg;
|
|
|
|
|
|
|
|
|
|
READ_BOOT_PARA(&cfg);
|
|
|
|
|
cfg.AppSize = AppSize;
|
|
|
|
|
cfg.Crc32Check = Crc32;
|
|
|
|
|
cfg.PackageCnt = (uint16_t)((AppSize + NUP_PACKET_DATA - 1) / NUP_PACKET_DATA);
|
|
|
|
|
cfg.AppFlag = 0;
|
|
|
|
|
cfg.UpdateFlag = APP_UPDATE_SPI_FLAG;
|
|
|
|
|
|
|
|
|
|
NetUpgradeSavePkg(0); /*清除进度记录:本次升级已完结,下次升级从0重新开始*/
|
|
|
|
|
U_DBG_LOG("Upgrade ready: Size=%d Crc=0x%08x, reboot\r\n", AppSize, Crc32);
|
|
|
|
|
SAVE_BOOT_PARA(&cfg);
|
|
|
|
|
U_DELAY_MS(200);
|
|
|
|
|
U_SYSTEM_TESET();
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}/*****************************************************************************************
|
|
|
|
|
* 函 数 名: NetUpgradeActive
|
|
|
|
|
* 功 能: 升级会话状态查询
|
|
|
|
|
*****************************************************************************************/
|
|
|
|
|
bool NetUpgradeActive(void)
|
|
|
|
|
{
|
|
|
|
|
return Nup.Active;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************************
|
|
|
|
|
* 函数名称: NetUpgradeTick
|
|
|
|
|
* 功能描述: 1ms轮询(CatOne主循环调用): 等包超时催发请求, 长期无进展放弃会话
|
|
|
|
|
*****************************************************************************************/
|
|
|
|
|
void NetUpgradeTick(void)
|
|
|
|
|
{
|
|
|
|
|
if(!Nup.Active) {
|
|
|
|
|
if(NupFrameLen > 0) {
|
|
|
|
|
NupFrameLen = 0; /*非会话期清理残片, 防止后续0x7A业务流被组帧器吞掉*/
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
uint32_t Now = rt_tick_get();
|
|
|
|
|
if(Now - Nup.LastTick > NUP_IDLE_TIMEOUT_MS) {
|
|
|
|
|
Nup.Active = false;
|
|
|
|
|
NupFrameLen = 0;
|
|
|
|
|
U_DBG_LOG("NetUpgrade idle timeout(30min), abort session\r\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(Now - Nup.LastTick > NUP_TIMEOUT_MS) {
|
|
|
|
|
Nup.LastTick = Now;
|
|
|
|
|
NupFrameLen = 0; /*等包超时: 残片必为损坏流, 清掉重同步*/
|
|
|
|
|
Nup.ErrCnt++;
|
|
|
|
|
if(Nup.ErrCnt > NUP_TIMEOUT_MAX) {
|
|
|
|
|
Nup.Active = false; //放弃会话(不复位), 服务器可重新0x81发起
|
|
|
|
|
NupFrameLen = 0;
|
|
|
|
|
U_DBG_LOG("NetUpgrade timeout, abort session\r\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
NetUpgradeSendReq(Nup.ExpectIdx); //催发: 服务端重发当前批次
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************************
|
|
|
|
|
* 函数名称: UpdateFromStash
|
|
|
|
|
* 功能描述: 暂存区校验通过后, 置APP_UPDATE_SPI_FLAG并复位, Boot从外部Flash搬运升级
|
|
|
|
|
*****************************************************************************************/
|
|
|
|
|
void UpdateFromStash(uint32_t AppSize, uint32_t Crc32)
|
|
|
|
|
{
|
|
|
|
|
boot_para_t cfg;
|
|
|
|
|
|
|
|
|
|
READ_BOOT_PARA(&cfg);
|
|
|
|
|
cfg.AppSize = AppSize;
|
|
|
|
|
cfg.Crc32Check = Crc32;
|
|
|
|
|
cfg.PackageCnt = (uint16_t)((AppSize + NUP_PACKET_DATA - 1) / NUP_PACKET_DATA);
|
|
|
|
|
cfg.AppFlag = 0;
|
|
|
|
|
cfg.UpdateFlag = APP_UPDATE_SPI_FLAG;
|
|
|
|
|
|
|
|
|
|
NetUpgradeSavePkg(0); /*清除进度记录:本次升级已完结,下次升级从0重新开始*/
|
|
|
|
|
U_DBG_LOG("Upgrade ready: Size=%d Crc=0x%08x, reboot\r\n", AppSize, Crc32);
|
|
|
|
|
SAVE_BOOT_PARA(&cfg);
|
|
|
|
|
U_DELAY_MS(200);
|
|
|
|
|
U_SYSTEM_TESET();
|
|
|
|
|