固件 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]>
这个提交包含在:
+104
-6
@@ -97,8 +97,8 @@ static void test_config_over_usb_is_saved_and_applied(void)
|
||||
"\"ok\":true");
|
||||
TEST_ASSERT_EQUAL_INT(2, s_saves);
|
||||
TEST_ASSERT_EQUAL_INT(2, s_changed);
|
||||
TEST_ASSERT_EQUAL_STRING("farm-2g", s_saved.ssid);
|
||||
TEST_ASSERT_EQUAL_STRING("s3cret-pass", s_saved.pass); /* 第二次存的是整份:WiFi 那部分还在 */
|
||||
TEST_ASSERT_EQUAL_STRING("farm-2g", s_saved.wifi[0].ssid);
|
||||
TEST_ASSERT_EQUAL_STRING("s3cret-pass", s_saved.wifi[0].pass); /* 第二次存的是整份:WiFi 那部分还在 */
|
||||
TEST_ASSERT_EQUAL_STRING("mqtt://10.5.5.13:1883", s_saved.uri);
|
||||
TEST_ASSERT_EQUAL_UINT32(2000, s_saved.tele_ms);
|
||||
|
||||
@@ -172,7 +172,7 @@ static void test_config_validation(void)
|
||||
pass[63] = '\0';
|
||||
snprintf(line, sizeof(line), "{\"seq\":11,\"cmd\":\"wifi\",\"ssid\":\"x\",\"pass\":\"%s\"}", pass);
|
||||
ASSERT_HAS(send_on(CMD_LINK_USB, line), "\"ok\":true");
|
||||
TEST_ASSERT_EQUAL_STRING(pass, s_saved.pass);
|
||||
TEST_ASSERT_EQUAL_STRING(pass, s_saved.wifi[1].pass);
|
||||
TEST_ASSERT_EQUAL_INT(3, s_saves);
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ static void test_unsaved_config_does_not_take_effect(void)
|
||||
"\"err\":\"io\"");
|
||||
netcfg_t c;
|
||||
netcfg_get(&c);
|
||||
TEST_ASSERT_EQUAL_STRING("old", c.ssid);
|
||||
TEST_ASSERT_EQUAL_STRING("old", c.wifi[0].ssid);
|
||||
TEST_ASSERT_EQUAL_INT(1, s_changed);
|
||||
}
|
||||
|
||||
@@ -197,11 +197,11 @@ static void test_loaded_config_is_sanitised(void)
|
||||
netcfg_t junk;
|
||||
memset(&junk, 'A', sizeof(junk));
|
||||
junk.tele_ms = 5;
|
||||
memcpy(junk.ssid, "a\"b\\c\n", 6);
|
||||
memcpy(junk.wifi[0].ssid, "a\"b\\c\n", 6);
|
||||
netcfg_init(&junk, NULL, NULL, NULL);
|
||||
netcfg_t c;
|
||||
netcfg_get(&c);
|
||||
TEST_ASSERT_EQUAL_size_t(NETCFG_SSID_MAX, strlen(c.ssid));
|
||||
TEST_ASSERT_EQUAL_size_t(NETCFG_SSID_MAX, strlen(c.wifi[0].ssid));
|
||||
TEST_ASSERT_EQUAL_size_t(NETCFG_URI_MAX, strlen(c.uri));
|
||||
TEST_ASSERT_EQUAL_UINT32(NETCFG_TELE_DEFAULT_MS, c.tele_ms);
|
||||
|
||||
@@ -210,6 +210,101 @@ static void test_loaded_config_is_sanitised(void)
|
||||
TEST_ASSERT_EQUAL_CHAR('}', r[strlen(r) - 1]);
|
||||
}
|
||||
|
||||
/* ---- 多组 WiFi(0.1.9)--------------------------------------------------- */
|
||||
|
||||
/* ⭐ 加第二组不挤掉第一组;同名再发 = 改口令、不多占一格;回应带组数。 */
|
||||
static void test_wifi_adds_and_updates_by_name(void)
|
||||
{
|
||||
ASSERT_HAS(send_on(CMD_LINK_USB, "{\"seq\":1,\"cmd\":\"wifi\",\"ssid\":\"home\",\"pass\":\"pass-home-1\"}"),
|
||||
"\"n\":1");
|
||||
ASSERT_HAS(send_on(CMD_LINK_USB, "{\"seq\":2,\"cmd\":\"wifi\",\"ssid\":\"hotspot\",\"pass\":\"pass-hot-1\"}"),
|
||||
"\"n\":2");
|
||||
ASSERT_HAS(send_on(CMD_LINK_USB, "{\"seq\":3,\"cmd\":\"wifi\",\"ssid\":\"home\",\"pass\":\"pass-home-2\"}"),
|
||||
"\"n\":2");
|
||||
netcfg_t c;
|
||||
netcfg_get(&c);
|
||||
TEST_ASSERT_EQUAL_INT(2, netcfg_wifi_count(&c));
|
||||
TEST_ASSERT_EQUAL_STRING("home", c.wifi[0].ssid);
|
||||
TEST_ASSERT_EQUAL_STRING("pass-home-2", c.wifi[0].pass);
|
||||
TEST_ASSERT_EQUAL_STRING("hotspot", c.wifi[1].ssid);
|
||||
TEST_ASSERT_EQUAL_STRING("pass-hot-1", c.wifi[1].pass);
|
||||
TEST_ASSERT_EQUAL_MEMORY(&s_saved, &c, sizeof(c)); /* 存的是整张表 */
|
||||
|
||||
/* net:ssid = 正在连的那组(状态里 wifi_idx),ssids = 整张表;任何一组的口令都不出现。 */
|
||||
net_status_t st;
|
||||
memset(&st, 0, sizeof(st));
|
||||
st.wifi_idx = 1;
|
||||
net_status_set(&st);
|
||||
const char *r = send_on(CMD_LINK_WIFI, "{\"cmd\":\"net\"}");
|
||||
ASSERT_HAS(r, "\"ssid\":\"hotspot\",\"pass_set\":true,\"ssids\":[\"home\",\"hotspot\"]");
|
||||
ASSERT_LACKS(r, "pass-home");
|
||||
ASSERT_LACKS(r, "pass-hot");
|
||||
}
|
||||
|
||||
/* ⭐ 删一组后面的往前补;删没有的 = range;满了再加新名字 = state、表不变;满了改已有的照样行。 */
|
||||
static void test_wifi_delete_and_full_table(void)
|
||||
{
|
||||
char line[128];
|
||||
for (int i = 0; i < NETCFG_WIFI_N; i++) {
|
||||
snprintf(line, sizeof(line), "{\"seq\":%d,\"cmd\":\"wifi\",\"ssid\":\"n%d\",\"pass\":\"12345678\"}",
|
||||
i + 1, i);
|
||||
ASSERT_HAS(send_on(CMD_LINK_USB, line), "\"ok\":true");
|
||||
}
|
||||
ASSERT_HAS(send_on(CMD_LINK_USB, "{\"seq\":20,\"cmd\":\"wifi\",\"ssid\":\"extra\",\"pass\":\"12345678\"}"),
|
||||
"\"err\":\"state\"");
|
||||
ASSERT_HAS(send_on(CMD_LINK_USB, "{\"seq\":21,\"cmd\":\"wifi\",\"ssid\":\"n3\",\"pass\":\"87654321\"}"),
|
||||
"\"ok\":true");
|
||||
TEST_ASSERT_EQUAL_INT(NETCFG_WIFI_N + 1, s_saves);
|
||||
|
||||
ASSERT_HAS(send_on(CMD_LINK_USB, "{\"seq\":22,\"cmd\":\"wifi\",\"ssid\":\"n1\",\"del\":true}"),
|
||||
"\"n\":3");
|
||||
netcfg_t c;
|
||||
netcfg_get(&c);
|
||||
TEST_ASSERT_EQUAL_INT(NETCFG_WIFI_N - 1, netcfg_wifi_count(&c));
|
||||
TEST_ASSERT_EQUAL_STRING("n0", c.wifi[0].ssid);
|
||||
TEST_ASSERT_EQUAL_STRING("n2", c.wifi[1].ssid);
|
||||
TEST_ASSERT_EQUAL_STRING("n3", c.wifi[2].ssid);
|
||||
TEST_ASSERT_EQUAL_STRING("87654321", c.wifi[2].pass);
|
||||
TEST_ASSERT_EQUAL_STRING("", c.wifi[3].ssid);
|
||||
TEST_ASSERT_EQUAL_STRING("", c.wifi[3].pass); /* 挪走之后末尾清干净,不留口令 */
|
||||
|
||||
ASSERT_HAS(send_on(CMD_LINK_USB, "{\"seq\":23,\"cmd\":\"wifi\",\"ssid\":\"n1\",\"del\":true}"),
|
||||
"\"err\":\"range\"");
|
||||
ASSERT_HAS(send_on(CMD_LINK_USB, "{\"seq\":24,\"cmd\":\"wifi\",\"ssid\":\"n1\",\"del\":1}"),
|
||||
"\"err\":\"arg\"");
|
||||
/* 删也只收 USB。 */
|
||||
ASSERT_HAS(send_on(CMD_LINK_WIFI, "{\"seq\":25,\"cmd\":\"wifi\",\"ssid\":\"n0\",\"del\":true}"),
|
||||
"\"err\":\"link\"");
|
||||
/* 删到空:net 回应仍是合法 JSON,ssids 是空数组。 */
|
||||
for (int i = 0; i < 3; i++) {
|
||||
snprintf(line, sizeof(line), "{\"seq\":%d,\"cmd\":\"wifi\",\"ssid\":\"%s\",\"del\":true}", 30 + i,
|
||||
i == 0 ? "n0" : i == 1 ? "n2" : "n3");
|
||||
ASSERT_HAS(send_on(CMD_LINK_USB, line), "\"ok\":true");
|
||||
}
|
||||
ASSERT_HAS(send_on(CMD_LINK_USB, "{\"cmd\":\"net\"}"), "\"ssid\":\"\",\"pass_set\":false,\"ssids\":[]");
|
||||
}
|
||||
|
||||
/* NVS 读回来的表中间有空位:挤到前面,count 才算得对、轮换才不会停在空位上。 */
|
||||
static void test_loaded_table_is_compacted(void)
|
||||
{
|
||||
netcfg_t in;
|
||||
memset(&in, 0, sizeof(in));
|
||||
strcpy(in.wifi[1].ssid, "b");
|
||||
strcpy(in.wifi[1].pass, "12345678");
|
||||
strcpy(in.wifi[3].ssid, "d");
|
||||
strcpy(in.wifi[2].pass, "orphan-pass"); /* 空 SSID 带着口令:整格丢掉 */
|
||||
netcfg_init(&in, NULL, NULL, NULL);
|
||||
netcfg_t c;
|
||||
netcfg_get(&c);
|
||||
TEST_ASSERT_EQUAL_INT(2, netcfg_wifi_count(&c));
|
||||
TEST_ASSERT_EQUAL_STRING("b", c.wifi[0].ssid);
|
||||
TEST_ASSERT_EQUAL_STRING("12345678", c.wifi[0].pass);
|
||||
TEST_ASSERT_EQUAL_STRING("d", c.wifi[1].ssid);
|
||||
TEST_ASSERT_EQUAL_INT(1, netcfg_wifi_find(&c, "d"));
|
||||
TEST_ASSERT_EQUAL_INT(-1, netcfg_wifi_find(&c, ""));
|
||||
TEST_ASSERT_EQUAL_STRING("", c.wifi[2].pass);
|
||||
}
|
||||
|
||||
/* ---- MQTT 链路的平台无关部分 --------------------------------------------- */
|
||||
|
||||
static void test_topics_follow_the_mac(void)
|
||||
@@ -287,6 +382,9 @@ int main(void)
|
||||
RUN_TEST(test_config_validation);
|
||||
RUN_TEST(test_unsaved_config_does_not_take_effect);
|
||||
RUN_TEST(test_loaded_config_is_sanitised);
|
||||
RUN_TEST(test_wifi_adds_and_updates_by_name);
|
||||
RUN_TEST(test_wifi_delete_and_full_table);
|
||||
RUN_TEST(test_loaded_table_is_compacted);
|
||||
RUN_TEST(test_topics_follow_the_mac);
|
||||
RUN_TEST(test_inbound_messages);
|
||||
RUN_TEST(test_backoff_doubles_and_caps);
|
||||
|
||||
在新工单中引用
屏蔽一个用户