前言:
而今姐妹们对“pythoncrc32校验”都比较关切,你们都需要知道一些“pythoncrc32校验”的相关文章。那么小编同时在网络上收集了一些关于“pythoncrc32校验””的相关资讯,希望同学们能喜欢,姐妹们快快来了解一下吧!作为通用的物联网设备,由于用户需求各不相同,不少用户有一些个性化的定制要求;
设备所对接的传感器协议也多种多样,比如Modbus读写参数的数据类型,某些物理量需要特殊的数据类型;
甚至可能还存在意想不到的bug。
因此,远程升级的功能对于设备来说必不可少。
远程固件升级需要解决以下问题:
1)设备的远程访问
当设备被安装于局域网内部时,位于远程的固件升级软件工具无法穿透路由器访问设备。
2)固件的分包以及传送
由于设备的处理器资源有限,无法移植开源的http、FTP等协议栈,无法通过http、FTP等协议从服务器上下载固件,而需要自己实现代码,采用TCP协议进行固件包的发送;
而且对于几十k甚至上百k的固件,需要将固件拆成几百个字节的数据包,逐一发给设备;
4)固件的有效性检验
固件在传输过程中,难免会出现错误。
比如WiFi模块,或者是ethernet模块将数据通过uart转发给处理器时,如果有干扰、数据可能被破坏;
或者是处理器太忙,来不及接收数据,导致固件包丢失数据;
如果不对固件进行有效性检验,将被破坏的固件升级进控制器,会导致设备变砖而无法使用;
5)bootloader程序
bootloader程序需要下载固件的有效性检验,程序的擦除、固件数据从备份区到程序区的搬移。
6)处理器的固件升级软件实现
软件需要实现数据包接收,固件有效性验证、存储,数据应答等。
远程固件升级系统架构
设备作为TCP客户端连接到云服务器上的TCP服务端,定时发送心跳,维护连接,从而实现TCP的长链接。
在PC电脑上开发远程升级工具,作为TCP客户端与云服务器上的TCP服务器建立连接;
当需要远程升级时,通过PC工具向云服务器发送消息,所发消息中包括了远程设备的设备编号,以及PC工具的设备编号;
服务器收到消息之后,根据消息中的目标设备编号,从其维护的长链接中找到与该编号对应的链接,通过该链接向设备转发该消息;
设备收到消息之后,对消息中的固件包进行有效性验证,如果有效,则写入到固件暂存区,并回复成功,否则回复失败。
一些设计要点
处理器的存储空间安排:
以STM32F103RCT6为例,该处理器有256KByte的FLASH空间;
4KByte的空间用于bootloader程序。
52KByte用于存储用户数据;
剩余的FLASH空间一半作为程序存储区,一半作为固件暂存区,程序必须小于100KByte。
固件的生成与分包
在Keil中,将程序的memory的起始地址设置为0x8001000,大小设置为0x19000。
同时,设置运行fromelf.exe,使得编译程序时自动生成用于固件升级的bin文件。
通过delphi将生成出来的bin文件读入,并采用下述代码进行发包,加上协议头以及CRC32的校验值。
pkgs := stream.Size div perpage; rem := stream.Size mod perpage; addr := 0; if(rem > 0) then begin pkgs := pkgs + 1; end; strcrc := ''; for i:= 0 to (pkgs - 1) do begin curlen := perpage; if((i + 1) * perpage > bytecount) then begin curlen := bytecount - (i * perpage); end; payload := inttohex(i* perpage, 8)+inttohex(curlen, 8); // stream.Position := i * perpage; k := 0; tmpstr := ''; for j:= 0 to (curlen - 1) do begin stream.Read(val, 1); if((k and 1) = 0) then begin tmpstr := inttohex(val, 2); end else begin tmpstr := inttohex(val, 2) + tmpstr; end; inc(k); if((k and 1) = 0) then begin payload := payload + tmpstr; end; end; tempcrc := crc(payload); payload := tempcrc +payload; payload := inttohex((2 + 4 + 4 + perpage) * i, 8) + payload; payload := '01'+payload; strcrc := strcrc + tempcrc; payload := payload + crc(payload);; str := header+'&msgid='+inttostr(msgid)+'&length='+inttostr(1 + 2 + 4 + 4 + 4 + 2+ curlen)+'&cmd='+payload; inc(msgid); strcommands.Add(str); end;
固件的有效性验证以及升级的可靠性保证
整个固件包根据处理器的资源拆分为500个byte一个数据包;
每一个数据包都计算CRC32的数值并加入数据包中;
所以CRC32的数值再计算一遍CRC32数值并放入开始升级的命令之中;
控制器收到固件之后,重新计算500个byte的CRC32的计算值并与收到的CRC32值进行比对,只有两者相等时才存入暂存区;
当收到所有数据包时,从暂存区中按包读出固件,计算CRC32值与同时存储的CRC32值比对,同时计算所有CRC32数值的CRC32数值,与开始升级的命令中所携带的数值比对。
只有所有CRC32的数值都相同的情况下,应用程序才将升级程序的标志位写入到FLASH中,并重启处理器进入bootloader程序。
bootloader程序从FLASH中读取到升级程序的标志,则从暂存区中按包读取数据,进行同样的CRC32的验证过程,确保无误的情况下,将暂存区中的固件搬移到程序区。
全部程序搬移完之后,再逐个字节比较暂存区以及程序区的内容。
比对时,再检验CRC32是否正确。
只有CRC32数值正确并且与程序区的数据都相等的情况下,才清空升级程序的标志,完成升级过程。
升级程序的步骤及代码
步骤1:PC工具发送清空暂存区的命令,将暂存区的内存都擦写成0xff。
步骤2:PC工具发送写固件数据包的命令,处理器收到之后,进行有效性验证,并写入暂存区,重复该过程,完成整个固件的发送。
步骤3:PC工具发送开始升级的命令,处理器收到之后,再进行一次有效性验证,并重启,进入bootloader程序。
步骤4:bootloader程序进行有效性验证之后,将暂存区的固件搬移至程序区,完成升级;
代码如下:
U32 data, value, dataB;U8 res = FALSE;U8 flag;U16 pointer;U16 len;U8 *ins = lins + AP_ID_HEX_BYTE;if(fnCRC16_Check(lins, llen)){ len = 0; if(llen >= AP_ID_HEX_BYTE){ len = llen - AP_ID_HEX_BYTE; } if(inscode == FM_OPERATECODE_START){ if(fmups.m_uchState == FM_STATE_IDLE){ if(len == (1 + 4 + FM_STARTCODE_LEN + 2 )){ if(fnFM_IsStartStopValid(&ins[1 + 4])){ data = (U32)ins[1] << 24; data |= (U32)ins[2] << 16; data |= (U32)ins[3] << 8; data |= (U32)ins[4]; if(data < FLASH_ROM_SIZE_FIRMWARE){ fmups.m_uchState = FM_STATE_INIT; fmups.m_ulLen = data; fmups.m_uiTimer = FM_STATE_TIME; res = TRUE; } } } } } else if(inscode == FM_OPERATECODE_DOWNLOAD){ if(fmups.m_uchState == FM_STATE_DOWNLOAD){ if((len > (1 + 4 + 2 + 4 + 4 + 2)) && (len <= (1 + 4 + 2 + 4 + 4 + 2 + FM_DOWNLOAD_EVERYMSG))){ data = (U32)ins[1] << 24; data |= (U32)ins[2] << 16; data |= (U32)ins[3] << 8; data |= (U32)ins[4]; value = (U32)ins[7] << 24; value |= (U32)ins[8] << 16; value |= (U32)ins[9] << 8; value |= (U32)ins[10]; dataB = (U32)ins[11] << 24; dataB |= (U32)ins[12] << 16; dataB |= (U32)ins[13] << 8; dataB |= (U32)ins[14]; flag = TRUE; if(value != fmups.m_uchPointer){ flag = FALSE; if((value + dataB) == fmups.m_uchPointer){ res = TRUE; } } if(data >= (FLASH_ROM_SIZE_FIRMWARE - (FM_DOWNLOAD_EVERYMSG + 4+ 4 + 2))){ flag = FALSE; } if(dataB > FM_DOWNLOAD_EVERYMSG){ flag = FALSE; } if((fmups.m_uchPointer + dataB) > fmups.m_ulLen){ flag = FALSE; } if(flag){ if(value == fmups.m_uchPointer){ res = fnFL_WriteBytesAndCheck(data + FLASH_ROM_ADDR_FIRMWARE, (2 + 4 + 4 + dataB), &ins[5]); if(res){ fmups.m_uchPointer += dataB; } }else{ res = TRUE; } } } } } else if(inscode == FM_OPERATECODE_STOP){ if(len == (1 + 2 + 2 + FM_STARTCODE_LEN)){ if(fnFM_IsStartStopValid(&ins[3])){ if(fmups.m_uchState == FM_STATE_COMPLETE){ if(fnFM_Check(ins[1], ins[2])){ res = fnFM_ProCon(ins[1], ins[2]); if(res){ fmups.m_uchReStartTimer = 10; } } } } } } else if(inscode == FM_OPERATECODE_RESET){ if(len == (1 + 2 + FM_STARTCODE_LEN)){ if(fnFM_IsStartStopValid(&ins[1])){ res = TRUE; fmups.m_uchState = FM_STATE_IDLE; fmups.m_uiTimer = 0; } } }}ack[0] = inscode | 0x80;ack[1] = res;ack[2] = 0 ;pointer = 3;return(pointer);
标签: #pythoncrc32校验