chore(编号): 存量编号全量转语义短语,门禁识别面与语料同批重打
登记簿、文档与代码注释里的存量字母加数字编号(N-x / S-x / T-x / E-x / A-x / 卡号) 一律改写为语义短语,净删 2,028 处引用;删除基线与待确认、并行分道方案、排期详述、 采集保护收尾 4 篇(内容已并入 docs/任务规划/README 与登记簿)。 门禁机器与三张账同批重打:check_ids.py 新增变更记录行豁免与第二根护栏 undecidable_total_ceiling;check_test_traceability.py 只加 stdout/stderr UTF-8 reconfigure(TC_RE 未动);check_cubemx_survival.py 的 --write 固定 newline=LF; id_registry / id_aliases(+19 条 retired-to-phrase)/ id_known_backlog 重打。 test/ 56 个文件同步 TC 标签语义化,其中 18 个 TU 改了 CHECK / printf 里的标签文字, 是本批唯一改变构建产物的文件集合。 为什么合成一笔、不拆四笔(实测撞闸,非偏好):pre-commit 跑钩子前会 stash 未 staged 部分,拆开后中间提交必然是「新规则 + 旧语料」——实跑可判定 85.15% < 基线 86.00%、 不可判定 1,453 > 上限 1,166,编号门禁直接拦下。编号识别面与它描述的语料只能同码移动。 实跑基线(工作区全量):754 文件 / 8,230 处编号字面量 / 可判定 7,079 = 86.01% (基线 86.0%,容差 0.1pp)/ 不可判定绝对数 1,151(上限 1,166)/ 校验 1-6 错误级 0 / 告警 = 悬空 2(App/algo/freq.c 的 S2,属 §4.4 同号不同义)+ 孤儿 50。 基线从 84.0 抬到 86.0 的理由见 docs/门禁说明/id-check.md §7.6:本批真删了 2,028 处 引用,可判定面随真实内容上升,不是把分母做小。同批新增排除 docs/硬件平台/ 语料,使 识别面少 264 处——芯片手册位号与网表料号不属编号空间(registry 有 excluded_paths_note)。 ⚠ 余量只剩 0.11pp(约 10 处)与绝对数 15 处:把「可判定的引用」改成散文会立刻撞第二 根护栏。另遗留一项:id_aliases 里 retired 的 N / S / T / A 别名没有 scope(U1~U5 有), 今后有人新写一个 A-4,校验 3 不会响,只能靠人,建议下批补 scope。 固件不变证据:115 个 .c/.h 剥注释并归一字符串后与 HEAD 逐字节全等,残留代码差异 0; App / Src / Drivers 的字符串字面量零改动。@build 0 错误 0 警告;40/40 主机套件、2,889 断言全通过;覆盖率 line 89.2% / func 92.6%;pre-commit 48 钩子 --all-files 全绿; check_doc_links --all 通过(176 文档,章节引用无法判定 0);逐字节卫生核过:14 个带 BOM 文件与 HEAD 一致、0 个 CR、0 个 U+FFFD,字符串字面量纯 ASCII。 .cubemx_survival_baseline.json 的 watchdog-module 哈希 56bf27 变 2bb051 属合法: Src/freertos.c 的 USER CODE 区内只有注释文字随编号改写,代码未变。 同批带上体积同码凭证与 RAM 台账行(@build 之后盖戳):RW_IRAM1 79,008 B / 60.3%, RW_CCM 57,376 B / 87.9%,阈值 92%。
This commit is contained in:
+12
-12
@@ -8,9 +8,9 @@
|
||||
* 修改记录:
|
||||
* 2026-03-14 王建锋 创建初始版本,按代码规范重构
|
||||
* 2026-07-18 王建锋 改进write_send_buf/read_recv_buf使用SPI2 DMA批量传输
|
||||
* 2026-10-02 王建锋 E-34:3 处字节级 SPI 调用由 HAL_MAX_DELAY 改有限超时(100ms)
|
||||
* 2026-10-02 王建锋 3 处字节级 SPI 调用由 HAL_MAX_DELAY 改有限超时(100ms)
|
||||
* + 返回值检查 + 故障锁存(沿程只记一条日志);原 SPI 异常时调用方永久挂死
|
||||
* 2026-10-04 王建锋 P2-2:ch395f_spi_dma_transfer 由 void 改为返回状态(0 成功/-1 失败),
|
||||
* 2026-10-04 王建锋 ch395f_spi_dma_transfer 由 void 改为返回状态(0 成功/-1 失败),
|
||||
* DMA 初始化失败/超时中止均锁存通道故障;read_recv_buf 在 DMA 失败时不再把
|
||||
* rx_buf 内容拷入调用方缓冲(改零填充),消除"失败当成功"的静默数据损坏
|
||||
*/
|
||||
@@ -40,7 +40,7 @@
|
||||
#define CH395F_CHECK_EXIST_TEST_DATA 0x57U /* 芯片检测测试数据 */
|
||||
#define CH395F_RESET_DELAY_MS 20U /* 复位后等待延时(ms) */
|
||||
#define CH395F_INIT_TIMEOUT_MS 500U /* 初始化超时时间(ms) */
|
||||
#define CH395F_SPI_BYTE_TIMEOUT_MS 100U /* E-34:字节级SPI有限超时(原 HAL_MAX_DELAY) */
|
||||
#define CH395F_SPI_BYTE_TIMEOUT_MS 100U /* 字节级SPI有限超时(原 HAL_MAX_DELAY) */
|
||||
/* DMA缓冲大小使用ch395f.h中公开的CH395F_SPI_DMA_BUF_SIZE */
|
||||
#define CH395F_DMA_BUF_SIZE CH395F_SPI_DMA_BUF_SIZE
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
* 静态变量定义区 - DMA传输相关
|
||||
*/
|
||||
static volatile uint8_t s_spi2_dma_done = 0U; /* DMA传输完成标志 */
|
||||
static uint8_t s_spi_fault = 0U; /* E-34/P2-2:SPI 通道故障锁存(字节级或 DMA 级超时/出错置位,MCU复位清除) */
|
||||
static uint8_t s_spi_fault = 0U; /* SPI 通道故障锁存(字节级或 DMA 级超时/出错置位,MCU复位清除) */
|
||||
|
||||
__attribute__((aligned(4)))
|
||||
static uint8_t s_spi2_dma_tx_buf[CH395F_DMA_BUF_SIZE]; /* DMA发送缓冲区 */
|
||||
@@ -90,7 +90,7 @@ static void ch395f_spi_end(void) {
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:锁存一次 SPI 通道故障(E-34/P2-2:仅首条故障记日志)
|
||||
* 函数功能:锁存一次 SPI 通道故障(仅首条故障记日志)
|
||||
* 入口参数:kind - 故障类别标签("byte"/"dma-hal"/"dma-timeout") const char*
|
||||
* 返回值:无
|
||||
* 限定条件:无
|
||||
@@ -114,7 +114,7 @@ static void ch395f_spi_fault_set(const char *kind) {
|
||||
* 2. 阻塞等待DMA完成回调置标志位
|
||||
* 3. 超时(1秒)时强制中止SPI DMA并打印错误信息
|
||||
* 4. 传输完成后检查SPI错误码并清除溢出标志
|
||||
* 5. P2-2(2026-10-04):失败路径锁存通道故障并返回 -1,调用方据此
|
||||
* 5.(2026-10-04):失败路径锁存通道故障并返回 -1,调用方据此
|
||||
* 判定 rx_buf 内容不可信,不再"失败当成功"继续消费
|
||||
*/
|
||||
static int ch395f_spi_dma_transfer(uint16_t len) {
|
||||
@@ -209,7 +209,7 @@ void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi) {
|
||||
uint8_t ch395f_write_cmd(uint8_t cmd) {
|
||||
uint8_t rx_data = 0xFFU;
|
||||
|
||||
/* 通过SPI发送命令并接收回显(E-34:有限超时+返回值检查;失败返回0xFF占位并锁存故障) */
|
||||
/* 通过SPI发送命令并接收回显(有限超时+返回值检查;失败返回0xFF占位并锁存故障) */
|
||||
if (HAL_SPI_TransmitReceive(&hspi2, &cmd, &rx_data, 1,
|
||||
CH395F_SPI_BYTE_TIMEOUT_MS) != HAL_OK) {
|
||||
ch395f_spi_fault_set("byte");
|
||||
@@ -226,7 +226,7 @@ uint8_t ch395f_write_cmd(uint8_t cmd) {
|
||||
uint8_t ch395f_write_data(uint8_t data) {
|
||||
uint8_t rx_data = 0xFFU;
|
||||
|
||||
/* 通过SPI发送数据并接收回显(E-34:有限超时+返回值检查) */
|
||||
/* 通过SPI发送数据并接收回显(有限超时+返回值检查) */
|
||||
if (HAL_SPI_TransmitReceive(&hspi2, &data, &rx_data, 1,
|
||||
CH395F_SPI_BYTE_TIMEOUT_MS) != HAL_OK) {
|
||||
ch395f_spi_fault_set("byte");
|
||||
@@ -244,7 +244,7 @@ uint8_t ch395f_read_data(void) {
|
||||
uint8_t tx_dummy = 0xFFU;
|
||||
uint8_t rx_data = 0xFFU;
|
||||
|
||||
/* 发送0xFF作为时钟源,读取芯片返回数据(E-34:有限超时+返回值检查) */
|
||||
/* 发送0xFF作为时钟源,读取芯片返回数据(有限超时+返回值检查) */
|
||||
if (HAL_SPI_TransmitReceive(&hspi2, &tx_dummy, &rx_data, 1,
|
||||
CH395F_SPI_BYTE_TIMEOUT_MS) != HAL_OK) {
|
||||
ch395f_spi_fault_set("byte");
|
||||
@@ -253,7 +253,7 @@ uint8_t ch395f_read_data(void) {
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:查询 SPI 通道故障锁存(E-34 / P2-2)
|
||||
* 函数功能:查询 SPI 通道故障锁存
|
||||
* 返回值:0 - 正常 1 - 曾发生 SPI 超时/错误(字节级或 DMA 级)
|
||||
* 限定条件:无
|
||||
* 函数说明:锁存式(不自动清除,MCU 复位前一直有效);上层据此判定
|
||||
@@ -1197,7 +1197,7 @@ void ch395f_write_send_buf(uint8_t sock, uint8_t *p_data, uint16_t len) {
|
||||
/* 数据同步屏障:确保memcpy写入对DMA可见 */
|
||||
__DSB();
|
||||
|
||||
/* CS低 → DMA批量传输 → CS高(P2-2:失败已由 transfer 锁存通道故障并记日志,
|
||||
/* CS低 → DMA批量传输 → CS高(失败已由 transfer 锁存通道故障并记日志,
|
||||
* 调用方经 ch395f_spi_byte_fault() 查询;此处无后续处理,失败即放弃本次发送) */
|
||||
ch395f_spi_begin();
|
||||
(void)ch395f_spi_dma_transfer(total);
|
||||
@@ -1250,7 +1250,7 @@ void ch395f_read_recv_buf(uint8_t sock, uint8_t *p_data, uint16_t len) {
|
||||
rc = ch395f_spi_dma_transfer(total);
|
||||
ch395f_spi_end();
|
||||
|
||||
/* P2-2(2026-10-04):DMA 失败时 rx_buf 内容不可信,禁止拷入调用方缓冲
|
||||
/* (2026-10-04):DMA 失败时 rx_buf 内容不可信,禁止拷入调用方缓冲
|
||||
* (否则把总线残留/半截数据当有效载荷 → 静默数据损坏);改零填充并返回,
|
||||
* 调用方据 ch395f_spi_byte_fault() 判定通道异常。 */
|
||||
if (rc != 0) {
|
||||
|
||||
@@ -307,7 +307,7 @@ uint8_t ch395f_write_data(uint8_t data);
|
||||
uint8_t ch395f_read_data(void);
|
||||
|
||||
/*
|
||||
* 函数功能:查询 SPI 通道故障锁存(E-34 / P2-2)
|
||||
* 函数功能:查询 SPI 通道故障锁存
|
||||
* 返回值:0 - 正常 1 - 曾发生 SPI 超时/错误(字节级或 DMA 级)
|
||||
* 限定条件:无
|
||||
* 函数说明:锁存式(MCU 复位前一直有效);上层据此判定"SPI 通道异常"
|
||||
@@ -584,7 +584,7 @@ uint16_t ch395f_get_recv_len(uint8_t sock);
|
||||
* 任何未配对 SINT 消费的读取都会吞掉其它 Socket 的事件通知。
|
||||
* **唯一读者 = net_poll(net_socket.c);测试/台架代码同样禁自行读取**
|
||||
* (用户裁定 2026-10-13)——等事件一律直读本 Socket ch395f_get_sock_int_status()。
|
||||
* 唯一例外:被测对象就是本 API 的板级用例(P1-06 寄存器断言 / Phase 12 L1
|
||||
* 唯一例外:被测对象就是本 API 的板级用例(寄存器断言 / Phase 12 L1
|
||||
* 时延基准,硬件层独占上下文、无并发消费者)。
|
||||
*/
|
||||
uint16_t ch395f_get_glob_int_status_all(void);
|
||||
|
||||
@@ -62,7 +62,7 @@ static volatile uint8_t s_spi1_dma_done;
|
||||
* 源/目的全部为文件作用域静态缓冲。 */
|
||||
|
||||
/* DMA 可达内存窗口 GD5F_DMA_RAM_BASE/END 与 CCM 窗口常量已上移到 gd5f2gq5ue.h
|
||||
* (N-26,2026-10-12:nand_ftl.c 的 init 期自检也要用),并带编译期守卫
|
||||
* (DMA 可达性三层防线,2026-10-12:nand_ftl.c 的 init 期自检也要用),并带编译期守卫
|
||||
* (白名单窗口与 CCM 永不相交、阈值契约)。此处只留语义提醒:
|
||||
* 窗口必须与分散加载 RW_IRAM1(0x20000000,128KB,SRAM1+SRAM2)一致;
|
||||
* CCM(0x10000000,64KB)DMA1/DMA2 物理不可达,RW_CCM 区任何缓冲都不得进 DMA。
|
||||
@@ -130,7 +130,7 @@ static int gd5f_private_bbt_find_best(void);
|
||||
static int gd5f_bbt_load(void);
|
||||
static int gd5f_bbt_save(void);
|
||||
|
||||
/* DMA 可达性守卫:实现见下方(N-26 起为公开 API,声明在 gd5f2gq5ue.h) */
|
||||
/* DMA 可达性守卫:实现见下方(随 DMA 可达性三层防线升为公开 API,声明在 gd5f2gq5ue.h) */
|
||||
|
||||
/* ======================== DMA 可达性守卫 ======================== */
|
||||
|
||||
@@ -174,7 +174,7 @@ int gd5f_dma_buf_ok(const void *p_buf, size_t size) {
|
||||
* GD5F_ERROR(-1) - SPI 传输真故障(不可重试,须上报自检)
|
||||
* 限定条件:SPI 已初始化
|
||||
* 函数说明:循环读取状态寄存器直到 OIP 位清零或超时。
|
||||
* E-53(2026-10-03,GD5F 错误通道统一):三处 HAL 调用的返回值**必须**检查
|
||||
* (2026-10-03,GD5F 错误通道统一):三处 HAL 调用的返回值**必须**检查
|
||||
* ——原实现全部丢弃,失败时 `status` 保持初值 0 → `(status & OIP) == 0`
|
||||
* 立即成立 → **把"操作完成"伪造出来**,后续命令在未就绪的芯片上执行,
|
||||
* 最终表现为"静默报成功但数据没落盘"。现区分两类失败:
|
||||
@@ -217,7 +217,7 @@ int32_t gd5f_wait_busy(uint32_t timeout_ms) {
|
||||
GD5F_CS_HIGH();
|
||||
|
||||
if (hs != HAL_OK) {
|
||||
/* E-53:SPI 真故障——绝不伪造成"操作完成"(详见函数说明) */
|
||||
/* SPI 真故障——绝不伪造成"操作完成"(详见函数说明) */
|
||||
return GD5F_ERROR;
|
||||
}
|
||||
|
||||
@@ -500,8 +500,8 @@ int32_t gd5f_check_ecc(void) {
|
||||
* 返回值:GD5F_OK - 成功;其它 - SPI 传输/等待失败错误码
|
||||
* 限定条件:SPI 已初始化
|
||||
* 函数说明:先写使能,发 1Fh + 地址 + 数据,等待操作完成。
|
||||
* E-53(2026-10-03):HAL 传输与 wait_busy 的返回值必须检查并上报——
|
||||
* 原实现恒返回 GD5F_OK,"配置未生效"对上层不可见(E-10 同族问题)。
|
||||
* (2026-10-03):HAL 传输与 wait_busy 的返回值必须检查并上报——
|
||||
* 原实现恒返回 GD5F_OK,"配置未生效"对上层不可见(同族问题)。
|
||||
*/
|
||||
static int gd5f_set_feature(uint8_t addr, uint8_t data) {
|
||||
uint8_t cmd[3];
|
||||
@@ -534,10 +534,10 @@ static int gd5f_set_feature(uint8_t addr, uint8_t data) {
|
||||
* 出口参数:p_data - 读到的字节输出指针 uint8_t* 不为 NULL
|
||||
* 返回值:GD5F_OK - 成功;GD5F_ERROR - SPI 传输失败
|
||||
* 限定条件:SPI 已初始化
|
||||
* 函数说明:E-10(2026-10-03):init 需**回读** B0h 校验 ECC 使能位真正生效
|
||||
* 函数说明:(2026-10-03):init 需**回读** B0h 校验 ECC 使能位真正生效
|
||||
* (原实现只写不读,"init 返回 OK 但 ECC 未打开"→ 存储栈在无 ECC
|
||||
* 保护下静默降级)。与 gd5f_read_status 同构(后者固定 C0h),
|
||||
* 此处参数化地址;同样检查 HAL 返回值(E-53)。
|
||||
* 此处参数化地址;同样检查 HAL 返回值。
|
||||
*/
|
||||
static int gd5f_private_get_feature(uint8_t addr, uint8_t *p_data) {
|
||||
uint8_t cmd = GD5F_CMD_GET_FEATURE;
|
||||
@@ -600,7 +600,7 @@ int32_t gd5f_block_erase(uint32_t block_addr) {
|
||||
* 限定条件:SPI 已初始化,ECC 尚未使能
|
||||
* 函数说明:读取每个块首页(page 0)的 spare byte 0,
|
||||
* 若不为 0xFF 则为出厂坏块(符合 datasheet §12.4)。
|
||||
* E-42(2026-10-03,GD5F 错误通道统一):原实现丢弃 page_read /
|
||||
* (2026-10-03,GD5F 错误通道统一):原实现丢弃 page_read /
|
||||
* read_from_cache 的返回值且对外恒返回 GD5F_OK——SPI 读失败时
|
||||
* `spare[8]` 保持上一轮的**陈旧内容**,且"整片扫描全失败也返回成功",
|
||||
* 上层以为坏块表可用(rebuild 路径还会把错表持久化覆盖好副本)。
|
||||
@@ -689,7 +689,7 @@ int32_t gd5f2gq5ue_bbt_rebuild(void) {
|
||||
/* 3. 重新使能 ECC:无论扫描成败都必须恢复,而且要**验证真的生效**
|
||||
* (2026-10-23,由 bsp-err 的 consume-result 检查照出)。原先这两行返回值全丢:SPI 一抖 ECC 就保持关闭,而
|
||||
* gd5f_check_ecc() 在 ECC 关闭时恒读"无 ECC 错"——整条链再没有任何信号,设备
|
||||
* 从此在无位翻转保护下读写却"一切正常"。init 路径有 E-10 的"写完回读 B0h 校验
|
||||
* 从此在无位翻转保护下读写却"一切正常"。init 路径有"写完回读 B0h 校验
|
||||
* ECC_EN 位",这里补同一套;ECC 没恢复比扫描失败更严重,所以优先返回它。 */
|
||||
restore_ret = gd5f_set_feature(0xB0, 0x10);
|
||||
if ((gd5f_wait_busy(100) != GD5F_OK) && (restore_ret == GD5F_OK)) {
|
||||
@@ -710,7 +710,7 @@ int32_t gd5f2gq5ue_bbt_rebuild(void) {
|
||||
return restore_ret;
|
||||
}
|
||||
|
||||
/* E-42(2026-10-03,数据安全优先):扫描失败 → **放弃持久化**(保留持久区
|
||||
/* (2026-10-03,数据安全优先):扫描失败 → **放弃持久化**(保留持久区
|
||||
* 既有好副本),并从盘上回读 BBT 恢复 RAM 视图。原实现无论扫描成败都照常
|
||||
* save(),会把"读失败拼出来的错表"覆盖掉正确副本。 */
|
||||
if (ret != GD5F_OK) {
|
||||
@@ -806,7 +806,7 @@ int32_t gd5f2gq5ue_init(void) {
|
||||
DBG_INFO("Scanning bad blocks...");
|
||||
ret = gd5f_bbt_scan();
|
||||
if (ret != GD5F_OK) {
|
||||
/* E-10:扫坏块失败 → init 失败,不静默继续(上层据此上报自检并降级) */
|
||||
/* 扫坏块失败 → init 失败,不静默继续(上层据此上报自检并降级) */
|
||||
DBG_ERROR("BBT scan failed: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
@@ -817,7 +817,7 @@ int32_t gd5f2gq5ue_init(void) {
|
||||
DBG_ERROR("Enable ECC failed: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
/* E-10:回读 B0h 校验 ECC 使能位(bit4)**真正生效**——原实现只写不读,
|
||||
/* 回读 B0h 校验 ECC 使能位(bit4)**真正生效**——原实现只写不读,
|
||||
* "init 返回 OK 但 ECC 未真正打开"会使存储栈在无 ECC 保护下静默降级。 */
|
||||
{
|
||||
uint8_t feat = 0;
|
||||
|
||||
@@ -77,7 +77,7 @@ extern "C" {
|
||||
*/
|
||||
#define GD5F_DMA_THRESHOLD 1024
|
||||
|
||||
/* ==================== DMA 可达内存窗口(N-26,2026-10-12) ====================
|
||||
/* ==================== DMA 可达内存窗口(DMA 可达性三层防线,2026-10-12) ====================
|
||||
* DMA1/DMA2 物理不可达 CCM(0x10000000~0x1000FFFF):以 CCM 缓冲做 DMA 源/目的
|
||||
* 会静默不落地(2026-09-20 首轮 CCM 扩容实验实证根因;口径见
|
||||
* docs/内存管理/内存内容分配策略.md §2 与 §4 规则 R2/R3)。
|
||||
@@ -93,7 +93,7 @@ extern "C" {
|
||||
#define GD5F_CCM_RAM_BASE 0x10000000UL
|
||||
#define GD5F_CCM_RAM_END 0x10010000UL
|
||||
|
||||
/* 编译期守卫(N-26):AC5 无 _Static_assert(C11 不支持),用项目惯用的
|
||||
/* 编译期守卫(DMA 可达性三层防线一环):AC5 无 _Static_assert(C11 不支持),用项目惯用的
|
||||
* 负数组 typedef(同 App/cfg/cfg_file.c、Drivers/BSP/UI/ui_menu_tab.h)——
|
||||
* 条件不成立则数组尺寸 -1 → 编译错。
|
||||
* ① DMA 白名单窗口与 CCM 窗口**永不得重叠**(有人改上面常量时立即爆炸);
|
||||
@@ -116,7 +116,7 @@ typedef char gd5f_dma_threshold_contract_check_t[
|
||||
/* 返回值定义 */
|
||||
#define GD5F_OK 0
|
||||
#define GD5F_ERROR -1
|
||||
#define GD5F_WAIT_EXPIRED -2 /* 旧名 GD5F_BUSY_TIMEOUT;S-5 的 timeout-name 检查:**返回码不许叫 *_TIMEOUT** */
|
||||
#define GD5F_WAIT_EXPIRED -2 /* 旧名 GD5F_BUSY_TIMEOUT;timeout-name 检查:**返回码不许叫 *_TIMEOUT** */
|
||||
#define GD5F_ECC_ERROR -3
|
||||
#define GD5F_PROGRAM_FAIL -4
|
||||
#define GD5F_ERASE_FAIL -5
|
||||
@@ -160,7 +160,7 @@ int32_t gd5f2gq5ue_read_id(uint8_t *p_mid, uint8_t *p_did);
|
||||
* 返回值:GD5F_OK(0) - SPI 传输完成;其它 - 错误码
|
||||
* 限定条件:gd5f2gq5ue_init() 已成功调用
|
||||
* 函数说明:自动处理跨页读取,每次读取不超过当前页剩余空间。
|
||||
* ⚠ **raw 契约(E-56,2026-10-03 显式文档化)**:返回 0 只表示 **SPI 传输完成**,
|
||||
* ⚠ **raw 契约(2026-10-03 显式文档化)**:返回 0 只表示 **SPI 传输完成**,
|
||||
* **不代表数据无位翻转**——ECC 不可纠正页(ECCS 非零)在 SPI 层属正常完成,
|
||||
* 本函数仍返回 0。数据正确性由 **ECC 层**保证:生产主路径经 dhara glue
|
||||
* (`nand_ftl.c`)自有 ECC 检查保护;**直接使用本 raw API** 的调用方
|
||||
@@ -277,7 +277,7 @@ int32_t gd5f_bbt_reload(void);
|
||||
* 入口参数:timeout_ms - 等待上限 uint32_t 毫秒
|
||||
* 返 回 值:GD5F_OK - 已空闲;GD5F_WAIT_EXPIRED - 时限内未空闲(**可重试**,旧名 BUSY_TIMEOUT);GD5F_ERROR - SPI 读取失败
|
||||
* 限定条件:SPI 已初始化;不得在中断里调用
|
||||
* 函数说明:E-32 把"超时"与"读状态本身失败"分开返回,两者处置不同(前者再等、后者查硬件)
|
||||
* 函数说明:把"超时"与"读状态本身失败"分开返回,两者处置不同(前者再等、后者查硬件)
|
||||
*/
|
||||
int32_t gd5f_wait_busy(uint32_t timeout_ms);
|
||||
|
||||
@@ -286,7 +286,7 @@ int32_t gd5f_wait_busy(uint32_t timeout_ms);
|
||||
* 入口参数:无
|
||||
* 返 回 值:GD5F_OK - 成功;其它 - SPI 传输或等待失败错误码
|
||||
* 限定条件:SPI 已初始化
|
||||
* 函数说明:E-53 规定本函数返回值必须被检查并上报,忽略它会让后续 program/erase 静默无效
|
||||
* 函数说明:本函数返回值必须被检查并上报(错误通道统一纪律),忽略它会让后续 program/erase 静默无效
|
||||
*/
|
||||
int32_t gd5f_write_enable(void);
|
||||
|
||||
@@ -295,7 +295,7 @@ int32_t gd5f_write_enable(void);
|
||||
* 入口参数:p_status - 状态字节输出 uint8_t* 不得为 NULL
|
||||
* 返 回 值:GD5F_OK - 成功(*p_status 有效);GD5F_ERROR - SPI 失败(*p_status 不可信,调用方不得读用)
|
||||
* 限定条件:SPI 已初始化
|
||||
* 函数说明:E-42 同族纪律——失败时出参内容不可信,故判成败看返回值而不是看 *p_status 是否像样
|
||||
* 函数说明:同族纪律——失败时出参内容不可信,故判成败看返回值而不是看 *p_status 是否像样
|
||||
*/
|
||||
int32_t gd5f_read_status(uint8_t *p_status);
|
||||
|
||||
@@ -315,7 +315,7 @@ int32_t gd5f_page_read(uint32_t page_addr);
|
||||
* size - 读取字节数 uint32_t 1 - GD5F_PAGE_SIZE-column
|
||||
* 返 回 值:GD5F_OK - 成功;GD5F_ERROR - 参数非法或 SPI 失败(**此时 p_buf 内容不可信**)
|
||||
* 限定条件:必须先成功调用 gd5f_page_read() 完成阵列→缓存装载
|
||||
* 函数说明:E-42 同族——调用方不得在失败分支继续使用 p_buf(FTL 侧据此把读失败保守判为"非空页")
|
||||
* 函数说明:同族——调用方不得在失败分支继续使用 p_buf(FTL 侧据此把读失败保守判为"非空页")
|
||||
*/
|
||||
int32_t gd5f_read_from_cache(uint16_t column, uint8_t *p_buf, uint32_t size);
|
||||
|
||||
@@ -353,7 +353,7 @@ int32_t gd5f_block_erase(uint32_t block_addr);
|
||||
* 入口参数:无
|
||||
* 返 回 值:GD5F_OK - 无不可纠错误(可能含已纠正的位翻转);GD5F_ECC_ERROR - **存在不可纠正的 ECC 错误**
|
||||
* 限定条件:SPI 已初始化且 ECC 已使能(init 期扫描在使能前调用本函数无意义)
|
||||
* 函数说明:这是数据正确性的唯一判定点——SPI 层读到"内容"不等于"内容对"(见 §8.1 与本头 E-42/E-53 注释)
|
||||
* 函数说明:这是数据正确性的唯一判定点——SPI 层读到"内容"不等于"内容对"(见 §8.1 与本头"同族纪律"注释)
|
||||
*/
|
||||
int32_t gd5f_check_ecc(void);
|
||||
|
||||
@@ -363,7 +363,7 @@ int32_t gd5f_check_ecc(void);
|
||||
* size - 传输字节数 size_t
|
||||
* 返回值:1 - 整段 DMA 可达;0 - 不可达(含 size=0 / 地址回绕 / 越窗)
|
||||
* 限定条件:无
|
||||
* 函数说明:N-26(2026-10-12)由 gd5f2gq5ue.c 私有守卫升级为公开 API——
|
||||
* 函数说明:2026-10-12 由 gd5f2gq5ue.c 私有守卫升级为公开 API(DMA 可达性三层防线一环)——
|
||||
* 驱动内部每次 >阈值 传输前用它(不可达即回落 CPU 轮询),
|
||||
* FTL 层(nand_ftl.c)在 init 期用它自检静态页缓冲的落位。
|
||||
*/
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
* 创建日期:2026-07-20
|
||||
* 修改记录:
|
||||
* 2026-07-20 王建锋 创建初始版本
|
||||
* 2026-09-21 E-31 resume 失败按错误分类:仅真空白判新卷,其余失败
|
||||
* 2026-09-21 resume 失败按错误分类:仅真空白判新卷,其余失败
|
||||
* 返回 mount 层(禁止静默清 map 触发整卷重格式化)
|
||||
* 2026-10-02 王建锋 resume 成功后增打 journal head/tail/epoch:复盘
|
||||
* "复位后所有写入丢失"时 sectors used 不足以判定
|
||||
* journal 回退(覆盖写不改 count),head/tail/epoch 是
|
||||
* 唯一能暴露 resume 锚错 checkpoint 的证据
|
||||
* 2026-10-15 王建锋 N-21(报告 N-12/N-13):① is_free 改**整页扫描**——
|
||||
* 2026-10-15 王建锋 落实 dhara 移植层两条硬约束:① is_free 改**整页扫描**——
|
||||
* 旧实现只看页首 64 B,会把"页首 0xFF、后段有数据"的
|
||||
* 已编程页误判空闲,dhara 遂往已编程页再编程 = 数据丢失
|
||||
* (页首有数据的绝大多数页走快路径,成本与旧实现同价);
|
||||
@@ -65,7 +65,7 @@
|
||||
* 而忘了同步这里的字面量,守卫会静默算错——偏大就是越界守卫失效,正是它要防的
|
||||
* 那一类错误,而且不报任何错。下面两条把"字面量 == GD5F 常量的 log2"钉死,
|
||||
* 不一致直接编译错。负数组 typedef 是 AC5 下的项目惯用法(AC5 不支持 C11
|
||||
* _Static_assert),同本目录 gd5f2gq5ue.h 的 N-26 DMA 契约守卫。 */
|
||||
* _Static_assert),同本目录 gd5f2gq5ue.h 的 DMA 契约守卫。 */
|
||||
typedef char ftl_geometry_log2_page_size_check_t[
|
||||
(FTL_PAGE_SIZE == (1 << FTL_LOG2_PAGE_SIZE)) ? 1 : -1];
|
||||
typedef char ftl_geometry_log2_ppb_check_t[
|
||||
@@ -76,7 +76,7 @@ static inline uint32_t ftl_phy_block(dhara_block_t b) { return b + FTL_START_BLO
|
||||
static inline uint32_t ftl_phy_page(dhara_page_t p) { return p + FTL_START_PAGE; }
|
||||
|
||||
/*
|
||||
* N-21(2026-10-15,报告 N-13):移植层地址守卫
|
||||
* dhara 移植层硬约束(2026-10-15):移植层地址守卫
|
||||
*
|
||||
* 旧实现把 dhara 传来的页/块号直接加偏移送进 SPI 命令,**不做任何上界校验**。
|
||||
* 越界页号(含 dhara 的"无页"哨兵 DHARA_PAGE_NONE = 0xffffffff,journal.h:46)
|
||||
@@ -89,8 +89,8 @@ static inline uint32_t ftl_phy_page(dhara_page_t p) { return p + FTL_START_PAG
|
||||
* 为什么不用 DHARA_E_BAD_BLOCK:journal.c:904 的 recover_from 只对 BAD_BLOCK
|
||||
* 走"标坏块 + 跳块重试"——对一个凭空的地址标坏块 = 毁掉一个无辜的好块。
|
||||
* 为什么不会触发静默清卷:map.c:275 的 try_recover 只对 E_RECOVER 启动回收,
|
||||
* 其余错误一律原样上抛(E-31 教训:单次瞬态毛刺不得销毁整卷数据)。
|
||||
* is_free / is_bad 没有错误通道 → 一律保守取值(判非空 / 判坏),与 E-42 同族
|
||||
* 其余错误一律原样上抛(教训:单次瞬态毛刺不得销毁整卷数据)。
|
||||
* is_free / is_bad 没有错误通道 → 一律保守取值(判非空 / 判坏),与同族
|
||||
* 口径一致:宁可少用一个块,不可把不可信的内容当有效。
|
||||
*/
|
||||
static int ftl_page_in_range(const struct dhara_nand *n, dhara_page_t p) {
|
||||
@@ -156,7 +156,7 @@ static const char *ftl_err_name(dhara_error_t err) {
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:把 dhara 错误归类成统一失败类(C2,报告 S-5)
|
||||
* 函数功能:把 dhara 错误归类成统一失败类(C2)
|
||||
* 入口参数:err - dhara 错误枚举值
|
||||
* 返回值:BSP_ERR_CRC(位翻转不可纠 / 页太坏);BSP_ERR_NO_SPACE(journal 或映射层预算
|
||||
* 耗尽);其余(坏块 / 找回失败 / 映射损坏 / 越界)→ BSP_ERR_IO
|
||||
@@ -164,10 +164,10 @@ static const char *ftl_err_name(dhara_error_t err) {
|
||||
* 函数说明:分这三类的理由是它们在**处置上真的不同**,不是为了码好看:
|
||||
* · ECC/TOO_BAD → 该重试读或标页坏,**不是**卷的问题;
|
||||
* · JOURNAL_FULL/MAP_FULL → 介质还健康,是**块池/日志预算见底**,此时重格式化只是
|
||||
* 把问题推回去(E-31 的教训正是"别把非空白错误当新卷清 map"),该走容量恢复流程;
|
||||
* 把问题推回去(教训正是"别把非空白错误当新卷清 map"),该走容量恢复流程;
|
||||
* · BAD_BLOCK/CORRUPT_MAP/RECOVER → 映射或介质完整性故障,该保卷 + 上报,不许自愈重格式化。
|
||||
* 本函数先把这三类**打出来**(就地日志,最早且唯一同时知道 LPN 与原始码的位置);
|
||||
* 要让 defaultTask 的卷健康探针按类分支,还需要一个跨调用存活的快照(S-5 的 C4 待还)。
|
||||
* 要让 defaultTask 的卷健康探针按类分支,还需要一个跨调用存活的快照(C4 待还)。
|
||||
*/
|
||||
static bsp_err_t ftl_class_from_dhara(dhara_error_t err) {
|
||||
switch (err) {
|
||||
@@ -284,7 +284,7 @@ int dhara_nand_prog(const struct dhara_nand *n, dhara_page_t p, const uint8_t *d
|
||||
}
|
||||
|
||||
/*
|
||||
* N-21(2026-10-15,报告 N-12):整页扫描
|
||||
* dhara 移植层硬约束(2026-10-15):整页扫描
|
||||
*
|
||||
* 旧实现只看页首 64 B。dhara 的 journal 用 is_free 判断"检查点组是否未编程"
|
||||
* (journal.c:416 cp_free、journal.c:520 找下一空闲页),其正确性前提是
|
||||
@@ -317,7 +317,7 @@ int dhara_nand_is_free(const struct dhara_nand *n, dhara_page_t p) {
|
||||
|
||||
for (off = 0; off < FTL_PAGE_SIZE; off += sizeof(buf)) {
|
||||
if (gd5f_read_from_cache((uint16_t)off, buf, sizeof(buf)) != GD5F_OK) {
|
||||
/* E-42 同族(2026-10-03):读失败 → buf 可能为陈旧/垃圾内容,
|
||||
/* 同族(2026-10-03):读失败 → buf 可能为陈旧/垃圾内容,
|
||||
* 保守判为非空(块不可复用),避免把"没读到内容的块"判成空闲。 */
|
||||
return 0;
|
||||
}
|
||||
@@ -350,7 +350,7 @@ int dhara_nand_read(const struct dhara_nand *n, dhara_page_t p, size_t offset, s
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* E-42 同族(2026-10-03):read_from_cache 返回值必须检查——失败时 data 内容
|
||||
/* 同族(2026-10-03):read_from_cache 返回值必须检查——失败时 data 内容
|
||||
* 不可信,原实现仍返回 0(成功),会把未读到的数据当有效数据交给上层。 */
|
||||
if (gd5f_read_from_cache((uint16_t)offset, data, length) != GD5F_OK) {
|
||||
dhara_set_error(err, DHARA_E_ECC);
|
||||
@@ -360,7 +360,7 @@ int dhara_nand_read(const struct dhara_nand *n, dhara_page_t p, size_t offset, s
|
||||
}
|
||||
|
||||
/*
|
||||
* N-21(2026-10-15,报告 N-13):src / dst 双端守卫
|
||||
* dhara 移植层硬约束(2026-10-15):src / dst 双端守卫
|
||||
*
|
||||
* 报告原判断"dhara map 在回收/擦除路径会用 DHARA_NO_PAGE 试探"经逐点核对
|
||||
* **不成立**:本仓裁剪版没有 DHARA_NO_PAGE,哨兵叫 DHARA_PAGE_NONE
|
||||
@@ -401,7 +401,7 @@ DSTATUS disk_initialize(BYTE pdrv) {
|
||||
|
||||
DBG_INFO("Initializing NAND FTL...");
|
||||
|
||||
/* N-26 启动期地址自检(2026-10-12):本文件三个页缓冲是 SPI1 DMA 路径上
|
||||
/* DMA 可达性三层防线——启动期地址自检(2026-10-12):本文件三个页缓冲是 SPI1 DMA 路径上
|
||||
* 唯一的**静态**缓冲(dhara_map_read/write → dhara_nand_read/prog/copy,
|
||||
* 2048 B > GD5F_DMA_THRESHOLD;s_page_buf 页内虽只攒 132 B 元数据,
|
||||
* 但编程的是**整页**(journal.c:992),传输长度同为 2048 B、同样走 DMA,
|
||||
@@ -410,7 +410,7 @@ DSTATUS disk_initialize(BYTE pdrv) {
|
||||
* **静默不落地**(数据错而传输"成功")。缓冲地址链接期才确定,armcc
|
||||
* 无法编译期断言(见 gd5f2gq5ue.h 的窗口常量注释),故在 init 期自检:
|
||||
* 任一缓冲越出 DMA 白名单窗口 → 上报并拒绝挂载(存储降级、不挂死,
|
||||
* 与 E-31 的"保留卷、上报自检"形态一致)。每次传输的运行期守卫
|
||||
* 与"保留卷、上报自检"形态一致)。每次传输的运行期守卫
|
||||
* (gd5f_read_from_cache/gd5f_program_load 内)保留作第二层兜底。 */
|
||||
if ((gd5f_dma_buf_ok(s_cache_buf, FTL_PAGE_SIZE) == 0) ||
|
||||
(gd5f_dma_buf_ok(s_copy_buf, FTL_PAGE_SIZE) == 0) ||
|
||||
@@ -442,7 +442,7 @@ DSTATUS disk_initialize(BYTE pdrv) {
|
||||
DBG_INFO("No valid map found (dhara=%s), creating fresh", ftl_err_name(err));
|
||||
dhara_map_clear(&s_map);
|
||||
} else {
|
||||
/* E-31(2026-09-21 审计 P0 修复):非"空白"错误(ECC /
|
||||
/* (2026-09-21 审计 P0 修复):非"空白"错误(ECC /
|
||||
* BAD_BLOCK / CORRUPT_MAP / 瞬态 I/O 等)= 真实完整性故障——
|
||||
* 芯片上 journal 可能仍持有有效 checkpoint。旧行为把任何失败
|
||||
* 当新卷清 map,上层随即整卷重格式化 → 单次瞬态毛刺即静默销毁
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-09
|
||||
* 修改记录:
|
||||
* 2026-10-23 王建锋 补模块头与函数注释(S-5 的 return-doc 检查);返回值语义写明"失败类目前
|
||||
* 2026-10-23 王建锋 补模块头与函数注释(return-doc 检查);返回值语义写明"失败类目前
|
||||
* 只进日志、不外传",避免调用方以为能拿到 ECC / 预算耗尽的区别
|
||||
*/
|
||||
|
||||
@@ -27,8 +27,8 @@ extern "C" {
|
||||
* 函数说明:⚠ 这里的 -1 **抹掉了失败类**——"ECC 读不动"、"journal 满"与"映射损坏"对外
|
||||
* 都只是 -1。分类信息目前只在失败点就地进日志(见 nand_ftl.c 的 ftl_class_from_dhara
|
||||
* 与 ../架构设计/STM32F4-Base存储架构说明.md §10.4);要让调用方按类分支,需要跨调用
|
||||
* 存活的失败类快照(报告 S-5 的 C4 待还项,当前无消费者故未做)。
|
||||
* 调用方**不得**把 -1 解读成"卷坏了,可以重格式化"——E-31 的教训正在这条上。
|
||||
* 存活的失败类快照(C4 待还项,当前无消费者故未做)。
|
||||
* 调用方**不得**把 -1 解读成"卷坏了,可以重格式化"——教训正在这条上。
|
||||
*/
|
||||
int nand_ftl_init(void);
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
真正兜底 = D10 预算到期 + 对账形态④ 重新登记)
|
||||
- 仅异常路径生效,正常 FIN 路径零改动
|
||||
|
||||
### 错误码(E-03 修复)
|
||||
### 错误码
|
||||
|
||||
- **按任务隔离**:`s_net_errno_slots[8]`(每槽 `{任务句柄, err}`),替代原全局 `s_net_errno`
|
||||
- `net_get_errno()` 只读本任务槽位,**对外语义不变**(成功不清零)
|
||||
|
||||
@@ -64,7 +64,7 @@ static command_t commands[] = {
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
/* N-19 FTP 鉴权:全局失败计数/锁定状态(跨会话持久——单连接服务器,全局
|
||||
/* FTP 鉴权:全局失败计数/锁定状态(跨会话持久——单连接服务器,全局
|
||||
* 计数即可;成功清零、锁定期满自动放行,见 lftpd_auth.c) */
|
||||
static ftp_auth_state_t s_auth_state;
|
||||
|
||||
@@ -343,7 +343,7 @@ static int cmd_cwd(lftpd_client_t *client, const char *arg)
|
||||
|
||||
static int cmd_dele(lftpd_client_t *client, const char *arg)
|
||||
{
|
||||
/* N-19:写命令门——[ftp] write=0 时拒绝(鉴权门已保证此处必为已登录态) */
|
||||
/* 写命令门——[ftp] write=0 时拒绝(鉴权门已保证此处必为已登录态) */
|
||||
const ftp_cfg_t *cfg = ftp_cfg_get();
|
||||
|
||||
if ((cfg == NULL) || (cfg->write_en == 0u)) {
|
||||
@@ -638,7 +638,7 @@ static int cmd_size(lftpd_client_t *client, const char *arg)
|
||||
|
||||
static int cmd_stor(lftpd_client_t *client, const char *arg)
|
||||
{
|
||||
/* N-19:写命令门——[ftp] write=0 时拒绝(鉴权门已保证此处必为已登录态) */
|
||||
/* 写命令门——[ftp] write=0 时拒绝(鉴权门已保证此处必为已登录态) */
|
||||
const ftp_cfg_t *cfg = ftp_cfg_get();
|
||||
|
||||
if ((cfg == NULL) || (cfg->write_en == 0u)) {
|
||||
@@ -757,7 +757,7 @@ static int handle_control_channel(lftpd_client_t *client)
|
||||
command_tmp[i] = (char)toupper((int)command_tmp[i]);
|
||||
}
|
||||
|
||||
/* N-19:未鉴权命令门——仅 QUIT/FEAT/SYST/NOOP 放行(客户端兼容需要,
|
||||
/* 未鉴权命令门——仅 QUIT/FEAT/SYST/NOOP 放行(客户端兼容需要,
|
||||
* 且无信息量);其余一律 530。USER/PASS 本身也在放行名单外,
|
||||
* 但它们在 gate 之前不可能通过 → 单独放行见下(USER/PASS 例外) */
|
||||
if (client->auth_logged_in == 0) {
|
||||
@@ -817,7 +817,7 @@ int lftpd_start(const char *directory, int port, lftpd_t *lftpd)
|
||||
lftpd->port = port;
|
||||
lftpd->server_socket = -1; /* memset 清零后显式置"无监听器"(0 是合法 fd) */
|
||||
|
||||
/* N-19:出厂默认口令在用告警(台架锚点;改了 [ftp] pwd_hash 即消失) */
|
||||
/* 出厂默认口令在用告警(台架锚点;改了 [ftp] pwd_hash 即消失) */
|
||||
if (ftp_cfg_is_default_pwd() != 0) {
|
||||
lftpd_log_info("using factory default password");
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ typedef struct {
|
||||
char directory[256];
|
||||
int socket;
|
||||
int data_socket;
|
||||
/* N-19 FTP 鉴权会话态(每会话 memset 0 = 未登录;跨会话锁定计数在
|
||||
/* FTP 鉴权会话态(每会话 memset 0 = 未登录;跨会话锁定计数在
|
||||
* lftpd.c 的 s_auth_state,不在此处) */
|
||||
char auth_user[32]; /* USER 阶段暂存的用户名 */
|
||||
uint8_t auth_user_ok; /* 1 = 用户名与 [ftp] user 匹配 */
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-10-11
|
||||
* 修改记录:
|
||||
* v1.0 2026-10-11 王建锋 创建初始版本(N-19 FTP 鉴权;契约由
|
||||
* v1.0 2026-10-11 王建锋 创建初始版本(FTP 鉴权;契约由
|
||||
* test/host/ftp_auth 主机单测钉死)
|
||||
*/
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-10-11
|
||||
* 修改记录:
|
||||
* v1.0 2026-10-11 王建锋 创建初始版本(N-19 FTP 鉴权;lftpd.c 为唯一消费者)
|
||||
* v1.0 2026-10-11 王建锋 创建初始版本(FTP 鉴权;lftpd.c 为唯一消费者)
|
||||
*/
|
||||
|
||||
#ifndef LFTPD_AUTH_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* E-02 头阻塞修复 + recv pending 化(M3 台架实证):
|
||||
* 头阻塞修复 + recv pending 化(M3 台架实证):
|
||||
* netTask 是全部 socket 操作的唯一执行者;lftpd 若用**阻塞** net_recv 等待对端
|
||||
* 下一行/下一块数据 → 只要客户端连上却不发完整行,netTask 就被长期占用,
|
||||
* 其余任务(含远端显示)的网络操作整体冻结(实测一次空闲 FTP 登录让 LCDMEM
|
||||
@@ -109,7 +109,7 @@ int lftpd_inet_accept_timeout(int socket, int timeout_ms)
|
||||
/* F-NET-15 M2(自愈专项实验 2026-10-12):镜像门控退役——原直读 p_sock->state 在
|
||||
* relisten 忙期(CLOSED 瞬态)误判"已关闭",扔掉 ~4.9s 等待预算;armed 门控
|
||||
* 认"监听器在服役(LISTENING)或待重建且 RX 有残留(closed-with-data 救回窗)",
|
||||
* 与 :7003 的 N-32 P1 同型修复 */
|
||||
* 与 :7003 的监听生命周期 P1 同型修复 */
|
||||
if (net_listener_armed(socket) == 0) {
|
||||
/* **故意留 error**:控制连接还活着、我方数据监听却已不在服役 →
|
||||
* 这是本侧异常,不是对端行为 */
|
||||
|
||||
@@ -123,7 +123,7 @@ void handle_connect_event(net_sock_t *p_sock) {
|
||||
p_sock->remote_port = (uint16_t)(remote[4] | (remote[5] << 8));
|
||||
/* 状态 → ESTABLISHED(监听自身转数据通道) */
|
||||
p_sock->state = NET_SOCK_STATE_ESTABLISHED;
|
||||
/* N-32(P1):新会话开始 —— 清"上一条会话已结束"电平。必须在置
|
||||
/* 监听生命周期 P1:新会话开始 —— 清"上一条会话已结束"电平。必须在置
|
||||
* ESTABLISHED 之后立刻做:否则抢先 relisten 后到新连接的窗口内
|
||||
* recv 仍会误得 EOF(把新客户端踢开) */
|
||||
p_sock->session_dead = 0U;
|
||||
@@ -164,7 +164,7 @@ void handle_connect_event(net_sock_t *p_sock) {
|
||||
p_sock->remote_port = (uint16_t)(remote[4] | (remote[5] << 8));
|
||||
/* 状态 → ESTABLISHED */
|
||||
p_sock->state = NET_SOCK_STATE_ESTABLISHED;
|
||||
/* N-32(P1):新会话开始 —— 清"上一条会话已结束"电平(同 LISTENING
|
||||
/* 监听生命周期 P1:新会话开始 —— 清"上一条会话已结束"电平(同 LISTENING
|
||||
* 分支:必须在转 ESTABLISHED 后立刻做,防抢先 relisten 窗口误 EOF) */
|
||||
p_sock->session_dead = 0U;
|
||||
/* F-NET-17 M3 前置:清可疑电平(同 LISTENING 分支) */
|
||||
@@ -201,9 +201,9 @@ void handle_disconnect_event(net_sock_t *p_sock) {
|
||||
|
||||
/* 监听态:DISCONNECT 落在监听器上 */
|
||||
if (p_sock->state == NET_SOCK_STATE_LISTENING) {
|
||||
/* TRAP-NET-17 / N-6:监听态收到 DISCONNECT——bit3=1(0x08)下芯片**不**关该 Socket(停 0x05/0x00,芯片 TCP 侧已 CLOSED);不重开则此后所有 SYN 全被拒 = 监听永久死亡;
|
||||
/* TRAP-NET-17:监听态收到 DISCONNECT——bit3=1(0x08)下芯片**不**关该 Socket(停 0x05/0x00,芯片 TCP 侧已 CLOSED);不重开则此后所有 SYN 全被拒 = 监听永久死亡;
|
||||
* 触发 = 断连后 <~1s 快速复连时 CONNECT 中断未上报(控制块滞留 LISTENING)后该连接断开(2026-09-23 生产固件复现);
|
||||
* N-32 P2:本分支**只回读留痕、不再 relisten** —— 重建统一交
|
||||
* 监听生命周期 P2:本分支**只回读留痕、不再 relisten** —— 重建统一交
|
||||
* net_reconcile_tick 形态③(每 100 ms 读驱动缓存,监听失位即重建)。原处直接
|
||||
* relisten 是 12 个所有者之一,且位于 DISCONNECT 事件路径,可能"抢先"
|
||||
* 于消费者 recv(P1 已消除其后果,P2 消除其可能)。
|
||||
@@ -275,7 +275,7 @@ void handle_disconnect_event(net_sock_t *p_sock) {
|
||||
/* F-NET-15 M1(自愈专项实验 2026-10-12):沉降**无条件**登记。原 recv_bytes!=0 门的
|
||||
* 受害者由事件时序定义(accept 后 ~20ms 被陈旧 DISCONNECT 杀 → recv_bytes==0 是
|
||||
* 构造性必然),门对"残渣循环自持"形态失效(n30_repro 背靠背 9/10 失败,E1 实测);
|
||||
* 门原保护目标(:21 @0ms 快复连)已被 N-32 单一重建入口延迟化(恢复窗实测 0.3~1s)架空,
|
||||
* 门原保护目标(:21 @0ms 快复连)已被监听生命周期单一重建入口延迟化(恢复窗实测 0.3~1s)架空,
|
||||
* +100ms 沉降落在窗内不可见。沉降窗口同时让残渣 DISCONNECT 在 state==CLOSED
|
||||
* (无害、仅留痕)时被消费,断开"杀下一条 → 新拆链 → 再杀"的繁殖链 */
|
||||
{
|
||||
@@ -288,12 +288,12 @@ void handle_disconnect_event(net_sock_t *p_sock) {
|
||||
}
|
||||
/* 正常释放(对端 FIN):断连时挂起项以 EOF(0) 结束 */
|
||||
p_sock->released_abnormal = 0U;
|
||||
/* N-32(P1 不变量 I):置"本会话已结束"电平。须在置 CLOSED **之前**,
|
||||
/* 监听生命周期 P1 不变量 I:置"本会话已结束"电平。须在置 CLOSED **之前**,
|
||||
* 使 session_dead 覆盖"CLOSED 等待 recv 排空"整个窗口——排空期间
|
||||
* recv 的 DONTWAIT 快路径先返数据(recv_len>0 优先),数据尽后判据
|
||||
* 落到本标志 → 仍得 EOF,不因排空慢而漏报 */
|
||||
p_sock->session_dead = 1U;
|
||||
/* N-30(TRAP-NET-20):登记本连接对端端口(幽灵态甄别基准,须在状态
|
||||
/* TRAP-NET-20:登记本连接对端端口(幽灵态甄别基准,须在状态
|
||||
* 迁移前记录——remote_port 此刻仍有效,relisten 清零) */
|
||||
p_sock->last_peer_port = p_sock->remote_port;
|
||||
/* 状态 → CLOSED */
|
||||
@@ -382,9 +382,9 @@ void handle_timeout_event(net_sock_t *p_sock) {
|
||||
* NET_ERR_CONNRESET 结束(而非 EOF),应用(lftpd STOR)回报 5xx
|
||||
* 而非误报 226(见 net_pending_tick 断连分支) */
|
||||
p_sock->released_abnormal = 1U;
|
||||
/* N-30(TRAP-NET-20):异常释放同样登记对端端口(幽灵甄别基准) */
|
||||
/* TRAP-NET-20:异常释放同样登记对端端口(幽灵甄别基准) */
|
||||
p_sock->last_peer_port = p_sock->remote_port;
|
||||
/* N-32(P1 不变量 I):异常结束同样是"本会话已结束"电平(TIMEOUT/RST
|
||||
/* 监听生命周期 P1 不变量 I:异常结束同样是"本会话已结束"电平(TIMEOUT/RST
|
||||
* 已在下方 requarantine,本标志只表达"会话结束了"这一事实,与
|
||||
* released_abnormal(结束得好不好看)正交) */
|
||||
p_sock->session_dead = 1U;
|
||||
@@ -564,7 +564,7 @@ void net_reconcile_tick(void) {
|
||||
} else if (p_sock->state == NET_SOCK_STATE_LISTENING) {
|
||||
if (c.tcp_state == CH395F_TCP_ESTABLISHED) {
|
||||
/* ② 本层 LISTENING 而芯片已完成握手(CONNECT 事件未收到)→ 补做 accept
|
||||
* N-30(TRAP-NET-20)幽灵态甄别:拆链收尾窗口内旧连接未拆净,状态如实
|
||||
* TRAP-NET-20幽灵态甄别:拆链收尾窗口内旧连接未拆净,状态如实
|
||||
* 显示 ESTABLISHED(E15:bit3=1 保留现场契约 + TCP 拆链状态机,非谎报),
|
||||
* 回读对端端口 = 上一条连接端口 → 不补 accept(补了会把数据发给
|
||||
* 已死的旧连接 = 生产 LIST#4 数据被吞的直接成因),等拆净或新 SYN。
|
||||
@@ -590,7 +590,7 @@ void net_reconcile_tick(void) {
|
||||
* 被动修正零风险:不去抖、不占冷却(原 pump 同口径) */
|
||||
DBG_INFO("sock%d reconcile: chip listening, resync CLOSED->LISTENING (U11)", i);
|
||||
p_sock->state = NET_SOCK_STATE_LISTENING;
|
||||
/* N-30(TRAP-NET-20):死连接对端端口转登幽灵甄别基准 + 探针计数清零
|
||||
/* TRAP-NET-20:死连接对端端口转登幽灵甄别基准 + 探针计数清零
|
||||
* —— 芯片监听器未被重开,芯片侧对端信息可能仍是上一条连接的,
|
||||
* 必须转登为基准,否则形态② 的幽灵拦截会失效 */
|
||||
p_sock->last_peer_port = p_sock->remote_port;
|
||||
@@ -629,7 +629,7 @@ void net_reconcile_tick(void) {
|
||||
DBG_INFO("sock%d reconcile: chip closed (0x%02X/0x%02X) -> disconnect",
|
||||
i, c.open, c.tcp_state);
|
||||
/* 复用断开状态机(含陈旧事件甄别 + 状态迁移 + 事件派发);
|
||||
* 只置事实,重建由本 tick 形态③④统一做(N-32 P2 单一所有者) */
|
||||
* 只置事实,重建由本 tick 形态③④统一做(监听生命周期 P2 单一所有者) */
|
||||
handle_disconnect_event(p_sock);
|
||||
} else if (bad == 5) {
|
||||
/* 类型⑤:静默回收 → RESYNC 语义(原 NET_MSG_RESYNC_LISTEN 分派体
|
||||
@@ -640,7 +640,7 @@ void net_reconcile_tick(void) {
|
||||
i, c.open, c.tcp_state);
|
||||
/* 仅修 MCU 侧;新连接的 CONNECT 中断会把两侧重新同步 */
|
||||
p_sock->state = NET_SOCK_STATE_LISTENING;
|
||||
/* N-30(TRAP-NET-20):死连接对端端口转登幽灵甄别基准 + 探针计数清零 */
|
||||
/* TRAP-NET-20:死连接对端端口转登幽灵甄别基准 + 探针计数清零 */
|
||||
p_sock->last_peer_port = p_sock->remote_port;
|
||||
p_sock->lost_conn_seen = 0U;
|
||||
/* 取消本 fd 在死连接上的挂起 recv(必通知,防调用方挂死) */
|
||||
|
||||
@@ -109,7 +109,7 @@ static void net_drain_chip_rx(int sockfd) {
|
||||
* 3. 复用原本地端口重新 OPEN + LISTEN,仅把 state 置回 LISTENING、不 memset
|
||||
* —— 实现 BSD 风格"监听 Socket 常驻",应用层无需手动重监听。
|
||||
* 4. fd 由参数传入(不用 `p_sock - s_net_socks` 反推),控制块经 net_get_sock()
|
||||
* 取 —— 本模块**不访问** net_socket.c 的 static 数组(N-32 §10)。
|
||||
* 取 —— 本模块**不访问** net_socket.c 的 static 数组(监听生命周期模块化)。
|
||||
*/
|
||||
static int net_relisten_locked(int sockfd) {
|
||||
uint8_t status;
|
||||
@@ -206,12 +206,12 @@ static int net_relisten_locked(int sockfd) {
|
||||
|
||||
/* 状态置回 LISTENING(fd 保留;auto_relisten 保持为 1,下次断连仍自动重监听) */
|
||||
p_sock->state = NET_SOCK_STATE_LISTENING;
|
||||
/* ⚠ 此处**刻意不清 session_dead**(N-32 P1):重建监听只是"芯片侧恢复就位",与
|
||||
/* ⚠ 此处**刻意不清 session_dead**(监听生命周期 P1):重建监听只是"芯片侧恢复就位",与
|
||||
* "应用是否已确认上一条会话结束"是两件事;清了它,抢先 relisten 之后消费者就再也
|
||||
* 得不到 EOF(B10"消费者卡死"原型)。它只由新 CONNECT 成功或 memset 清零。 */
|
||||
/* 新监听不得继承上一条连接的释放原因(TRAP-NET-18 待办 #3) */
|
||||
p_sock->released_abnormal = 0U;
|
||||
/* N-30(TRAP-NET-20):清零前把对端端口转登为幽灵甄别基准;去抖计数随之清零 */
|
||||
/* TRAP-NET-20:清零前把对端端口转登为幽灵甄别基准;去抖计数随之清零 */
|
||||
p_sock->last_peer_port = p_sock->remote_port;
|
||||
p_sock->lost_conn_seen = 0U;
|
||||
/* 以下四项 = 清上一条的对端信息,新连接待用 */
|
||||
@@ -361,7 +361,7 @@ void net_listener_tick(void) {
|
||||
/* 已到放弃时限(0 = 尚未起算,见下) */
|
||||
if ((s_relisten_dead[i] != 0U) && ((int32_t)(now - s_relisten_dead[i]) >= 0)) {
|
||||
net_listener_clear(i);
|
||||
/* 预算耗尽 ≠ 放弃:交 reconciler 形态③④ 周期接管(N-32 单一重建入口),
|
||||
/* 预算耗尽 ≠ 放弃:交 reconciler 形态③④ 周期接管(监听生命周期单一重建入口),
|
||||
* 监听不会永久失效——旧文案 "give up" 夸大了失效语义 */
|
||||
DBG_ERROR("sock%d relisten retry budget exhausted, reconciler takes over", i);
|
||||
continue;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-10-12
|
||||
* 修改记录:
|
||||
* 2026-10-12 王建锋 从 net_socket.c 抽出监听生命周期(N-32 §10 模块化)
|
||||
* 2026-10-12 王建锋 从 net_socket.c 抽出监听生命周期(模块化,详述 docs/网络/网络自愈架构设计.md §9.3)
|
||||
* 2026-10-14 王建锋 单一所有者收口:net_listener_try(各调用点自带门、当场动作)
|
||||
* 改为 net_listener_request(只登记意图)+ net_listener_tick
|
||||
* (唯一执行者,门集与芯片在听判据集中一处)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* 限定条件:本文件真机专属——模拟器走 sim/net_socket_sim.c,
|
||||
* simulator/CMakeLists.txt 不编译本文件(同 net_listener.c 先例)
|
||||
*
|
||||
* 阻塞 recv / send 挂起模型(E-02 结构演进):阻塞等待 = 挂起请求 + 主循环节拍完成
|
||||
* 阻塞 recv / send 挂起模型(结构演进):阻塞等待 = 挂起请求 + 主循环节拍完成
|
||||
* "无数据 / 发送缓冲未空 + 阻塞等待"不再自旋占用 netTask:登记 pending 后立即返回
|
||||
* net_pending_tick / net_send_pending_tick(与 D10 重监听重试同节奏,
|
||||
* net_process_messages 开头每轮调用)
|
||||
@@ -73,7 +73,7 @@ void net_pending_capture_owner(void) {
|
||||
* 返回值:无
|
||||
* 限定条件:netTask 上下文;sockfd 合法且挂起在位(否则静默返回,防重复通知)
|
||||
* 函数说明:通知值 = 结果本身(与消息分派同一回传通道,调用方直接按通知值
|
||||
* 取结果);失败记入 netTask 自己的 errno 槽位(E-03)
|
||||
* 取结果);失败记入 netTask 自己的 errno 槽位
|
||||
*/
|
||||
static void net_pending_complete(int sockfd, int result) {
|
||||
/* 本 fd 挂起请求指针 */
|
||||
@@ -89,7 +89,7 @@ static void net_pending_complete(int sockfd, int result) {
|
||||
if (p->active == 0U) {
|
||||
return;
|
||||
}
|
||||
/* 失败结果:记入 netTask 自己的错误码槽位(E-03;不再写入跨任务共享全局) */
|
||||
/* 失败结果:记入 netTask 自己的错误码槽位(不再写入跨任务共享全局) */
|
||||
if (result < 0) {
|
||||
(void)net_set_errno(result);
|
||||
}
|
||||
@@ -233,7 +233,7 @@ void net_pending_tick(net_sock_t *p_socks) {
|
||||
}
|
||||
|
||||
/* ③ 断连:排空 → 数据或 EOF(0) + 自动重监听。
|
||||
* 判据同 net_recv_locked(N-32 P1 不变量 I):`state == CLOSED ||
|
||||
* 判据同 net_recv_locked(监听生命周期 P1 不变量 I):`state == CLOSED ||
|
||||
* session_dead`。只判 CLOSED 时,抢先 relisten 后 ①(要求 ESTABLISHED)
|
||||
* 与 ③(要求 CLOSED) 两头落空 → 挂起的 recv 只能干等 ② deadline 超时
|
||||
* (lftpd 阻塞 recv 的"消费者卡死"原型)。无限等待登记没有 ②,
|
||||
@@ -259,7 +259,7 @@ void net_pending_tick(net_sock_t *p_socks) {
|
||||
* 原内层 `state == CLOSED` 门已**上收到 tick**——它防的是"对已回
|
||||
* LISTENING 的 fd 再 open+listen → 因 USE 错误走进关闭分支、关掉
|
||||
* 正听着的 Socket"(U12 同源),属执行侧安全不变量,不由登记点复述。
|
||||
* N-32 P2 修正:**保留本处即时登记** —— 它只在有**挂起 recv**
|
||||
* 监听生命周期 P2 修正:**保留本处即时登记** —— 它只在有**挂起 recv**
|
||||
* 时到达(`p->active != 0`),属"消费者在等这条连接结局"的
|
||||
* 消费者驱动路径,不是周期性抢先(同 net_recv_locked 的理由)。 */
|
||||
if (p_sock->auto_relisten != 0U) {
|
||||
@@ -312,7 +312,7 @@ void net_pending_tick(net_sock_t *p_socks) {
|
||||
* 出口参数:无
|
||||
* 返回值:1 - 有挂起;0 - 无(含描述符越界) int
|
||||
* 限定条件:任意上下文(纯 RAM 读,不发起 RPC)
|
||||
* 函数说明:1. N-32 §10 模块化:net_listener_tick 用它跳过"重开 Socket
|
||||
* 函数说明:1. 监听生命周期模块化:net_listener_tick 用它跳过"重开 Socket
|
||||
* 会摧毁在途连接"的 fd(挂起 recv 保险,原为直接读 s_net_pending[i].active)
|
||||
* 2. 声明在 net_pending.h(配对头,规范 S17 2.2)
|
||||
*/
|
||||
|
||||
@@ -123,7 +123,7 @@ void net_pending_settle_close(int sockfd, net_sock_t *p_sock);
|
||||
* 出口参数:无
|
||||
* 返回值:1 - 有挂起;0 - 无(含描述符越界) int
|
||||
* 限定条件:任意上下文(纯 RAM 读,不发起 RPC)
|
||||
* 函数说明:N-32 §10 模块化:net_listener_tick 用它跳过"重开 Socket
|
||||
* 函数说明:监听生命周期模块化:net_listener_tick 用它跳过"重开 Socket
|
||||
* 会摧毁在途连接"的 fd(挂起 recv 保险)
|
||||
*/
|
||||
int net_pending_active(int sockfd);
|
||||
|
||||
@@ -255,7 +255,7 @@ int net_poll_events(net_pollfd_t *fds, int nfds, int timeout) {
|
||||
* 出口参数:无
|
||||
* 返回值:1 - 可读(接收缓冲非空);0 - 不可读或描述符无效 int
|
||||
* 限定条件:net_init() 已调用
|
||||
* 函数说明:1. P2-7(2026-10-04):LISTENING 态**不再**恒判可读。本网络层无
|
||||
* 函数说明:1.(2026-10-04):LISTENING 态**不再**恒判可读。本网络层无
|
||||
* "待 accept 的挂起连接队列"——新连接到达时 CONNECT 事件把该 socket
|
||||
* 自身直接转为 ESTABLISHED(handle_connect_event:"监听自身转数据通道"),
|
||||
* 故监听态恒无数据可读。原实现对 LISTENING 恒返回 1,会使
|
||||
@@ -272,7 +272,7 @@ static int check_socket_readable(int sockfd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 监听态恒不可读(见上方 P2-7 说明) */
|
||||
/* 监听态恒不可读(见上方说明) */
|
||||
if (NET_SOCK_STATE_LISTENING == p_sock->state) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ int net_msg_queue_adopt(osMessageQueueId_t queue_id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================= 错误码存储(E-03 修复:按任务隔离,消除跨任务覆写竞态) =================
|
||||
/* ================= 错误码存储(按任务隔离,消除跨任务覆写竞态) =================
|
||||
*
|
||||
* 旧实现是单个全局 `static int s_net_errno`:netTask 在处理消息时写入本层的
|
||||
* 「最后错误码」,调用方包装器随后在**自己的上下文**再写一次。两条写路径分属不同
|
||||
@@ -227,7 +227,7 @@ static uint32_t net_errno_slot(void) {
|
||||
* 返回值:err 原值(便于写成 `return net_set_errno(NET_ERR_XXX);`)
|
||||
* 限定条件:无
|
||||
* 函数说明:1. 只写本任务的槽位,其他任务读不到、也改不了 → 消除跨任务覆写竞态
|
||||
* 2. N-32 §10 模块化:由 static 提升为**模块间可见**(net_listener.c
|
||||
* 2. 监听生命周期模块化:由 static 提升为**模块间可见**(net_listener.c
|
||||
* 也需要设 errno),声明与 NET_ERR_RETURN_1 宏见 net_socket.h
|
||||
*/
|
||||
int net_set_errno(int err) {
|
||||
@@ -332,7 +332,7 @@ static bool s_mac_is_zero(const uint8_t *p_mac) {
|
||||
* 无关),且违反保留位规定 → 0x09 改 0x08(2026-10-11 定案:官方手册
|
||||
* V1C/V1E/V2.2/V2.3 的 bit0 全是保留位,官方例程 bit0=0 下 Socket 0~7 照常
|
||||
* 可用、FTP 例程本身就传 0x08;证据链见 TRAP-NET-15,
|
||||
* 0x08 下的多 Socket 台架复测登记 N-31) */
|
||||
* 0x08 下的多 Socket 台架复测登记为 Phase 7 复跑项) */
|
||||
ch395f_set_fun_para(fun_para);
|
||||
|
||||
/* 设置 TCP MSS:维持 1024(512 裕量方案未采纳,当年支撑它的台架判据不可信,
|
||||
@@ -358,7 +358,7 @@ static bool s_mac_is_zero(const uint8_t *p_mac) {
|
||||
/* 设置 MAC(手册 §9.2.1 步骤①:SET_MAC 必须在 INIT_CH395 之前——SET_MAC 写芯片
|
||||
* EEPROM,而 INIT_CH395 会初始化/加载 MAC;顺序反了则本次上电芯片仍用旧 MAC,
|
||||
* UI 配置的 MAC 不生效(回落芯片内置/上次值),设备在线身份与 UI 显示不符。
|
||||
* P1-7,2026-10-04);NULL 或全零 = 保持芯片内置 MAC,不下发;
|
||||
* 2026-10-04);NULL 或全零 = 保持芯片内置 MAC,不下发;
|
||||
* 写 EEPROM,每上电重放同值幂等 */
|
||||
if (mac != NULL && s_mac_is_zero(mac) == false) {
|
||||
ch395f_set_mac_addr((uint8_t *)mac);
|
||||
@@ -572,7 +572,7 @@ int net_poll(void) {
|
||||
for (int i = 0; i < NET_MAX_SOCKETS; i++) {
|
||||
if (s_net_socks[i].in_use != 0U) {
|
||||
(void)ch395f_get_sock_state((uint8_t)i);
|
||||
/* E-02 收口:驱动 sock_reset 状态机在 net_poll 步进
|
||||
/* 驱动 sock_reset 状态机在 net_poll 步进
|
||||
* (驱动头注释契约"在 net_poll 或测试循环里周期调用")。IDLE 槽位
|
||||
* 纯 RAM 判返回 0 无 SPI;仅活跃复位机做短 SPI。作用:同步包装
|
||||
* (net_sock_reset_sync)600ms 放弃后复位机不搁浅,芯片条件满足
|
||||
@@ -663,7 +663,7 @@ void net_process_messages(void) {
|
||||
net_send_pending_tick(s_net_socks);
|
||||
/* TRAP-NET-17 状态对账 + 监听重建合一(单一 100ms tick):
|
||||
* 判据读驱动缓存(net_poll 每轮全量刷新),①②⑤ 失同步 + ③④ 重建 +
|
||||
* U11 重同步全部在此(本层唯一周期重建入口,N-32 P2 单一所有者) */
|
||||
* U11 重同步全部在此(本层唯一周期重建入口,监听生命周期 P2 单一所有者) */
|
||||
net_reconcile_tick();
|
||||
|
||||
/* 队列排空:超时 0 非阻塞取,每条处理一轮,直到本轮队列为空 */
|
||||
@@ -758,8 +758,8 @@ void net_process_messages(void) {
|
||||
break;
|
||||
}
|
||||
case NET_MSG_DROP_CONN: {
|
||||
/* E-02 收口:应用放弃会话的主动拆除(拆连接、保监听)。监听型
|
||||
* 登记即返(N-17:拆链排渣交 net_listener_tick,本消息不再占用
|
||||
/* 应用放弃会话的主动拆除(拆连接、保监听)。监听型
|
||||
* 登记即返(探针窗口心跳缺口修复:拆链排渣交 net_listener_tick,本消息不再占用
|
||||
* netTask 数百 ms) */
|
||||
net_sock_t *p_sock = net_get_sock(msg.sockfd);
|
||||
if (p_sock == NULL) {
|
||||
@@ -813,7 +813,7 @@ void net_process_messages(void) {
|
||||
uint32_t notify_val = (uint32_t)msg.result;
|
||||
|
||||
/* 失败:回传本条消息**自身**的精确错误码(NET_ERR_WOULDBLOCK 等)。
|
||||
* E-03 后取的是 netTask 自己的错误码槽位——锁定实现(*_locked)在
|
||||
* 取的是 netTask 自己的错误码槽位——锁定实现(*_locked)在
|
||||
* 失败返回前记录的码,不受其他任务影响;未置位时回退通用 NET_ERR。 */
|
||||
if (msg.result < 0) {
|
||||
int te = s_net_errno_slots[net_errno_slot()].err;
|
||||
@@ -909,7 +909,7 @@ int net_socket(int domain, int type) {
|
||||
p_sock->blocking = 1;
|
||||
/* 新 fd 不得继承上一条连接的释放原因(TRAP-NET-18 待办 #3) */
|
||||
p_sock->released_abnormal = 0;
|
||||
/* N-32(P1):新 fd 不得继承"上一条会话已结束"电平(否则新建即 EOF,
|
||||
/* 监听生命周期 P1:新 fd 不得继承"上一条会话已结束"电平(否则新建即 EOF,
|
||||
* 消费侧连数据都收不到)——与 released_abnormal 同理,显式清零 */
|
||||
p_sock->session_dead = 0;
|
||||
/* 新 fd 不得继承上一次的待重试状态(D10) */
|
||||
@@ -1165,7 +1165,7 @@ int net_listen_locked(int sockfd) {
|
||||
p_sock->state = NET_SOCK_STATE_LISTENING;
|
||||
/* 单连接模式:连接断开后由 net 层自动回到 LISTEN(模拟 BSD 监听常驻) */
|
||||
p_sock->auto_relisten = 1;
|
||||
/* N-30(TRAP-NET-20):新监听会话,事件未收到去抖计数清零 */
|
||||
/* TRAP-NET-20:新监听会话,事件未收到去抖计数清零 */
|
||||
p_sock->lost_conn_seen = 0U;
|
||||
|
||||
/* 监听建立完成 */
|
||||
@@ -1232,7 +1232,7 @@ int net_listen(int sockfd) {
|
||||
* 限定条件:Socket 处于 LISTENING 状态
|
||||
* 函数说明:单连接:监听 Socket 自身在 CONNECT 后已转为 ESTABLISHED
|
||||
*/
|
||||
/* ===== N-30 accept 路径"CONNECT 事件未收到补 accept"(2026-10-11 台架实证;
|
||||
/* ===== TRAP-NET-20 accept 路径"CONNECT 事件未收到补 accept"(2026-10-11 台架实证;
|
||||
* E14 复核 2026-10-14:事件非芯片侧丢失,是被读清消费——机制不变)=====
|
||||
* 台架结论(剥离 OS/net/FTP 直接对芯片做受控 close→open→listen→connect 矩阵):
|
||||
* 芯片关闭连接后的拆链收尾窗口**变长且不可见**(状态寄存器显示 CLOSED 也不代表
|
||||
@@ -1274,7 +1274,7 @@ static int net_accept_locked(int sockfd, struct net_sockaddr *addr, int *addrlen
|
||||
/* 先轮询一次:把状态机刷新到芯片侧最新状态 */
|
||||
net_poll();
|
||||
|
||||
/* N-30(TRAP-NET-20):监听等待期兼做芯片状态第二信源——CONNECT 事件未收到时
|
||||
/* TRAP-NET-20:监听等待期兼做芯片状态第二信源——CONNECT 事件未收到时
|
||||
* 去抖补 accept(台架实证:拆链窗口事件未收到是数据被吞/425 的主根因,
|
||||
* E14 复核:事件非芯片丢失、被读清消费吞掉;纯事件等待无自愈可能;
|
||||
* 详见 net_lost_connect_probe 区块注释) */
|
||||
@@ -1286,13 +1286,13 @@ static int net_accept_locked(int sockfd, struct net_sockaddr *addr, int *addrlen
|
||||
* (含上一步探针补 accept 的命中);其余失同步由 net_reconcile_tick()
|
||||
* 周期对账(带去抖)兜底 */
|
||||
if (p_listen_sock->state != NET_SOCK_STATE_ESTABLISHED) {
|
||||
/* N-30(2026-10-11 手册 §5.23⑤ + 生产时间线定案):
|
||||
/* TRAP-NET-20(2026-10-11 手册 §5.23⑤ + 生产时间线定案):
|
||||
* "closed-but-readable" 接受——STOR 类传输客户端**发完数据立即关数据连接**
|
||||
* (正常 FTP 行为,Python ftplib sendall 后即 close),芯片按
|
||||
* FUN_PARA **bit3 SOCKET_CLOSE=1**(`0x08`,§5.52 ②)规格保留 Socket 与 RX 缓冲供 MCU 排空
|
||||
* (实测 DISCONNECT 后 st=0x05/0x00、recv_len=1027=完整载荷)。
|
||||
* 若 accept 轮询晚于对端 FIN,盲目 relisten(close+open 清缓冲)会把
|
||||
* 已到达的数据销毁 → 425(此前 N-30"425/被吞"的主根因,并非芯片杀连接)。
|
||||
* 已到达的数据销毁 → 425(此前 TRAP-NET-20"425/被吞"的主根因,并非芯片杀连接)。
|
||||
* 处置:芯片 RX 缓冲有数据 → 接受这条"已关但可读"连接,应用经
|
||||
* net_recv_locked 快路径(无状态门槛)排空,排空后 EOF 自然触发 relisten。 */
|
||||
int drain_pending = 0;
|
||||
@@ -1303,7 +1303,7 @@ static int net_accept_locked(int sockfd, struct net_sockaddr *addr, int *addrlen
|
||||
} else {
|
||||
/* 连接已断开(CLOSED)且无残留数据:登记重建请求,下一次 accept
|
||||
* 即可等待新连接(BSD 风格监听常驻)。
|
||||
* N-32 P2 修正:**保留本处即时登记** —— 它由消费者调 accept 触发
|
||||
* 监听生命周期 P2 修正:**保留本处即时登记** —— 它由消费者调 accept 触发
|
||||
* (消费者正在等新连接),不是周期性抢先;删掉会把 CLOSED 窗口
|
||||
* 拉长、导致调用方高频空转 accept(实测 [WD] task stall)。
|
||||
* 单一所有者收口后:动作发生在下一轮 net_listener_tick(≤1ms),非阻塞 */
|
||||
@@ -1446,7 +1446,7 @@ int net_listener_armed(int sockfd) {
|
||||
return 1;
|
||||
}
|
||||
/* 断连待重建态:**仅当芯片 RX 可能仍有残留数据**时放行,让
|
||||
* net_accept_locked 的 "closed-but-readable" 接受(N-30,对端"发完即 FIN")
|
||||
* net_accept_locked 的 "closed-but-readable" 接受(TRAP-NET-20,对端"发完即 FIN")
|
||||
* 仍能拿到该连接。
|
||||
* ⚠ 无残留时必须返回 0 —— 否则调用方会在整个 CLOSED 窗口内每轮都发起
|
||||
* net_accept(RPC:入队 + xTaskNotifyWait 回执**无上界**)→ 队列积压 →
|
||||
@@ -1694,11 +1694,11 @@ static int net_connect_locked(int sockfd, const struct net_sockaddr *addr, int a
|
||||
* 交给 CONNECT/TIM_OUT 裁定,不得当成失败(否则慢芯片会被误杀)。
|
||||
* 其余非 SUCCESS 均为明确的命令级失败(VAL/ARG/USE/OPEN/IF/MEM/BUF/RTE…):
|
||||
* 此前返回值被直接丢弃 → 本层停在 CONNECTING 干等 recv 30 s 超时才暴露
|
||||
* (2026-10-12 审计 B2)。按 §9.2.2 ⑧"再次连接需从 ⑤ 重开"回滚。 */
|
||||
* (2026-10-12 审计)。按 §9.2.2 ⑧"再次连接需从 ⑤ 重开"回滚。 */
|
||||
if ((status != CH395F_ERR_SUCCESS) && (status != CH395F_ERR_BUSY)) {
|
||||
DBG_ERROR("[CONN] sock%d TCP_CONNECT rejected by chip: 0x%02X", sockfd, status);
|
||||
(void)ch395f_close_socket((uint8_t)sockfd);
|
||||
/* N-32(P1 不变量 I):命令级失败同样是"本会话已结束"——此前这里只置
|
||||
/* 监听生命周期 P1 不变量 I:命令级失败同样是"本会话已结束"——此前这里只置
|
||||
* CLOSED,而 CONNECTING 态从未置 session_dead,挂起的 recv 只能干等
|
||||
* deadline(B2 审计发现的"停在 CONNECTING 干等 30s 超时才暴露"同源) */
|
||||
p_sock->session_dead = 1U;
|
||||
@@ -1891,7 +1891,7 @@ static int net_send_locked(net_sock_t *p_sock, const void *buf, int len,
|
||||
* 函数说明:1. 数据已在(快速路径)→ 立即读出返回
|
||||
* 2. 非阻塞(NET_MSG_DONTWAIT 单次覆盖 **或** socket blocking 属性为 0,
|
||||
* 模式属性)无数据立即返回 -1(NET_ERR_WOULDBLOCK)
|
||||
* 3. 无数据 + 阻塞等待 → 登记挂起请求(pending 化,E-02 结构演进)
|
||||
* 3. 无数据 + 阻塞等待 → 登记挂起请求(pending 化,结构演进)
|
||||
* 4. netTask 零占用立即返回;完成条件(数据/到点[仅显式预算]/断连)由 net_pending_tick 按主循环节拍检查
|
||||
* 5. 并通知 caller;关闭/网络重建/陈旧重同步由对应路径显式结束(取消必通知)
|
||||
* 6. CLOSED 状态语义(排空 + EOF + 自动重监听)逐项保留在 tick 内
|
||||
@@ -1936,7 +1936,7 @@ static int net_recv_locked(net_sock_t *p_sock, void *buf, int len, int flags,
|
||||
/* 非阻塞且当前无数据:若连接已断开则视为 EOF(0) 并自动重监听,
|
||||
* 否则返回 WOULDBLOCK(-1) 表示暂时无数据 */
|
||||
/* 连接已断开(CLOSED)**或**本会话已结束(session_dead):按 EOF 处理。
|
||||
* 判据从纯 `state == CLOSED` 放宽为 `|| session_dead`(N-32 P1 不变量 I):
|
||||
* 判据从纯 `state == CLOSED` 放宽为 `|| session_dead`(监听生命周期 P1 不变量 I):
|
||||
* 抢先 relisten 后 state 已是 LISTENING 而会话确实已结束,旧判据在此
|
||||
* 恒返 WOULDBLOCK → EOF 永久失踪(新连接被旧会话静默吸收)。
|
||||
* 有数据时走上方快路径(recv_len>0 优先),本判据只在"无数据"时生效,
|
||||
@@ -1948,7 +1948,7 @@ static int net_recv_locked(net_sock_t *p_sock, void *buf, int len, int flags,
|
||||
* ch395f_close_socket → 把正听着新 SYN 的 Socket 当场关掉"(U12 同源
|
||||
* 事故)。这是**执行侧安全不变量**,不该由每个登记点各自复述——
|
||||
* 漏一处即事故;收口后 tick 另加"芯片已在听即了结",结构上不可能再犯。
|
||||
* N-32 P2 修正(2026-10-12 台架实证):**保留本处即时登记**——
|
||||
* 监听生命周期 P2 修正(2026-10-12 台架实证):**保留本处即时登记**——
|
||||
* 它是"消费者动作触发"(消费者正在等这条连接的结局),不是周期性
|
||||
* "抢先";删掉它会把 CLOSED 窗口从 ~0 拉长到 reconciler 周期+隔离期
|
||||
* (~100ms),期间调用方高频发起 net_accept(RPC 无上界)→
|
||||
@@ -2020,7 +2020,7 @@ static int net_close_locked(net_sock_t *p_sock) {
|
||||
}
|
||||
|
||||
/* 清零控制块(memset 0 = 释放本 fd 全部状态) */
|
||||
/* N-30(TRAP-NET-20):幽灵甄别基准跨 fd 释放保留(幽灵属芯片 Socket 级状态,
|
||||
/* TRAP-NET-20:幽灵甄别基准跨 fd 释放保留(幽灵属芯片 Socket 级状态,
|
||||
* 与 fd 复用无关——close 后新 listen 落在同一芯片 Socket 上仍可能撞幽灵) */
|
||||
uint16_t keep_peer = p_sock->remote_port;
|
||||
memset(p_sock, 0, sizeof(net_sock_t));
|
||||
@@ -2042,11 +2042,11 @@ static int net_close_locked(net_sock_t *p_sock) {
|
||||
* 出口参数:无
|
||||
* 返回值:0 - 拆除完成(监听型 fd 已重监听或交 D10) int
|
||||
* 限定条件:netTask 上下文;p_sock 在用且为 TCP 流
|
||||
* 函数说明:1. E-02 收口(《网络自愈架构设计》§5.2 E13):应用放弃的会话若 TCP 仍活
|
||||
* 函数说明:1.(《网络自愈架构设计》§5.2 E13):应用放弃的会话若 TCP 仍活
|
||||
* (PC 内核自动 ACK keepalive,僵尸判不死),单连接监听被永久
|
||||
* 占住;应用又不得 net_close 监听 fd(毁监听)——本函数补上
|
||||
* "拆连接不拆监听"的应用侧形态
|
||||
* 2. 芯片侧拆除(TRAP-NET-18 异常释放语义,N-17 收口改异步):监听型 fd
|
||||
* 2. 芯片侧拆除(TRAP-NET-18 异常释放语义,探针窗口心跳缺口收口改异步):监听型 fd
|
||||
* = net_listener_settle(QUARANTINE) + REQ_DROP 登记即返,动作全部交
|
||||
* net_listener_tick(隔离窗内持续排空/关闭正是该机的既有语义);
|
||||
* 非监听 client fd = 同步 sock_reset QUARANTINE(600ms 封顶,原形态)
|
||||
@@ -2064,7 +2064,7 @@ static int net_drop_conn_locked(net_sock_t *p_sock) {
|
||||
* 在本函数体内**没有任何机器表达**,而函数体是无条件的:置 CLOSED、清
|
||||
* readable、给监听型 fd 登记重建。也就是说——将来任何新增路径绕过
|
||||
* NET_MSG_DROP_CONN 的分派门直接调它,就会把一个**健康监听器**当会话拆掉
|
||||
* (症状是端口偶发不再 accept,与 N-30 一族同源难查)。断言把这条"进来时
|
||||
* (症状是端口偶发不再 accept,与 TRAP-NET-20 一族同源难查)。断言把这条"进来时
|
||||
* 必须处于活动会话态"钉成机器可查的不变量,正是"不该发生"而不是"外部输入"。
|
||||
* ⚠ 分派处(case NET_MSG_DROP_CONN)的三条错误返回原样保留——它们负责真机
|
||||
* 上把误用变成 -1,本断言负责在测试构建里把误用**当场喊出来**。
|
||||
@@ -2091,7 +2091,7 @@ static int net_drop_conn_locked(net_sock_t *p_sock) {
|
||||
* FIN 5/5 的通过版本)。旧形态在本处理器里 net_sock_reset_sync 同步等待,
|
||||
* netTask 被占用 400ms 底/600ms 顶:串行总线整窗停摆、UI/FTP/对时的 API 回
|
||||
* 执顺延、NET 与对时位同窗丢 100ms 抽样 → 800ms 停喂声明 stall,距 IWDG
|
||||
* 最坏超时余量仅 ~0.7s(登记簿 N-17;方向评估与否决论证 → 《网络自愈架构
|
||||
* 最坏超时余量仅 ~0.7s(探针窗口心跳缺口;方向评估与否决论证 → 《网络自愈架构
|
||||
* 设计》§4.6)。返回语义随之明确:返回 = 已登记,芯片未必已拆完。
|
||||
* 非监听 client fd:无监听可保,维持同步确定性排渣(600ms 封顶;全仓
|
||||
* 零生产调用者,形态原样保留防漂移)。 */
|
||||
@@ -2105,7 +2105,7 @@ static int net_drop_conn_locked(net_sock_t *p_sock) {
|
||||
/* 会话簿记收口(保留 fd:不 memset、不动 local_port/auto_relisten) */
|
||||
p_sock->state = NET_SOCK_STATE_CLOSED;
|
||||
p_sock->readable = 0U;
|
||||
/* N-30(TRAP-NET-20):新会话起点,事件未收到去抖计数清零 */
|
||||
/* TRAP-NET-20:新会话起点,事件未收到去抖计数清零 */
|
||||
p_sock->lost_conn_seen = 0U;
|
||||
|
||||
if (p_sock->auto_relisten) {
|
||||
@@ -2293,7 +2293,7 @@ int net_recv_nb(int sockfd, void *buf, int len) {
|
||||
* 出口参数:无
|
||||
* 返回值:>0 字节数;0 = 对端关闭(EOF);-1 = 真错误(errno 可查);**-2 = 超时无数据**
|
||||
* 限定条件:非 netTask 上下文;net 层已初始化
|
||||
* 函数说明:1. E-02 修复配套接口:lftpd 等"等对端下一行/下一块数据"的调用方
|
||||
* 函数说明:1. 修复配套接口:lftpd 等"等对端下一行/下一块数据"的调用方
|
||||
* 若无限阻塞 recv,会把 netTask(全部 socket 操作的唯一执行者)长期占住
|
||||
* 2. 导致其余任务的网络操作整体冻结(M3 实测一次空闲 FTP 登录冻结远端显示 17.7s)
|
||||
* 3. 用本接口把等待切成 ≤timeout_ms 的片,调用方自行累计总预算:总超时语义不变、单次占用有界
|
||||
@@ -2335,7 +2335,7 @@ int net_recv_to(int sockfd, void *buf, int len, uint32_t timeout_ms) {
|
||||
msg.len = len;
|
||||
/* 阻塞式:netTask 侧轮询至"有数据"或"本片超时"(勿置 NET_MSG_DONTWAIT) */
|
||||
msg.flags = 0;
|
||||
/* 本片预算:netTask 最多等待 timeout_ms,保证对 netTask 的占用有界(E-02) */
|
||||
/* 本片预算:netTask 最多等待 timeout_ms,保证对 netTask 的占用有界 */
|
||||
msg.timeout_ms = timeout_ms;
|
||||
/* 记录调用任务句柄,netTask 处理后经 xTaskNotify() 精准回执 */
|
||||
msg.caller = xTaskGetCurrentTaskHandle();
|
||||
@@ -2440,9 +2440,9 @@ int net_close(int sockfd) {
|
||||
* (net 层 auto_relisten 已接管,见 AGENTS 单连接断开语义)
|
||||
* 函数说明:1. 单连接模型下挂起但 TCP 仍活的客户端会永久占住监听(keepalive
|
||||
* 被 PC 内核自动 ACK 判不死,《网络自愈架构设计》§5.2 E13);应用不得
|
||||
* net_close 监听 fd → 本 API 拆连接不拆监听(E-02 收口)
|
||||
* net_close 监听 fd → 本 API 拆连接不拆监听
|
||||
* 2. 监听型 fd:netTask 侧仅登记隔离沉降 + 重建请求即返回(动作在
|
||||
* net_listener_tick,netTask 零占用,登记簿 N-17 收口);非监听 client
|
||||
* net_listener_tick,netTask 零占用,探针窗口心跳缺口收口);非监听 client
|
||||
* fd 仍同步排渣(600ms 封顶)。见 net_drop_conn_locked
|
||||
*/
|
||||
int net_drop_conn(int sockfd) {
|
||||
@@ -2886,7 +2886,7 @@ int net_setblocking(int sockfd, int on) {
|
||||
* 出口参数:无
|
||||
* 返回值:错误码(NET_OK=0, NET_ERR_xxx=-N);本任务无失败记录时为 NET_OK
|
||||
* 限定条件:无(任何上下文可调用;中断上下文读 [0] 槽)
|
||||
* 函数说明:1. E-03 修复:错误码**按任务隔离**——只读本任务自己的槽位,
|
||||
* 函数说明:1. 错误码**按任务隔离**——只读本任务自己的槽位,
|
||||
* 其他任务的 net 调用再也覆盖不了它(旧实现为单一全局量,跨任务竞态)
|
||||
* 2. 调用成功时**不清零**(保持历史语义,向后兼容既有调用方)
|
||||
* 3. 超时场景(net_recv_to)请直接用返回码 -2 判定,不要依赖本接口
|
||||
|
||||
@@ -38,7 +38,7 @@ typedef enum {
|
||||
NET_MSG_CONNECT,
|
||||
NET_MSG_LISTEN,
|
||||
NET_MSG_ACCEPT,
|
||||
NET_MSG_DROP_CONN, /* E-02 收口:主动拆会话、保监听(见 net_drop_conn) */
|
||||
NET_MSG_DROP_CONN, /* 主动拆会话、保监听(见 net_drop_conn) */
|
||||
/* F-NET-2/3:NET_MSG_RESYNC_LISTEN / NET_MSG_RELISTEN 已删——
|
||||
* 静默回收由对账⑤自动认领(net_reconcile_tick),重建由 reconciler
|
||||
* 形态③④/D10 单一
|
||||
@@ -186,7 +186,7 @@ int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen);
|
||||
* 函数说明:1. 不变量 II(单一重建所有者;补齐 ESTABLISHED 放行):取代已退役的
|
||||
* `net_can_accept()`(只认 ESTABLISHED)作为监听 accept 门控——原门控使
|
||||
* :7003 永不进 `net_accept()`,
|
||||
* `net_lost_connect_probe`(CONNECT 事件未收到补 accept,N-30 实证的
|
||||
* `net_lost_connect_probe`(CONNECT 事件未收到补 accept,TRAP-NET-20 实证的
|
||||
* "数据被吞/425"主根因修复)对该端口等于从未运行
|
||||
* 2. 放行 LISTENING:探针与 "closed-but-readable 接受" 都发生在
|
||||
* `net_accept_locked` **内部**,门控挡在外面就永远到不了
|
||||
@@ -196,7 +196,7 @@ int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen);
|
||||
* (i104 200ms 抢不过对账② ~400ms 去抖)永不 accept、会话整场饿死
|
||||
* (实测全 18 项 FAIL)。此态 accept 必返 fd,无风暴风险
|
||||
* 3. 放行 CLOSED+auto_relisten **且 readable≠0**(有残留数据):
|
||||
* 保住 N-30 的 "closed-but-readable" 接受;**无残留时必须返回 0**,
|
||||
* 保住 TRAP-NET-20 的 "closed-but-readable" 接受;**无残留时必须返回 0**,
|
||||
* 否则调用方会在整个 CLOSED 窗口内每轮发起 `net_accept`(RPC 无上界)
|
||||
* → 队列积压 → 喂不上狗(2026-10-12 P2a 台架实测 48 条 task stall)。
|
||||
* 重建由 `net_reconcile_tick` 形态③④ 负责,调用方无需催促
|
||||
@@ -251,7 +251,7 @@ int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen);
|
||||
* 拷贝数据后触发发送——健康链路下(实测 219us 量级)行为与旧版逐字节一致
|
||||
* 2. 慢路径:自旋超预算后把请求**挂起登记**给 netTask,由
|
||||
* net_send_pending_tick 在发送缓冲区空闲时续传(分片 NET_SEND_CHUNK_MAX),
|
||||
* 调用方在任务通知上睡眠——**不再占用 netTask 执行者**(消除 E-02 队头阻塞)
|
||||
* 调用方在任务通知上睡眠——**不再占用 netTask 执行者**(消除队头阻塞)
|
||||
* 3. 短写语义:无论快路径超时还是挂起完成,只要存在未写完字节即按已发数返回,
|
||||
* 不假装全部成功;调用方按短写重试剩余部分(见 BSD_Socket_API 使用指南 §3.5)
|
||||
* 4. ⚠ 禁止在 IWDG required_mask 内任务做**无预算**的整块发送;挂起路径本身
|
||||
@@ -319,7 +319,7 @@ int net_setblocking(int sockfd, int on);
|
||||
* 函数说明:1. **显式预算**便捷入口(等价 Python settimeout,
|
||||
* 不再有隐藏默认值):net_recv 的无限阻塞 + 本接口的显式预算构成
|
||||
* 超时语义的全部来源;超时首选仍是 net_select
|
||||
* 2. E-02 修复配套:lftpd 等"等对端下一行/下一块数据"的调用方
|
||||
* 2. 修复配套:lftpd 等"等对端下一行/下一块数据"的调用方
|
||||
* 若无限阻塞 recv,会把 netTask(全部 socket 操作的唯一执行者)长期占住
|
||||
* 3. 用本接口把等待切成 ≤timeout_ms 的片,调用方自行累计总预算:总超时语义不变、单次占用有界
|
||||
* 4. 超时用独立返回码 -2(而非靠 errno 区分)→ 无跨任务 errno 竞态
|
||||
@@ -394,7 +394,7 @@ int net_recvfrom(int sockfd, void *buf, int len, int flags,
|
||||
int net_close(int sockfd);
|
||||
|
||||
/*
|
||||
* 函数功能:主动拆掉当前 TCP 会话,**保留监听**(E-02 收口)
|
||||
* 函数功能:主动拆掉当前 TCP 会话,**保留监听**
|
||||
* 入口参数:sockfd - socket 描述符
|
||||
* 返回值:0 成功(**监听型 fd 的“成功”= 拆除与重建已登记**,芯片未必已拆完,
|
||||
* 见函数说明 2;含幂等:无活动会话),-1 失败
|
||||
@@ -403,14 +403,14 @@ int net_close(int sockfd);
|
||||
* 单连接模型禁止对监听 fd net_close(连监听一起毁,AGENTS 约定),
|
||||
* 而挂起但 TCP 仍活的客户端会永久占住单连接监听(PC 内核自动
|
||||
* ACK keepalive,芯片僵尸判不死——《网络自愈架构设计》§5.2 E13 定案缺口)
|
||||
* 2. 实现(2026-10-25 N-17 起):auto_relisten fd = 登记 QUARANTINE 隔离
|
||||
* 2. 实现(2026-10-25 探针窗口心跳缺口修复起):auto_relisten fd = 登记 QUARANTINE 隔离
|
||||
* 沉降 + REQ_DROP 重建请求,**登记即返**——“FIN 关闭 + 排渣 + 排空
|
||||
* 事件 + 等 byte0=00H”(TRAP-NET-18 异常释放语义)与重建由
|
||||
* net_listener_tick 按 30ms 节奏异步执行,端口恢复窗 ~0.4-1s 与被动
|
||||
* 断连同型;**调用方不得按旧语义假设“返回即芯片已 CLOSED”**——返回
|
||||
* 后 accept/recv 得 WOULDBLOCK 直至重建完成(time_sync 既有轮询天然
|
||||
* 容忍)。旧同步形态曾使 netTask 占用 400-600ms、五任务心跳同窗
|
||||
* 缺席声明 stall(《网络自愈架构设计》§4.6 N-17 记录,勿复活)。
|
||||
* 缺席声明 stall(《网络自愈架构设计》§4.6 记录,勿复活)。
|
||||
* 非 auto_relisten(client fd)无监听可保,仍同步排渣(600ms 封顶)
|
||||
* 3. 幂等:非 ESTABLISHED/CONNECTING 直接返 0,不动监听
|
||||
*/
|
||||
@@ -441,7 +441,7 @@ int net_set_event_cb(int sockfd, net_event_cb_t cb, void *arg);
|
||||
* 出口参数:无
|
||||
* 返回值:错误码(NET_ERR_xxx);本任务尚无失败记录时为 NET_OK(0)
|
||||
* 限定条件:无(任何上下文可调用,含中断——查询为纯本任务索引读)
|
||||
* 函数说明:1. **按任务隔离**(2026-09-25 E-03 修复):错误码存在每个任务自己的
|
||||
* 函数说明:1. **按任务隔离**(2026-09-25):错误码存在每个任务自己的
|
||||
* 槽位里,任务间互不干扰,不存在跨任务覆写竞态——旧实现的单一全局
|
||||
* 变量会被 netTask/其他任务的 net 调用交错覆盖,调用方可能读到别人的码
|
||||
* 2. 语义:本任务最后一次返回 -1 的 net_*() 调用所对应的精确码;
|
||||
@@ -562,13 +562,13 @@ net_sock_t *net_sock_raw(int sockfd);
|
||||
* 返回值:err 原值(便于写成 `return net_set_errno(NET_ERR_XXX);`)
|
||||
* 限定条件:无
|
||||
* 函数说明:1. 只写本任务的槽位,其他任务读不到、也改不了 → 消除跨任务覆写竞态
|
||||
* 2. N-32 §10 模块化:由 net_socket.c 的 static 提升为**模块间可见**,
|
||||
* 2. 监听生命周期模块化:由 net_socket.c 的 static 提升为**模块间可见**,
|
||||
* 供 net_listener.c 等同目录内部模块复用(定义仍在 net_socket.c)
|
||||
*/
|
||||
int net_set_errno(int err);
|
||||
|
||||
/* 「记本任务错误码 + 统一失败返回 -1」的紧凑写法(取代 `s_net_errno = X; return -1;`)
|
||||
* N-32 §10:原定义在 net_socket.c,随 net_set_errno 一并提升到本头文件 */
|
||||
* 监听生命周期模块化:原定义在 net_socket.c,随 net_set_errno 一并提升到本头文件 */
|
||||
#define NET_ERR_RETURN_1(err) (net_set_errno(err), -1)
|
||||
|
||||
/*
|
||||
|
||||
@@ -203,18 +203,18 @@ typedef struct {
|
||||
* 连接的释放原因。 */
|
||||
uint8_t released_abnormal;
|
||||
|
||||
/* N-30(2026-10-11 裸机芯片台架实证):本 Socket 上一条被释放连接的**对端端口**。
|
||||
/* TRAP-NET-20(2026-10-11 裸机芯片台架实证):本 Socket 上一条被释放连接的**对端端口**。
|
||||
* 芯片拆链收尾窗口内旧连接未拆净,Socket 如实为 ESTABLISHED(幽灵态,E15:
|
||||
* bit3=1 保留现场契约,非谎报),此时回读的对端端口
|
||||
* = 旧连接端口;新连接的临时端口几乎必然不同。accept 路径补 accept 与对账②
|
||||
* 均以此甄别幽灵态(见 net_socket.c TRAP-NET-20)。跨 fd 释放保留(幽灵属芯片
|
||||
* Socket 级,与 fd 复用无关),新连接断开时刷新。 */
|
||||
uint16_t last_peer_port;
|
||||
/* N-30:accept 路径"CONNECT 事件未收到补 accept"的去抖计数(连续确认次数,
|
||||
/* TRAP-NET-20:accept 路径"CONNECT 事件未收到补 accept"的去抖计数(连续确认次数,
|
||||
* 节拍 = accept 轮询 100ms;新监听/补 accept 后清零) */
|
||||
uint8_t lost_conn_seen;
|
||||
|
||||
/* N-32 / B10 根治 P1(2026-10-12,设计文档 §2.3 不变量 I):本会话"已结束"的
|
||||
/* 监听生命周期 P1(B10 根治,2026-10-12,设计文档 §2.3 不变量 I):本会话"已结束"的
|
||||
* **电平**(粘滞),取代 `state == CLOSED` 这一**边沿**。
|
||||
* 为什么必须电平化:单连接复用模型下同一个 fd 既是监听器又是连接(handle
|
||||
* aliasing),"关掉一条连接"与"毁掉一个监听器"在类型上无法区分;而"会话结束"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-10-11
|
||||
* 修改记录:
|
||||
* v1.0 2026-10-11 王建锋 创建初始版本(N-19 FTP 鉴权)
|
||||
* v1.0 2026-10-11 王建锋 创建初始版本(FTP 鉴权)
|
||||
*/
|
||||
|
||||
/* 头文件包含区 */
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-10-11
|
||||
* 修改记录:
|
||||
* v1.0 2026-10-11 王建锋 创建初始版本(N-19 FTP 鉴权)
|
||||
* v1.0 2026-10-11 王建锋 创建初始版本(FTP 鉴权)
|
||||
*/
|
||||
|
||||
#ifndef FTP_CFG_H
|
||||
@@ -24,7 +24,7 @@ extern "C" {
|
||||
|
||||
/* 工厂默认:user=admin、口令=admin(pwd_hash = SHA256("adminadmin"))、write=1。
|
||||
* write=1 保持既有维护工作流(FTP 推 config.ini);生产配置应改口令并按需 write=0。
|
||||
* 出厂默认口令在用期间,lftpd_start 每次启动打 INFO 告警锚点(N-19) */
|
||||
* 出厂默认口令在用期间,lftpd_start 每次启动打 INFO 告警锚点(FTP 鉴权) */
|
||||
#define FTP_CFG_DEF_USER "admin"
|
||||
#define FTP_CFG_DEF_HASH "d82494f05d6917ba02f7aaa29689ccb444bb73f20380876cb05d1f37537b7892"
|
||||
#define FTP_CFG_DEF_WRITE 1u
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* v1.0 2026-09-10 王建锋 创建初始版本
|
||||
* v1.1 2026-09-14 王建锋 存储迁移至 cfg_file 引擎(INI);旧 NCFG 代码移至 net_cfg_legacy
|
||||
* v1.2 2026-09-15 王建锋 保存改跨任务交接(request/state/run + 通知回调);
|
||||
* 引擎属主 = defaultTask(P1-3 竞态修复)
|
||||
* 引擎属主 = defaultTask(竞态修复)
|
||||
* v1.3 2026-10-10 王建锋 **删除旧档 NCFG 迁移**(net_cfg_legacy 整体移除):该兼容
|
||||
* 路径把整条配置写链(net_cfg_save → cfg_file_save →
|
||||
* cfg_store_write_atomic → f_rename → FTL)挂进启动期调用图,
|
||||
@@ -148,7 +148,7 @@ static bool s_mac_is_zero(const uint8_t *p_mac) {
|
||||
*/
|
||||
int net_cfg_load(void) {
|
||||
s_net_register();
|
||||
/* N-19:[ftp] 段一并注册(所有受管段必须先注册、后 load,引擎按注册表解析) */
|
||||
/* [ftp] 段一并注册(所有受管段必须先注册、后 load,引擎按注册表解析) */
|
||||
ftp_cfg_register();
|
||||
|
||||
/* 旧档 NCFG 迁移已于 2026-10-10 删除(net_cfg_legacy 移除;理由见文件头 v1.3)。
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* v1.0 2026-09-10 王建锋 创建初始版本
|
||||
* v1.1 2026-09-14 王建锋 存储迁移至 cfg_file 引擎(INI [network] 段)
|
||||
* v1.2 2026-09-15 王建锋 保存改跨任务交接(request/state/run + 通知回调);
|
||||
* 引擎属主明确为 defaultTask(P1-3 竞态修复)
|
||||
* 引擎属主明确为 defaultTask(竞态修复)
|
||||
*/
|
||||
|
||||
#ifndef NET_CFG_H
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* 2026-07-18 王建锋 创建初始版本
|
||||
* 2026-07-20 王建锋 修复 DE 时序:添加 DE 建立延时替代 for 循环
|
||||
* 2026-07-20 王建锋 清理中文注释乱码,对齐代码规范
|
||||
* 2026-10-05 王建锋 P3-4:模块描述订正为实际实现 HAL_Delay(1)
|
||||
* 2026-10-05 王建锋 模块描述订正为实际实现 HAL_Delay(1)
|
||||
* (原描述称 DWT CYCCNT 微秒延时,与代码不符)
|
||||
*/
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ uint8_t sd2506_dec_to_bcd(uint8_t dec) {
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:把 HAL 的 I2C 状态映射成统一错误码(S-5,2026-10-23)
|
||||
* 函数功能:把 HAL 的 I2C 状态映射成统一错误码(2026-10-23)
|
||||
* 入口参数:status - HAL_I2C_* 返回的状态
|
||||
* 返回值:HAL_OK → BSP_OK;HAL_TIMEOUT → BSP_ERR_TIMEOUT(可重试);其余 → BSP_ERR_IO
|
||||
* 限定条件:仅本文件内部使用
|
||||
@@ -206,7 +206,7 @@ bsp_err_t sd2506_init(void) {
|
||||
/* 验证 I2C 通信: 尝试读取 8 字节 ID */
|
||||
ret = sd2506_read_regs(SD2506_REG_ID_START, a_id, SD2506_ID_SIZE);
|
||||
if (ret != BSP_OK) {
|
||||
/* 启动段可观测性(2026-10-02 S10):本函数原先所有失败路径均静默返回,
|
||||
/* 启动段可观测性(2026-10-02 加):本函数原先所有失败路径均静默返回,
|
||||
* 而它是启动死机最可疑的源头(I2C1 硬件不通即卡此步且无任何输出)。
|
||||
* 日志字符串必须纯 ASCII(文件无 BOM,ARMCC 按 CP936 解码)。 */
|
||||
DBG_ERROR("sd2506_init: ID read FAIL (I2C err=%d)", ret);
|
||||
|
||||
@@ -137,7 +137,7 @@ extern "C" {
|
||||
#define SD2506_CTR1_WRITE_OFF 0x7BU
|
||||
|
||||
/* ======================== 返回值定义 ========================
|
||||
* 本模块**不再自带错误码**(2026-10-23,S-5):统一走 Drivers/BSP/bsp_err.h。
|
||||
* 本模块**不再自带错误码**(2026-10-23):统一走 Drivers/BSP/bsp_err.h。
|
||||
* 旧码映射 —— SD2506_OK → BSP_OK;SD2506_ERROR(参数类)→ BSP_ERR_PARAM;
|
||||
* SD2506_I2C_ERROR → BSP_ERR_IO,其中 I2C 超时刻意单独归成 **BSP_ERR_TIMEOUT
|
||||
* (可重试)**:旧码把"总线上没人应答"和"超时"混成一个 -2,调用方没法规避。
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
|
||||
- **周期重触发由 TIM3 更新事件(1 kHz)驱动**(2026-10-10):`app_main_init` 末尾 `HAL_TIM_Base_Start_IT(&htim3)` 启动节拍,`Src/main.c` 的 `HAL_TIM_PeriodElapsedCallback` 在 TIM3 分支内调 `tpafe5160_start_conv_irq()`(ISR 内仅两次 GPIO 写)。B1 阶段曾由 `adcTask` 每 1 ms 软触发(已改)。⚠ **节拍源必须是 TIM3 而非 TIM6**:TIM3 的同一个更新事件还经 **TRGO** 硬件触发 STM32 ADC1,两片转换器由此同源对齐;F4 上 TIM6/TIM7 的 TRGO 只接 DAC,喂不到 ADC1
|
||||
- **取数只用 `tpafe5160_snapshot(int16_t *dst, uint8_t count)`**(**仅任务上下文**,内部临界区原子拷贝;返回 1=新帧 / 0=无新帧 / -1=参数无效)。配套的 `tpafe5160_frame_seq()` 给帧序号、`tpafe5160_frstdata_err()` 给"FRSTDATA 无跳变"帧计数
|
||||
- ⚠️ **不要用缓冲区指针取数**:旧的 `get_buf()` / `data_ready()` / `clear_ready()` 已于 2026-10-10 **删除**(审计 E-45 / E-58)——`get_buf` 只给指针、任务再逐通道拷,中间被 BUSY EXTI 抢占就拷回**两帧混合**数据;`s_ready` 电平标志在 `start_conv_irq` 里被清 0,等于**用重触发去丢帧**。现由**帧序号**(只增不清)+ **临界区快照**取代
|
||||
- **`tpafe5160_init()` 做首帧有效性自检**(E-44):完整跑一帧转换+读取,若整帧读下来 FRSTDATA **没有发生任何跳变**(芯片没在驱动并行总线;板上上拉会把它钉死为高)→ 返回 `BSP_ERR_NO_DEVICE`(旧 `TPAFE5160_FRSTDATA_ERR(-3)`,2026-10-23 S-5 收编)并打 `[ERR] Init FRSTDATA no-toggle`。判据刻意不锁死"哪个 RD 边沿拉高/拉低"(手册只给"RD 下降沿 → FRSTDATA 高/低"两个跳变,本板未实测边沿次序),只要求"一帧内必须跳变" → 既抓死芯片,也不会因极性假设错误误杀好芯片
|
||||
- ⚠️ **不要用缓冲区指针取数**:旧的 `get_buf()` / `data_ready()` / `clear_ready()` 已于 2026-10-10 **删除**——`get_buf` 只给指针、任务再逐通道拷,中间被 BUSY EXTI 抢占就拷回**两帧混合**数据;`s_ready` 电平标志在 `start_conv_irq` 里被清 0,等于**用重触发去丢帧**。现由**帧序号**(只增不清)+ **临界区快照**取代
|
||||
- **`tpafe5160_init()` 做首帧有效性自检**:完整跑一帧转换+读取,若整帧读下来 FRSTDATA **没有发生任何跳变**(芯片没在驱动并行总线;板上上拉会把它钉死为高)→ 返回 `BSP_ERR_NO_DEVICE`(旧 `TPAFE5160_FRSTDATA_ERR(-3)`,2026-10-23 收编)并打 `[ERR] Init FRSTDATA no-toggle`。判据刻意不锁死"哪个 RD 边沿拉高/拉低"(手册只给"RD 下降沿 → FRSTDATA 高/低"两个跳变,本板未实测边沿次序),只要求"一帧内必须跳变" → 既抓死芯片,也不会因极性假设错误误杀好芯片
|
||||
- 采样数据的消费者 `App/task/adc_task.c` **已实现**(B1,2026-10-10:`tpafe5160_snapshot()` 原子取数 + 帧统计;`adcTask` 在 `Src/freertos.c` 的 `USER CODE` 区创建)。**v2.2(2026-10-10)**:采样节拍改由定时器更新中断硬件触发,本任务退化为纯消费者;**v2.8(2026-10-10)**:节拍源改 TIM3(同时经 TRGO 触发 ADC1 + DMA),STM32 侧改为消费 DMA 乒乓缓冲,单拍耗时 122 µs → **8 µs**
|
||||
- CONVST→BUSY→RD 三段时序对**建立/保持时间敏感**,改动需对照芯片手册
|
||||
- ⚠️ 本项目 ADC 相关功能**新增任务/缓冲前须核算 RAM**(见 `docs/内存管理/`);接消费者前的强制门禁见根 `AGENTS.md`「接 ADC / RS-485 消费者前的强制门禁」
|
||||
- ⚠️ **通道语义不是通道号**:`buf[i]` 对应哪个电气量必须查 `docs/硬件平台/ADC通道映射说明.md`(`buf[2]=IA`、`buf[5]=UN`、`buf[6]=UA`);V0.1 上 8 路电气量分属两片转换器属硬件缺陷(N-18)→ **禁止**跨转换器做相位/功率/功率因数类运算
|
||||
- ⚠️ **通道语义不是通道号**:`buf[i]` 对应哪个电气量必须查 `docs/硬件平台/ADC通道映射说明.md`(`buf[2]=IA`、`buf[5]=UN`、`buf[6]=UA`);V0.1 上 8 路电气量分属两片转换器属硬件缺陷(登记簿条目「双转换器无共同采样触发」)→ **禁止**跨转换器做相位/功率/功率因数类运算
|
||||
|
||||
## 已知问题
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* 2026-07-17 王建锋 创建初始版本,参考 AD7606 并行驱动及 TPAFE5160 手册
|
||||
* 2026-07-17 王建锋 增加 EXTI 中断读取模式
|
||||
* 2026-09-20 王建锋 V0.1 引脚适配(引脚值随 main.h 宏,驱动逻辑不变)
|
||||
* 2026-10-10 王建锋 消费者接入前置修复(E-44 / E-45 / E-58),详见 tpafe5160.h
|
||||
* 2026-10-10 王建锋 消费者接入前置修复,详见 tpafe5160.h
|
||||
*/
|
||||
|
||||
/* 头文件包含区 */
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "tpafe5160.h"
|
||||
#include "main.h"
|
||||
|
||||
/* taskENTER_CRITICAL:把"选缓冲 + 拷数据"收进一个不可分割动作(E-58)。
|
||||
/* taskENTER_CRITICAL:把"选缓冲 + 拷数据"收进一个不可分割动作。
|
||||
* 与 App/log/console_log.c、Drivers/BSP/NET/net_socket.c 同一写法,仅任务上下文可用 */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
@@ -73,7 +73,7 @@ static bsp_err_t tpafe5160_read_channels(uint8_t count, int16_t *buf);
|
||||
* 函数说明:1. 设置过采样为无过采样 (000)
|
||||
* 2. 确保 RD 为高、CONVST 为低
|
||||
* 3. 等待 BUSY 释放(转换空闲)
|
||||
* 4. 采一帧并校验 FRSTDATA 有跳变(E-44:旧实现只看 BUSY,芯片死亡
|
||||
* 4. 采一帧并校验 FRSTDATA 有跳变(旧实现只看 BUSY,芯片死亡
|
||||
* 时照样报 Init OK,此后所有读数都是上拉/总线残值——静默死亡)
|
||||
*/
|
||||
bsp_err_t tpafe5160_init(void) {
|
||||
@@ -91,7 +91,7 @@ bsp_err_t tpafe5160_init(void) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 首帧有效性自检(E-44):一次完整转换 + 读取,确认芯片真的在响应 RD */
|
||||
/* 首帧有效性自检:一次完整转换 + 读取,确认芯片真的在响应 RD */
|
||||
int16_t probe[TPAFE5160_CH_NUM];
|
||||
tpafe5160_start_conv();
|
||||
ret = tpafe5160_wait_busy(TPAFE5160_CONV_TIMEOUT_MS);
|
||||
@@ -171,7 +171,7 @@ uint8_t tpafe5160_is_busy(void) {
|
||||
* 限定条件:GPIO 已初始化
|
||||
* 函数说明:1. 启动转换并等待 BUSY 释放
|
||||
* 2. 连续8次拉低RD读取各通道数据
|
||||
* 3. 校验 FRSTDATA 在这一帧内发生跳变(E-44)
|
||||
* 3. 校验 FRSTDATA 在这一帧内发生跳变
|
||||
*/
|
||||
bsp_err_t tpafe5160_read_all(int16_t *buf) {
|
||||
bsp_err_t ret = BSP_OK;
|
||||
@@ -266,7 +266,7 @@ uint16_t tpafe5160_read_bus(void) {
|
||||
* t14 数据建立 ≤ 21ns → 数据在 RD 下降沿后 21ns 内有效
|
||||
* 5 个 NOP (~30ns) 覆盖建立时间
|
||||
*
|
||||
* E-44(数据有效性):FRSTDATA 由芯片主动驱动,板上 R24 4.7k 上拉(V0.1 网表)。
|
||||
* 数据有效性:FRSTDATA 由芯片主动驱动,板上 R24 4.7k 上拉(V0.1 网表)。
|
||||
* 手册 Parallel Data Read:FRSTDATA 随首个 RD 下降沿变高标记通道 1 可读,t26/t27
|
||||
* 给出"RD 下降沿 → FRSTDATA 高/低"两个跳变。判据刻意**不锁死具体是哪个 RD 边沿
|
||||
* 拉高/拉低**(本板未实测确认边沿次序),只要求"一帧读下来必须发生跳变":
|
||||
@@ -304,11 +304,11 @@ static bsp_err_t tpafe5160_read_channels(uint8_t count, int16_t *buf) {
|
||||
static int16_t s_buf_a[TPAFE5160_CH_NUM];
|
||||
static int16_t s_buf_b[TPAFE5160_CH_NUM];
|
||||
static volatile uint8_t s_buf_sel = 0; /* 0 = 写 B / 读 A, 1 = 写 A / 读 B */
|
||||
/* E-45:帧序号取代"就绪电平标志"。旧 s_ready 有三个写者,其中 start_conv_irq
|
||||
/* 帧序号取代"就绪电平标志"。旧 s_ready 有三个写者,其中 start_conv_irq
|
||||
* 在触发前清 0 —— 重触发这个动作本身就会抹掉一帧还没被消费的数据(高速采样
|
||||
* 系统性丢样,且无从发现)。序号只增不清,消费者比较序号即可 */
|
||||
static volatile uint32_t s_frame_seq = 0;
|
||||
/* E-44:FRSTDATA 无跳变帧计数。中断里只加计数(不打日志),由消费者/自检侧上报 */
|
||||
/* FRSTDATA 无跳变帧计数。中断里只加计数(不打日志),由消费者/自检侧上报 */
|
||||
static volatile uint16_t s_frstdata_err = 0;
|
||||
/* 消费者游标:只在任务上下文读写(snapshot 内部),中断不碰 */
|
||||
static uint32_t s_consumer_seq = 0;
|
||||
@@ -341,7 +341,7 @@ void tpafe5160_irq_disable(void) {
|
||||
* 返回值:无
|
||||
* 限定条件:已调用 tpafe5160_irq_enable()
|
||||
* 函数说明:产生 CONVST 脉冲,转换完成后由 EXTI 中断自动读取 8 通道数据。
|
||||
* E-45:这里**不再清就绪标志**——旧实现"触发前置 0"等于用重触发去丢帧
|
||||
* 这里**不再清就绪标志**——旧实现"触发前置 0"等于用重触发去丢帧
|
||||
*/
|
||||
void tpafe5160_start_conv_irq(void) {
|
||||
TPAFE5160_CONVST_PULSE();
|
||||
@@ -352,7 +352,7 @@ void tpafe5160_start_conv_irq(void) {
|
||||
* 入口参数:无
|
||||
* 返回值:uint32_t 帧序号(EXTI 每读完一帧 +1)
|
||||
* 限定条件:中断模式已启用
|
||||
* 函数说明:见 tpafe5160.h 同名声明的契约说明(E-45)
|
||||
* 函数说明:见 tpafe5160.h 同名声明的契约说明
|
||||
*/
|
||||
uint32_t tpafe5160_frame_seq(void) {
|
||||
return s_frame_seq;
|
||||
@@ -363,7 +363,7 @@ uint32_t tpafe5160_frame_seq(void) {
|
||||
* 入口参数:无
|
||||
* 返回值:uint16_t 计数
|
||||
* 限定条件:中断模式已启用
|
||||
* 函数说明:非 0 = 至少一帧的 8 个值不可信(E-44),消费者据此上报自检
|
||||
* 函数说明:非 0 = 至少一帧的 8 个值不可信,消费者据此上报自检
|
||||
*/
|
||||
uint16_t tpafe5160_frstdata_err(void) {
|
||||
return s_frstdata_err;
|
||||
@@ -375,7 +375,7 @@ uint16_t tpafe5160_frstdata_err(void) {
|
||||
* count - 拷贝通道数 uint8_t 1 - 8
|
||||
* 返回值:1 - 取到新帧,0 - 无新帧,-1 - 参数无效
|
||||
* 限定条件:**任务上下文**(内部 taskENTER_CRITICAL,中断里不可调用)
|
||||
* 函数说明:E-58——把"选缓冲 + 拷数据 + 记游标"收进一个临界区。旧 get_buf() 只给
|
||||
* 函数说明:把"选缓冲 + 拷数据 + 记游标"收进一个临界区。旧 get_buf() 只给
|
||||
* 指针、任务再逐通道拷,两步之间被 BUSY EXTI 抢占并跨过一帧周期就拷回
|
||||
* 两帧混合的数据(8 通道失去同一时刻性)且无任何错误指示
|
||||
*/
|
||||
@@ -422,11 +422,11 @@ void tpafe5160_exti_handler(uint16_t GPIO_Pin) {
|
||||
/* 连续读取8个通道(内含 FRSTDATA 有效性校验),约 0.5µs @ 168MHz */
|
||||
int ret = tpafe5160_read_channels(TPAFE5160_CH_NUM, p_wr);
|
||||
|
||||
/* 切换缓冲区并推进帧序号(E-45:序号只增不清,重触发不会抹掉未消费帧) */
|
||||
/* 切换缓冲区并推进帧序号(序号只增不清,重触发不会抹掉未消费帧) */
|
||||
s_buf_sel ^= 1u;
|
||||
s_frame_seq++;
|
||||
|
||||
/* E-44:中断里不打日志,只累计;消费者据 tpafe5160_frstdata_err() 上报自检 */
|
||||
/* 中断里不打日志,只累计;消费者据 tpafe5160_frstdata_err() 上报自检 */
|
||||
if (ret != BSP_OK && s_frstdata_err < 0xFFFFu) {
|
||||
s_frstdata_err++;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* 2026-07-17 王建锋 创建初始版本,参考 AD7606 并行驱动及 TPAFE5160 手册
|
||||
* 2026-07-17 王建锋 增加 EXTI 中断读取模式
|
||||
* 2026-09-20 王建锋 V0.1 引脚适配(引脚值随 main.h 宏,驱动逻辑不变)
|
||||
* 2026-10-10 王建锋 消费者接入前置修复(历史审计 E-44 / E-45 / E-58,属主文档已删除):
|
||||
* 2026-10-10 王建锋 消费者接入前置修复:
|
||||
* FRSTDATA 数据有效性校验 + 帧序号取代就绪电平标志 +
|
||||
* 原子快照 API;移除会撕裂的 get_buf/data_ready/clear_ready
|
||||
*/
|
||||
@@ -69,11 +69,11 @@ typedef enum {
|
||||
} tpafe5160_range_t;
|
||||
|
||||
/* 返回值定义 */
|
||||
/* 本模块的成败码已收编到 Drivers/BSP/bsp_err.h(2026-10-23,S-5 C1):
|
||||
/* 本模块的成败码已收编到 Drivers/BSP/bsp_err.h(2026-10-23,C1):
|
||||
* 旧 TPAFE5160_OK(0) → BSP_OK;旧 TPAFE5160_ERROR(-1) → BSP_ERR_PARAM(三处全是参数校验,
|
||||
* 数值也同为 -1,**行为零变化**);旧 TPAFE5160_BUSY_TIMEOUT(-2) → BSP_ERR_TIMEOUT,
|
||||
* 于是 BUSY 不释放终于变成跨模块可判定的"可重试";
|
||||
* 旧 TPAFE5160_FRSTDATA_ERR(-3) → BSP_ERR_NO_DEVICE——它就是 E-44 的"芯片没驱动 DB 总线",
|
||||
* 旧 TPAFE5160_FRSTDATA_ERR(-3) → BSP_ERR_NO_DEVICE——它就是"芯片没驱动 DB 总线",
|
||||
* 语义是**器件不在响应**,归到 NO_DEVICE 比留在私有 -3 更有用(且避开与 BSP_ERR_TIMEOUT 撞值)。
|
||||
* ⚠ 例外:**tpafe5160_snapshot() 不是成败 API**,它是 1=有新帧 / 0=无新帧 / -1=参数错 的
|
||||
* 三态**状态**返回(0 不是错误,是"这一拍没有新数据"),因此**不套 bsp_err_t**,
|
||||
@@ -136,11 +136,11 @@ uint8_t tpafe5160_is_busy(void);
|
||||
* 函数功能:读取全部8通道转换结果
|
||||
* 入口参数:buf - 8个int16_t的输出缓冲区 int16_t* 不为 NULL
|
||||
* 返回值:BSP_OK - 成功;BSP_ERR_TIMEOUT - BUSY 超时;BSP_ERR_NO_DEVICE - FRSTDATA 无跳变
|
||||
* (E-44:芯片没驱动 DB 总线,读回的是上拉残值,不可信)
|
||||
* (芯片没驱动 DB 总线,读回的是上拉残值,不可信)
|
||||
* 限定条件:GPIO 已初始化
|
||||
* 函数说明:1. 启动转换并等待 BUSY 释放
|
||||
* 2. 连续8次拉低RD读取各通道数据
|
||||
* 3. 校验 FRSTDATA 在这一帧内发生过跳变(= 芯片确实在驱动数据线,E-44)
|
||||
* 3. 校验 FRSTDATA 在这一帧内发生过跳变(= 芯片确实在驱动数据线)
|
||||
*/
|
||||
bsp_err_t tpafe5160_read_all(int16_t *buf);
|
||||
|
||||
@@ -207,7 +207,7 @@ void tpafe5160_start_conv_irq(void);
|
||||
* 入口参数:无
|
||||
* 返回值:uint32_t 帧序号,EXTI 每读完一帧 +1
|
||||
* 限定条件:中断模式已启用
|
||||
* 函数说明:取代旧的 data_ready/clear_ready **电平标志**(E-45)——电平标志有三个
|
||||
* 函数说明:取代旧的 data_ready/clear_ready **电平标志**——电平标志有三个
|
||||
* 写者,其中 start_conv_irq 在触发前清 0,于是"重触发"本身就会抹掉一帧
|
||||
* 还没被消费的数据(高速采样系统性丢样且无从发现)。序号只增不清,
|
||||
* 消费者比较 seq 即可,重触发不会丢
|
||||
@@ -220,7 +220,7 @@ uint32_t tpafe5160_frame_seq(void);
|
||||
* count - 拷贝通道数 uint8_t 1 - 8
|
||||
* 返回值:1 - 取到新帧,0 - 无新帧,BSP_ERR_PARAM(-1) - 参数无效(**三态状态返回,故意不套成败码**:0 表示"这一拍没有新数据",不是错误)
|
||||
* 限定条件:**任务上下文**调用(内部用 taskENTER_CRITICAL,不可在中断里调)
|
||||
* 函数说明:E-58——旧 get_buf() 只返回缓冲区指针,任务再逐通道拷;两步之间被 BUSY
|
||||
* 函数说明:旧 get_buf() 只返回缓冲区指针,任务再逐通道拷;两步之间被 BUSY
|
||||
* EXTI 抢占并跨过一帧周期,拷回的就是**两帧混合**的 8 通道数据(同一时刻
|
||||
* 的 8 路值互相错位),且没有任何错误指示。本函数把"选缓冲 + 拷数据 +
|
||||
* 记游标"收进一个临界区(只盖 16 字节拷贝),撕裂在设计上消除
|
||||
@@ -232,7 +232,7 @@ int tpafe5160_snapshot(int16_t *dst, uint8_t count);
|
||||
* 入口参数:无
|
||||
* 返回值:uint16_t 计数(中断里只加计数不打日志)
|
||||
* 限定条件:中断模式已启用
|
||||
* 函数说明:E-44——非 0 表示至少有一帧的 8 个值不可信;消费者据此上报自检
|
||||
* 函数说明:非 0 表示至少有一帧的 8 个值不可信;消费者据此上报自检
|
||||
*/
|
||||
uint16_t tpafe5160_frstdata_err(void);
|
||||
|
||||
|
||||
@@ -28,9 +28,9 @@
|
||||
* 描述符 init_cb(开页后调一次,页面模块重置运行态)
|
||||
* 2026-09-13 王建锋 cp_draw_cb 按区块拆为四个绘制子函数(cp_draw_deco/header/rows/footer),
|
||||
* 主函数仅编排(行数取一次供行窗口/页脚共用),行为零变化
|
||||
* 2026-10-15 王建锋 U1 设计令牌层:屏幕/骨架/行距/缓冲/1bpp 语义色字面量收进
|
||||
* 2026-10-15 王建锋 UI 设计令牌层:屏幕/骨架/行距/缓冲/1bpp 语义色字面量收进
|
||||
* ui_tokens.h(纯替换,像素逐位一致)
|
||||
* 2026-10-15 王建锋 U3 页面原型化:删 content_page_id_t 枚举与 s_defs[],open() 改收
|
||||
* 2026-10-15 王建锋 UI 页面原型化:删 content_page_id_t 枚举与 s_defs[],open() 改收
|
||||
* 描述符指针、s_open 变指针(NULL = 未打开);7 个页面头包含移交
|
||||
* ui_page_registry.c;日志页身份改打描述符 id(ASCII 页名,比原
|
||||
* id=%u 更可定位);绘制/按键/几何一律未动
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
* 是否过密码页/所输密码决定);描述符新增 edit_capable(页面
|
||||
* 是否支持编辑模式)+ 新 API ui_content_page_is_editable
|
||||
* (页面钩子据以决定编辑行为:edit_capable 且修改权限)
|
||||
* 2026-10-15 王建锋 U3 页面原型化:删 content_page_id_t 枚举与框架侧 s_defs[],
|
||||
* 2026-10-15 王建锋 UI 页面原型化:删 content_page_id_t 枚举与框架侧 s_defs[],
|
||||
* open() 改收描述符指针;节点→页面绑定移交给生成物
|
||||
* ui_page_registry.c(菜单树 #page= 注记为唯一真源),
|
||||
* 逻辑层手写 menu_content_page_for() 随之删除;
|
||||
|
||||
@@ -53,7 +53,7 @@ uint8_t ui_menu_tab_children(uint8_t node, uint8_t out[], uint8_t max);
|
||||
* 入口参数:node - 节点下标 uint8_t 0 - 表长-1
|
||||
* 返回值:true - 有子项(显示为菜单,带 ▶);false - 无子项(叶子,可进内容页)
|
||||
* 限定条件:纯查询,无副作用;node 越界返回 false
|
||||
* 函数说明:这是**谓词**(bool 合法),不是成败码——S-5 的 err-type 检查里白名单放行的形态。
|
||||
* 函数说明:这是**谓词**(bool 合法),不是成败码——err-type 检查里白名单放行的形态。
|
||||
*/
|
||||
bool ui_menu_tab_has_children(uint8_t node);
|
||||
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
* 2026-09-10 王建锋 改为双端共用:底层改用 net_* API + 平台后端;接收改为逐字节
|
||||
* 状态机(失步自动重同步);断开/网络重建后经 net_get_sock 判活
|
||||
* 并重建监听(修复 MCU 单连接模型断线后无法重连的隐患)
|
||||
* 2026-10-02 王建锋 E-04:remo_send 校验 net_send 返回值(原丢弃)——短写/失败
|
||||
* 2026-10-02 王建锋 remo_send 校验 net_send 返回值(原丢弃)——短写/失败
|
||||
* 告警,连续 3 次失败阻断推送,新连接/网络重建解除阻断
|
||||
* (MCU 单连接模型不得 net_close 数据 fd,会连监听一起毁掉)
|
||||
* 2026-10-10 王建锋 I-1 门控 + I-2 兜底(销项 N-10):accept/recv
|
||||
* 2026-10-10 王建锋 判活门控 + 兜底收帧:accept/recv
|
||||
* 前先用 net_can_accept()/net_can_read()(纯 RAM 读控制块)判
|
||||
* "有没有活",无活直接返回——台架常态(无客户端)从每 10 ms
|
||||
* 一次 RPC(100 msg/s,与 FTP 抢深度 8 的队列)降到 0 次。
|
||||
@@ -23,7 +23,7 @@
|
||||
* "RX 非空但 readable=0",故每 32 轮无条件 recv 一次(≈320 ms);
|
||||
* 门控放行时若监听控制块已消失则置 g_listen=-1 触发重建,
|
||||
* 避免"门控把端口永久不再接受新客户端"这一新卡死路径
|
||||
* 2026-10-12 王建锋 N-32(B10 根治 P1,设计文档 §2.3 不变量 II):accept 门控
|
||||
* 2026-10-12 王建锋 监听生命周期 P1(B10 根治,设计文档 §2.3 不变量 II):accept 门控
|
||||
* 由 net_can_accept()(只认 ESTABLISHED)改判
|
||||
* net_listener_armed()(LISTENING 或 CLOSED+auto_relisten)——
|
||||
* 旧门控在断连待重建窗口恒 0,:7003 永不进 net_accept,
|
||||
@@ -35,7 +35,7 @@
|
||||
* (accept / recv_nb / send / close / 重建三件套)返回点
|
||||
* 调用——风暴期单轮多往返串成 UI 心跳缺口(实测 bit4
|
||||
* 8 连击、uisn=154ms 仍在段内样本),往返本身不动
|
||||
* (语义不变,上界收口 = 登记簿 E-27/E-28 批 3),心跳
|
||||
* (语义不变,上界收口为登记簿批 3 事项),心跳
|
||||
* 在往返边界续命。钩子未注册 = 零行为变化(模拟器/黄金
|
||||
* 回归不注册)。判读与设计口径见
|
||||
* docs/UI设计/UI_设计架构.md §5.8
|
||||
@@ -51,7 +51,7 @@
|
||||
#include "test_config.h" /* TEST_LATENCY_PROBE(链路时延探针编译开关) */
|
||||
#include "net_latency_test.h" /* M3 探针:prod_cycle_mcu(LCDMEM 处理净成本) */
|
||||
|
||||
/* E-04(2026-10-02):发送短写/失败告警(MCU=控制台日志,模拟器=printf 桩) */
|
||||
/* (2026-10-02):发送短写/失败告警(MCU=控制台日志,模拟器=printf 桩) */
|
||||
#define DBG_TAG "[UI_NET_SINK]"
|
||||
#include "dbg_log.h"
|
||||
|
||||
@@ -77,11 +77,11 @@ static int g_listen = -1; /* 监听 Socket fd(未启动或已停止时
|
||||
static int g_client = -1; /* 当前客户端 Socket fd(无连接时为 -1) */
|
||||
static uint16_t g_port; /* 监听端口(网络重建 / 断线后重监听用) */
|
||||
static uint32_t g_gen; /* 建立监听时的网络代次号(变化 = 网络已重建) */
|
||||
static uint8_t s_send_fail_run; /* 连续发送失败计数(E-04:0 = 正常) */
|
||||
static uint8_t s_send_fail_run; /* 连续发送失败计数(0 = 正常) */
|
||||
static uint8_t s_sink_blocked; /* 推送阻断标志(1 = 停发帧,等客户端重连解除) */
|
||||
|
||||
/*
|
||||
* 兜底收帧节拍(门控失效保险,2026-10-10 I-2):
|
||||
* 兜底收帧节拍(门控失效保险,2026-10-10):
|
||||
* net_can_read() 的 readable 只由 RECV_OK 中断置位,而 TRAP-NET-17 的
|
||||
* net_reconcile_tick() 三类对账**不含**"芯片 RX 非空但 readable=0" →
|
||||
* 该中断一旦丢失,纯门控会把已到达的数据永久藏住(改前靠每轮 recv 内的
|
||||
@@ -170,7 +170,7 @@ static void put_u32(uint8_t *p, uint32_t v) {
|
||||
* 限定条件:g_tx 空间足够容纳 4+len+1 字节;g_client >= 0(已有连接)
|
||||
* 函数说明:帧格式 [TAG_DEVICE][CMD][LEN_H][LEN_LO][DATA][CRC];CRC 为 payload 异或;
|
||||
* 无连接时直接返回
|
||||
* E-04(2026-10-02):校验 net_send 返回值(原丢弃)——短写 = 客户端收到坏帧
|
||||
* (2026-10-02):校验 net_send 返回值(原丢弃)——短写 = 客户端收到坏帧
|
||||
* (CRC 不符 → 画面卡死黑屏,而设备侧日志全正常);连续 3 次失败 →
|
||||
* 停发:客户端察觉无帧自行重连,芯片侧 DISCONNECT/TIMEOUT 自动重开
|
||||
* 监听重建连接;MCU 单连接模型严禁 net_close 数据 fd(会连监听一起毁)
|
||||
@@ -516,10 +516,10 @@ int ui_net_sink_start(uint16_t port) {
|
||||
* 3. 无客户端时**先门控**(net_listener_armed,纯 RAM 读)再 accept,成功则复位状态机。
|
||||
* 门控判据 = "监听器还在服役"(LISTENING 或 CLOSED+auto_relisten)而非
|
||||
* "本轮必然有连接"——后者会让断连待重建窗口内永不进 net_accept,
|
||||
* 把 CONNECT 事件未收到的补 accept 探测永久挡在门外(N-32)
|
||||
* 把 CONNECT 事件未收到的补 accept 探测永久挡在门外(监听生命周期模块化)
|
||||
* 4. 有客户端时**先门控**(net_can_read)再非阻塞 recv 逐字节喂入状态机;
|
||||
* 门控判为"无数据"时仍每 RM_LIVENESS_DIV 轮无条件收一次(兜底)
|
||||
* 5. 对端关闭/真错误时关闭客户端。**不再自行重建监听**(N-32 不变量 II):
|
||||
* 5. 对端关闭/真错误时关闭客户端。**不再自行重建监听**(监听生命周期不变量 II):
|
||||
* recv 的 EOF/错误分支已触发 net 层 auto_relisten,另有对账④兜底;
|
||||
* 仅 g_listen 的 fd 真消失(net_get_sock 返 NULL)才置 -1 交回 2 重启
|
||||
* ⚠ **门控只消除"无谓的往返",不消除"往返本身无上界"**:一旦真有活要干
|
||||
@@ -543,7 +543,7 @@ void ui_net_sink_poll(void) {
|
||||
sink_beat(); /* F3:重建前的一对 close 往返结束 */
|
||||
g_client = -1;
|
||||
rm_parser_reset();
|
||||
s_send_fail_run = 0U; /* 网络重建:失败累计清零、解除推送阻断(E-04) */
|
||||
s_send_fail_run = 0U; /* 网络重建:失败累计清零、解除推送阻断 */
|
||||
s_sink_blocked = 0U;
|
||||
s_liveness_ctr = 0U; /* 网络重建:兜底节拍重新起算 */
|
||||
(void)ui_net_sink_start(g_port);
|
||||
@@ -556,7 +556,7 @@ void ui_net_sink_poll(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* 无客户端时尝试接受连接(N-32 P1 不变量 II:门控从 net_can_accept〔只认
|
||||
/* 无客户端时尝试接受连接(监听生命周期 P1 不变量 II:门控从 net_can_accept〔只认
|
||||
* ESTABLISHED〕换成 net_listener_armed〔LISTENING 或 CLOSED+auto_relisten〕)
|
||||
* 原因:MCU 单连接模型下断连后 fd 会停在 CLOSED 等 relisten,旧门控在该窗口
|
||||
* 内恒 0 → :7003 永不进 net_accept → net_lost_connect_probe 对该端口等于
|
||||
@@ -577,14 +577,14 @@ void ui_net_sink_poll(void) {
|
||||
if (c >= 0) {
|
||||
g_client = c;
|
||||
rm_parser_reset();
|
||||
s_send_fail_run = 0U; /* 新连接:失败累计清零、解除推送阻断(E-04) */
|
||||
s_send_fail_run = 0U; /* 新连接:失败累计清零、解除推送阻断 */
|
||||
s_sink_blocked = 0U;
|
||||
s_liveness_ctr = 0U; /* 新连接:兜底节拍重新起算 */
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* 有客户端时非阻塞收帧(I-1 门控 + I-2 兜底;DONTWAIT 已转正
|
||||
/* 有客户端时非阻塞收帧(判活门控 + 兜底节拍;DONTWAIT 已转正
|
||||
* 为具名 API net_recv_nb——uiTask 在 IWDG required_mask 内且有 10ms UI 推流
|
||||
* 周期职责,禁止无限阻塞 recv,非阻塞轮询是义务):
|
||||
* 无数据可读 → 多数轮次直接返回,省掉一次 recv 往返(该往返内部
|
||||
@@ -612,7 +612,7 @@ void ui_net_sink_poll(void) {
|
||||
}
|
||||
g_client = -1;
|
||||
rm_parser_reset();
|
||||
/* N-32(P1 不变量 II):重建**不再**由本处自行 bind_listen。
|
||||
/* 监听生命周期 P1 不变量 II:重建**不再**由本处自行 bind_listen。
|
||||
* ① net_recv_locked 的 EOF 分支已触发 auto_relisten(D10 非阻塞重试);
|
||||
* ② 对账④还会兜底补一次 relisten(TRAP-NET-17 实证事件面不是可靠唯一信源——
|
||||
* E14 复核:非芯片丢事件——两层不可互替)。
|
||||
@@ -625,7 +625,7 @@ void ui_net_sink_poll(void) {
|
||||
} else {
|
||||
/* n < 0:区分"暂无数据"(继续等待)与"真错误"(断开并视情况重建监听) */
|
||||
if (net_get_errno() != NET_ERR_WOULDBLOCK) {
|
||||
/* N-32(P1):加 `g_client != g_listen` 护栏,与上面 n==0 分支
|
||||
/* 监听生命周期 P1:加 `g_client != g_listen` 护栏,与上面 n==0 分支
|
||||
* 的 :552 一致——MCU 单连接模型下 g_client 可能就是 g_listen 本身,
|
||||
* 无护栏的 net_close 会直接关掉监听 fd(:563,与 :134 注释"严禁"
|
||||
* 自相矛盾),端口随 TRAP-NET-09 沉降窗短死。PC 模拟器多连接后端下
|
||||
@@ -636,7 +636,7 @@ void ui_net_sink_poll(void) {
|
||||
sink_beat(); /* F3:EOF/错误路径的 close 往返结束 */
|
||||
g_client = -1;
|
||||
rm_parser_reset();
|
||||
/* N-32(P1 不变量 II):同 EOF 分支——不再自行 bind_listen,
|
||||
/* 监听生命周期 P1 不变量 II:同 EOF 分支——不再自行 bind_listen,
|
||||
* 重建交回 net 层(recv 的错误分支同样会走 relisten)。仅 fd 真消失
|
||||
* 时置 -1 交回主循环走 start */
|
||||
if (net_get_sock(g_listen) == NULL) {
|
||||
|
||||
@@ -71,7 +71,7 @@ void ui_net_sink_poll(void);
|
||||
* 重建三件套)返回处调用钩子。动因:netTask 重建风暴期,单轮内多个
|
||||
* 往返串行排队,把宿主(uiTask,IWDG 必需位)的心跳间隔拖过 800ms
|
||||
* (2026-10-25 台架实测 bit4 单任务 8 连击窗、uisn=154ms 仍在段内);
|
||||
* 往返时长本身不改(上界收口 = 登记簿 E-27/E-28,批 3),但心跳在每个
|
||||
* 往返时长本身不改(上界收口为登记簿批 3 事项),但心跳在每个
|
||||
* 往返边界续命——单任务停摆判据(按位连击,docs/子系统设计/看门狗设计说明.md
|
||||
* §5.3)只应
|
||||
* 抓真挂死,不该抓「多个都回来了但各自偏慢的往返之和」。
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* 创建日期:2026-09-14
|
||||
* 修改记录:
|
||||
* v1.0 2026-09-14 王建锋 创建初始版本(设计见 docs/子系统设计/运行与自检记录设计说明.md §5.3)
|
||||
* v1.1 2026-10-20 王建锋 改用 ui_w_records 共享组件(W6 U2:合并两页重复实现)
|
||||
* v1.1 2026-10-20 王建锋 改用 ui_w_records 共享组件(W6:合并两页重复实现)
|
||||
* v1.2 2026-10-25 王建锋 记录 reader 注入(道B task-6):不再 include sys_log.h,
|
||||
* 数据经组件内注入的 ui_rec_reader_t 取;日志 ID 换
|
||||
* 不透明编号 UI_W_REC_LOG_RUN(映射在两端绑定处)
|
||||
@@ -37,7 +37,7 @@
|
||||
* 返回值:总行数 uint16_t
|
||||
*/
|
||||
/*
|
||||
* 记录页薄跳板:内容全部走 ui_w_records 共享组件(W6 U2)。
|
||||
* 记录页薄跳板:内容全部走 ui_w_records 共享组件(W6)。
|
||||
* 实例 s_rec 携带日志 ID 与**本实例自己的**读盘缓存——两页共用组件代码,
|
||||
* 但缓存不得共享,否则切页会命中上一记录号而显示另一页的陈旧行。
|
||||
*/
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* 创建日期:2026-09-14
|
||||
* 修改记录:
|
||||
* v1.0 2026-09-14 王建锋 创建初始版本(设计见 docs/子系统设计/运行与自检记录设计说明.md §5.4)
|
||||
* v1.1 2026-10-20 王建锋 改用 ui_w_records 共享组件(W6 U2:合并两页重复实现)
|
||||
* v1.1 2026-10-20 王建锋 改用 ui_w_records 共享组件(W6:合并两页重复实现)
|
||||
* v1.2 2026-10-25 王建锋 记录 reader 注入(道B task-6):不再 include sys_log.h,
|
||||
* 数据经组件内注入的 ui_rec_reader_t 取;日志 ID 换
|
||||
* 不透明编号 UI_W_REC_LOG_SELFTEST(映射在两端绑定处)
|
||||
@@ -37,7 +37,7 @@
|
||||
* 返回值:总行数 uint16_t
|
||||
*/
|
||||
/*
|
||||
* 记录页薄跳板:内容全部走 ui_w_records 共享组件(W6 U2)。
|
||||
* 记录页薄跳板:内容全部走 ui_w_records 共享组件(W6)。
|
||||
* 实例 s_rec 携带日志 ID 与**本实例自己的**读盘缓存——两页共用组件代码,
|
||||
* 但缓存不得共享,否则切页会命中上一记录号而显示另一页的陈旧行。
|
||||
*/
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-10-15
|
||||
* 修改记录:
|
||||
* v1.0 2026-10-15 王建锋 创建初始版本(U3:原三处逐字相同的定义合并到此单一来源)
|
||||
* v1.0 2026-10-15 王建锋 创建初始版本(原三处逐字相同的定义合并到此单一来源)
|
||||
*/
|
||||
|
||||
/* 头文件包含区 */
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-10-15
|
||||
* 修改记录:
|
||||
* v1.0 2026-10-15 王建锋 创建初始版本(U3:合并三处逐字重复的 flat 常量样式定义)
|
||||
* v1.0 2026-10-15 王建锋 创建初始版本(合并三处逐字重复的 flat 常量样式定义)
|
||||
*/
|
||||
#ifndef UI_STYLE_H
|
||||
#define UI_STYLE_H
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-10-15
|
||||
* 修改记录:
|
||||
* v1.0 2026-10-15 王建锋 创建初始版本(U1:收编散落各 UI 文件的布局/颜色/缓冲魔数,
|
||||
* v1.0 2026-10-15 王建锋 创建初始版本(收编散落各 UI 文件的布局/颜色/缓冲魔数,
|
||||
* 纯替换、零行为变化;像素与替换前逐位一致)
|
||||
*/
|
||||
#ifndef UI_TOKENS_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-10-20
|
||||
* 修改记录:
|
||||
* v1.0 2026-10-20 王建锋 创建(W6 U2)
|
||||
* v1.0 2026-10-20 王建锋 创建(W6)
|
||||
* v2.0 2026-10-25 王建锋 reader 注入(道B task-6):syslog_count/syslog_get_record
|
||||
* 直调改为 s_reader 函数表调用;未注入按空态渲染
|
||||
*/
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-10-20
|
||||
* 修改记录:
|
||||
* v1.0 2026-10-20 王建锋 创建(W6 U2:合并 ui_page_runlog / ui_page_selftest 的重复实现)
|
||||
* v1.0 2026-10-20 王建锋 创建(W6:合并 ui_page_runlog / ui_page_selftest 的重复实现)
|
||||
* v2.0 2026-10-25 王建锋 记录 reader 注入(道B task-6):删 #include "sys_log.h",
|
||||
* 改 ui_rec_reader_t 函数表 + ui_w_records_bind();
|
||||
* log_id 换不透明编号(UI_W_REC_LOG_*);缓冲容量宏本地化
|
||||
|
||||
Reference in New Issue
Block a user