固件 0.1.5~0.1.13-c5:刷机模式、多组 WiFi、热插拔初始化、总线锁误判、硬重启断 VBUS

- 0.1.5/0.1.6:刷机模式(flash_mode,最多 2 路,60 分钟可加钟)——窗口内顶高按 4450 mV 绝对值判、不断 VBUS
- 0.1.7/0.1.8:反灌断 VBUS 阈值放宽到 -300 mA(adb reboot bootloader 过渡实测 -208 mA)
- 0.1.9:WiFi 最多存 4 组,连不上轮换;NVS v1 自动迁移并双写(OTA 回滚仍能上网)
- 0.1.10:热插拔进来的刀片重新初始化 PCA9555 + INA226(否则 VBUS 常开、电流恒读 0)
- 0.1.11:i2cbus 嵌套检测改看本任务持锁(原全局标志让 key 随机回 busy、vbus 随机回 io)
- 0.1.12:硬重启先断 VBUS,开机校验通过 60 s 后再接回(否则假重启 / 误判没开机 / 进关机充电)
- 0.1.13:这一路被安全判据断电时一并退出刷机模式(事件 21 arg 254)

26 ctest 全绿;新增用例均先在旧代码上确认变红。板 B 已 OTA 到 0.1.13-c5 并实测。

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
这个提交包含在:
zhou yang
2026-09-29 08:16:21 +08:00
共同撰写人 Claude Opus 5.5
父节点 385d2f9c47
当前提交 9fb5bba367
共修改 35 个文件,包含 5120 行新增和 3675 行删除
+26 -5
查看文件
@@ -2,7 +2,8 @@
IF-19 原话:「凭据与服务端地址存 NVS,**不编译进固件** —— 新板上架时先用 IF-13 的
USB 链路配网」。所以:
· 配置由两条命令写入:`wifi`(SSID / 密码)与 `mqtt`(broker 地址 / 账号 / 遥测周期),
· 配置由两条命令写入:`wifi`(SSID / 密码,**最多存 NETCFG_WIFI_N 组**,0.1.9)与
`mqtt`(broker 地址 / 账号 / 遥测周期),
**只收 USB 链路来的**(cmd.c 回 `link`)—— 经 WiFi 改 WiFi 配置,一次手误就把
唯一的远程通道弄断了,而那时只能拆机插 USB;
· 本模块只管「校验 + 在内存里持有一份 + 调存储后端 + 通知网络那一侧」,
@@ -14,8 +15,13 @@
---- 跨任务 --------------------------------------------------------------
写者是执行器任务(命令处理器),读者是链路任务(网络胶水)。配置读写都在
`hal_crit` 里整块拷贝(≈260 B 的 memcpy,关中断几微秒),读者永远拿到一份完整的。
网络状态反过来:链路任务写、命令处理器读,同样整块拷贝。 */
`hal_crit` 里整块拷贝(≈560 B 的 memcpy,关中断十几微秒),读者永远拿到一份完整的。
网络状态反过来:链路任务写、命令处理器读,同样整块拷贝。
---- 多组 WiFi(0.1.9,2026-09-28 用户要求)-------------------------------
`wifi` 命令 = **加一组或改同名那组的口令**,`"del":true` = 删同名那组;满了回 `state`。
连不上就按表里的顺序轮着换下一组(mlink_esp.c)。表里的空位(ssid 为空)一律跳过,
`netcfg_init` 会把它们挤到末尾。 */
#ifndef NETCFG_H
#define NETCFG_H
@@ -40,10 +46,16 @@ extern "C" {
#define NETCFG_TELE_MIN_MS 200
#define NETCFG_TELE_MAX_MS 60000
#define NETCFG_WIFI_N 4 /* 存几组 WiFi */
typedef struct {
char ssid[NETCFG_SSID_MAX + 1]; /* 空 = 空位 */
char pass[NETCFG_PASS_MAX + 1];
} netcfg_wifi_t;
/* ⚠️ 这个结构体**原样存进 NVS**(mlink_esp.c 带版本号存)。改字段就升版本号。 */
typedef struct {
char ssid[NETCFG_SSID_MAX + 1];
char pass[NETCFG_PASS_MAX + 1];
netcfg_wifi_t wifi[NETCFG_WIFI_N]; /* 按加入的顺序,空位都在末尾 */
char uri[NETCFG_URI_MAX + 1];
char user[NETCFG_USER_MAX + 1];
char mpass[NETCFG_MPASS_MAX + 1];
@@ -61,10 +73,18 @@ void netcfg_init(const netcfg_t *loaded, netcfg_save_fn save, netcfg_changed_fn
void netcfg_get(netcfg_t *out);
/* 校验 → 存 → 改内存 → 通知。校验不过 HAL_ERR_ARG,存不下是 save 的错误码。
`set_wifi`:同名的改口令,否则加到末尾;表满了 HAL_ERR_STATE。
`del_wifi`:没有同名的 HAL_ERR_ARG。
`mqtt` 的 tele_ms 传 0 = 用默认值。 */
hal_err_t netcfg_set_wifi(const char *ssid, const char *pass);
hal_err_t netcfg_del_wifi(const char *ssid);
hal_err_t netcfg_set_mqtt(const char *uri, const char *user, const char *mpass, uint32_t tele_ms);
/* 表里有几组(空位在末尾,所以有效的就是 [0, n))。 */
int netcfg_wifi_count(const netcfg_t *cfg);
/* 名为 ssid 的那组在第几个,没有 −1。 */
int netcfg_wifi_find(const netcfg_t *cfg, const char *ssid);
/* 纯校验,给命令处理器先判一遍好回准确的错误。 */
bool netcfg_wifi_ok(const char *ssid, const char *pass);
bool netcfg_mqtt_ok(const char *uri, const char *user, const char *mpass, uint32_t tele_ms);
@@ -88,6 +108,7 @@ typedef struct {
uint32_t tele_skipped; /* 该发遥测时命令队列满 / 上一条还没发完 */
uint8_t wifi_reason; /* 最近一次断开的原因码(wifi_err_reason_t;201 = 找不到 AP,
202 = 认证失败,15 = 四次握手超时 ≈ 口令错),0 = 没断过 */
uint8_t wifi_idx; /* 正在连 / 已连上的是表里第几组(net 回应的 ssid 取它) */
char id[13]; /* 板子 ID = STA MAC 的 12 位小写十六进制,topic 用它 */
} net_status_t;