当前位置: 首页 > news >正文

上位机签名脚本片段

CAN诊断实现基于UDS协议的OTA升级功能代码及资料(支持AB面升级 )。 产品包括: 1.升级上位机VS源码; 2.MCU端源码(boot+app),包含UDS协议框架(tp层代码基于iso15765和常用SID服务代码基于iso14229) 3.CAN学习资料和ISO14229资料。

最近在折腾CAN总线的OTA升级方案,刚好手头有个基于UDS协议的AB面升级实现。这个方案最骚的地方在于用标准诊断协议玩出了固件空中升级的花活,今天就跟大伙唠唠具体实现里那些有意思的坑。

先说整体架构,整个系统分三块打架:上位机负责发号施令,Bootloader负责接镖,App负责躺平被替换。这里有个骚操作——用UDS的0x34/0x36/0x37这三个诊断服务直接传输固件数据包,相当于把CAN总线当快递小哥使唤。

看这段服务处理代码就明白了:

// UDS服务路由表 const tUDS_Service UDS_ServiceTable[] = { {0x10, SessionControl}, // 会话控制 {0x34, RequestDownload}, // 请求下载 {0x36, TransferData}, // 传输数据 {0x37, RequestTransferExit}, // 请求传输退出 //...其他服务 }; // 固件数据传输处理 UDSServiceStatus TransferData(uint8_t *request, uint8_t *response) { uint16_t blockNum = (request[1] << 8) | request[2]; // 取数据块编号 uint8_t data[4096]; memcpy(data, &request[3], request[0]-3); // 提取有效数据 Flash_Write(FLASH_ADDR + blockNum*BLOCK_SIZE, data); // 写入Flash response[0] = 0x76; // 正响应格式 response[1] = blockNum >> 8; response[2] = blockNum & 0xFF; return POSITIVE_RESPONSE; }

这代码有个隐藏技巧——用数据块编号直接算Flash地址偏移。好处是不用维护额外映射表,但得确保上位机严格按照顺序发包。实测发现如果中间丢包,整个升级直接翻车,后来加了个CRC校验才稳如老狗。

传输层(TP)的实现也够有意思。ISO15765的流控机制和CAN报文的定时发送掐得死去活来,最后搞了个滑动窗口:

#define MAX_CAN_PAYLOAD 4096 static uint8_t tx_buffer[MAX_CAN_PAYLOAD]; static uint16_t window_size = 8; // 动态流控窗口 // 发送多帧处理 void ISO15765_SendMultiFrame(uint8_t *data, uint16_t len) { uint8_t sn = 0; uint16_t offset = 0; // 首帧发送 SendSingleFrame(0x10 | (len >> 8), len & 0xFF, data, 2); offset += 6; // 首帧带2字节长度 // 连续帧发送 while(offset < len) { if(WaitForFlowControl() == TIMEOUT) { // 等流控帧 AbortTransfer(); return; } for(uint8_t i=0; i<window_size; i++) { SendSingleFrame(0x20 | sn, 0, data+offset, 0); offset += 7; // 每帧7字节数据 sn = (sn + 1) % 16; if(offset >= len) break; } } }

这段代码最坑的是流控帧的等待超时处理。最早没加超时机制,遇到总线干扰直接卡死,后来加了个30ms超时重试才解决。还有那个动态调整window_size的骚操作,根据总线负载率自动缩放窗口大小,实测传输效率能提升40%以上。

CAN诊断实现基于UDS协议的OTA升级功能代码及资料(支持AB面升级 )。 产品包括: 1.升级上位机VS源码; 2.MCU端源码(boot+app),包含UDS协议框架(tp层代码基于iso15765和常用SID服务代码基于iso14229) 3.CAN学习资料和ISO14229资料。

AB面切换才是真·刺激战场。Bootloader里维护了个双备份结构体:

typedef struct { uint32_t magic_flag; uint8_t active_partition; uint32_t crc32; uint32_t version; } PartitionInfo; // 分区表存储在Flash最后4K #define PARTITION_TABLE_ADDR 0x0800F000 void SwitchPartition() { PartitionInfo *current = (PartitionInfo*)PARTITION_TABLE_ADDR; if(current->active_partition == PARTITION_A) { current->active_partition = PARTITION_B; current->crc32 = CalculateCRC(PARTITION_B_ADDR); } else { current->active_partition = PARTITION_A; current->crc32 = CalculateCRC(PARTITION_A_ADDR); } Flash_Erase(PARTITION_TABLE_ADDR); Flash_Write(PARTITION_TABLE_ADDR, (uint8_t*)current, sizeof(PartitionInfo)); }

