固件 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]>
这个提交包含在:
+76
-4
@@ -24,6 +24,9 @@ typedef struct {
|
||||
uint8_t good_n; /* HR_VERIFY:连续几个样本电流达标 */
|
||||
bool ua_seen; /* HR_VERIFY:这一轮窗口里读到过电流没有 */
|
||||
int32_t last_ua; /* HR_VERIFY:最近一个读到的样本 */
|
||||
bool vbus_back; /* HR:开始时断了 VBUS,开机校验通过后要接回(0.1.11) */
|
||||
bool vbus_pending; /* 已开机,等到 vbus_at 再接回 VBUS(ACT_HR_VBUS_BACK_MS) */
|
||||
uint32_t vbus_at;
|
||||
} act_rail_t;
|
||||
|
||||
static act_rail_t s_rail[PHONERAIL_RAIL_COUNT];
|
||||
@@ -118,6 +121,7 @@ static void boot_report(act_rail_t *r, int rail, bool booted)
|
||||
按下去过东西就必须经 CLEANUP,那是「键一定会松开」的唯一保证。 */
|
||||
static void finish(act_rail_t *r, act_result_t res, uint32_t now)
|
||||
{
|
||||
r->vbus_back = false; /* 只有 hr_ok() 会接回 VBUS;别的结局一律让它断着 */
|
||||
r->result = res;
|
||||
r->done++;
|
||||
if (r->release_mask != 0) {
|
||||
@@ -128,6 +132,39 @@ static void finish(act_rail_t *r, act_result_t res, uint32_t now)
|
||||
}
|
||||
}
|
||||
|
||||
/* HR 成功收尾:开始时断过 VBUS 的,排一个 ACT_HR_VBUS_BACK_MS 之后的「接回」
|
||||
(t_actuator_step 里做,那时执行器已空闲)。 */
|
||||
static void hr_ok(act_rail_t *r, int rail, uint32_t now)
|
||||
{
|
||||
(void)rail;
|
||||
if (r->vbus_back) {
|
||||
r->vbus_pending = true;
|
||||
r->vbus_at = now + ACT_HR_VBUS_BACK_MS;
|
||||
}
|
||||
finish(r, ACT_RES_OK, now);
|
||||
}
|
||||
|
||||
/* 到点了就接回 VBUS。返回下次最晚多久再来。
|
||||
这一路被关了电(安全判据 / 拔刀片)就作废;写失败下一拍再试(影子如实留在 off)。 */
|
||||
static uint32_t vbus_back_step(act_rail_t *r, int rail, uint32_t now)
|
||||
{
|
||||
if (!r->vbus_pending || r->state != ACT_ST_IDLE) {
|
||||
return ACT_IDLE_WAIT_MS;
|
||||
}
|
||||
const int32_t left = (int32_t)(r->vbus_at - now);
|
||||
if (left > 0) {
|
||||
return (uint32_t)left;
|
||||
}
|
||||
if (!rail_efuse_is_on(rail)) {
|
||||
r->vbus_pending = false;
|
||||
return ACT_IDLE_WAIT_MS;
|
||||
}
|
||||
if (slot_vbus_enable(rail, true) == HAL_OK) {
|
||||
r->vbus_pending = false;
|
||||
}
|
||||
return ACT_IDLE_WAIT_MS;
|
||||
}
|
||||
|
||||
/* ---- 状态机本体:一个状态一段,返回「还要多久再来」 ---------------------- */
|
||||
|
||||
static uint32_t state_step(act_rail_t *r, int rail, uint32_t now)
|
||||
@@ -181,7 +218,7 @@ static uint32_t state_step(act_rail_t *r, int rail, uint32_t now)
|
||||
return r->hold_ms - el;
|
||||
}
|
||||
if (s_ua == NULL) {
|
||||
finish(r, ACT_RES_OK, now); /* 不校验(0.1.1 行为):CLEANUP 松键 */
|
||||
hr_ok(r, rail, now); /* 不校验(0.1.1 行为):CLEANUP 松键 */
|
||||
return ACT_CLEANUP_RETRY_MS;
|
||||
}
|
||||
/* 要校验:先在这里松键(松不掉就走 CLEANUP 的「不放弃」,不再校验)。 */
|
||||
@@ -206,7 +243,7 @@ static uint32_t state_step(act_rail_t *r, int rail, uint32_t now)
|
||||
r->good_n = ua >= ACT_HR_BOOT_UA_MIN ? (uint8_t)(r->good_n + 1) : 0;
|
||||
if (r->good_n >= ACT_HR_VERIFY_GOOD_N) {
|
||||
boot_report(r, rail, true);
|
||||
finish(r, ACT_RES_OK, now);
|
||||
hr_ok(r, rail, now);
|
||||
return ACT_IDLE_WAIT_MS;
|
||||
}
|
||||
}
|
||||
@@ -216,7 +253,7 @@ static uint32_t state_step(act_rail_t *r, int rail, uint32_t now)
|
||||
}
|
||||
if (!r->ua_seen) {
|
||||
/* 整个窗口都读不到电流:判不了,**不重按**(ACT_HR_BOOT_TRIES 那段注释)。 */
|
||||
finish(r, ACT_RES_OK, now);
|
||||
hr_ok(r, rail, now);
|
||||
return ACT_IDLE_WAIT_MS;
|
||||
}
|
||||
if (r->presses < ACT_HR_BOOT_TRIES) {
|
||||
@@ -330,8 +367,25 @@ hal_err_t t_actuator_hard_reset(int rail)
|
||||
(void)out_write(rail, km, 0); /* 失败也照断电:断电永远比不断电安全 */
|
||||
}
|
||||
|
||||
/* 0.1.11(2026-09-28 板 B):VBUS 通着就**先断**,开机校验通过后再接回(hr_ok)。
|
||||
不断的三个后果,现场全见过:
|
||||
· 手机靠 USB 撑着,根本没断电 —— 硬重启是假的;
|
||||
· 手机吃 USB 的电,直供电流 ≈ 0 ⇒ 开机校验判「没开起来」、再按两下电源键;
|
||||
· 断电那一刻 USB 还在 ⇒ 被当成「插充电器开机」,进关机充电模式,一拔 USB 就关机。
|
||||
断不掉也照样断电(断电永远比不断电安全),只是事后不接回。 */
|
||||
r->vbus_back = false;
|
||||
r->vbus_pending = false; /* 上一次硬重启排的接回作废 */
|
||||
const bool had_vbus = slot_vbus_is_on(rail);
|
||||
if (had_vbus && slot_vbus_enable(rail, false) == HAL_OK) {
|
||||
r->vbus_back = true;
|
||||
}
|
||||
|
||||
const hal_err_t err = rail_efuse_enable(rail, false);
|
||||
if (err != HAL_OK) {
|
||||
if (r->vbus_back) {
|
||||
(void)slot_vbus_enable(rail, true); /* 序列没开始:恢复原样 */
|
||||
r->vbus_back = false;
|
||||
}
|
||||
return err; /* 序列没开始 */
|
||||
}
|
||||
r->seq = ACT_SEQ_HARD_RESET;
|
||||
@@ -396,6 +450,7 @@ hal_err_t t_actuator_edl(int rail)
|
||||
return HAL_ERR_STATE;
|
||||
}
|
||||
|
||||
r->vbus_pending = false; /* EDL 自己管 VBUS */
|
||||
const uint8_t mask = (uint8_t)(1u << PCA9555_BIT_EDL_EN);
|
||||
const hal_err_t err = out_write(rail, mask, mask);
|
||||
|
||||
@@ -417,6 +472,7 @@ void t_actuator_abort(int rail)
|
||||
return;
|
||||
}
|
||||
act_rail_t *r = at(rail);
|
||||
r->vbus_pending = false; /* 被打断的路(多半是安全判据关了电)不再接回 VBUS */
|
||||
if (r->state == ACT_ST_IDLE || r->state == ACT_ST_CLEANUP) {
|
||||
return; /* CLEANUP 已经在收尾了,别把它的结果覆盖掉 */
|
||||
}
|
||||
@@ -424,6 +480,18 @@ void t_actuator_abort(int rail)
|
||||
(void)rail_step(rail, hal_time_now_ms()); /* 立刻试一次收尾,别等下一拍 */
|
||||
}
|
||||
|
||||
void t_actuator_cancel_vbus_back(int rail)
|
||||
{
|
||||
if (s_inited && rail_valid(rail)) {
|
||||
at(rail)->vbus_pending = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool t_actuator_vbus_back_pending(int rail)
|
||||
{
|
||||
return s_inited && rail_valid(rail) && at(rail)->vbus_pending;
|
||||
}
|
||||
|
||||
uint32_t t_actuator_step(void)
|
||||
{
|
||||
if (!s_inited) {
|
||||
@@ -433,7 +501,11 @@ uint32_t t_actuator_step(void)
|
||||
uint32_t wait = ACT_IDLE_WAIT_MS;
|
||||
|
||||
for (int rail = 1; rail <= PHONERAIL_RAIL_COUNT; rail++) {
|
||||
const uint32_t w = rail_step(rail, now);
|
||||
uint32_t w = rail_step(rail, now);
|
||||
const uint32_t v = vbus_back_step(at(rail), rail, now);
|
||||
if (v < w) {
|
||||
w = v;
|
||||
}
|
||||
if (w < wait) {
|
||||
wait = w;
|
||||
}
|
||||
|
||||
在新工单中引用
屏蔽一个用户