meta-pass 是我给 AI Passport 写的多固件启动器:设备里常驻一个启动器,玩法固件装在 Flash 槽位里,开机从列表选择启动,不用每次整片重刷。MVP 的两天开发过程记录在上一篇复盘里。

MVP 上线后,第一条市场留言是骂它的:

没啥用,这玩意占用 3mb,剩下的也就两个 2mb 大小的空间了,稍微实用点的功能都装不下。

它说的基本是事实。接下来的六天里,我提交了 90 个 commit,顺着八条留言把真实问题挨个堵上,硬生生把 meta-pass 从 MVP 磨到了 v1.0:加到三个槽位、补上签名徽章、搞定备份还原、单文件固件、保数据升级、开机策略加固、USB 提速。可以说,v1.0 的大部分改动都是这几条留言提醒我改的。

装不下的问题

9 月 12 日那条骂它的留言,说到了根子上:启动器自己占了 3MB,剩下两个槽位各 2MB,大一点的玩法确实装不下。

MVP 的第二版合并镜像做到了 8MB,但里面 80% 以上是空的槽位区域,真正有用的固件代码只占一小部分,3MB 的打包方式也很没有效率。v1.0 做了压缩优化,把核心 factory 部分压到 1.44MB 以内,释放出来的空间让 slot 0 做到了 1.84MB。

MVP 时期的启动器列表:只有两个槽位可用

factory 缩小之后,Flash 上 cardid 前面那块一直空着的区域也能利用了,正好用来加第三个槽位。

9 月 15 日有用户问:「每个分区最多 2M 大小吗?能不能自由分配?」

不能自由分。按厂家规范,cardid 这块身份区固定在 Flash 中间,位置不能挪,它把可用空间切成两半,三个槽位的地址和大小全部跟着它的位置算出来。前面的空隙只能放下 1.84MB,第一个槽位拿走了;后面的空间按 64KB 对齐,第二个槽位维持原来的 2MB 不动,第三个把剩下的 2.61MB 全部拿走。

最大的留给最占空间的玩法,它还可以兼作录音固件的存储区。现在对讲机、雷达寻宝、第三个社区作品可以同时留在设备里,出门玩之前不用先删掉哪个。

改了名,进去还是 ai passport

有人改了显示名,但进去还是 ai passport。

追了一下根因,没找到确切答案。显示名 blob 的写入逻辑 MVP 时期就已经存在,按理说应该能正常工作。具体是哪个环节出了问题,没有找到证据,只能承认这个现象确实存在,但解释不清楚。

v1.0 把这个问题彻底解决了。USB 安装页现在会自动把玩法的英文标题或本地文件名填成显示名,Wi-Fi 导入页也加了可选名字输入框,不会再出现这种情况。

v1.0 的 Wi-Fi 导入页:导入时可以顺手填显示名

能不能加个忽略未签名的选项

有人说每次长按确认麻烦,能不能加个忽略未签名的选项。

这个选项不能加。警告页是最后一关,能忽略它签名机制就形同虚设了。

但长按确认确实繁琐,不熟悉的人每次都得试摸索一会儿。于是我把确认改成了短按:弹出警告页后,方向键选 BOOT,短按 OK 确认,默认停在「取消」上,防止一路按 OK 把未签名的固件启动起来。签名固件不进警告页,按 OK 直接启动。

没看懂具体怎么用

有人说看不懂怎么用它,以为是要把下载的玩法和 meta-pass 一起安装。

用户看不懂,纯粹是市场页面没写清楚。

v1.0 把 meta-pass 自己的市场介绍页面重新写了一遍,把使用流程讲清楚:怎么安装、怎么用、怎么切换固件。用户不用自己去猜。

没有留言催的改进

剩下这几项改进虽然没人催,但要想让人「放心用」,备份、升级和异常恢复必须做扎实。

安装页可以把设备里所有槽位的固件、槽位附带的数据、系统存储区整体打包成一个 zip,还原时按清单逐项校验,指纹对不上就拒绝使用,槽位放不下就明确拒绝,不会写一半把数据切坏。系统存储区是自动打包、自动写回的,用户不需要知道它叫什么。

备份要读整片槽位,速度决定这个功能可不可用。修复前读 1MB 要三分钟,还经常失败。把通信提速到 921600 波特,传输中断后按三级策略自动恢复,先补发确认重同步,再降速,最后整链路复位。现在 1MB 的备份一分钟左右完成,USB 接触扰动导致读取失败时会重试,不用从头再来。

v1.0 的 USB 安装页:安装、备份、还原在同一个页面完成

升级启动器本身也不动数据。网页先读回设备的分区表,和升级包逐字节比对,然后只写允许写的区域:bootloader、分区表、启动器应用。系统存储区、身份区、三个槽位,一个字节都不碰。装好的玩法和数据原样保留。

最后一件是修一个 MVP 时期的旧伤。回滚机制里「是否常驻」由玩法固件自己声明,一个用旧版模板编译的固件声明了常驻,设备就锁死在玩法里,断电重启也回不来,全程没有任何报错。把这个策略挪到了 bootloader 层,在任何固件运行之前执行,玩法固件无法绕过。被锁死的设备升级到这个版本后,断电重启一次就恢复正常。

踩坑踩出来的几条硬道理

六天九十个 commit,有几句经验值得写下来。

别浪费 Flash 里的闲置夹缝。 之前 MVP 的合并镜像里 80% 是空的。仔细盘了一下发现,cardid 位置虽然固定死,但前后其实空着两块空间,把 factory 压到 1.44MB 后,正好能把 slot 0 和 slot 2 塞进这两个夹缝里,白捡了几个兆。

读 Flash 报错,光靠加重试次数没用。 重试从五次提到八次该断还是断。后来提速到 921600 波特并加上「补发重同步 → 降速 → 整链路复位」的三级恢复策略,才彻底解决了中断问题。

分清 NVS、cardid、slot 和 otadata 的边界。 这四个存储区各有各的用处:NVS 存 Wi-Fi 密码和配置,cardid 存设备身份,slot 存固件镜像,otadata 记启动槽位。升级 launcher 时动错了哪个都有致命后果:动了 cardid 设备就丢身份,动了 otadata 下次可能走错槽,动了 NVS Wi-Fi 配置就全清空了。

别假设社区固件会按规范写。 显示名可能不写,签名可能没有,未适配的固件照样敢跑。所以协议层只传最基本的信息,绝不预设对方会按套路出牌。

获取方式


参考

  1. MVP 开发复盘:给孩子的 AI 玩具做个多卡带启动器:meta-pass 开发复盘
  2. meta-pass 仓库:alexwwang/meta-pass
  3. 玩法市场 meta-pass 页面(用户留言出处):ai-passport.folotoy.cn