Files
STM32F4-Base/test/board/ch395f_reuse_bench.c
T
wandering1 d1e6bb4ba7 W5波+N-19收口:FTP鉴权落地、Trap25三连定案修复(N-30)、N-20/N-23/N-26
N-19 FTP 鉴权:
- lftpd_auth(USER/PASS 状态机 + 连续5次失败锁60s)+ SHA-256
  (user||pwd) 口令哈希;config.ini [ftp] 段 user/pwd_hash/write,
  出厂 admin/admin 在用有启动告警;lftpd_log.c 删除并入 lftpd_auth
- ftp_cfg 配置读写;台架 ftp_auth_bench.py 13/13

N-30 / Trap 25(CH395F_Trap_Records.md 四次定案全记录):
- 修复1 closed-with-data accept:客户端发完正常 FIN 后芯片按
  FUN_PARA(0x09) §5.52② 保留 Socket+RX 缓冲,旧代码把 CLOSED 一律
  relisten 自毁缓冲 → STOR 必挂 425;改为接受"已关但可读"连接排空
- 修复2 丢 CONNECT 中断探针 net_lost_connect_probe + last_peer_port
  幽灵甄别(拆链窗口握手完成但中断丢失,双信源去抖补 accept)
- 修复3 send_list/send_nlst 批量单发:背靠背 ~60B 小段毒化芯片 TX
  (芯片报 SEND_OK 但对端全丢),整份目录一次性写入
- 证伪存档:固定沉降/Socket 轮换冷却/listen 门控(台架 v7 矩阵)
- 台架工具 test/board/ch395f_reuse_bench.{c,h} + host 脚本存档
  (不注册编译;实验分支 n30-chip-bench 保留)

N-20:Error_Handler 死循环降级(记录+复位路径)
N-23:scripts/check_registration.py 双端注册反向校验(pre-commit)
N-26:GD5F NAND 直 DMA 调用方缓冲窗口断言

验证:BUILD_OK 0/0;ftp_regression 连跑 4 轮 11/11(修复前
LIST#4/#7 100% 挂、STOR#2 曾 100% 425);ftp_auth_bench 13/13;
@test 启动标记 PASS;ci_local L0+L0.5 全过;doc-links 通过。
登记簿 N-30 已销项。
2026-10-11 18:50:24 +08:00

374 lines
14 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @file ch395f_reuse_bench.c
* @brief N-30 芯片级 Socket 复用时序台架(裸机,内核前运行,OS/net/FTP 全剥离)
* @details 直接调用 ch395f_* 命令,循环执行受控时序矩阵(延迟/关闭次序/载荷/Socket 号),
* 每步打印芯片状态与中断寄存器,定位"关→开→监听→连接"复用时序中
* 芯片行为的确切规律。配套主机脚本 test/host/ch395f_reuse_host.py。
* 定案结论与实验矩阵演进 → CH395F_Trap_Records.md Trap 25。
*
* 存档状态:本文件在主分支**不注册编译**(未加入 uvprojx),仅作实验工具存档;
* 运行方法:在实验分支(如 n30-chip-bench)把本 .c 注册进 uvprojx Test 组、
* Src/main.c 的 USER CODE 2 区在 app_main_init() 之前调 ch395f_reuse_bench()
* (内核前裸机循环,永不返回,断电退出),烧录后跑主机脚本对照芯片日志。
* 当前矩阵为定案轮(对照 vs "丢 CONNECT 捕获自 accept"修复组),见 s_vars[]。
*
* 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 "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 + 丢CONNECT捕获自accept */
{ 3, 300, 100, 0, 4 }, /* 300ms + 丢CONNECT捕获 */
{ 3, 800, 2000, 0, 4 }, /* 2KB + 丢CONNECT捕获 */
};
#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) {
uint16_t glob = ch395f_get_glob_int_status_all();
if ((glob & (1U << (sock + 4U))) != 0U) {
uint8_t si = ch395f_get_sock_int_status(sock);
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 09:link up 前 open 必失败) */
for (int i = 0; i < 100; i++) {
if (ch395f_get_phy_status() != 0U) {
break;
}
HAL_Delay(100);
}
ch395f_set_fun_para(0x09);
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 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;
}
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());
}
/* 清残留中断(与生产 listen 后一致) */
for (int j = 0; j < 8; j++) {
(void)ch395f_get_sock_int_status((uint8_t)j);
}
(void)ch395f_get_glob_int_status_all();
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 中断补发 */
while ((uint32_t)(HAL_GetTick() - tw) < budget) {
uint16_t glob = ch395f_get_glob_int_status_all();
if ((glob & (1U << (sock + 4U))) != 0U) {
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);
}
(void)ch395f_get_glob_int_status_all();
}
}
/* 2. 等 CONNECT(10s;幽灵等待期已见 CONNECT 则跳过)
* v6 关键探针:等待期每 500ms 读芯片状态;若已 ESTABLISHED(0x04)
* 说明握手完成但 CONNECT 中断丢失 → 补做 accept(对账②模拟) */
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) {
DBG_INFO("BENCH LOST-CONNECT caught: state ESTABLISHED, self-accept t=%u",
(unsigned)HAL_GetTick());
got = 1;
break;
}
}
}
if (!got) {
DBG_ERROR("BENCH no CONNECT within 10s (host not synced?)");
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 20) */
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 记状态+中断(抓"秒杀") */
for (int k = 0; k < 10; k++) {
uint16_t glob = ch395f_get_glob_int_status_all();
if ((glob & (1U << (sock + 4U))) != 0U) {
si = ch395f_get_sock_int_status(sock);
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 14 滞后中断取证) */
for (int k = 0; k < 20; k++) {
uint16_t glob = ch395f_get_glob_int_status_all();
uint8_t late = 0;
if ((glob & (1U << (sock + 4U))) != 0U) {
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);
}
void ch395f_reuse_bench(void) {
DBG_INFO("BENCH ===== N30 chip-level reuse bench START =====");
if (bench_chip_init() != 0) {
DBG_ERROR("BENCH init failed, giving up (normal boot continues)");
return;
}
DBG_INFO("BENCH chip ready, cycling %u variants forever", (unsigned)BENCH_N_VARS);
for (unsigned i = 0; i < 2048U; i++) {
s_tx_pat[i] = (uint8_t)(0xA5U + (i % 251U));
}
unsigned idx = 0;
for (;;) {
bench_round(idx);
idx = (idx + 1U) % (unsigned)BENCH_N_VARS;
}
}
#endif /* N30_CHIP_BENCH */