d1e6bb4ba7
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 已销项。
374 lines
14 KiB
C
374 lines
14 KiB
C
/**
|
||
* @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 */
|