固件 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]>
这个提交包含在:
@@ -5,8 +5,10 @@
|
||||
判重、名字表、回应拼装在 cmd.c;status / events 的正文在 cmd_report.c。 */
|
||||
#include <string.h>
|
||||
|
||||
#include "chgmode.h"
|
||||
#include "cmd_priv.h"
|
||||
#include "evlog.h"
|
||||
#include "hal_time.h"
|
||||
#include "i2cbus.h"
|
||||
#include "rail.h"
|
||||
#include "rail_cfg.h"
|
||||
@@ -209,6 +211,7 @@ cmd_err_t do_vbus(ctx_t *c)
|
||||
if (on && !rail_efuse_is_on(c->rail)) {
|
||||
return reject(c, CMD_ERR_STATE, 1);
|
||||
}
|
||||
t_actuator_cancel_vbus_back(c->rail); /* 人动了 VBUS:硬重启排的「过会儿接回」作废 */
|
||||
return from_bus(slot_vbus_enable(c->rail, on));
|
||||
}
|
||||
|
||||
@@ -234,6 +237,7 @@ cmd_err_t do_power(ctx_t *c)
|
||||
if (t_actuator_busy(c->rail)) {
|
||||
return CMD_ERR_BUSY; /* 硬重启走到一半再开关一次是自作主张(t_actuator_abort 同理) */
|
||||
}
|
||||
t_actuator_cancel_vbus_back(c->rail); /* 人动了电:硬重启排的「过会儿接回 VBUS」作废 */
|
||||
if (on) {
|
||||
const hal_err_t ee = rail_efuse_enable(c->rail, true);
|
||||
if (ee == HAL_OK) {
|
||||
@@ -248,10 +252,113 @@ cmd_err_t do_power(ctx_t *c)
|
||||
const hal_err_t ee = rail_efuse_enable(c->rail, false);
|
||||
if (ee == HAL_OK) {
|
||||
note_intent(c->rail, false); /* 直供确实断了:下次开机也别开它 */
|
||||
/* 这一路停了,刷机模式也一并退出(不占 CHG_MODE_MAX_RAILS 的名额)。 */
|
||||
if (chgmode_active(c->rail, hal_time_now_ms())) {
|
||||
(void)chgmode_set(c->rail, 0, hal_time_now_ms());
|
||||
evlog_put((uint8_t)c->rail, LOG_EV_CHG_MODE, CHG_EV_OFF, now_mv(c->rail), now_ua(c->rail));
|
||||
}
|
||||
}
|
||||
return from_bus(ee != HAL_OK ? ee : ev);
|
||||
}
|
||||
|
||||
/* 0.1.5 刷机模式(chgmode.h):`{"cmd":"flash_mode","rail":1,"on":true,"min":60}`。
|
||||
min 省略 = CHG_MODE_DEFAULT_MIN;关不带 min。回应带 `"left":秒`。
|
||||
0.1.6 加钟:`{"cmd":"flash_mode","rail":1,"add":30}`(与 on / min 互斥)—— 只给开着的窗口加,
|
||||
剩余最多 CHG_MODE_MAX_MIN 分钟(超出截断);没开着回 state。
|
||||
⚠️ 只改判据,**不动 VBUS**:开 VBUS 仍用 `vbus` 命令(顺序无所谓:先开模式再开 VBUS,
|
||||
或 VBUS 被 SW-8 断了之后开模式再重开 VBUS)。 */
|
||||
cmd_err_t do_flash_mode(ctx_t *c)
|
||||
{
|
||||
cmd_err_t e = need_rail(c);
|
||||
if (e != CMD_OK) {
|
||||
return e;
|
||||
}
|
||||
/* 加钟(0.1.6):`{"cmd":"flash_mode","rail":1,"add":30}`,与 on 二选一。 */
|
||||
int64_t add = 0;
|
||||
const int ga = cj_get_int(c->o, "add", &add);
|
||||
if (ga < 0) {
|
||||
return CMD_ERR_ARG;
|
||||
}
|
||||
if (ga == 1) {
|
||||
bool on_probe = false;
|
||||
int64_t min_probe = 0;
|
||||
if (cj_get_bool(c->o, "on", &on_probe) != 0 || cj_get_int(c->o, "min", &min_probe) != 0) {
|
||||
return CMD_ERR_ARG; /* add 不和 on / min 混用 */
|
||||
}
|
||||
if (add < 1 || add > CHG_MODE_MAX_MIN) {
|
||||
return reject(c, CMD_ERR_RANGE, add);
|
||||
}
|
||||
const uint32_t now = hal_time_now_ms();
|
||||
const hal_err_t he = chgmode_extend(c->rail, (uint32_t)add, now);
|
||||
if (he == HAL_ERR_STATE) {
|
||||
return reject(c, CMD_ERR_STATE, 0); /* 没开着:要重新开,不是加钟 */
|
||||
}
|
||||
if (he != HAL_OK) {
|
||||
return reject(c, CMD_ERR_RANGE, add);
|
||||
}
|
||||
evlog_put((uint8_t)c->rail, LOG_EV_CHG_MODE, (uint8_t)(CHG_EV_EXTEND | (uint32_t)add),
|
||||
now_mv(c->rail), now_ua(c->rail));
|
||||
cj_w(c->w, ",\"left\":%lu", (unsigned long)chgmode_left_s(c->rail, now));
|
||||
return CMD_OK;
|
||||
}
|
||||
bool on = false;
|
||||
if (cj_get_bool(c->o, "on", &on) != 1) {
|
||||
return CMD_ERR_ARG;
|
||||
}
|
||||
int64_t min = CHG_MODE_DEFAULT_MIN;
|
||||
const int g = cj_get_int(c->o, "min", &min);
|
||||
if (g < 0 || (!on && g == 1)) {
|
||||
return CMD_ERR_ARG;
|
||||
}
|
||||
const uint32_t now = hal_time_now_ms();
|
||||
if (!on) {
|
||||
const bool was = chgmode_active(c->rail, now);
|
||||
(void)chgmode_set(c->rail, 0, now);
|
||||
if (was) {
|
||||
evlog_put((uint8_t)c->rail, LOG_EV_CHG_MODE, CHG_EV_OFF, now_mv(c->rail), now_ua(c->rail));
|
||||
}
|
||||
cj_w(c->w, ",\"left\":0");
|
||||
return CMD_OK;
|
||||
}
|
||||
if (min < 1 || min > CHG_MODE_MAX_MIN) {
|
||||
return reject(c, CMD_ERR_RANGE, min);
|
||||
}
|
||||
/* 关着电的路开刷机模式没有意义(手机没电),与 vbus 命令同一条规矩。 */
|
||||
if (!rail_efuse_is_on(c->rail)) {
|
||||
return reject(c, CMD_ERR_STATE, 1);
|
||||
}
|
||||
const hal_err_t he = chgmode_set(c->rail, (uint32_t)min, now);
|
||||
if (he == HAL_ERR_STATE) {
|
||||
return reject(c, CMD_ERR_STATE, chgmode_count(now)); /* 已有 CHG_MODE_MAX_RAILS 路开着 */
|
||||
}
|
||||
if (he != HAL_OK) {
|
||||
return reject(c, CMD_ERR_RANGE, min);
|
||||
}
|
||||
evlog_put((uint8_t)c->rail, LOG_EV_CHG_MODE, (uint8_t)min, now_mv(c->rail), now_ua(c->rail));
|
||||
cj_w(c->w, ",\"left\":%lu", (unsigned long)chgmode_left_s(c->rail, now));
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
void cmd_chgmode_tick(uint32_t now)
|
||||
{
|
||||
const uint32_t ended = chgmode_tick(now);
|
||||
for (int r = 1; r <= PHONERAIL_RAIL_COUNT; r++) {
|
||||
if ((ended & (1u << (r - 1))) != 0) {
|
||||
evlog_put((uint8_t)r, LOG_EV_CHG_MODE, CHG_EV_EXPIRED, now_mv(r), now_ua(r));
|
||||
}
|
||||
}
|
||||
/* 0.1.13:这一路已经断了电(刀片被拔走 / SR-5 等判据关路 / mux 失联全断 —— 都是 t_safety 关的 eFuse,
|
||||
不经过 `power` 命令)⇒ 刷机模式一并退出。不退的话它一直占着 CHG_MODE_MAX_RAILS 的名额
|
||||
(2026-09-28 板 B:第 2 槽刀片拔走后还挂着 48 分钟),插回来上电时还带着放宽的判据。
|
||||
硬重启那几秒 eFuse 本来就关着,不算(执行器忙)。 */
|
||||
for (int r = 1; r <= PHONERAIL_RAIL_COUNT; r++) {
|
||||
if (chgmode_active(r, now) && !rail_efuse_is_on(r) && !t_actuator_busy(r)) {
|
||||
(void)chgmode_set(r, 0, now);
|
||||
evlog_put((uint8_t)r, LOG_EV_CHG_MODE, CHG_EV_DROPPED, now_mv(r), now_ua(r));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cmd_err_t do_fan(ctx_t *c)
|
||||
{
|
||||
int64_t duty = 0;
|
||||
|
||||
在新工单中引用
屏蔽一个用户