Files
STM32F4-Base/test/board/ch395f_reuse_bench.c
T
wandering1 d758d5cd7b docs+net: FUN_PARA 定案 0x08——bit0 保留位证伪,Trap18 定案更正 + N-31
CH395F FUN_PARA 的 bit0 之争定案:取 0x08(bit3 SOCKET_CLOSE=1,bit0=0)。

证据(一手,按强度):
- 官方手册 V2.2/V2.3 与旧版 V1C/V1E/2020 版 §5.52 位表:bit0 一律
  「保留,必须为0」,任何版本都不存在「bit0=多 Socket」这一行。
- 官方 SDK CH395INC.H:349-353 位宏只有 bit1/3/4/7/8,无 bit0 宏。
- 官方例程直接反例:EXAM5_TCP_Server 传 0x02(bit0=0)却给 Socket 0~7
  全部配缓冲;EXAM11_FTPClient 直接传 0x08;全 EVT 包无一处 0x09。
- 手册命令章前言:8 Socket 是芯片原生能力,靠 _SN 索引寻址;§5.45
  真正的门槛是缓冲分配(Socket 个数 >4 须重分配缓冲)。
- 概念讹传源是 bit1 FUN_PARA_FLAG_TCP_SERVER(服务器多连接,§9.2.6)。
- 互联网检索无任何出处称 bit0 为单/多 Socket 模式。

Trap 18 的「bit0 决定 Socket 数量」是推论而非实测:无日志、无 TC 号,
且当年 Socket 1~7 未显式配缓冲(Trap 01/02 混淆因子未排除);TC704
40/40 与结论出自同一提交,属自证,不构成 0x08 的对照。

改动:
- net_socket.c:0x09→0x08(原为未提交改动,现已过编译门禁)+ 版本留痕
- ch395f_reuse_bench.c:0x09→0x08,与生产 net_init 同构
- net_test_task.c:TC704 注释纠正(Socket 可用性不依赖 FUN_PARA)
- Trap 18 新增「定案更正」完整证据链;Trap 25 疑点改判为定案
- Test_Guide / 产品需求 / 架构总览 / BSD 调用关系:0x09→0x08 改口径
- 待处理内容.md 登记 N-31:0x08 下多 Socket 台架复测(TC704 降并发
  ≤5 + FTP 回归),补 Trap 25 销项时漏登记的尾巴

验证:@build 0 错误 0 警告;check_doc_links --all 通过;无 U+FFFD。
2026-10-11 20:05:22 +08:00

375 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);
}
/* 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 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 */