固件 0.1.3-c5:硬重启开机校验 + 重按(0.1.2)、status 上报上游电脑在不在(host)
- 0.1.2:power_cycle 按完电源键后看电流,没开就重按,最多 3 次;新事件 19 BOOT_CHECK - 0.1.3:UP_VBUS_DET(IO6)启动时配成输入,status 加 "host":true|false|null - rack:单板页显示「上游:已连电脑 / 未连电脑」 - HANDOFF:损耗两档的来历(Hub 工作 ≈1.1 W)、板 B 第 2 槽 PRSNT2# 卡低 Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
+112
-16
@@ -20,12 +20,19 @@ typedef struct {
|
||||
act_result_t result;
|
||||
uint32_t done;
|
||||
uint32_t cleanup_retries;
|
||||
uint8_t presses; /* HR:这一次硬重启已经按了几次电源键 */
|
||||
uint8_t good_n; /* HR_VERIFY:连续几个样本电流达标 */
|
||||
bool ua_seen; /* HR_VERIFY:这一轮窗口里读到过电流没有 */
|
||||
int32_t last_ua; /* HR_VERIFY:最近一个读到的样本 */
|
||||
} act_rail_t;
|
||||
|
||||
static act_rail_t s_rail[PHONERAIL_RAIL_COUNT];
|
||||
static act_pg_fn s_pg;
|
||||
static void *s_pg_ctx;
|
||||
static bool s_inited;
|
||||
static act_rail_t s_rail[PHONERAIL_RAIL_COUNT];
|
||||
static act_pg_fn s_pg;
|
||||
static void *s_pg_ctx;
|
||||
static act_ua_fn s_ua;
|
||||
static act_boot_fn s_boot_done;
|
||||
static void *s_boot_ctx;
|
||||
static bool s_inited;
|
||||
|
||||
/* ---- 小工具 -------------------------------------------------------------- */
|
||||
|
||||
@@ -67,12 +74,46 @@ static bool pg_now(int rail, bool *pg)
|
||||
return s_pg(s_pg_ctx, rail, pg);
|
||||
}
|
||||
|
||||
static bool ua_now(int rail, int32_t *ua)
|
||||
{
|
||||
if (s_ua == NULL) {
|
||||
return false;
|
||||
}
|
||||
return s_ua(s_boot_ctx, rail, ua);
|
||||
}
|
||||
|
||||
static void enter(act_rail_t *r, act_state_t st, uint32_t now)
|
||||
{
|
||||
r->state = st;
|
||||
r->t0_ms = now;
|
||||
}
|
||||
|
||||
/* HR:按下电源键开机(HR_PG 第一次、HR_VERIFY 重按走同一个口)。
|
||||
和 KEY 序列一样:先记 release_mask 再看写没写成 —— 写失败时器件里那个字节
|
||||
是未知的,照样走 CLEANUP 把它显式清一遍。返回 false = 写失败,已 finish(IO)。 */
|
||||
static void finish(act_rail_t *r, act_result_t res, uint32_t now);
|
||||
|
||||
static bool hr_press(act_rail_t *r, int rail, uint32_t now)
|
||||
{
|
||||
const uint8_t mask = key_out_mask(ACT_KEYS_PWR);
|
||||
r->release_mask = mask;
|
||||
r->hold_ms = ACT_HR_BOOT_KEY_MS;
|
||||
r->presses++;
|
||||
if (out_write(rail, mask, mask) != HAL_OK) {
|
||||
finish(r, ACT_RES_IO, now); /* 电是开着的,只是没按上键 */
|
||||
return false;
|
||||
}
|
||||
enter(r, ACT_ST_HR_BOOT, now);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void boot_report(act_rail_t *r, int rail, bool booted)
|
||||
{
|
||||
if (s_boot_done != NULL) {
|
||||
s_boot_done(s_boot_ctx, rail, booted, r->presses, r->last_ua);
|
||||
}
|
||||
}
|
||||
|
||||
/* 序列结束(成功、超时、出错、被打断走的是同一条路)。
|
||||
按下去过东西就必须经 CLEANUP,那是「键一定会松开」的唯一保证。 */
|
||||
static void finish(act_rail_t *r, act_result_t res, uint32_t now)
|
||||
@@ -122,18 +163,8 @@ static uint32_t state_step(act_rail_t *r, int rail, uint32_t now)
|
||||
case ACT_ST_HR_PG: {
|
||||
bool pg = false;
|
||||
if (pg_now(rail, &pg) && pg) {
|
||||
/* 电好了 ⇒ 长按电源键开机(ACT_HR_BOOT_KEY_MS 的注释)。
|
||||
和 KEY 序列一样:先记 release_mask 再看写没写成 —— 写失败时器件里那个字节
|
||||
是未知的,照样走 CLEANUP 把它显式清一遍。 */
|
||||
const uint8_t mask = key_out_mask(ACT_KEYS_PWR);
|
||||
r->release_mask = mask;
|
||||
r->hold_ms = ACT_HR_BOOT_KEY_MS;
|
||||
if (out_write(rail, mask, mask) != HAL_OK) {
|
||||
finish(r, ACT_RES_IO, now); /* 电是开着的,只是没按上键 */
|
||||
return ACT_CLEANUP_RETRY_MS;
|
||||
}
|
||||
enter(r, ACT_ST_HR_BOOT, now);
|
||||
return ACT_HR_BOOT_KEY_MS;
|
||||
/* 电好了 ⇒ 长按电源键开机(ACT_HR_BOOT_KEY_MS 的注释)。 */
|
||||
return hr_press(r, rail, now) ? ACT_HR_BOOT_KEY_MS : ACT_CLEANUP_RETRY_MS;
|
||||
}
|
||||
if (el >= ACT_HR_PG_TIMEOUT_MS) {
|
||||
/* ⚠️ 电**继续开着**。见 ACT_RES_NO_PG 的注释:把「看不见」当成
|
||||
@@ -146,6 +177,57 @@ static uint32_t state_step(act_rail_t *r, int rail, uint32_t now)
|
||||
}
|
||||
|
||||
case ACT_ST_HR_BOOT:
|
||||
if (el < r->hold_ms) {
|
||||
return r->hold_ms - el;
|
||||
}
|
||||
if (s_ua == NULL) {
|
||||
finish(r, ACT_RES_OK, now); /* 不校验(0.1.1 行为):CLEANUP 松键 */
|
||||
return ACT_CLEANUP_RETRY_MS;
|
||||
}
|
||||
/* 要校验:先在这里松键(松不掉就走 CLEANUP 的「不放弃」,不再校验)。 */
|
||||
if (out_write(rail, r->release_mask, 0) != HAL_OK) {
|
||||
finish(r, ACT_RES_IO, now);
|
||||
return ACT_CLEANUP_RETRY_MS;
|
||||
}
|
||||
r->release_mask = 0;
|
||||
r->good_n = 0;
|
||||
r->ua_seen = false;
|
||||
enter(r, ACT_ST_HR_VERIFY, now);
|
||||
return ACT_HR_VERIFY_DELAY_MS;
|
||||
|
||||
case ACT_ST_HR_VERIFY: {
|
||||
if (el < ACT_HR_VERIFY_DELAY_MS) {
|
||||
return ACT_HR_VERIFY_DELAY_MS - el;
|
||||
}
|
||||
int32_t ua = 0;
|
||||
if (ua_now(rail, &ua)) {
|
||||
r->ua_seen = true;
|
||||
r->last_ua = ua;
|
||||
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);
|
||||
return ACT_IDLE_WAIT_MS;
|
||||
}
|
||||
}
|
||||
if (el < ACT_HR_VERIFY_DELAY_MS + ACT_HR_VERIFY_WINDOW_MS) {
|
||||
const uint32_t left = ACT_HR_VERIFY_DELAY_MS + ACT_HR_VERIFY_WINDOW_MS - el;
|
||||
return left < ACT_HR_VERIFY_POLL_MS ? left : ACT_HR_VERIFY_POLL_MS;
|
||||
}
|
||||
if (!r->ua_seen) {
|
||||
/* 整个窗口都读不到电流:判不了,**不重按**(ACT_HR_BOOT_TRIES 那段注释)。 */
|
||||
finish(r, ACT_RES_OK, now);
|
||||
return ACT_IDLE_WAIT_MS;
|
||||
}
|
||||
if (r->presses < ACT_HR_BOOT_TRIES) {
|
||||
return hr_press(r, rail, now) ? ACT_HR_BOOT_KEY_MS : ACT_CLEANUP_RETRY_MS;
|
||||
}
|
||||
/* ⚠️ 电**继续开着**:关掉也不会让弹片压上,反而丢了人工到场前的现场。 */
|
||||
boot_report(r, rail, false);
|
||||
finish(r, ACT_RES_NO_BOOT, now);
|
||||
return ACT_IDLE_WAIT_MS;
|
||||
}
|
||||
|
||||
case ACT_ST_KEY_HOLD:
|
||||
if (el < r->hold_ms) {
|
||||
return r->hold_ms - el;
|
||||
@@ -213,9 +295,19 @@ void t_actuator_init(act_pg_fn pg, void *ctx)
|
||||
memset(s_rail, 0, sizeof(s_rail));
|
||||
s_pg = pg;
|
||||
s_pg_ctx = ctx;
|
||||
s_ua = NULL;
|
||||
s_boot_done = NULL;
|
||||
s_boot_ctx = NULL;
|
||||
s_inited = true;
|
||||
}
|
||||
|
||||
void t_actuator_set_boot_check(act_ua_fn ua, act_boot_fn done, void *ctx)
|
||||
{
|
||||
s_ua = ua;
|
||||
s_boot_done = done;
|
||||
s_boot_ctx = ctx;
|
||||
}
|
||||
|
||||
hal_err_t t_actuator_hard_reset(int rail)
|
||||
{
|
||||
if (!s_inited) {
|
||||
@@ -244,6 +336,8 @@ hal_err_t t_actuator_hard_reset(int rail)
|
||||
}
|
||||
r->seq = ACT_SEQ_HARD_RESET;
|
||||
r->release_mask = 0; /* 断电这一段没按任何东西;开机那一下在 HR_PG 里才记 */
|
||||
r->presses = 0;
|
||||
r->last_ua = 0;
|
||||
r->result = ACT_RES_NONE;
|
||||
enter(r, ACT_ST_HR_OFF, hal_time_now_ms());
|
||||
return HAL_OK;
|
||||
@@ -368,6 +462,7 @@ const char *t_actuator_state_str(act_state_t st)
|
||||
case ACT_ST_HR_RAMP: return "hr-ramp";
|
||||
case ACT_ST_HR_PG: return "hr-pg";
|
||||
case ACT_ST_HR_BOOT: return "hr-boot";
|
||||
case ACT_ST_HR_VERIFY: return "hr-verify";
|
||||
case ACT_ST_KEY_HOLD: return "key-hold";
|
||||
case ACT_ST_EDL_SHORT: return "edl-short";
|
||||
case ACT_ST_EDL_ENUM: return "edl-enum";
|
||||
@@ -384,6 +479,7 @@ const char *t_actuator_result_str(act_result_t r)
|
||||
case ACT_RES_NO_PG: return "no-pg";
|
||||
case ACT_RES_IO: return "io";
|
||||
case ACT_RES_ABORTED: return "aborted";
|
||||
case ACT_RES_NO_BOOT: return "no-boot";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
在新工单中引用
屏蔽一个用户