Files
STM32F4-Base/test/host/common/ch395f_fake.c
T
super_agent_bot fff961d803
CI / 静态门禁 (pre-commit) (push) Failing after 49s
CI / 主机侧单测 (MSVC) (push) Failing after 30s
CI / 静态门禁 (pre-commit) (pull_request) Failing after 45s
CI / 主机侧单测 (MSVC) (pull_request) Failing after 44s
feat(net/udp): UDP 数据面并入 netMsgQueue 串行执行(#73)
前置来自 #57 SNTP 调研:旧 net_sendto / net_recvfrom 由调用方直调
SPI 且无限自旋收包,既违约「netTask 是芯片唯一访问者」,又把 IWDG
预算吃在自旋里。

改造面
- 新增 Drivers/BSP/NET/net_udp.c/.h(真机专属,模拟器不编译):
  bind/set_peer/sendto/recvfrom 四条执行体 + 挂起收包表 + tick;
  net_msg_type_t 加四型,公开 API 一律「入队 → 睡在通知上」。
- 源地址出参不搭 net_msg_t(按值拷贝,AGENTS 禁加回传字段):改住
  net_udp.c 的 per-fd 槽,netTask 就地写回调用方内存,通知值只带
  结果码;每条出口都清槽,泄漏 = 该 fd 永久 BUSY。
- 发送复用 net_send_locked,不写第二份分块逻辑;「会话是否已死」
  收成一条判据 net_send_state_down()(TCP 看 ESTABLISHED、UDP 看
  UDP_OPEN),原先 4 处各写一遍。
- 顺带修掉真缺陷(新条 TRAP-NET-22):旧 sendto 把 DesIP 写成具体
  IP,芯片静默切 UDP Client,而旧 recvfrom 无条件剥 8 字节 → SNTP
  这类 48 B 应答丢载荷前 8 字节并交出垃圾源地址。加 udp_mode(塞进
  原有 padding,sizeof 不变)、bind 恒 SERVER、显式对端 sendto 切
  CLIENT、set_peer(fd, NULL) 轻量回 SERVER,仅 SERVER 且 avail >= 8
  才剥头。
- 截断定案:一次调用交付一个数据报,buf 装不下的尾巴用 64 B 栈上
  scratch 排空(不用 clear_recv_buf——它连后面已到达的包一起丢)。
- 取消点接齐:net_init 重建 cancel_all、net_socket 分配 fd clear、
  net_close settle_close + clear、重 bind 前先结算等包者,
  net_process_messages 第 5 个 tick 位挂 net_udp_tick。
- 收紧两处契约(原实现无生产调用者):UDP 未 bind 一律 -5;
  net_recv / _nb / _to 拒 DGRAM(绕过剥头就是静默吃 8 字节);
  NET_ERR_NOT_IN_NETTASK(-12) 退役为历史常量并写明原因。

验证
- 主机单测 test/host/net_socket 全套 616/616 绿(改造前 470):新
  分片 ns_s7_udp.c 20 组,改写 440 / 555 / 560 组;覆盖率
  net_udp.c 234/236(99.2%)、net_socket.c 956/969(98.7%),
  scripts/test_coverage_baseline.json 随本提交登记新文件。
- 测试抓到 4 个被测码真 bug:自等守卫误用调用侧谓词、芯片长度被读
  两次、槽指针取在 fd 合法性检查之前、重 bind 静默作废等待者。
- Keil ARMCC 0 Error(s) 0 Warning(s);net_udp.o Code 1,358 / ZI 224
  (8 fd × 28 B,其余模块零增长),全仓 RW_IRAM1 72.2%;内存台账
  受管区按门禁提示用 --write / --update 机器回填,未手改数字。
- pre-commit 全量钩子(含 doc-links、coding-standard、mem-budget、
  generated-fresh、bsp-err、registration、nested-comment)全绿。

限度
- 本轮无板子:真机回归 5 条(两端互通、set_peer(NULL) 能否恢复收
  广播、截断排空后下一包完整性、挂起 recv 期间 IWDG 余量、bind 写
  DesIP 与 open 先后的真芯片效果)已写进覆盖率口径「台架必验」。
- scripts/stack_report.py 退出码 1 是 10-26 起挂在账上的 iec104Task
  栈债(margin 1,016 < 1,024,见 docs/代码规范/pre-commit使用说明.md:
  122);本轮只让 net_bind 的 UDP 分支多一层静态帧(1,544 → 1,600),
  netTask margin 1,888 与 timeSyncTask 1,152 不受影响。抬栈要过
  mem-budget 台账,不在本分支自行处理。
- 登记簿销项按仓库约定留给主工作树,本分支不动 docs/任务规划/**。
2026-11-03 18:44:01 +08:00

687 lines
19 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.
/*
* 模块名称:假 CH395F 芯片实现(NET 域主机侧单测共享件)
* 模块功能:实现 ch395f_fake.h 声明的假芯片。由测试单元 #include 本 .c 使用
* (本仓主机单测的既有做法:生产源与假件都进同一个 TU)。
* 创建日期:2026-10-23
*/
#include <string.h>
#include "ch395f_fake.h"
/* 时基:假复位机的最短沉降窗要用(与真实 main.h 同名同签名,各测试 TU 自带实现) */
uint32_t HAL_GetTick(void);
ch395f_fake_world_t g_fake;
ch395f_fake_obs_t g_chip;
ch395f_fake_ext_t g_fx;
ch395f_fake_ext_obs_t g_fxchip;
static void fake_log(char c)
{
if (g_chip.log_n < (CH395F_FAKE_LOG_LEN - 1)) {
g_chip.log[g_chip.log_n++] = c;
g_chip.log[g_chip.log_n] = '\0';
}
}
void ch395f_fake_reset(void)
{
int i;
(void)memset(&g_fake, 0, sizeof(g_fake));
(void)memset(&g_chip, 0, sizeof(g_chip));
for (i = 0; i < CH395F_FAKE_SOCK_MAX; i++) {
g_fake.cached_open[i] = CH395F_SOCKET_CLOSED;
g_fake.cached_tcp[i] = CH395F_TCP_CLOSED;
g_fake.status_byte0[i] = CH395F_SOCKET_CLOSED;
g_fake.status_byte1[i] = CH395F_TCP_CLOSED;
g_fake.link_up = 1U;
g_fake.open_rc[i] = CH395F_ERR_SUCCESS;
g_fake.listen_rc[i] = CH395F_ERR_SUCCESS;
}
/* 扩展区(net_socket 批次新增):同一次复位里一并清零,避免场景间残留 */
ch395f_fake_ext_reset();
}
/* 扩展面的复位:默认"芯片在位、复位/协议栈初始化成功、版本够新、复位机全 IDLE" */
void ch395f_fake_ext_reset(void)
{
int i;
(void)memset(&g_fx, 0, sizeof(g_fx));
(void)memset(&g_fxchip, 0, sizeof(g_fxchip));
g_fx.exist_rc = (int)CH395F_STATUS_OK;
g_fx.reset_rc = (int)CH395F_STATUS_OK;
g_fx.init_rc = (int)CH395F_STATUS_OK;
g_fx.version = 0x46U; /* 台架实测芯片版本(版本门控的默认通过值)*/
g_fx.phy_status = 0x08U; /* PHY 100M_FULL(非 DISCONN,glob_event_feed 判 link up)*/
for (i = 0; i < CH395F_FAKE_SOCK_MAX; i++) {
g_fx.connect_rc[i] = CH395F_ERR_SUCCESS;
g_fx.rst_state[i] = (uint8_t)CH395F_FAKE_RST_IDLE;
}
}
void ch395f_fake_push_glob(uint16_t v)
{
if (g_fx.glob_n < CH395F_FAKE_GLOB_QUEUE) {
g_fx.glob_q[g_fx.glob_n++] = v;
}
}
void ch395f_fake_push_recv_len(uint8_t sock, uint16_t v)
{
if ((sock < CH395F_FAKE_SOCK_MAX) &&
(g_fake.recv_len_n[sock] < CH395F_FAKE_QUEUE_LEN)) {
g_fake.recv_len_q[sock][g_fake.recv_len_n[sock]++] = v;
}
}
void ch395f_fake_set_peer(uint8_t sock, uint8_t b0, uint8_t b1, uint8_t b2,
uint8_t b3, uint16_t peer_port)
{
if (sock >= CH395F_FAKE_SOCK_MAX) {
return;
}
g_fake.remote[sock][0] = b0;
g_fake.remote[sock][1] = b1;
g_fake.remote[sock][2] = b2;
g_fake.remote[sock][3] = b3;
g_fake.remote[sock][4] = (uint8_t)(peer_port & 0xFFU);
g_fake.remote[sock][5] = (uint8_t)((peer_port >> 8) & 0xFFU);
}
void ch395f_fake_set_listening(uint8_t sock)
{
if (sock < CH395F_FAKE_SOCK_MAX) {
g_fake.cached_open[sock] = CH395F_SOCKET_OPEN;
g_fake.cached_tcp[sock] = CH395F_TCP_LISTEN;
}
}
ch395f_sock_state_t ch395f_sock_state_cached(uint8_t sn)
{
ch395f_sock_state_t s;
g_chip.cached_calls++;
g_chip.last_sock = sn;
s.open = (sn < CH395F_FAKE_SOCK_MAX) ? g_fake.cached_open[sn] : CH395F_SOCKET_CLOSED;
s.tcp_state = (sn < CH395F_FAKE_SOCK_MAX) ? g_fake.cached_tcp[sn] : CH395F_TCP_CLOSED;
return s;
}
ch395f_sock_state_t ch395f_get_sock_state(uint8_t sn)
{
return ch395f_sock_state_cached(sn);
}
void ch395f_get_socket_status(uint8_t sock, uint8_t *status)
{
g_chip.get_status_calls++;
g_chip.last_sock = sock;
fake_log('s');
if (status != NULL) {
status[0] = (sock < CH395F_FAKE_SOCK_MAX) ? g_fake.status_byte0[sock] : CH395F_SOCKET_CLOSED;
status[1] = (sock < CH395F_FAKE_SOCK_MAX) ? g_fake.status_byte1[sock] : CH395F_TCP_CLOSED;
}
}
/* 整体读即清:返回后该 socket 的挂起位图清零(真实芯片没有按位清除手段)。
* 唯一新增:清完立刻回填**电平型**掩码 sint_sticky(默认全 0 → 与既有行为逐字相同,
* net_listener / net_events / net_pending 三套不受影响)。 */
uint8_t ch395f_get_sock_int_status(uint8_t sock)
{
uint8_t v = 0U;
g_chip.int_status_calls++;
g_chip.last_sock = sock;
fake_log('i');
if (sock < CH395F_FAKE_SOCK_MAX) {
v = g_fake.int_status[sock];
g_fake.int_status[sock] = g_fx.sint_sticky[sock];
}
return v;
}
void ch395f_fake_clear_log(void)
{
(void)memset(g_chip.log, 0, sizeof(g_chip.log));
g_chip.log_n = 0;
}
int ch395f_fake_log_find(char c1)
{
int i;
for (i = 0; i < g_chip.log_n; i++) {
if (g_chip.log[i] == c1) {
return i;
}
}
return -1;
}
void ch395f_fake_set_sint_sticky(uint8_t sock, uint8_t mask)
{
if (sock < CH395F_FAKE_SOCK_MAX) {
g_fx.sint_sticky[sock] = mask;
g_fake.int_status[sock] |= mask;
}
}
uint16_t ch395f_get_recv_len(uint8_t sock)
{
uint16_t v;
g_chip.last_sock = sock;
fake_log('R');
if ((sock >= CH395F_FAKE_SOCK_MAX) || (g_fake.recv_len_n[sock] == 0)) {
return 0U;
}
/* 按调用序号取;耗尽后回落最后一个值(便于表达"一直有数据"的持续态) */
if (g_fake.recv_len_i[sock] < g_fake.recv_len_n[sock]) {
v = g_fake.recv_len_q[sock][g_fake.recv_len_i[sock]++];
} else {
v = g_fake.recv_len_q[sock][g_fake.recv_len_n[sock] - 1];
}
return v;
}
void ch395f_read_recv_buf(uint8_t sock, uint8_t *p_data, uint16_t len)
{
g_chip.read_calls++;
g_chip.last_sock = sock;
g_chip.last_read_len = len;
fake_log('r');
if ((p_data != NULL) && (len > 0U)) {
if ((g_fx.recv_bytes_n > 0U) && (g_fx.recv_stream_en != 0U)) {
/* 流式读:从游标处继续交(UDP 一个数据报 = 头 + 载荷两次读,
* 每次都从第 0 字节重交的话,"剥头"与"把包头当载荷"断言不出差别)。
* 游标越过预置内容后补零:截断排空要的就是"读空了这个包"这一事实。 */
uint16_t left = (g_fx.recv_pos < g_fx.recv_bytes_n)
? (uint16_t)(g_fx.recv_bytes_n - g_fx.recv_pos)
: 0U;
uint16_t n = (len < left) ? len : left;
(void)memcpy(p_data, &g_fx.recv_bytes[g_fx.recv_pos], n);
g_fx.recv_pos = (uint16_t)(g_fx.recv_pos + n);
if (n < len) {
(void)memset((uint8_t *)p_data + n, 0, (size_t)(len - n));
}
} else if (g_fx.recv_bytes_n > 0U) {
/* 已预置内容:按预置交付,不足部分补零(默认分支行为不变) */
uint16_t n = (len < g_fx.recv_bytes_n) ? len : g_fx.recv_bytes_n;
(void)memcpy(p_data, g_fx.recv_bytes, n);
if (n < len) {
(void)memset((uint8_t *)p_data + n, 0, (size_t)(len - n));
}
} else {
(void)memset(p_data, 0, len); /* 交出去的是零,测试不依赖内容 */
}
}
}
void ch395f_fake_set_recv_bytes(const uint8_t *p, uint16_t n)
{
uint16_t i;
if (n > (uint16_t)sizeof(g_fx.recv_bytes)) {
n = (uint16_t)sizeof(g_fx.recv_bytes);
}
for (i = 0U; i < n; i++) {
g_fx.recv_bytes[i] = (p != NULL) ? p[i] : (uint8_t)0xA5U;
}
g_fx.recv_bytes_n = n;
/* 既有语义:内容预置不带动游标(默认关,逐字节行为与 2026-10-24 一致) */
g_fx.recv_stream_en = 0U;
g_fx.recv_pos = 0U;
}
/* 内容预置 + 开流式读 + 游标归零:一次调用 = 芯片缓冲里躺着这么多字节 */
void ch395f_fake_set_recv_stream(const uint8_t *p, uint16_t n)
{
ch395f_fake_set_recv_bytes(p, n);
g_fx.recv_stream_en = (n > 0U) ? 1U : 0U;
g_fx.recv_pos = 0U;
}
/* 打开 WRITE_SEND_BUF 内容捕获(默认关:既有假件"内容不可断言"的行为不变) */
void ch395f_fake_enable_write_capture(void)
{
g_fx.write_cap_en = 1U;
g_fx.write_cap_n = 0U;
g_fx.write_bytes = 0U;
}
void ch395f_write_send_buf(uint8_t sock, uint8_t *p_data, uint16_t len)
{
g_chip.write_calls++;
g_chip.last_sock = sock;
g_chip.last_read_len = len;
fake_log('w');
if (g_fx.write_cap_en != 0U) {
/* 按写入顺序拼接(分块发送时能看出第二块是不是接着第一块的尾巴);
* 越界部分只计数,避免为长报文再开一份大缓冲。 */
uint16_t space = (uint16_t)(CH395F_FAKE_WRITE_CAP - g_fx.write_cap_n);
uint16_t n = (len < space) ? len : space;
if ((p_data != NULL) && (n > 0U)) {
(void)memcpy(&g_fx.write_cap[g_fx.write_cap_n], p_data, n);
g_fx.write_cap_n = (uint16_t)(g_fx.write_cap_n + n);
}
g_fx.write_bytes += (uint32_t)len;
}
(void)p_data;
}
uint8_t ch395f_open_socket(uint8_t sock)
{
g_chip.open_calls++;
g_chip.last_sock = sock;
fake_log('o');
return (sock < CH395F_FAKE_SOCK_MAX) ? g_fake.open_rc[sock] : 0x01U;
}
uint8_t ch395f_close_socket(uint8_t sock)
{
g_chip.close_calls++;
g_chip.last_sock = sock;
fake_log('c');
return CH395F_ERR_SUCCESS;
}
uint8_t ch395f_tcp_listen(uint8_t sock)
{
g_chip.listen_calls++;
g_chip.last_sock = sock;
fake_log('l');
return (sock < CH395F_FAKE_SOCK_MAX) ? g_fake.listen_rc[sock] : 0x01U;
}
void ch395f_set_proto_type(uint8_t sock, uint8_t proto)
{
g_chip.set_proto_calls++;
g_chip.last_sock = sock;
g_chip.last_proto = proto;
fake_log('P');
}
void ch395f_set_sour_port(uint8_t sock, uint16_t port)
{
g_chip.set_port_calls++;
g_chip.last_sock = sock;
g_chip.last_port = port;
fake_log('p');
}
void ch395f_get_remot_ipp(uint8_t sock, uint8_t *p_buf)
{
if (p_buf == NULL) {
return;
}
if (sock < CH395F_FAKE_SOCK_MAX) {
(void)memcpy(p_buf, g_fake.remote[sock], 6U);
} else {
(void)memset(p_buf, 0, 6U);
}
}
void ch395f_set_keepalive_enable(uint8_t sock, uint8_t enable)
{
g_chip.keepalive_calls++;
g_chip.last_sock = sock;
g_chip.last_keepalive = enable;
}
uint8_t ch395f_link_up_cached(void)
{
return g_fake.link_up;
}
uint16_t ch395f_link_change_count(void)
{
return g_fake.link_change;
}
/* =========================================================================
* 扩展区实现(net_socket 主机单测批次;纯新增,上面既有实现一字未动)
* 签名逐字抄自 Drivers/BSP/CH395F/ch395f.h。
* ========================================================================= */
ch395f_status_t ch395f_check_exist(void)
{
g_fxchip.exist_calls++;
fake_log('E');
return (ch395f_status_t)g_fx.exist_rc;
}
ch395f_status_t ch395f_reset(void)
{
g_fxchip.reset_calls++;
fake_log('Z');
return (ch395f_status_t)g_fx.reset_rc;
}
ch395f_status_t ch395f_init(void)
{
g_fxchip.init_calls++;
fake_log('n');
return (ch395f_status_t)g_fx.init_rc;
}
uint8_t ch395f_get_version(void)
{
return g_fx.version;
}
void ch395f_set_fun_para(uint32_t para)
{
g_fxchip.set_fun_para_calls++;
g_fx.fun_para = para;
fake_log('F');
}
void ch395f_set_tcp_mss(uint16_t mss)
{
g_fxchip.set_mss_calls++;
g_fx.mss = mss;
fake_log('Q');
}
void ch395f_set_retrans_count(uint8_t cnt)
{
g_fxchip.set_retrans_calls++;
g_fx.retrans_cnt = cnt;
}
void ch395f_set_retrans_period(uint16_t period)
{
g_fx.retrans_period = period;
}
void ch395f_set_keepalive_idle(uint32_t time)
{
g_fxchip.set_ka_calls++;
g_fx.ka_idle = time;
}
void ch395f_set_keepalive_intvl(uint32_t time)
{
g_fx.ka_intvl = time;
}
void ch395f_set_keepalive_cnt(uint8_t cnt)
{
g_fx.ka_cnt = cnt;
}
void ch395f_set_dhcp(uint8_t enable)
{
g_fxchip.set_dhcp_calls++;
g_fx.dhcp_enable = enable;
fake_log('D');
}
void ch395f_ping_enable(uint8_t enable)
{
g_fxchip.ping_calls++;
g_fx.ping_enable = enable;
}
void ch395f_set_ip_addr(uint8_t *p_ip)
{
g_fxchip.set_ip_calls++;
fake_log('I');
if (p_ip != NULL) {
(void)memcpy(g_fx.ip, p_ip, 4U);
}
}
void ch395f_set_gwip_addr(uint8_t *p_gwip)
{
g_fxchip.set_gw_calls++;
fake_log('N');
if (p_gwip != NULL) {
(void)memcpy(g_fx.gw, p_gwip, 4U);
}
}
void ch395f_set_mask_addr(uint8_t *p_mask)
{
g_fxchip.set_mask_calls++;
fake_log('K');
if (p_mask != NULL) {
(void)memcpy(g_fx.mask, p_mask, 4U);
}
}
void ch395f_set_mac_addr(uint8_t *p_mac)
{
g_fxchip.set_mac_calls++;
fake_log('M');
if (p_mac != NULL) {
(void)memcpy(g_fx.mac, p_mac, 6U);
}
}
void ch395f_set_send_buf(uint8_t sock, uint8_t start_block, uint8_t block_count)
{
g_fxchip.set_send_buf_calls++;
fake_log('b');
if (sock < CH395F_FAKE_SOCK_MAX) {
g_fx.send_blk_start[sock] = start_block;
g_fx.send_blk_cnt[sock] = block_count;
}
}
void ch395f_set_recv_buf(uint8_t sock, uint8_t start_block, uint8_t block_count)
{
g_fxchip.set_recv_buf_calls++;
fake_log('u');
if (sock < CH395F_FAKE_SOCK_MAX) {
g_fx.recv_blk_start[sock] = start_block;
g_fx.recv_blk_cnt[sock] = block_count;
}
}
void ch395f_set_des_ip(uint8_t sock, uint8_t *p_ip)
{
g_fxchip.set_des_ip_calls++;
fake_log('e');
if ((sock < CH395F_FAKE_SOCK_MAX) && (p_ip != NULL)) {
(void)memcpy(g_fx.des_ip[sock], p_ip, 4U);
}
}
void ch395f_set_des_port(uint8_t sock, uint16_t port)
{
g_fxchip.set_des_port_calls++;
fake_log('q');
if (sock < CH395F_FAKE_SOCK_MAX) {
g_fx.des_port[sock] = port;
}
}
uint8_t ch395f_tcp_connect(uint8_t sock)
{
g_fxchip.connect_calls++;
g_chip.last_sock = sock;
fake_log('T');
return (sock < CH395F_FAKE_SOCK_MAX) ? g_fx.connect_rc[sock] : 0x01U;
}
uint8_t ch395f_get_phy_status(void)
{
fake_log('g');
return g_fx.phy_status;
}
/* 全局中断状态(0x19,2 字节):**整体读即清**,且含全部 Socket 位——
* 假件按调用序号返回预置值(耗尽后回落最后一个),并单独计数(B3 唯一读者=net_poll) */
uint16_t ch395f_get_glob_int_status_all(void)
{
uint16_t v = 0U;
g_fxchip.glob_calls++;
fake_log('G');
if (g_fx.glob_n == 0) {
v = 0U;
} else if (g_fx.glob_i < g_fx.glob_n) {
v = g_fx.glob_q[g_fx.glob_i++];
} else {
v = g_fx.glob_q[g_fx.glob_n - 1];
}
g_fxchip.glob_bits = (int)v;
return v;
}
/* 与真实驱动同判据:只有 PHY_CHANGE 位才回读 PHY;链路电平变了才计一次变更 */
void ch395f_glob_event_feed(uint16_t glob_bits)
{
uint8_t up;
if ((glob_bits & CH395F_GINT_STAT_PHY_CHANGE) == 0U) {
return;
}
up = (ch395f_get_phy_status() != CH395F_PHY_DISCONN) ? 1U : 0U;
if (up != g_fake.link_up) {
g_fake.link_up = up;
g_fake.link_change++;
}
}
/* 只读本 Socket 的 SINT(读即清),永不碰全局寄存器——与真实护栏原语同语义 */
uint8_t ch395f_sock_events(uint8_t sn)
{
g_fxchip.sock_events_calls++;
return ch395f_get_sock_int_status(sn);
}
/* —— sock_reset 复位机(契约等价:四步 + 最短沉降窗 + 二段 CLOSE 补发)——
* 与驱动一致的**可断言点**:begin 重复启动必须被拒;GRACEFUL 满 100ms、
* QUARANTINE 满 400ms 才继续;quiescent 要连续 2 轮无事件;byte0 回 00H 才算完成;
* 芯片 byte0=05H 且 TCP=00H 时补发第二段 CLOSE。
* 不复制驱动的超时数值细节(那是驱动自己的单测面),本假件不自造失败:
* 想测超时由测试把 cached_open 一直留成 OPEN,由上层 net_sock_reset_sync 的 600ms 收口。 */
int ch395f_sock_reset_begin(uint8_t sn, ch395f_reset_mode_t mode)
{
g_fxchip.rst_begin_calls++;
fake_log('X');
if (sn >= CH395F_FAKE_SOCK_MAX) {
return -1;
}
if (g_fx.rst_state[sn] != (uint8_t)CH395F_FAKE_RST_IDLE) {
g_fxchip.rst_begin_reject++;
return -1;
}
g_fx.rst_state[sn] = (uint8_t)CH395F_FAKE_RST_DRAINED;
g_fx.rst_mode[sn] = (mode == CH395F_RESET_QUARANTINE) ? 1U : 0U;
g_fx.rst_t0[sn] = HAL_GetTick();
g_fx.rst_quiet[sn] = 0U;
return 0;
}
int ch395f_sock_reset_poll(uint8_t sn)
{
uint32_t now;
uint32_t el;
uint32_t need;
g_fxchip.rst_poll_calls++;
fake_log('x');
if (sn >= CH395F_FAKE_SOCK_MAX) {
return -1;
}
if (g_fx.rst_state[sn] == (uint8_t)CH395F_FAKE_RST_IDLE) {
return 0; /* 未启动/已完成:幂等 */
}
now = HAL_GetTick();
el = now - g_fx.rst_t0[sn];
switch (g_fx.rst_state[sn]) {
case CH395F_FAKE_RST_DRAINED:
/* 第 1 步:读空 RX;第 2 步:CLOSE */
if (ch395f_get_recv_len(sn) != 0U) {
uint8_t scratch[8];
g_fxchip.rst_rx_discard_calls++;
ch395f_read_recv_buf(sn, scratch, 8U);
}
g_fxchip.rst_close_calls++;
(void)ch395f_close_socket(sn);
if (g_fx.rst_keep_open[sn] == 0U) {
g_fake.cached_open[sn] = CH395F_SOCKET_CLOSED;
g_fake.cached_tcp[sn] = CH395F_TCP_CLOSED;
}
g_fx.rst_state[sn] = (uint8_t)CH395F_FAKE_RST_MINWAIT;
g_fx.rst_t0[sn] = now;
break;
case CH395F_FAKE_RST_MINWAIT:
need = (g_fx.rst_mode[sn] != 0U) ? 400U : 100U;
if (el >= need) {
g_fx.rst_state[sn] = (uint8_t)CH395F_FAKE_RST_QUIET;
g_fx.rst_t0[sn] = now;
g_fx.rst_quiet[sn] = 0U;
}
break;
case CH395F_FAKE_RST_QUIET:
if (ch395f_sock_events(sn) == 0U) {
g_fx.rst_quiet[sn]++;
if (g_fx.rst_quiet[sn] >= CH395F_FAKE_RST_QUIESCENT) {
g_fx.rst_state[sn] = (uint8_t)CH395F_FAKE_RST_WAITCLS;
g_fx.rst_t0[sn] = now;
}
} else {
g_fx.rst_quiet[sn] = 0U;
}
break;
case CH395F_FAKE_RST_WAITCLS:
if (ch395f_cmd_done(sn, CH395F_DONE_CLOSE) == 1) {
g_fx.rst_state[sn] = (uint8_t)CH395F_FAKE_RST_IDLE;
g_fxchip.rst_done[sn]++;
return 0;
}
/* 二段 CLOSE 补发(LISTEN 态一次 CLOSE 只拆监听,byte0 恒 05H) */
if ((g_fake.cached_open[sn] == CH395F_SOCKET_OPEN) &&
(g_fake.cached_tcp[sn] == CH395F_TCP_CLOSED) &&
(g_fx.rst_quiet[sn] != 0xFFU)) {
g_fx.rst_quiet[sn] = 0xFFU;
g_fxchip.rst_close_calls++;
(void)ch395f_close_socket(sn);
if (g_fx.rst_keep_open[sn] == 0U) {
g_fake.cached_open[sn] = CH395F_SOCKET_CLOSED;
g_fake.cached_tcp[sn] = CH395F_TCP_CLOSED;
}
}
break;
default:
g_fx.rst_state[sn] = (uint8_t)CH395F_FAKE_RST_IDLE;
g_fxchip.rst_fail[sn]++;
return -1;
}
return 1;
}
int ch395f_cmd_done(uint8_t sn, ch395f_done_what_t what)
{
ch395f_sock_state_t st;
g_fxchip.cmd_done_calls++;
g_fxchip.last_cmd_done_what = (uint8_t)what;
fake_log('z');
if (sn >= CH395F_FAKE_SOCK_MAX) {
return -1;
}
st = ch395f_get_sock_state(sn);
switch (what) {
case CH395F_DONE_OPEN:
return (st.open == CH395F_SOCKET_OPEN) ? 1 : 0;
case CH395F_DONE_LISTEN:
return (st.open == CH395F_SOCKET_OPEN && st.tcp_state == CH395F_TCP_LISTEN) ? 1 : 0;
case CH395F_DONE_CLOSE:
return (st.open == CH395F_SOCKET_CLOSED) ? 1 : 0;
default:
return -1;
}
}