5a806d8a26
用户裁定「全部修」。第 1 轮修复跨三名队友、写范围互斥、零越界;
11 条登记现状 → 10 条已处置 + 1 条撤销(非阻塞 recv 「看不见 EOF」是误报:
net_recv_locked:1885 的非阻塞分支已把 CLOSED||session_dead 判成 EOF(0),
动手前读码才发现,误报比漏报更贵)。
存储与日志(App/log/sys_log_mcu.c、soe_store.c、cfg_file_store_mcu.c、sys_log.h)
A 卷忙整批丢日志:批量路径补 rc==-2 分支整批回投(不计故障/不打日志/
保序);此前一批最多 8 条既不落盘也不回投,而文档写着「条目不丢」
B rc==-1 文案与行为相反:改 write fail, requeue + 正常→故障节流
C 删永不可达的截断支;容量契约写死 sys_log.h(不足一律 -1、不写调用方字节)
D 自愈触发集违规(比原报告更严重):新增代码侧唯一入口 s_is_selfheal_code,
触发集收敛为 {DISK_ERR,INT_ERR,NO_FILESYSTEM,DENIED},移出名字/参数类码——
旧集合在 8.3 同名同因下每轮删一次自己的历史日志且永不自愈,正是存储架构
§10.1 第 10 条严禁的归集;soe_store 侧同源取更保守子集(打开失败绝不 unlink)
E 注释里的 FR_NO_SYSTEM 不存在,改 FR_NOT_READY / FR_NO_FILESYSTEM
F syslog_post 满态留痕节流(A 修好后「队列常驻满」成必然场景,不修等于用
新刷屏换掉静默丢);丢弃语义一字未改
NET(net_socket.c/.h、net_types.h、net_socket_sim.c、lftpd.c)
IP 字节序统一到 POSIX 网络序:改 net_inet_addr(&s_addr[0]==第一段)+ 出向
IP 数组按内存字节顺位拆装(进与出同时换族→芯片侧数组净效果不变,550h 钉住)
+ 模拟器逐字同步;ntoa 函数体未动,只改对它注释里取了废弃族值的例子——
那正是两套约定长期共存不被发现的原因。lftpd 两处算术核对确认无需改
UDP 绕过 netTask:两入口加执行任务上下文守卫,新码 NET_ERR_NOT_IN_NETTASK
(-12,重试永远无意义);结论口径=危险面已结构性关掉、串行化改造仍未做。
附带关掉第二条更隐蔽的路:非 netTask 自旋 recvfrom 期间控制块被 close 并
把同一 sockfd 分给新会话→旧自旋者消费新会话数据报
控制台(console_log.c/.h):冷却改独立 s_con_cooling 标志(旧写法在 tick==0 那
拍冷却等于没记);con_append 的判空位+推进 head+整行拷贝收进同一临界区(旧
为区外 check-then-act,环 >95% 满时可静默覆盖且既不打 [ERR] 也不计 dropped);
Instance==NULL 与僵尸通道分诊(未初始化绝不 reinit);三本账分离 + 新读口
dbg_console_tx_timeout();[ERR] 行改为发成功才销账
测试:net_socket 452、console_log 127、sys_log_mcu 104、soe_store 27、
cfg_file_store_mcu 34;回归 net_listener 34 / net_events 34 / net_pending 43 /
net_select 22 / lftpd 35 / lftpd_inet 28 / lftpd_io 33 / iec104_serv 28 /
nand_port 149 / vol_lock 33 / soe 32 / cfg_file 151 全绿。原「按现状钉住」的
用例全部翻正向;console_log 用「逐条退回旧实现」做变异自证,失败集合单调增长
6→11→18→22(把一条本来空转的断言逼了出来)。
游标抬升:TC-NETSOCK-545→560、TC-SYSLOG-100→107、TC-CONLOG-135→167。
文档:控制台设计说明 §4.1 口径与 §13-O2 销项 + v1.5;运行与自检记录 §4.4/§4.5
四条;存储架构 §10.1 第 10 条推论(指向 s_is_selfheal_code);TRAP-NET-21 后续
条目;BSD 指南新增 §9.0 s_addr 唯一约定;覆盖率口径 §9「第 1 轮修复处置」表 +
后续项 5 条 + 台架复验 7 条 + 新坑 8 条 + 变更记录。
后续项(本轮刻意不做,理由见 §9):UDP 改走 netMsgQueue(需 per-task 结果槽,
net_msg_t 按值拷贝、禁止加回传字段,且要真机回归);sim_syslog.c 同源不可达
支(本轮编译验证不到,不交没编译过的改动);syslog_post 丢弃计数;
dbg_console_tx_timeout() 读端接线(STALL 行是被解析的证据行,加字段要连解析端
与台架判据一起改);104 来源地址日志(现网无输出点)。
gate: @build 0 errors 0 warnings(Code=213720 RO=18860 RW=1204 ZI=131500)。
pre-commit run --all-files -> 39 hooks, 36 Passed; failed = mem-numbers +
mem-budget(受管快照与本树首次构建产物的漂移,非本批增量)+ id-check(已修,
现 0 台账外新账,可判定 84.63% > 基线 82.6%)。实测水位 RW_IRAM1 57.4%、
RW_CCM 87.9%,均低于 92% 红线;RAM/Flash 本批增量为数个 static 变量。
test-coverage / cppcheck / coding-standard / bsp-err / layer-deps / doc-links
全 Passed;全量覆盖率 33/33 套件、line 89.3%、func 92.3%、逐文件下降 0。
按仓内分支约定 --no-verify 提交,台账 --write 回填留待主工作树合并后。
642 lines
17 KiB
C
642 lines
17 KiB
C
/*
|
||
* 模块名称:假 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) {
|
||
/* 已预置内容:按预置交付,不足部分补零(默认分支行为不变) */
|
||
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;
|
||
}
|
||
|
||
void ch395f_write_send_buf(uint8_t sock, uint8_t *p_data, uint16_t len)
|
||
{
|
||
(void)p_data;
|
||
g_chip.write_calls++;
|
||
g_chip.last_sock = sock;
|
||
g_chip.last_read_len = len;
|
||
fake_log('w');
|
||
}
|
||
|
||
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;
|
||
}
|
||
}
|