做TBOX软件设计的第一年,我最大的感受是——很多人把这活干成了“堆功能”。需求下来了,远程开空调,好,写个CAN报文发送;要OTA升级,好,把FOTA的SDK集成进去。等代码写到上万行的时候,问题全来了:改一个上报逻辑要动五个模块,加一个远程指令要在六处补分支,休眠功耗超标了却不知道是哪个任务没释放资源。后来复盘才明白,TBOX软件设计这件事,真正的分水岭不在于你会不会写驱动、懂不懂CAN协议,而在于你有没有一套能把“产品需求”翻译成“软件结构”的方法论。这篇总结我就把这条路捋一遍,从架构分层到电源管理,从通信链路到测试验证,说说我实际跑过的设计思路,希望能给正在做TBOX或者准备上手的朋友一点参考。
1. 从产品角度重新理解TBOX软件设计这件事
1.1 TBOX在车联网里的角色:它到底解决什么问题
TBOX全称Telematics BOX,说人话就是给车装一个“能联网的盒子”。今天一部智能汽车,手机App要远程开空调、远程解锁,车厂后台要实时看到车辆位置和电量,出了碰撞事故要自动报警,这些能力基本都挂在TBOX身上。它是车辆和云端对话的翻译官:往上走,用4G/5G和云端通信;往下走,用CAN总线、以太网和整车各个控制器(ECU)打交道。
想清楚软件设计,第一步不是画架构图,而是想明白一个根本问题:TBOX和车上的其他控制器有什么本质区别?我理解下来,区别有两点。
第一,它天生是“被唤醒型”设备。整车上电后,发动机控制器、车身控制器都在干活,但TBOX大部分时间是休眠的,只有被特定的条件唤醒才起来干活。所以它的软件里必须有非常清晰的电源状态机,从休眠、唤醒、运行再到重新休眠,每一个状态切换都要精确可控。
第二,它是云-管-端的“端”。TBOX是车联网链条里暴露在外界环境中的一环,要面对弱网、断网、基站切换、SIM卡异常、网络延迟、尤其是安全攻击。这和车内封闭的CAN网络环境完全不同,很多软件设计问题都是这个身份带来的。
搞明白这两点,再看软件设计,思路会清晰很多:架构要服务的核心目标不是“把功能跑起来”,而是“在休眠和唤醒的切换中可靠工作,在恶劣网络条件下不丢重要数据,在软件迭代时尽量少动底层”。
1.2 软件设计的起点:不是UML图,是产品场景清单
很多嵌入式软件工程师拿到TBOX需求后喜欢直接开画架构图,画完V模型、画完分层图,然后开始写代码,结果往往是架构图和最终代码完全对不上。我现在的做法反过来了:先拉场景清单。
所谓场景清单,就是把产品需求翻译成“在什么时间、什么条件下、系统要做一件什么事”的表述。举个例子,产品需求里写“支持远程寻车”,翻译成场景是这样的:
- 车辆熄火、TBOX休眠状态下,手机App下发远程寻车指令;
- 云端通过短信把唤醒指令推送到TBOX模组,TBOX被唤醒并建立网络连接;
- TBOX向云端发送指令请求,确认云端确实发过这条指令;
- TBOX通过CAN总线向车身控制器发送寻车报文(闪灯+鸣笛);
- 执行完成后,TBOX上报执行结果,云端推送通知到App;
- 如果整个流程超过30秒仍未完成,TBOX主动上报超时并再次休眠。
不要小看这个翻译过程。它逼着你想清楚几个关键点:唤醒链路到底怎么走、指令去重怎么做、超时定多少秒、失败后要不要重试。架构图回答的是“系统由哪些部分组成”,场景清单回答的是“系统在真实世界里如何行为”。后者才是软件设计的真正依据。
我把这一步归纳成四个维度:触发条件(何时开始)、执行链路(经过哪些模块)、异常分支(失败了怎么办)、结束状态(完成后回到什么状态)。每个产品需求都按这四个维度拆一遍,拆完之后你会发现,很多设计问题在动手写代码之前就已经暴露了,这是成本最低的排雷方式。
2. 架构先行:分层、模块化与消息总线
2.1 典型的TBOX软件分层架构
TBOX软件一般跑双芯方案:一颗MCU(如NXP的S32K、TI的TMS570)负责CAN收发、电源管理、安全逻辑,一颗模组侧芯片(通常是4G模组自带的应用处理器,比如移远EC25、广和通L610内置的ARM核)负责网络通信、协议栈、业务逻辑。也有单芯方案,但双芯仍然是主流,因为电源管理和整车通信的实时性要求与网络协议栈的处理需求差异太大,强行放一个核里反而互相干扰。
抛开具体芯片,我倾向于把TBOX软件分成四层:
| 层级 | 职责 | 典型内容 |
|---|---|---|
| 应用层 | 承接产品需求,实现具体业务逻辑 | 远程控制、OTA管理、报警上报、数据采集 |
| 中间件层 | 屏蔽平台差异,提供通用服务 | 消息总线、日志、配置管理、时间同步、存储管理 |
| 协议栈层 | 处理通信协议 | TCP/UDP、MQTT、HTTPS、UDS诊断、CAN协议栈 |
| 驱动与平台层 | 直接操作硬件 | GPIO、UART、SPI、CAN驱动、GPIO模拟电源控制、休眠唤醒等 |
这个分层结构本身没什么新奇的,关键是各级之间的边界必须钉死,否则分层就是写在文档里的空话。我举个实际例子,应用层的远程空调模块要发一个空调开启指令,它不直接调用驱动接口,而是发一个带CAN ID和报文数据的消息给中间件,中间件转给设备抽象层,由设备抽象层根据当前车辆平台(不同车型的报文格式不一样)去组帧。这样如果你从A车型适配到B车型,改动范围被限制在设备抽象层,应用层代码一滴都不用动。
2.2 模块边界怎么划分才不容易改崩
模块划分是TBOX软件设计的重头戏,划分得好,后期加功能是加法;划分得烂,加一个功能是重构。我的经验是,模块不能按“功能清单”来分,而要按“变化频率”和“依赖方向”来分。
先说变化频率。一个远程空调功能,CAN报文格式可能会随车型变化,定时上报逻辑可能会随运营需求调整,但底层驱动几乎不变。所以驱动、协议格式、业务逻辑应该拆开。实际工作中,车型适配导致CAN报文变化是最常见的需求来源,如果把车身适配逻辑和应用逻辑混在一个文件里,每来一个新车型,你动的地方和别人动的地方就会重叠,代码冲突只是时间问题。
再说依赖方向。我给自己定了一条规矩:上层模块只能依赖下层模块的接口,同层模块之间不许互相调用,只能通过消息总线通信。这条规矩最直接的效果就是,你很难写出一个“牵一发动全身”的代码结构。比如数据采集模块需要把车辆数据发给通信模块上报,它不直接调用通信模块的函数,而且往消息总线上投递一条“数据上报请求”的消息,通信模块订阅到这条消息再执行发送。模块对彼此的存在感知降到了最低。
这套思想并不新鲜,汽车行业常用的AUTOSAR架构本质上也是这套思路的体系化表达,但小团队做TBOX不一定要上AUTOSAR,把分层的原则落实到代码组织里,效果是一样的。
2.3 消息总线:让模块之间对话方式统一
我见过很多TBOX初版代码的通信方式是“直接函数调用满天飞”。模块A需要模块B的数据,就调用module_b_get_data(),模块B需要通知模块C,又直接调module_c_notify()。这种代码在前三个月开发期跑得飞快,到半年后开始加功能时就会失控。
我的方案是做一条轻量级的消息总线。说白了就是一个带队列的消息分发中心,任何模块可以向总线发布消息,任何模块也可以订阅自己关心的消息类型。消息在内部是结构体,定义清楚消息类型(MSG_TYPE)和载荷(payload)。比如碰撞报警这个消息,数据采集模块在CAN总线上检测到安全气囊控制器的碰撞信号,把它打包成一条“碰撞报警”消息发到总线上,GPS模块、通信模块、日志模块各自订阅,各自响应,不像以前靠模块间互相绑定的方式去层层回调。
这套机制自己实现并不复杂,一个带互斥锁的环形队列加一张订阅注册表就够了。但如果公司有成熟方案(比如车企软件平台已经带了IPC中间件),直接用现成的更稳。关键是这个机制必须在架构里定下来,否则每个模块都有自己的通知方式,最后还是乱。
有一次排查一个疑难问题:模块A收不到模块B的数据,两位同事分别看代码,一个说“B明明发了”,一个说“A确实没收到”,撕了一个小时。后来发现B发的是结构体指针,A拿到的完整数据,原因只是消息队列在中断上下文里没有被正确保护,偶发丢失。如果之间有标准消息总线,这类问题排查起来会快很多——只管看总线入口出口,不用去翻所有调用点。
3. 状态机与电源管理:TBOX软件设计的命门
3.1 从休眠到唤醒:远程控制链路里的状态切换
如果说架构是TBOX软件设计的骨架,那电源状态机就是它的命门。TBOX是车上睡眠时间最长的控制器,但用户按一下App的按钮,它必须在几秒钟内醒来干活,干完活再睡回去。怎么保证这个“睡-醒-干-睡”的循环稳定可靠,是我做TBOX软件设计时花时间最多的地方。
先定义状态机。我常用的状态是四态模型:
- 关机态(Off):TBOX完全下电,只有极少电路维持,等待硬线唤醒或电平唤醒;
- 休眠态(Sleep):MCU和模组进入低功耗模式,保留RAM数据,等待RTC定时唤醒、外部中断唤醒、网络唤醒或硬线唤醒;
- 工作态(Active):全功能运行,执行远程控制、数据上报、OTA等业务;
- 过渡态(中间状态):比如正在初始化、正在进入休眠、正在驻网。
每个状态的进入条件和退出条件都要在需求阶段就定义好,不能边写代码边拍脑袋。举一个实际场景:车辆熄火后,TBOX不能立刻休眠,要先进入“熄火延时上报”状态,在这段时间里把最后一次定位、里程、电量等数据发到云端,云端记录好停车位置,然后再进入低功耗。如果你把这个逻辑当成一个简单延时函数写在主循环里,休眠流程会被其他任务卡住,功耗就降不下去。
3.2 短信唤醒的实现思路与注意事项
短信唤醒是目前TBOX远程控制最可靠的唤醒手段,也是被很多人低估了难度的部分。它的原理不复杂:TBOX的通信模组待机时仍然能让短信到达并产生URC(Unsolicited Result Code,模块主动上报的不请自来的消息)通知,MCU捕捉到这个URC信号,从休眠中唤醒,解析短信内容,确认是有效唤醒指令后,去连接网络并向云端发起指令请求。
这里有几个跟直觉不一样的设计细节,值得展开说。
第一,短信唤醒不是只靠模组的URC就够的。休眠状态下MCU要监听哪个UART串口、由哪个中断触发唤醒、唤醒后如何快速启动模组的电源,这些外围电路和软件配合要提前规划。我曾经遇到过一个问题:MCU休眠后UART接收中断没配置成唤醒源,结果短信到了模组,模组把URC发了过来,MCU却还在睡觉,典型的功能和功耗两头都丢了。
第二,短信内容要用指令码而非明文指令,而且要带序列号。短信在网络里是明文传输的,设计时默认不携带任何敏感操作的关键信息。常见的做法是短信里只带一个“触发码”,TBOX收到后不直接执行任何车身操作,而是先联网向云端确认“是否真的有一条远程开门指令待下发给本车”。云端确认属实才进入控制链路。这套设计多了一次网络往返,但把安全边界划得非常清楚:即使短信被伪造或劫持,攻击者得到的只是一个“唤醒信号”,没有真正的控制能力。
第三,短信唤醒必须处理短信轰炸和误触发的场景。一辆车一天被同一号码触发了20次唤醒,每次都联网确认、上报记录,虽然不执行实际操作,但也浪费流量和电。设计里要有唤醒频率限制,比如同一触发码5分钟内只响应一次,超过则忽略并记录日志。这个限制同时降低了被恶意消耗的风险。
3.3 如何防止TBOX把车辆蓄电池耗干
TBOX长期接在蓄电池上,休眠功耗是硬指标。很多项目要求的静态功耗在3到5毫安以内,而模组待机功耗、MCU低功耗模式的消耗、外围芯片(CAN收发器、电源芯片)的静态漏电,每一项都在蚕食这个预算。软件设计在这个问题上能做的主要是两件事。
一是别让任何任务“偷偷跑”。我在实际排查中碰到过一个特别典型的案例:静态功耗稳定在20毫安,怎么也降不下来。后来逐项排查才发现,日志模块里某个串口的DMA通道在休眠前没有被关闭,外设时钟没关完,MCU始终没有进入最深的低功耗模式。后来定了一个规矩:休眠流程必须有一个“资源释放检查清单”,谁申请了外设谁负责释放,释放完成后最后一步读一次所有唤醒源的状态寄存器,确认没有悬空中断。这一步看起来繁琐,但能把排查功耗问题的时间从几天缩短到几小时。
二是给休眠流程设计看门狗保护。TBOX进入休眠的流程经常因为某个任务卡住而导致无法入睡。我的做法是在休眠判断里加超时强制跳转:如果系统尝试休眠超过一定时间(比如5秒)还没有完成,就强制检查当前阻塞点、释放所有缓存、直接进入浅睡眠保底状态。宁可浅睡眠多耗一点电,也不能因为睡不过去而整夜全功耗运行,那样蓄电池几天就耗尽。
另外想提醒一句:休眠状态下的RTC定时上报,千万别设计成“每隔一小时无条件唤醒并发网络请求”。停车场景下有些地方地库信号极差,模组反复搜网会带来很高的峰值功耗,而且可能把蓄电池耗亏。更稳妥的做法是:在信号好的区域正常定时上报,连续多次失败后自动降级为“只在用户远程唤醒时补报”,或采用“上电后报一次,之后按策略递增间隔”的自适应方案。
4. 通信链路设计:弱网下的可靠性和实时性平衡
4.1 报文设计:字段定义不能拍脑袋
TBOX对上通信的主流协议有MQTT、MQTT over TLS、HTTP/HTTPS,也有部分方案走自定义TCP长连接。不管用哪套,核心是要把“上报数据”的报文结构设计清楚。我在这块踩过最大的坑,就是一开始把所有字段塞进一个大JSON里,灵活是灵活了,但云端解析容易出错,端侧解析也费内存,弱网下同样内容的字节开销还更大。
现在的做法是分类设计:
- 实时控制类指令:使用轻量级二进制或紧凑JSON结构,字段名短,必要时把所有布尔值打包成一个bit位图;
- 周期性上报数据:用固定模式的结构体,并且用“增量上报”替代“全量上报”;
- 日志和诊断类数据:这类数据量大但对实时性要求低,可以攒批次上报,走独立的队列。
而且每个上行报文都要带上发送时间戳和报文序列号。别小看这两个字段,弱网环境下它俩是排查“数据错乱、重复、乱序”的救命稻草。曾经遇到过车载数据上报到云端后,和实际时间差了8个小时,排查半天才发现是时区处理漏了,报文里有时间戳后,这类问题一对比就暴露了。
4.2 断线重连与心跳保活机制
车辆这东西特殊:它不像手机一直待在稳定的网络环境里,隧道、地库、高速移动、偏远地区都会导致网络长时间不可用。断线重连本身不复杂,复杂的是重连策略。
最忌讳的是“掉线后疯狂重连”。只能在10分钟里反复重连80次,每次模组都要重新搜网、附网、建立连接,不仅把功耗拉高,还可能导致SIM卡被网络侧临时封禁。我的重连策略是“指数退避+时间抖动”:第一次重连等5秒,第二次10秒,第三次20秒,最长不超过10分钟,同时每次等待时间加一个随机的1到5秒抖动,避免大量车辆同时掉线后同步重连造成服务器拥塞。
心跳保活也比想L的复杂些。心跳间隔太短,流量消耗大、费电;太长,NAT映射容易过期,云端可能误判设备离线。实际项目里我经常这样平衡:5分钟心跳是很多车联网平台的默认值,但如果你发现运营商的NAT超时比较短,就调到3分钟;而且要支持“云端主动探测”——当云端想确认设备在线时,可以下发一个心跳要求,TBOX收到后必须在指定时间内响应。这样既保证了常态下的低流量,又给了云端主动探活的窗口。
4.3 数据上报策略:什么时候传、传多少、丢了怎么办
TBOX会上报很多数据:位置、车速、电量、续航、车门状态、充电状态、报警事件等。如果什么都每秒钟传一次,流量费用会让运营方哭,服务器也扛不住。我常用的上报策略分三个优先级:
- 紧急数据(碰撞、断网后的补报缓存数据):立即上报,并且不合并等待,尽量保证第一时间到达;
- 周期数据(位置、电量、行驶状态,典型周期是10秒、30秒、60秒、5分钟不等):按车辆状态动态调整,行驶中提高频率、停驻时降频;
- 汇总数据(每日行程、充电记录、统计类信息):攒起来在合适时机(比如车辆充电时网络良好、电量充足)批量上传。
“丢了怎么办”这个问题,核心是队列和缓存。
飞行中遇到隧道断网,数据在网络层发送失败后,不能直接丢弃。位置数据可以丢了就丢了(下一包会更新),但碰撞报警、故障上报这类就不能丢。我的设计是建两级缓存:第一级是内存环形队列,轻量、快速;第二级是掉电不丢的Flash存储区,存放关键事件。内存队列满了就把最老的非关键数据丢弃,但关键事件一律落到Flash里,等网络恢复后逐个补报。
这里有一个经验教训:一开始图省事,把缓存统一存Flash,结果每上报一条数据都要等Flash擦写完成,把正常的实时上报卡得一顿一顿的。后来改成“内存队列做实时性保障、Flash只负责关键事件”,整个系统才顺了。回想起来,做设计不能只看可靠性,还要看对实时性的影响,两级缓存各司其职要好过统一大池子。
5. 远程控制全链路设计:一条指令从云端到执行器要走几步
5.1 指令链路拆解
远程控制是TBOX最核心的产品能力,也是软件设计里涉及模块最多的场景。一条“远程开空调”指令,涉及手机App、云端后台、TBOX、空调控制器四个节点。链路拆开是:
- App发起请求到云端后台;
- 云端校验用户权限、车辆状态,生成指令任务;
- 云端通过短信唤醒(如果TBOX休眠)或直接下发MQTT指令(如果在线);
- TBOX收到指令后,先向云端回执“指令已收到”;
- TBOX解析指令,校验指令参数(比如空调目标温度、开启时长是否在合法范围);
- TBOX通过CAN总线向空调控制器发送控制报文;
- TBOX定时读取执行结果(空调状态位翻转),确认执行成功;
- 将成功/失败结果上报云端,云端推送给App。
每个环节都可能出问题,所以我在设计时特别强调“回执”和“状态上报”的重要性。最简单实用的模式是一条指令要有三次状态反馈:接收确认(收到指令)、执行中(已转发给执行器)、执行完成(成功或失败)。很多初版设计只做了最后一次上报,一旦中间卡住,用户手机上永远显示“等待执行”,根本没法排查是云端没下发、模组没收到、还是CAN总线没发出去。
5.2 指令安全与防重放
远程控制涉及车身安全,安全设计不是可选项。这块我的做法分三条线。
第一,通信层加密。MQTT上必须走TLS,证书双向认证,设备侧证书一机一密地写进安全芯片或加密存储区域,不能直接把私钥写在明文配置里。
第二,指令层防重放。恶意攻击者如果截获了一条合法的“远程开车门”指令,然后反复重放这条指令,会造成车门被频繁打开和关闭。设计里要给每条指令分配一个唯一的指令ID,TBOX处理完一条指令后把指令ID存下来,短时间内重复出现(比如5分钟内相同指令ID),直接丢弃。再配合时间戳校验,超时指令也直接丢弃,基本能挡掉重放攻击。
第三,执行层安全确认。车身控制类的指令不能只有一个“授权信号”。比如远程启动发动机,TBOX要向云端确认这辆车当前挡位在P挡、驻车状态、发动机没在运行中,然后才下发启动报文。多一道确认,出大事的概率就小一个数量级。
5.3 超时与异常处理
远程控制链路里的异常比正常情况多得多,软件设计必须从“假设一切正常”切换到“先假设哪里都会出问题”。我总结三条必须实现的异常分支。
第一,端侧指令超时。TBOX把指令发给CAN总线后,可能由于总线错误或对方ECU没醒,收不到执行结果。设计上给每条控制指令设置一个超时定时器(常用的是10秒以内),超时后先重试一次,再失败就回滚到执行前状态并上报失败原因。
第二,云端等待超时。云端下发指令后如果TBOX长时间不回应,云端要能标记该指令超时并通知用户“车辆可能不在线”。这里有一项设计:如果车辆在线但业务层卡住了,模组的网络层是正常的,云端只能干等。因此TBOX必须在协议层就支持“指令ACK即时回执”,业务层是否成功再单独上报,两者不要混在一起。
第三,指令冲突。场景是:用户刚发了一条远程空调开门指令,又来了一条远程锁车指令。如果TBOX同时在执行两条指令,CAN总线上报文会打架。我的设计是在应用层加一个指令队列,同一时间只处理一条控制指令,新来的指令如果和正在执行的指令冲突(基于类型判断),直接拒绝并告知云端原因,等前一条执行完再接收最新一条。
远程控制这个功能做个demo很简单,但要做成可商用的状态,难点全在这些异常分支是否完备。
6. TBOX软件测试:台架、实车与回归
6.1 台架测试环境搭建
软件写得再好,测试跟不上,实车阶段还是会翻车。TBOX软件测试的核心思路是“尽量把问题留在台架上”,因为实车测试的成本高、复现难。我搭台架的经验有三块必不可少。
第一块是硬件在环(HIL)最小系统。把TBOX、模拟车身网络的CAN盒、可编程电源、信号发生器组合在一起。用CAN盒模拟车身控制器,用可编程电源模拟蓄电池电压变化(测试低电压、掉电、瞬间跌落场景),用信号发生器模拟车速、点火信号、门状态信号等。这套台架补齐了“整车环境”的缺失。
第二块是弱网模拟。这是TBOX测试区别于一船嵌入式产品的地方。我用过网络损伤仪(Network Impairment Emulator),也可以临时用可编程衰减器来模拟弱网信号衰减、丢包、高延迟。没有这套设备的话,很多断网重连、缓存补报的bug在实验室复现不出来,上实车后碰一次网络环境就懵一次。
第三块是休眠功耗测试。台架上要对四态状态机的每一个状态切换做功耗测量,尤其是从工作态到休眠态的整个过程的功耗曲线。实测中经常发现某个GPIO没拉低导致功耗居高不下,台架上一分钟就能定位,到实车上就难查了。
6.2 关键测试场景与用例设计
TBOX的测试用例设计视角和普通嵌入式软件不太一样,我觉得应该按照“场景故事”来组织,而不是按“函数功能”来组织。举个例子,“远程开门”这个功能,测试用例不能只有“正常情况下开门成功”,要包括下面这些场景:
- TBOX休眠时收到远程开门指令,能否正常唤醒并执行;
- TBOX网络离线时收到远程开门指令(短信唤醒已触发但网络连不上),能否在恢复网络后自动补拉指令;
- 连续下发两条冲突指令,后一条是否被正确拒绝;
- CAN总线上控制器无响应时,能否在超时后上报失败;
- 用户在App上执行开门后立刻锁车,指令队列如何处理;
- 低频重复攻击下,防重放是否生效。
每一条都对应前面软件设计里的一个模块或一个分支。我的体会是,测试用例其实是和软件设计同步产出的,每一条设计决策都能对应到至少一条测试用例。“先定用例再写代码”的习惯,能直接逼着你把需求场景想完整,避免代码写完才发现分支没覆盖。
6.3 软件版本管理与回归策略
TBOX软件迭代非常频繁,新车型、新功能、新协议格式的改动络绎不绝。版本管理如果只在“改代码后确认能编译”这个层面,迟早出大事故。我的做法是两个维度。
第一,特性分支和主分支严格分离。每次开发新功能从主分支切特性分支,合入前必须过一轮“冒烟测试”,保证核心功能(上电、休眠唤醒、远程控制、数据上报、OTA)不回归。TBOX最怕的不是新功能不工作,而是老功能被改坏。因为改动老功能的问题往往在实车跑了几天后才发现,代价极高。
第二,配套一个自动化回归脚本库,把6.1的台架自动化起来。至少要做到每天自动跑一遍核心场景集并输出报告。比如凌晨无人值守时跑远程控制、数据上报、休眠功耗、断网重接连这几组场景,早上来直接看报告。这类自动化台架成本不算高,但极大降低“回归不全”带来的风险。
OTA本身也是TBOX的关键能力,软件设计里要把OTA升级包校验、升级失败回滚、升级过程中断处理都安排成独立模块。因为OTA一旦升级失败导致TBOX变砖,车子连远程控制都失效,只能返厂或让用户到店处理,这是最严重的事故。测试环节里要专门安排“升级到一半断网”“升级到一半断电”“下载到一半模组重启”这三类破坏性测试,跑通之后才能说OTA功能可靠。
做TBOX软件设计这几年,我最大的体会是:真正决定这个产品好坏的,往往不是那些看得见的功能代码,而是休眠功耗控制、断线重连策略、指令防重放、异常分支处理这些平时不显山不露水的部分。它们占代码量可能只有三成,却决定了产品在真实工况下是否可靠。希望这篇总结能让同行们在动手写代码之前,先花两三天把架构、状态机、报文和测试用例定明白——这个前期投入,后面十倍百倍地赚回来。