固件 0.1.14~0.1.16-c5:Hub 按需启停(hubctl)、开机长按统一 5 s
Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
@@ -0,0 +1,121 @@
|
||||
/* Hub(U32 USB2517I)按需启停(0.1.14,2026-09-29 用户定,推翻 R2 D13 代价 2 / R-11 的
|
||||
「运行期不许动 `HUB_RST#`」)。
|
||||
|
||||
为什么要有它:五台手机的 VBUS 平时全关,但 Hub 只要上行插着电脑就一直是活动态 ——
|
||||
ESP32 自己的 USB-Serial-JTAG 挂在第 6 口上,电脑永远不会把它挂起。
|
||||
2026-09-29 板 B 实测 Hub 工作 vs 按住复位差 1.03 W(12 V 输入差约 88 mA),而这 1 W 大部分时间什么都没在干。
|
||||
把 `RESET_N`(43 脚)拉低 ⇒ Hub 从电脑那边消失,PHY 与 24 MHz 晶振都停,只剩 U31 的静态电流。
|
||||
|
||||
---- 什么时候开(任一条成立就开,并刷新「最后一次需要」的时刻)-------------
|
||||
| why | 条件 |
|
||||
|---------|------|
|
||||
| mode | 模式 = 常开(`hub` 命令,存 NVS) |
|
||||
| vbus | 任一路 VBUS 通着 —— 手机的 USB 只有这时才在 Hub 上 |
|
||||
| flash | 任一路刷机模式窗口内(chgmode.h) |
|
||||
| act | 任一路执行器在跑序列(EDL 要枚举 9008;硬重启中途 VBUS 暂时是关的) |
|
||||
| hold | `hub` 命令给的保持窗口内(要用 ESP32 的 USB 控制台 / 烧录) |
|
||||
| link | MQTT 连续 HUB_LINK_LOST_MS 没连上(含从没配过网)⇒ **USB 是唯一的路,必须开** |
|
||||
| idle | 以上都不成立,但离「最后一次需要」还不到 HUB_IDLE_MS |
|
||||
「最后一次需要」还会被三件事刷新:启动、上行电脑插上(`UP_VBUS_DET` 上升沿)、
|
||||
USB 链路上来了一条命令 —— 都是「有人正要用 USB」的信号。
|
||||
全不成立 ⇒ 关(`HUB_RST#` 拉低)。
|
||||
|
||||
---- 退路(这是推翻 R-11 的前提,一条都不许删)-----------------------------
|
||||
1. `link`:WiFi/MQTT 断了 ⇒ 1 分钟内 Hub 自己回来,USB 控制台可用;
|
||||
2. ESP32 任何一次复位(上电 / 看门狗 / esp_restart / esptool / J33 EN)引脚都回到高阻,
|
||||
R716 把 Hub 拉出复位,而且启动算一次「需要」⇒ 至少 HUB_IDLE_MS 的窗口;
|
||||
3. 板子断电重上 = 第 2 条;
|
||||
4. J33 UART 应急口不经过 Hub,永远在。
|
||||
⚠️ 只许**拉低**或**放成输入**(靠 R716 拉高),不许主动驱高 —— 和 bringup 的脉冲同一口径:
|
||||
放开 = 高阻,ESP32 这一侧出任何事 Hub 都停在「工作」那一边。
|
||||
|
||||
---- 线程 ----------------------------------------------------------------
|
||||
**只有执行器任务写**(`hubctl_tick()` 在执行器循环里、命令处理器也在那个任务里),
|
||||
status 跨任务读几个单字,遥测无害(cmd.h 同一条)。 */
|
||||
#ifndef HUBCTL_H
|
||||
#define HUBCTL_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hal_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HUB_IDLE_MS (10u * 60000u) /* 最后一次需要之后再开多久 */
|
||||
#define HUB_LINK_LOST_MS 60000u /* MQTT 断多久算「只剩 USB 这条路」 */
|
||||
#define HUB_HOLD_MAX_MIN 240
|
||||
|
||||
/* 模式。⚠️ 进 NVS,冻结。 */
|
||||
typedef enum {
|
||||
HUB_MODE_AUTO = 0,
|
||||
HUB_MODE_ON = 1,
|
||||
HUB_MODE_COUNT,
|
||||
} hub_mode_t;
|
||||
|
||||
/* 为什么开着 / 关着。⚠️ 进事件(LOG_EV_HUB 的 bus_mv),冻结,只许在末尾追加。 */
|
||||
typedef enum {
|
||||
HUB_WHY_OFF = 0,
|
||||
HUB_WHY_MODE = 1,
|
||||
HUB_WHY_VBUS = 2,
|
||||
HUB_WHY_FLASH = 3,
|
||||
HUB_WHY_ACT = 4,
|
||||
HUB_WHY_HOLD = 5,
|
||||
HUB_WHY_LINK = 6,
|
||||
HUB_WHY_IDLE = 7,
|
||||
HUB_WHY_COUNT,
|
||||
} hub_why_t;
|
||||
|
||||
/* LOG_EV_HUB 的 arg。⚠️ 进 flash,冻结。 */
|
||||
#define HUB_EV_OFF 0u
|
||||
#define HUB_EV_ON 1u
|
||||
#define HUB_EV_MODE 0x10u /* | 新模式 */
|
||||
|
||||
/* 一拍的输入(`hubctl_tick()` 自己采;宿主机测试直接喂 `hub_decide()`)。 */
|
||||
typedef struct {
|
||||
bool vbus_any;
|
||||
bool flash_any;
|
||||
bool act_any;
|
||||
bool link_up;
|
||||
bool host; /* UP_VBUS_DET */
|
||||
} hub_in_t;
|
||||
|
||||
/* 模式存盘回调(app_main 写 NVS)。NULL = 不存(宿主机测试)。 */
|
||||
typedef void (*hub_save_fn)(void *ctx, hub_mode_t mode);
|
||||
|
||||
/* 起步:记下模式、把 `HUB_RST#` 放成输入(Hub 工作),启动算一次「需要」。
|
||||
模式越界按 AUTO。 */
|
||||
void hubctl_init(hub_mode_t mode, hub_save_fn save, void *ctx, uint32_t now);
|
||||
|
||||
/* 纯判定:这一拍 Hub 该不该开、为什么。会推进内部的时刻(最后一次需要 / 断线起点 / 上行边沿),
|
||||
**不碰引脚**。宿主机测试用它。 */
|
||||
hub_why_t hub_decide(const hub_in_t *in, uint32_t now);
|
||||
|
||||
/* 执行器循环每拍调:采输入 → `hub_decide()` → 状态变了才动引脚、记事件。 */
|
||||
void hubctl_tick(uint32_t now);
|
||||
|
||||
/* USB 链路上来了一条命令(cmd.c 调):算一次「需要」。 */
|
||||
void hubctl_touch(uint32_t now);
|
||||
|
||||
/* 命令:改模式(存盘、记事件)。越界 HAL_ERR_ARG。 */
|
||||
hal_err_t hubctl_set_mode(hub_mode_t mode);
|
||||
/* 命令:保持 minutes 分钟(1~HUB_HOLD_MAX_MIN,覆盖原窗口);0 = 取消保持**并结束 idle 窗口**
|
||||
(没有别的理由就下一拍关 —— 实测省电用)。越界 HAL_ERR_ARG。 */
|
||||
hal_err_t hubctl_hold(uint32_t minutes, uint32_t now);
|
||||
|
||||
hub_mode_t hubctl_mode(void);
|
||||
bool hubctl_is_on(void); /* 引脚此刻放着(Hub 在工作) */
|
||||
hub_why_t hubctl_why(void); /* 上一拍的结论 */
|
||||
uint32_t hubctl_hold_left_s(uint32_t now);
|
||||
uint32_t hubctl_idle_left_s(uint32_t now); /* why == idle 时离自动关还有几秒,否则 0 */
|
||||
const char *hub_mode_str(hub_mode_t m);
|
||||
const char *hub_why_str(hub_why_t w);
|
||||
bool hub_mode_parse(const char *s, hub_mode_t *out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HUBCTL_H */
|
||||
在新工单中引用
屏蔽一个用户