固件 0.1.1-c3:I²C 不应答不再被报成「没初始化 / 忙」(关电回 busy 的根因)
- 根因:IDF 5.4 的 i2c_master_transmit / receive / transmit_receive 在从机 NACK / SCL 超时时返回 ESP_ERR_INVALID_STATE,HAL 照翻成 HAL_ERR_STATE(= 没 init);命令层 from_hal 又把 STATE 当成 「执行器忙」⇒ PCA9555 不应答时 power off 回 busy(eFuse 其实已关、意图已清),I2C_LOST 错误码是 5 - hal_i2c_esp.c:传输函数用 map_xfer_err(INVALID_STATE → NAK);总线没建起来仍单独报 STATE - cmd_exec.c:新增 from_bus,set_voltage / vbus / power 的器件失败一律 io;from_hal 只留给执行器 - sim:sim_i2c_inject_err_ch() 可指定注入的错误码;test_cmd 加 STATE 注入 ⇒ 必须 io 不是 busy (改回 from_hal 时这段确实红)。26 个 ctest 全绿 - 板 B(台架镜像,CH1 强制在位,未提交):power off 回 io、CH1 关掉;I2C_LOST 错误码 5 → 2。现跑 0.1.1-c3 Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
+17
-4
@@ -38,6 +38,7 @@ static cmd_err_t need_rail(ctx_t *c)
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
/* 执行器(t_actuator_*)的返回值 → 回应。它的 HAL_ERR_STATE 就是「这一路正在跑别的序列」。 */
|
||||
static cmd_err_t from_hal(hal_err_t e)
|
||||
{
|
||||
switch (e) {
|
||||
@@ -48,6 +49,18 @@ static cmd_err_t from_hal(hal_err_t e)
|
||||
}
|
||||
}
|
||||
|
||||
/* 直接动器件(I²C / GPIO)的返回值 → 回应。**失败一律 io**,不许借用 from_hal:
|
||||
总线上的 HAL_ERR_STATE 不是「忙」(2026-09-27:PCA9555 不应答时关电回了 busy,
|
||||
上位机会以为没执行、换个时机再关一次,其实 eFuse 早就关了)。 */
|
||||
static cmd_err_t from_bus(hal_err_t e)
|
||||
{
|
||||
switch (e) {
|
||||
case HAL_OK: return CMD_OK;
|
||||
case HAL_ERR_ARG: return CMD_ERR_RANGE;
|
||||
default: return CMD_ERR_IO;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- 各条命令 ------------------------------------------------------------ */
|
||||
|
||||
typedef struct {
|
||||
@@ -79,7 +92,7 @@ cmd_err_t do_set_voltage(ctx_t *c)
|
||||
/* ⚠️ DAC 在主干上,但 `rail_set_mv()` 自己**不拿锁**(它比 i2cbus 早)。
|
||||
不包这一层就是在巡检的事务中间插一笔 —— 总线上两个主机同时说话。 */
|
||||
set_mv_arg_t a = { .rail = c->rail, .mv = (int)mv };
|
||||
e = from_hal(i2cbus_xact(I2CBUS_CH_TRUNK, SLOT_LOCK_TIMEOUT_MS, set_mv_fn, &a));
|
||||
e = from_bus(i2cbus_xact(I2CBUS_CH_TRUNK, SLOT_LOCK_TIMEOUT_MS, set_mv_fn, &a));
|
||||
if (e == CMD_OK) {
|
||||
cj_w(c->w, ",\"set\":%d", rail_setpoint_mv(c->rail));
|
||||
}
|
||||
@@ -196,7 +209,7 @@ cmd_err_t do_vbus(ctx_t *c)
|
||||
if (on && !rail_efuse_is_on(c->rail)) {
|
||||
return reject(c, CMD_ERR_STATE, 1);
|
||||
}
|
||||
return from_hal(slot_vbus_enable(c->rail, on));
|
||||
return from_bus(slot_vbus_enable(c->rail, on));
|
||||
}
|
||||
|
||||
/* A15:意图出口(cmd.h 的 `cmd_intent_fn`)。 */
|
||||
@@ -226,7 +239,7 @@ cmd_err_t do_power(ctx_t *c)
|
||||
if (ee == HAL_OK) {
|
||||
note_intent(c->rail, true);
|
||||
}
|
||||
return from_hal(ee);
|
||||
return from_bus(ee);
|
||||
}
|
||||
/* 关:与 `rail_all_off()` 同序 —— **先断 VBUS 再关 eFuse**。
|
||||
VBUS 走 I²C 可能断不掉,eFuse 是 GPIO 永远关得掉:前者失败也照样关后者,
|
||||
@@ -236,7 +249,7 @@ cmd_err_t do_power(ctx_t *c)
|
||||
if (ee == HAL_OK) {
|
||||
note_intent(c->rail, false); /* 直供确实断了:下次开机也别开它 */
|
||||
}
|
||||
return from_hal(ee != HAL_OK ? ee : ev);
|
||||
return from_bus(ee != HAL_OK ? ee : ev);
|
||||
}
|
||||
|
||||
cmd_err_t do_fan(ctx_t *c)
|
||||
|
||||
在新工单中引用
屏蔽一个用户