这个设计有个暗坑——写分区表前必须严格校验新固件的CRC,否则切到坏镜像直接变砖。后来在Boot流程里加了三重验证:CRC校验、向量表校验、栈指针校验,确保万无一失。

实战中发现OTA成功率受CAN总线负载影响极大。解决方法是在上位机加了智能重传机制——连续丢3个包就自动降速,同时用0x78否定响应码通知上位机重传特定数据块。这个优化让升级成功率从75%直接飙到99%。

代码仓库里还有个骚气功能——模拟器模式。把CAN驱动替换成虚拟总线,直接在本机跑完整升级流程。这对调试帮助巨大,毕竟不用每次都烧录到板子上测试。不过要小心虚拟模式和实际硬件的时序差异,有些死锁问题只在真机上才会暴露。

最后给个忠告:OTA安全千万不能马虎!项目里实现了简单的签名验证,用的是ECC算法。虽然比不上专业的HSM,但总比裸奔强:

from ecdsa import SigningKey sk = SigningKey.generate() # 生成私钥 vk = sk.verifying_key # 公钥烧录到MCU with open("firmware.bin", "rb") as f: firmware = f.read() signature = sk.sign(firmware) # 将签名附加到固件尾部 with open("signed_firmware.bin", "wb") as f: f.write(firmware) f.write(signature)

这套方案虽然比不上AES加密,但胜在资源占用小。STM32F103这种老爷车都能跑起来,实测签名校验代码只占2KB Flash,真·贫民窟方案。

玩转UDS OTA的核心秘诀就八个字:分而治之,冗余校验。把升级流程拆成无数个小步骤,每个环节都做好错误恢复。代码里那些看似多余的校验,关键时刻都是救命的稻草。

http://www.jsqmd.com/news/535700/

相关文章:

  • DFI Retail与SymphonyAI合作,共同推动人工智能驱动的销售能力
  • ChatGPT Cookie 实战指南:安全存储与高效管理的最佳实践
  • 远程信息收集技术
  • GFLV2 (Generalized Focal Loss V2):在回归分支引入分布统计信息,提升定位质量——YOLOv8 改进实战
  • 5分钟掌握DownKyi:B站视频下载的完整解决方案
  • Aspose.Cells实战:如何优雅处理复杂Excel报表的PDF导出(含分页与缩放配置)
  • 网络入侵检测系统(NIDS)中的人工智能安全问题
  • 3款强力游戏文件处理工具:XISO工具助你轻松管理Xbox游戏镜像
  • 亚洲美女-造相Z-Turbo效果展示:多人合影构图、空间透视与人物比例协调性验证
  • OCR服务配置参数错误排查:从现象到根治的系统方法
  • 酒店会场预订的三种类型怎么选?酒店哥哥给你出招
  • 揭秘CompactGUI社区数据库:游戏压缩优化的集体智慧革命
  • GLM-OCR实战教程:将GLM-OCR嵌入RAG系统,构建文档智能问答助手
  • MediaCrawler:现代社交平台数据采集的智能化解决方案
  • 【全身灵巧操作:3D扩散策略、力自适应与接触显式学习】第八章 8.2 实战项目一:双臂协调物体搬运
  • The Estée Lauder Companies关于与Puig潜在交易的声明
  • 2026分布式训练核心:Parameter Server(参数服务器)全维度解析
  • 2024最新版VS Code + Spring Boot开发环境配置:含Maven镜像加速技巧
  • 零基础解锁AI图像修复全攻略:让老照片焕发新生
  • 如何构建你自己的“AirTag“系统:深入探索OpenHaystack定位网络技术
  • 告别Python环境混乱!Miniconda保姆级配置指南(附Pycharm联动技巧)
  • 智驭未来:AI量化策略交易软件开启投资新纪元
  • 从抗生素发现到推荐系统:谷本系数的8种跨界应用场景
  • 智能客服文档系统的架构设计与性能优化实战
  • Python数据分析实战:用matplotlib绘制对比统计特征图的两种方法(附完整代码)
  • 【全身灵巧操作:3D扩散策略、力自适应与接触显式学习】第八章 系统集成与实战项目 8.3 实战项目二:接触-rich门操作接触密集型操作
  • Cyberduck跨平台文件传输架构深度解析与实战应用
  • APS6404L-SQNX-SN:智能设备内存新选择
  • K8S证书管理避坑大全:从1年有效期的坑,到自动化轮换的最佳实践
  • 跨媒介工业流:2026年6款专业 AI写作与漫剧短剧转化软件横评