/** * @file ch395f_reuse_bench.c * @brief relisten 沉降段原语化受阻的芯片级 Socket 复用时序台架(裸机,内核前运行,OS/net/FTP 全剥离) * @details 直接调用 ch395f_* 命令,循环执行受控时序矩阵(延迟/关闭次序/载荷/Socket 号), * 每步打印芯片状态与中断寄存器,定位"关→开→监听→连接"复用时序中 * 芯片行为的确切规律。配套主机脚本 test/host/ch395f_reuse_host.py。 * 定案结论与实验矩阵演进 → CH395F_Trap_Records.md TRAP-NET-20。 * * 存档状态:本文件在主分支**不注册编译**(未加入 uvprojx),仅作实验工具存档; * 运行方法:在实验分支(如 n30-chip-bench)把本 .c 注册进 uvprojx Test 组、 * Src/main.c 的 USER CODE 2 区在 app_main_init() 之前调 ch395f_reuse_bench() * (内核前裸机循环,永不返回,断电退出),烧录后跑主机脚本对照芯片日志。 * 早先那轮定案矩阵(对照 vs "CONNECT 事件未收到捕获自 accept"修复组)保留在 s_vars[]/ * bench_round(),由 s_bench_legacy=0 停泊不运行。 * * 驱动原语前置实验:同一固件合并跑 E2/E3/E4—— * E2 = GET_SOCKET_STATUS 单次 SPI 成本(DWT 周期计数)+ TCP_LISTEN 可见延迟矩阵; * E3 = GET_CMD_STATUS 判别力矩阵(OPEN/LISTEN/CLOSE/SET_SOUR_PORT/SET_PROTO_TYPE, * 含"命令未发时"对照读,复核 Trap 记录的 SET 类无判别力 + 陈旧 BUSY 残留); * E4 = sock_reset 内部顺序 A/B/C 变体 ×10 轮(轮间换端口)+ 立即复连载荷完整性自证 * (配套 test/host/ch395f_reuse_host.py --mode e4)。 * 判据与结果锚点 → docs/网络/网络自愈架构设计.md §5.2 E2/E3/E4(过程全文已归档,见该文档 §12)。 * * close_mode:0=主机先关(芯片等 DISCONNECT);1=芯片先关;2=无数据连上即关 * verify:0=无修复;1=listen 后确认 LISTEN 重试;2=缓冲重分配; * 3=幽灵耐心等;4=等 CONNECT 期轮询状态+自 accept(定案修复) */ #include "ch395f_reuse_bench.h" #if N30_CHIP_BENCH #include "ch395f.h" #include "dbg_log.h" #include "main.h" #include "stm32f4xx_hal.h" /* 变体表:{sock, close 后复开延迟 ms, TX 字节数, close_mode, verify_listen} */ typedef struct { uint8_t sock; uint16_t delay_ms; uint16_t tx_len; uint8_t close_mode; uint8_t verify; /* 1 = listen 后确认 TCP==0x01,否则 close 重试(修复假设) */ } bench_var_t; static const bench_var_t s_vars[] = { { 3, 0, 100, 0, 0 }, /* 0ms 对照 */ { 3, 300, 100, 0, 0 }, /* 300ms 对照 */ { 3, 800, 2000, 0, 0 }, /* 2KB 对照 */ { 3, 0, 100, 0, 4 }, /* 0ms + 事件未收捕获自accept */ { 3, 300, 100, 0, 4 }, /* 300ms + 事件未收捕获 */ { 3, 800, 2000, 0, 4 }, /* 2KB + 事件未收捕获 */ }; #define BENCH_N_VARS (sizeof(s_vars) / sizeof(s_vars[0])) #define BENCH_PORT(i) (5000U + (uint16_t)(i)) /* TX 图案缓冲(静态,SRAM;2KB = 最大变体载荷) */ static uint8_t s_tx_pat[2048]; /* RX 排空缓冲 */ static uint8_t s_rx_buf[2048]; /* * 函数功能:轮询本 Socket 中断(读全局→读本 Socket,读即清) * 入口参数:sock - Socket 号 uint8_t * timeout - 超时 ms uint32_t * out_bits - 输出最后一次读到的 SINT 位 uint8_t * * 返回值:1=拿到中断 0=超时 int */ static int bench_wait_sock_int(uint8_t sock, uint32_t timeout, uint8_t *out_bits) { uint32_t t0 = HAL_GetTick(); while ((uint32_t)(HAL_GetTick() - t0) < timeout) { /* 直读本 Socket SINT(读即清)。不用全局寄存器门控:它读即清,未配对 * 读取会吞事件;且门控观察分不清"芯片未锁存"与"全局位被读清" * (TRAP-NET-20 观察混淆源)。唯一读者 = net_poll(唯一读者红线(docs/网络/网络自愈架构设计.md §7 I7))。 */ uint8_t si = ch395f_get_sock_int_status(sock); if (si != 0U) { if (out_bits != 0) { *out_bits = si; } return 1; } HAL_Delay(10); } return 0; } /* 打印芯片两字节状态(Socket 态 / TCP 态) */ static void bench_log_state(const char *tag, uint8_t sock) { uint8_t st[2] = { 0, 0 }; ch395f_get_socket_status(sock, st); DBG_INFO("BENCH %s sock%u st=0x%02X/0x%02X t=%u", tag, (unsigned)sock, st[0], st[1], (unsigned)HAL_GetTick()); } /* 芯片级初始化(复刻 net_init 序列,剥离全部内核 API) */ static int bench_chip_init(void) { if (ch395f_check_exist() != CH395F_STATUS_OK) { DBG_ERROR("BENCH chip not found"); return -1; } ch395f_reset(); /* 等 PHY link(TRAP-NET-09:link up 前 open 必失败;B9 修正:判据是 != DISCONN, * 旧写法 !=0 对 01H=DISCONN 也成立) */ for (int i = 0; i < 100; i++) { if (ch395f_get_phy_status() != CH395F_PHY_DISCONN) { break; } HAL_Delay(100); } /* bit3=1 SOCKET_CLOSE;bit0 保留必须为 0(§5.52)→ 与生产 net_init 同构 */ ch395f_set_fun_para(0x08); ch395f_set_tcp_mss(CH395F_TCP_MSS); ch395f_set_retrans_count(3); ch395f_set_retrans_period(200); ch395f_set_keepalive_idle(60000); ch395f_set_keepalive_intvl(5000); ch395f_set_keepalive_cnt(3); /* 静态 IP(与生产一致) */ { uint8_t ip[4] = { 192, 168, 1, 100 }; uint8_t gw[4] = { 192, 168, 1, 1 }; uint8_t msk[4] = { 255, 255, 255, 0 }; ch395f_set_ip_addr(ip); ch395f_set_gwip_addr(gw); ch395f_set_mask_addr(msk); } if (ch395f_init() != CH395F_STATUS_OK) { DBG_ERROR("BENCH ch395f_init failed"); return -1; } /* 8 Socket 缓冲布局(与生产一致) */ for (int i = 7; i >= 0; i--) { uint8_t recv_start = (uint8_t)(i * 6); ch395f_set_send_buf((uint8_t)i, (uint8_t)(recv_start + 4), 2); ch395f_set_recv_buf((uint8_t)i, recv_start, 4); } ch395f_ping_enable(1); return 0; } /* 单轮实验 */ static void bench_round(unsigned idx) { const bench_var_t *v = &s_vars[idx]; uint8_t sock = v->sock; uint16_t port = BENCH_PORT(idx); uint8_t si = 0; /* 幽灵等待期已见 CONNECT 的标志(跳过后续 CONNECT 等待) */ int pre_connected = 0; DBG_INFO("BENCH === r%u sock%u port%u delay%u tx%u mode%u t=%u", idx, (unsigned)sock, (unsigned)port, (unsigned)v->delay_ms, (unsigned)v->tx_len, (unsigned)v->close_mode, (unsigned)HAL_GetTick()); /* 1. open + listen(TRAP-NET-09:close 后需延时重开,失败重试 ×3) */ ch395f_set_proto_type(sock, CH395F_PROTO_TYPE_TCP); ch395f_set_sour_port(sock, port); uint8_t ost = CH395F_ERR_SUCCESS; for (int open_try = 0; open_try < 3; open_try++) { ost = ch395f_open_socket(sock); if (ost == CH395F_ERR_SUCCESS) { break; } DBG_INFO("BENCH open retry%d err=0x%02X t=%u", open_try, ost, (unsigned)HAL_GetTick()); ch395f_close_socket(sock); HAL_Delay(500); } if (ost != CH395F_ERR_SUCCESS) { DBG_ERROR("BENCH open fail 0x%02X", ost); return; } /* 排事件在 LISTEN **之前**(对齐生产 listen 路径 E14 改法:post-listen 排事件 * 会吞掉快速到达的 CONNECT——上一版矩阵 3/48 被本探针现场抓获,现已根除该 * 自伤形态;本探针保留,drain 若仍见 CONNECT 即回归信号)。 * 逐 Socket SINT 读(读即清,不读全局——唯一读者 = net_poll,唯一读者红线) */ for (int j = 0; j < 8; j++) { uint8_t dj = ch395f_get_sock_int_status((uint8_t)j); if (dj != 0U) { DBG_INFO("BENCH drain-int sock%u=0x%02X t=%u", (unsigned)j, dj, (unsigned)HAL_GetTick()); } } uint8_t lst = ch395f_tcp_listen(sock); if (lst != CH395F_ERR_SUCCESS) { DBG_ERROR("BENCH listen fail 0x%02X", lst); ch395f_close_socket(sock); return; } /* 缓冲重分配变体:listen 后重设收发缓冲(隔离"缓冲管理残留"假设) */ if (v->verify == 2U) { uint8_t recv_start = (uint8_t)(sock * 6); ch395f_clear_recv_buf(sock); ch395f_set_send_buf(sock, (uint8_t)(recv_start + 4), 2); ch395f_set_recv_buf(sock, recv_start, 4); DBG_INFO("BENCH realloc done sock%u t=%u", (unsigned)sock, (unsigned)HAL_GetTick()); } bench_log_state("post-listen", sock); /* 修复假设验证:listen 后 TCP 态必须真正 == 0x01(LISTEN); * mode1:close 快速重试;mode3:耐心等幽灵消退(5s,每 100ms 复查), * 期间幽灵→LISTEN 转变会补发 CONNECT 中断则直接放行 */ if (v->verify == 1U || v->verify == 3U) { uint32_t budget = (v->verify == 3U) ? 5000U : 1000U; int att_max = (v->verify == 3U) ? 2 : 4; for (int att = 0; att < att_max; att++) { uint8_t st[2] = { 0, 0 }; uint32_t tw = HAL_GetTick(); int connect_fired = 0; /* 等 TCP 进 LISTEN(幽灵消退)或 CONNECT 中断补发(直读本 Socket SINT) */ while ((uint32_t)(HAL_GetTick() - tw) < budget) { uint8_t si = ch395f_get_sock_int_status(sock); if ((si & CH395F_SINT_STAT_CONNECT) != 0U) { connect_fired = 1; DBG_INFO("BENCH verify CONNECT during ghost-wait att%d t=%u", att, (unsigned)HAL_GetTick()); break; } ch395f_get_socket_status(sock, st); if (st[1] == 0x01U) { break; } HAL_Delay(100); } DBG_INFO("BENCH verify att%d st=0x%02X/0x%02X cf=%d t=%u", att, st[0], st[1], connect_fired, (unsigned)HAL_GetTick()); if (connect_fired) { /* 幽灵期主机已连上:跳过 CONNECT 等待直接进流程 */ pre_connected = 1; break; } if (st[1] == 0x01U) { break; } /* 幽灵未消:close → 50ms → 重新 open+listen(mode3 只试一次) */ ch395f_close_socket(sock); HAL_Delay(50); ch395f_open_socket(sock); ch395f_tcp_listen(sock); for (int j = 0; j < 8; j++) { (void)ch395f_get_sock_int_status((uint8_t)j); } } } /* 2. 等 CONNECT(10s;幽灵等待期已见 CONNECT 则跳过) * v6 关键探针:等待期每 500ms 读芯片状态;若已 ESTABLISHED(0x04) * 说明握手完成但 CONNECT 事件未收到 → 补做 accept(对账②模拟)。 * E14 复核(2026-10-14,48 轮):事件从未被芯片丢失——"未收到"全部 * 是 drain 读清消费(见 drain-int)或竞态(见 CONNECT-in-SINT) */ int got = pre_connected; uint32_t t0 = HAL_GetTick(); while (!got && (uint32_t)(HAL_GetTick() - t0) < 10000U) { if (bench_wait_sock_int(sock, 100, &si)) { if ((si & CH395F_SINT_STAT_CONNECT) != 0U) { got = 1; break; } DBG_INFO("BENCH unexpected int=0x%02X while wait", si); } if (v->verify == 4U) { uint8_t st[2] = { 0, 0 }; ch395f_get_socket_status(sock, st); if ((uint32_t)(HAL_GetTick() - t0) % 1000U < 110U) { DBG_INFO("BENCH wait-state st=0x%02X/0x%02X t=%u", st[0], st[1], (unsigned)HAL_GetTick()); } if (st[1] == 0x04U) { /* 丢中断复核实验:宣布"未收到"之前补读 SINT ×3(10ms 间隔)—— * 若 CONNECT 在锁存,这是竞态不是丢失 */ int sint_seen = 0; for (int rr = 0; rr < 3; rr++) { if ((ch395f_get_sock_int_status(sock) & CH395F_SINT_STAT_CONNECT) != 0U) { sint_seen = 1; break; } HAL_Delay(10); } if (sint_seen != 0) { DBG_INFO("BENCH CONNECT-in-SINT at state-04 (race, NOT lost) t=%u", (unsigned)HAL_GetTick()); } else { /* E14 定案:本形态若上方有 drain-int 0x08,事件是被 drain 消费 * (非芯片丢失);无 drain-int 才是真·未锁存(48 轮矩阵未出现) */ DBG_INFO("BENCH NO-CONNECT-EVENT at state-04, SINT empty x3 (check drain-int above) t=%u", (unsigned)HAL_GetTick()); } got = 1; break; } } } if (!got) { /* 丢中断复核实验:对照变体 10s 内 SINT 每 10ms 读一次从未见 CONNECT—— * 此刻读状态+对端端口归类:0x04=芯片未锁存(实锤);0x01=主机未连(同步问题) */ uint8_t st[2] = { 0, 0 }; uint8_t rem[6] = { 0 }; ch395f_get_socket_status(sock, st); ch395f_get_remot_ipp(sock, rem); DBG_ERROR("BENCH no CONNECT within 10s: st=0x%02X/0x%02X rport=%u t=%u", st[0], st[1], (unsigned)(rem[4] | (rem[5] << 8)), (unsigned)HAL_GetTick()); ch395f_close_socket(sock); HAL_Delay(v->delay_ms); return; } bench_log_state("post-accept", sock); /* 对端信息 + RX 残渣检查(旧连接残留的直接证据) */ { uint8_t rem[6] = { 0 }; ch395f_get_remot_ipp(sock, rem); uint16_t rl = ch395f_get_recv_len(sock); DBG_INFO("BENCH remote port=%u recv_len=%u", (unsigned)(rem[4] | (rem[5] << 8)), (unsigned)rl); if (rl > 0U) { uint16_t n = (rl > 2048U) ? 2048U : rl; ch395f_read_recv_buf(sock, s_rx_buf, n); DBG_INFO("BENCH drained %u residue bytes", (unsigned)n); } } /* 3. TX 探针(1KB 分块,TRAP-NET-16) */ if (v->tx_len > 0U) { uint16_t sent = 0; while (sent < v->tx_len) { uint16_t chunk = (uint16_t)(v->tx_len - sent); if (chunk > 1024U) { chunk = 1024U; } ch395f_write_send_buf(sock, &s_tx_pat[sent], chunk); sent += chunk; /* 等 SENBUF_FREE(500ms) */ if (sent < v->tx_len) { uint32_t tw = HAL_GetTick(); while ((uint32_t)(HAL_GetTick() - tw) < 500U) { if (bench_wait_sock_int(sock, 50, &si)) { if ((si & CH395F_SINT_STAT_SENBUF_FREE) != 0U) { break; } } } } } DBG_INFO("BENCH tx %u written t=%u", (unsigned)v->tx_len, (unsigned)HAL_GetTick()); /* 连接存活观察窗:500ms 内每 50ms 记状态+中断(抓"秒杀";直读 SINT) */ for (int k = 0; k < 10; k++) { si = ch395f_get_sock_int_status(sock); if (si != 0U) { DBG_INFO("BENCH int during window=0x%02X t=%u", si, (unsigned)HAL_GetTick()); } HAL_Delay(50); bench_log_state("window", sock); } } /* 4. 关闭次序 */ if (v->close_mode == 1U) { /* 芯片先关 */ HAL_Delay(300); ch395f_close_socket(sock); DBG_INFO("BENCH chip closed first t=%u", (unsigned)HAL_GetTick()); } else { /* 等主机关(DISCONNECT 事件,5s) */ uint32_t tw = HAL_GetTick(); int disc = 0; while ((uint32_t)(HAL_GetTick() - tw) < 5000U) { if (bench_wait_sock_int(sock, 100, &si)) { if ((si & (CH395F_SINT_STAT_DISCONNECT | CH395F_SINT_STAT_SOCK_TIMEOUT)) != 0U) { disc = 1; break; } } } DBG_INFO("BENCH host-close seen=%d t=%u", disc, (unsigned)HAL_GetTick()); ch395f_close_socket(sock); } /* 5. 关闭后拆链观察:1s 内每 50ms 记状态 + 中断(TRAP-NET-12 滞后中断取证;直读 SINT) */ for (int k = 0; k < 20; k++) { uint8_t late = ch395f_get_sock_int_status(sock); if (late != 0U) { DBG_INFO("BENCH late-int=0x%02X t=%u", late, (unsigned)HAL_GetTick()); } if ((k % 4) == 0) { bench_log_state("post-close", sock); } HAL_Delay(50); } /* 6. 受控延迟后进入下一轮 */ HAL_Delay(v->delay_ms); } /* ===================================================================== * 驱动原语前置实验区:E2 / E3 / E4 一次固件合并跑 * ===================================================================== */ /* 早先那轮定案矩阵的停泊开关:0 = 不运行(保留代码备查,勿删) */ static const int s_bench_legacy = 0; /* --- DWT 周期计数器:168 MHz,1 cycle ~= 5.95 ns(不依赖 HAL 时基/中断) --- */ static void bench_dwt_enable(void) { CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CYCCNT = 0U; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; } static uint32_t bench_cyc(void) { return DWT->CYCCNT; } /* cycles -> us(1 位小数,纯整数运算:MicroLIB 不支持 %f) */ static void bench_log_cyc(const char *tag, uint32_t cyc) { DBG_INFO("BENCH %s=%lu.%luus (%lucyc)", tag, (unsigned long)(cyc / 168U), (unsigned long)(((cyc % 168U) * 10U) / 168U), (unsigned long)cyc); } /* --- 裸命令下发:绕过驱动 poll_cmd_status(E2/E3 要观察命令自身状态轨迹)。 * CS 包裹与驱动内部 ch395f_spi_begin/end 完全同构(该二函数为 static 未导出) --- */ static void bench_spi_begin(void) { HAL_GPIO_WritePin(CH395_SCS_GPIO_Port, CH395_SCS_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(CH395_SCS_GPIO_Port, CH395_SCS_Pin, GPIO_PIN_RESET); } static void bench_spi_end(void) { HAL_GPIO_WritePin(CH395_SCS_GPIO_Port, CH395_SCS_Pin, GPIO_PIN_SET); } static void bench_raw_cmd(uint8_t cmd, uint8_t sock, const uint8_t *args, uint8_t nargs) { bench_spi_begin(); (void)ch395f_write_cmd(cmd); (void)ch395f_write_data(sock); for (uint8_t i = 0U; i < nargs; i++) { (void)ch395f_write_data(args[i]); } bench_spi_end(); } /* 等 Socket byte0 回 00H(SOCKET_CLOSED);返回等待耗时 ms,-1=超时 */ static int bench_wait_closed(uint8_t sock, uint32_t timeout_ms) { uint32_t t0 = HAL_GetTick(); uint8_t st[2] = { 0, 0 }; for (;;) { ch395f_get_socket_status(sock, st); if (st[0] == CH395F_SOCKET_CLOSED) { return (int)(HAL_GetTick() - t0); } if ((uint32_t)(HAL_GetTick() - t0) >= timeout_ms) { return -1; } HAL_Delay(5); } } /* 排空本 Socket 事件:直读 SINT(读即清),连续 2 轮(20ms 节奏)无新位即停; * 返回排空期间见过的 SINT 位 OR(E8 M5 drain-until-quiescent 的 bench 版)。 * 不读全局寄存器——读即清,唯一读者 = net_poll(唯一读者红线(docs/网络/网络自愈架构设计.md §7 I7)) */ static uint8_t bench_drain_events(uint8_t sock, uint32_t max_ms) { uint32_t t0 = HAL_GetTick(); uint8_t seen = 0U; int quiet = 0; while ((uint32_t)(HAL_GetTick() - t0) < max_ms) { uint8_t si = ch395f_get_sock_int_status(sock); if (si != 0U) { seen |= si; quiet = 0; } else if (++quiet >= 2) { break; } HAL_Delay(20); } return seen; } /* 读空 RX(GET_RECV_LEN -> read_recv_buf 直到长度 0),返回总字节数 */ static uint32_t bench_drain_rx(uint8_t sock) { uint32_t total = 0U; for (;;) { uint16_t rl = ch395f_get_recv_len(sock); if (rl == 0U) { break; } uint16_t n = (rl > 2048U) ? 2048U : rl; ch395f_read_recv_buf(sock, s_rx_buf, n); total += n; if (total > 65535U) { break; } } return total; } /* 让命令落定:>=2ms 节奏轮询 GET_CMD_STATUS 直到非 BUSY;返回终值 */ static uint8_t bench_cmd_settle(uint32_t max_ms) { uint32_t t0 = HAL_GetTick(); uint8_t s; do { HAL_Delay(2); s = ch395f_get_cmd_status(); } while (s == CH395F_ERR_BUSY && (uint32_t)(HAL_GetTick() - t0) < max_ms); return s; } /* ------------------------- E2:状态回读成本 + LISTEN 可见延迟 ------------------------- */ static void bench_e2(void) { static const uint16_t grid_ms[4] = { 0U, 10U, 50U, 100U }; uint8_t st[2] = { 0, 0 }; uint32_t min = 0xFFFFFFFFUL, max = 0U, sum = 0U; DBG_INFO("BENCH E2 ===== GET_SOCKET_STATUS cost + LISTEN visibility ====="); /* 1) 单次回读成本 N=1000(socket 空闲态,与生产 net_poll 刷新同形) */ for (uint32_t i = 0U; i < 1000U; i++) { uint32_t c0 = bench_cyc(); ch395f_get_socket_status(3U, st); uint32_t d = bench_cyc() - c0; if (d < min) { min = d; } if (d > max) { max = d; } sum += d; } bench_log_cyc("E2 gs_min", min); bench_log_cyc("E2 gs_avg", sum / 1000U); bench_log_cyc("E2 gs_max", max); /* 2) LISTEN 可见性矩阵:裸 TCP_LISTEN(不 poll 命令态)后 +0/10/50/100ms 回读; * 100ms 仍不可见则 10ms 节奏续查到 1000ms,记录首次观察到 TCP=01H 的延迟 */ for (unsigned r = 0U; r < 12U; r++) { uint16_t port = (uint16_t)(5200U + r); int grid[4] = { 0, 0, 0, 0 }; int first_ms = -1; (void)ch395f_close_socket(3U); (void)bench_wait_closed(3U, 2000U); ch395f_set_proto_type(3U, CH395F_PROTO_TYPE_TCP); ch395f_set_sour_port(3U, port); if (ch395f_open_socket(3U) != CH395F_ERR_SUCCESS) { DBG_ERROR("BENCH E2 v2 r%u open fail", r); continue; } uint32_t t0 = HAL_GetTick(); bench_raw_cmd(CH395F_CMD_TCP_LISTEN_SN, 3U, 0, 0U); for (int g = 0; g < 4; g++) { while ((uint32_t)(HAL_GetTick() - t0) < grid_ms[g]) { } ch395f_get_socket_status(3U, st); if (st[1] == CH395F_TCP_LISTEN) { grid[g] = 1; if (first_ms < 0) { first_ms = (int)(HAL_GetTick() - t0); } } } while (first_ms < 0 && (uint32_t)(HAL_GetTick() - t0) < 1000U) { HAL_Delay(10); ch395f_get_socket_status(3U, st); if (st[1] == CH395F_TCP_LISTEN) { first_ms = (int)(HAL_GetTick() - t0); } } DBG_INFO("BENCH E2 listen r%u port%u grid=%d%d%d%d first=%dms st=0x%02X/0x%02X", r, (unsigned)port, grid[0], grid[1], grid[2], grid[3], first_ms, st[0], st[1]); (void)bench_cmd_settle(2000U); (void)ch395f_close_socket(3U); (void)bench_wait_closed(3U, 2000U); } } /* ------------------------- E3:GET_CMD_STATUS 判别力矩阵 ------------------------- */ static void bench_e3_one(const char *name, uint8_t cmd, uint8_t sock, uint16_t port0, int pre_open, int pre_listen, const uint8_t *args, uint8_t nargs) { for (int r = 0; r < 5; r++) { uint16_t port = (uint16_t)(port0 + (uint16_t)r); uint8_t largs[2]; const uint8_t *pa = args; uint8_t n = nargs; (void)ch395f_close_socket(sock); (void)bench_wait_closed(sock, 2000U); ch395f_set_proto_type(sock, CH395F_PROTO_TYPE_TCP); ch395f_set_sour_port(sock, port); if (pre_open) { if (ch395f_open_socket(sock) != CH395F_ERR_SUCCESS) { DBG_ERROR("BENCH E3 %s r%d pre-open fail", name, r); continue; } if (pre_listen) { if (ch395f_tcp_listen(sock) != CH395F_ERR_SUCCESS) { DBG_ERROR("BENCH E3 %s r%d pre-listen fail", name, r); continue; } } } /* 对照读:命令未发时的残留状态(Trap 记录:陈旧 BUSY 残留即在此现形) */ uint8_t pre = ch395f_get_cmd_status(); if (cmd == CH395F_CMD_SET_SOUR_PORT_SN) { largs[0] = (uint8_t)(port & 0xFFU); largs[1] = (uint8_t)(port >> 8); pa = largs; n = 2U; } uint32_t t0 = HAL_GetTick(); bench_raw_cmd(cmd, sock, pa, n); int busy_seen = 0, polls = 0, done_ms = -1; uint8_t firstv = 0xFFU; HAL_Delay(2); /* 手册 §9.2.1:发命令后 >=2ms 才发首个 GET_CMD_STATUS */ while ((uint32_t)(HAL_GetTick() - t0) < 2000U) { uint8_t s = ch395f_get_cmd_status(); polls++; if (s == CH395F_ERR_BUSY) { busy_seen = 1; HAL_Delay(1); continue; } firstv = s; done_ms = (int)(HAL_GetTick() - t0); break; } DBG_INFO("BENCH E3 %s r%d pre=0x%02X busy=%d first=0x%02X done=%dms polls=%d", name, r, pre, busy_seen, firstv, done_ms, polls); (void)bench_cmd_settle(1000U); (void)ch395f_close_socket(sock); (void)bench_wait_closed(sock, 2000U); } } static void bench_e3(void) { static const uint8_t proto_tcp = CH395F_PROTO_TYPE_TCP; DBG_INFO("BENCH E3 ===== GET_CMD_STATUS discriminative matrix ====="); bench_e3_one("OPEN", CH395F_CMD_OPEN_SOCKET_SN, 3U, 5300U, 0, 0, 0, 0U); bench_e3_one("LISTEN", CH395F_CMD_TCP_LISTEN_SN, 3U, 5310U, 1, 0, 0, 0U); bench_e3_one("CLOSE", CH395F_CMD_CLOSE_SOCKET_SN, 3U, 5320U, 1, 1, 0, 0U); bench_e3_one("SET_SOUR_PORT", CH395F_CMD_SET_SOUR_PORT_SN, 3U, 5330U, 0, 0, 0, 0U); bench_e3_one("SET_PROTO_TYPE", CH395F_CMD_SET_PROTO_TYPE_SN, 3U, 5340U, 0, 0, &proto_tcp, 1U); } /* ------------------------- E4:sock_reset 内部顺序 A/B/C ------------------------- * A:读空 RX -> CLOSE -> 排空本 socket 事件 -> 轮询等 byte0=00H * B:CLEAR_RECV_BUF -> CLOSE -> 排空事件 -> 等 CLOSED * C:什么都不做 -> CLOSE -> 等 CLOSED * 每轮先"污染会话"(主机连上发 3000B 后 RST,TRAP-NET-18 形态),复位后立即 * open+listen,主机立即上传 4096B 图案载荷;芯片侧按图案自证完整性 * (PASS 口径 = 消费者在 DISCONNECT/TIM_OUT 前实际读到的字节数与图案)。 */ #define E4_SOCK 3U #define E4_BASE_PORT 5100U #define E4_ROUNDS 10U #define E4_PAYLOAD 4096U static uint8_t s_e4_acc[8192]; static uint8_t e4_seed(unsigned rg) { return (uint8_t)(rg * 97U + 13U); } /* 污染阶段收尾:等芯片 DISCONNECT/TIM_OUT(RST 中止的死亡事件),1=见到 */ static int bench_e4_wait_death(uint8_t sock, uint32_t timeout_ms, uint8_t *out_bits) { uint32_t t0 = HAL_GetTick(); while ((uint32_t)(HAL_GetTick() - t0) < timeout_ms) { uint8_t si = ch395f_get_sock_int_status(sock); if ((si & (CH395F_SINT_STAT_DISCONNECT | CH395F_SINT_STAT_SOCK_TIMEOUT)) != 0U) { if (out_bits != 0) { *out_bits = si; } return 1; } HAL_Delay(10); } return 0; } static void bench_e4_round(unsigned rg, uint8_t variant) { uint16_t port = (uint16_t)(E4_BASE_PORT + rg); uint8_t si = 0U; uint32_t rx_drained = 0U; int closed_ms; DBG_INFO("BENCH E4 rg%u var=%c port%u t=%u", rg, (char)('A' + variant), (unsigned)port, (unsigned)HAL_GetTick()); /* 轮前统一清洁(所有变体同起点) */ (void)ch395f_close_socket(E4_SOCK); (void)bench_wait_closed(E4_SOCK, 2000U); (void)bench_drain_events(E4_SOCK, 300U); ch395f_set_proto_type(E4_SOCK, CH395F_PROTO_TYPE_TCP); ch395f_set_sour_port(E4_SOCK, port); if (ch395f_open_socket(E4_SOCK) != CH395F_ERR_SUCCESS) { DBG_ERROR("BENCH E4 rg%u open fail", rg); return; } if (ch395f_tcp_listen(E4_SOCK) != CH395F_ERR_SUCCESS) { DBG_ERROR("BENCH E4 rg%u listen fail", rg); (void)ch395f_close_socket(E4_SOCK); return; } /* 污染会话:主机 connect -> 发 3000B -> RST;芯片侧只等死亡事件(不读 RX, * 残渣留给变体处置——A 的排空 / B 的 CLEAR / C 的什么都不做 正是被测对象) */ if (!bench_e4_wait_death(E4_SOCK, 15000U, &si)) { DBG_ERROR("BENCH E4 rg%u contam: no death event (host not synced?)", rg); (void)ch395f_close_socket(E4_SOCK); (void)bench_wait_closed(E4_SOCK, 2000U); HAL_Delay(500); return; } /* 被测复位序列 */ if (variant == 0U) { rx_drained = bench_drain_rx(E4_SOCK); } else if (variant == 1U) { ch395f_clear_recv_buf(E4_SOCK); } (void)ch395f_close_socket(E4_SOCK); if (variant != 2U) { (void)bench_drain_events(E4_SOCK, 500U); } closed_ms = bench_wait_closed(E4_SOCK, 2000U); DBG_INFO("BENCH E4 rg%u var=%c reset done rxdrain=%lu closed_ms=%d t=%u", rg, (char)('A' + variant), (unsigned long)rx_drained, closed_ms, (unsigned)HAL_GetTick()); /* 立即重开 + LISTEN(主机立即上传全载荷) */ ch395f_set_sour_port(E4_SOCK, port); if (ch395f_open_socket(E4_SOCK) != CH395F_ERR_SUCCESS) { DBG_ERROR("BENCH E4 rg%u reopen fail", rg); return; } if (ch395f_tcp_listen(E4_SOCK) != CH395F_ERR_SUCCESS) { DBG_ERROR("BENCH E4 rg%u relisten fail", rg); (void)ch395f_close_socket(E4_SOCK); return; } /* 等载荷连接 CONNECT(C 变体的陈旧 DISCONNECT 若在此同读出现 = 新连接被杀,如实计 FAIL) */ if (!bench_wait_sock_int(E4_SOCK, 15000U, &si) || ((si & CH395F_SINT_STAT_CONNECT) == 0U)) { DBG_ERROR("BENCH E4 rg%u var=%c VERIFY FAIL: no CONNECT (si=0x%02X)", rg, (char)('A' + variant), si); (void)ch395f_close_socket(E4_SOCK); (void)bench_wait_closed(E4_SOCK, 2000U); (void)bench_drain_events(E4_SOCK, 300U); HAL_Delay(200); return; } /* 消费循环:电平式 GET_RECV_LEN 收集(对 RECV 事件未收到免疫),DISCONNECT/TIM_OUT 即止 * (= 生产 net 层释放语义;closed-with-data 救回不在本判据内,事后读空仅作取证) */ int death = ((si & (CH395F_SINT_STAT_DISCONNECT | CH395F_SINT_STAT_SOCK_TIMEOUT)) != 0U) ? 1 : 0; uint32_t total = 0U; uint32_t tr = HAL_GetTick(); while (!death && (uint32_t)(HAL_GetTick() - tr) < 6000U) { uint16_t rl = ch395f_get_recv_len(E4_SOCK); while (rl > 0U && total < (uint32_t)sizeof(s_e4_acc)) { uint16_t n = (rl > 2048U) ? 2048U : rl; uint32_t room = (uint32_t)sizeof(s_e4_acc) - total; if ((uint32_t)n > room) { n = (uint16_t)room; } ch395f_read_recv_buf(E4_SOCK, &s_e4_acc[total], n); total += (uint32_t)n; rl = ch395f_get_recv_len(E4_SOCK); } si = ch395f_get_sock_int_status(E4_SOCK); if ((si & (CH395F_SINT_STAT_DISCONNECT | CH395F_SINT_STAT_SOCK_TIMEOUT)) != 0U) { death = 1; } if (!death) { HAL_Delay(5); } } uint32_t loop_total = total; /* 事后读空(取证:数据是否其实还在芯片缓冲里) */ for (int k = 0; k < 20; k++) { uint16_t rl = ch395f_get_recv_len(E4_SOCK); if (rl == 0U) { break; } uint32_t room = (uint32_t)sizeof(s_e4_acc) - total; if (room == 0U) { break; } uint16_t n = (rl > 2048U) ? 2048U : rl; if ((uint32_t)n > room) { n = (uint16_t)room; } ch395f_read_recv_buf(E4_SOCK, &s_e4_acc[total], n); total += (uint32_t)n; } /* 载荷自证:图案种子随全局轮次变,上一轮残渣必失配 */ uint8_t seed = e4_seed(rg); int mm = -1; for (uint32_t i = 0U; i < loop_total; i++) { if (s_e4_acc[i] != (uint8_t)(seed + i)) { mm = (int)i; break; } } int ok = (loop_total == E4_PAYLOAD) && (mm < 0); DBG_INFO("BENCH E4 rg%u var=%c VERIFY loop=%lu extra=%lu mm=%d death=%d head=%02X %02X %02X %02X => %s", rg, (char)('A' + variant), (unsigned long)loop_total, (unsigned long)(total - loop_total), mm, death, s_e4_acc[0], s_e4_acc[1], s_e4_acc[2], s_e4_acc[3], ok ? "OK" : "FAIL"); /* 轮后清洁 */ (void)ch395f_close_socket(E4_SOCK); (void)bench_wait_closed(E4_SOCK, 2000U); (void)bench_drain_events(E4_SOCK, 300U); HAL_Delay(200); } static void bench_e4(void) { DBG_INFO("BENCH E4 ===== sock_reset A/B/C x%u (host: ch395f_reuse_host.py --mode e4) =====", (unsigned)E4_ROUNDS); unsigned rg = 0U; for (uint8_t v = 0U; v < 3U; v++) { for (unsigned r = 0U; r < E4_ROUNDS; r++, rg++) { bench_e4_round(rg, v); } } } void ch395f_reuse_bench(void) { DBG_INFO("BENCH ===== E2/E3/E4 chip bench START (legacy matrix parked) ====="); if (bench_chip_init() != 0) { DBG_ERROR("BENCH init failed, giving up (normal boot continues)"); return; } for (unsigned i = 0; i < 2048U; i++) { s_tx_pat[i] = (uint8_t)(0xA5U + (i % 251U)); } bench_dwt_enable(); if (s_bench_legacy != 0) { /* 丢中断复核实验(2026-10-14):固定 8 周期 × 6 变体后返回正常启动 * (主机脚本 ch395f_reuse_host.py --mode legacy --cycles 8 同步收工) */ DBG_INFO("BENCH legacy matrix: 8 cycles x %u variants", (unsigned)BENCH_N_VARS); unsigned idx = 0; for (unsigned cyc = 0U; cyc < 8U; cyc++) { for (unsigned iv = 0U; iv < (unsigned)BENCH_N_VARS; iv++) { bench_round(idx); idx = (idx + 1U) % (unsigned)BENCH_N_VARS; } } DBG_INFO("BENCH legacy matrix DONE, normal boot continues"); return; } bench_e2(); bench_e3(); bench_e4(); DBG_INFO("BENCH ===== E2/E3/E4 ALL DONE (reflash or power-cycle to exit) ====="); for (;;) { HAL_Delay(1000); } } #endif /* N30_CHIP_BENCH */