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 回填留待主工作树合并后。
351 lines
19 KiB
C
351 lines
19 KiB
C
/*
|
||
* 模块名称:假 CH395F 芯片(NET 域主机侧单测共享件)
|
||
* 模块功能:给 NET 域的主机侧单测一个**可脚本化的假芯片**。真实 ch395f.h 拉 HAL 与
|
||
* SPI 寄存器定义,PC 上编不动;而 net_listener / net_pending / net_events
|
||
* 的行为恰恰完全由"芯片此刻报什么状态"决定,必须有假件才能测。
|
||
*
|
||
* ⚠ 仅供 test/host/** 使用,不参与 MCU 构建。
|
||
*
|
||
* 为什么值得共享一份(而不是每模块自带桩):三份假芯片各自漂移时,"假件与被测代码
|
||
* 同时错"这类问题再也不会报出来。各模块的 stub/ch395f.h 只做一件事——include 本文件,
|
||
* 于是签名与常量只有一份定义。
|
||
*
|
||
* 常量与类型必须与 Drivers/BSP/CH395F/ch395f.h 逐字一致(2026-10-23 从真实头抄录):
|
||
* CH395F_ERR_SUCCESS 0x00 / CH395F_PROTO_TYPE_TCP 0x03 / CH395F_SOCKET_CLOSED 0x00
|
||
* CH395F_TCP_CLOSED 0x00 / CH395F_TCP_LISTEN 0x01;ch395f_sock_state_t 为
|
||
* { uint8_t open; uint8_t tcp_state; } 两字节。
|
||
*
|
||
* 必须复刻的两条芯片怪癖(不复刻就等于把被测代码的坑假件掉):
|
||
* 1. ch395f_get_sock_int_status() 是**整体读即清**、芯片没有按位清除手段。本假件
|
||
* 返回该 socket 的挂起位图并同步清零。AGENTS 模块约定里 B3 的实证坑("顺手
|
||
* 全量清一遍"把别的在用 Socket 的门焊死)靠这条才照得出来。
|
||
* 2. *_cached 系列返回的是**缓存值**而不是现场值:open 状态与 TCP 状态分开、且
|
||
* "监听还活着"的判据是 (open != CLOSED && tcp_state == LISTEN)。测试据此能构造
|
||
* "缓存陈旧"的形态。
|
||
*
|
||
* 脚本化模型(沿用本仓既有假件风格:nand_port 的真头+假 diskio、lftpd_io 的可注入假堆):
|
||
* - 每个读函数一条按调用序号取的返回队列,队列耗尽后回落到**最后一个值**(便于
|
||
* 写"一直可读""一直关不掉"这类持续状态);
|
||
* - 每个写/控制函数一条调用记录(次数 + 最近一次入参),另给逐函数调用计数,
|
||
* 让"这一轮根本不该碰芯片"成为可断言的事;
|
||
* - g_chip.log[] 记录**调用顺序**(短名),用于断言"先清接收、再关、再读即清"这类
|
||
* 时序契约;
|
||
* - ch395f_fake_reset() 一次全清。
|
||
*
|
||
* 创建日期:2026-10-23
|
||
*/
|
||
|
||
#ifndef CH395F_FAKE_H
|
||
#define CH395F_FAKE_H
|
||
|
||
#include <stdint.h>
|
||
|
||
/* —— 与真实 ch395f.h 逐字一致的常量(值抄自真实头,勿"顺手改")—— */
|
||
#define CH395F_ERR_SUCCESS 0x00U
|
||
#define CH395F_PROTO_TYPE_TCP 0x03U
|
||
#define CH395F_SOCKET_CLOSED 0x00U
|
||
#define CH395F_SOCKET_OPEN 0x05U /* 真头 ch395f.h:220 = 0x05U(05H SOCKET_OPEN,docs/芯片手册/CH395F.md:527)*/
|
||
#define CH395F_TCP_CLOSED 0x00U
|
||
#define CH395F_TCP_LISTEN 0x01U
|
||
#define CH395F_TCP_ESTABLISHED 0x04U /* 真头 ch395f.h:229 = 0x04U(04H TCP_ESTABLISHED,docs/芯片手册/CH395F.md:539)*/
|
||
|
||
/* 发送/接收缓冲尺寸宏链:**与真实 ch395f.h 同构转抄**(2026-10-23 逐条核对)。
|
||
* net_pending.h 里的 NET_SEND_CHUNK_MAX 由这两个宏推导,是"一次最多往芯片写多少"
|
||
* 的真实上界,假件不能自己发明数字(否则分块测试就是在测假件的常量):
|
||
* RAM_BLOCK_SIZE 512 / SEND_BLOCKS 2 → SEND_BUF 1024
|
||
* RECV_BLOCKS 4 → RECV_BUF 2048 → SPI_DMA_BUF 2052 → SPI_DMA_MAX_PAYLOAD 2048
|
||
* ⇒ NET_SEND_CHUNK_MAX = min(1024, 2048) = 1024 */
|
||
#define CH395F_RAM_BLOCK_SIZE 512U
|
||
#define CH395F_SEND_BLOCKS 2U
|
||
#define CH395F_SEND_BUF_SIZE_BYTES (CH395F_SEND_BLOCKS * CH395F_RAM_BLOCK_SIZE)
|
||
#define CH395F_RECV_BLOCKS 4U
|
||
#define CH395F_RECV_BUF_SIZE_BYTES (CH395F_RECV_BLOCKS * CH395F_RAM_BLOCK_SIZE)
|
||
#define CH395F_SPI_DMA_BUF_SIZE (CH395F_RECV_BUF_SIZE_BYTES + 4U)
|
||
#define CH395F_SPI_DMA_MAX_PAYLOAD (CH395F_SPI_DMA_BUF_SIZE - 4U)
|
||
|
||
#define CH395F_FAKE_SOCK_MAX 8 /* 与 NET_MAX_SOCKETS 同量级,测试自用 */
|
||
#define CH395F_FAKE_QUEUE_LEN 24
|
||
#define CH395F_FAKE_LOG_LEN 96
|
||
#define CH395F_FAKE_GLOB_QUEUE 24
|
||
|
||
/* ===== 扩展区(2026-10-24,net_socket 主机单测批次;**纯新增**,上面既有宏/字段/函数
|
||
* 一字未动,net_listener / net_events / net_pending 三套的语义不受影响)=====
|
||
*
|
||
* 追加的是 net_socket.c 这一层会调、而前三个模块不调的芯片原语(初始化下发类 +
|
||
* 全局中断 + sock_reset 复位机 + cmd_done 判据)。签名/常量同样**逐字抄自真实头**
|
||
* Drivers/BSP/CH395F/ch395f.h,改真头即编译期/断言期暴露漂移。
|
||
*
|
||
* 必须复刻的第三条芯片怪癖(前两套测不到、net_socket.c 却是主路):
|
||
* 3. GET_GLOB_INT_STATUS_ALL(0x19,2 字节)**整体读即清**,且它是全局寄存器
|
||
* (含全部 Socket 事件位)。AGENTS 模块约定 B3:唯一读者只能是 net_poll。
|
||
* 假件按调用序号返回预置值,并单独计数,让"别处偷偷读全局"成为可断言的事。
|
||
* 4. sock_reset 复位机(E4 定案四步:读空 RX → CLOSE → 排空事件(quiescent) →
|
||
* 等 byte0=00H,含 LISTEN 态二段 CLOSE 补发)。这里做**契约等价**实现:
|
||
* 阶段推进与最短等待(GRACEFUL 100ms / QUARANTINE 400ms)照抄驱动,
|
||
* 但不复制驱动的超时数值细节(那属于驱动自己的单测面)。
|
||
*/
|
||
#define CH395F_ERR_BUSY 0x10U /* 真头 ch395f.h:170 */
|
||
#define CH395F_ERR_MEM 0x11U /* 真头 ch395f.h:171 */
|
||
#define CH395F_ERR_TIMEOUT 0x13U /* 真头 ch395f.h:173 */
|
||
#define CH395F_ERR_VAL 0x19U /* 真头 ch395f.h:179 */
|
||
#define CH395F_ERR_USE 0x1BU /* 真头 ch395f.h:181(open 已被占用)*/
|
||
#define CH395F_PROTO_TYPE_UDP 0x02U /* 真头 ch395f.h:213 */
|
||
#define CH395F_FUN_PARA_SOCKET_CLOSE (1UL << 3) /* 真头 ch395f.h:205 */
|
||
#define CH395F_TCP_MSS 1024U /* 真头 ch395f.h:124 */
|
||
#define CH395F_PHY_DISCONN 0x01U /* 真头 ch395f.h:191 */
|
||
#define CH395F_GINT_STAT_PHY_CHANGE 0x04U /* 真头 ch395f.h:245 */
|
||
#define CH395F_SOCK_STATE_NONE 0xFFU /* 真头 ch395f.h:762 */
|
||
|
||
#define CH395F_SINT_STAT_SENBUF_FREE 0x01U /* 真头 ch395f.h:263 */
|
||
#define CH395F_SINT_STAT_SEND_OK 0x02U /* 真头 ch395f.h:264 */
|
||
#define CH395F_SINT_STAT_RECV_OK 0x04U /* 真头 ch395f.h:265 */
|
||
#define CH395F_SINT_STAT_CONNECT 0x08U /* 真头 ch395f.h:266 */
|
||
#define CH395F_SINT_STAT_DISCONNECT 0x10U /* 真头 ch395f.h:267 */
|
||
#define CH395F_SINT_STAT_SOCK_TIMEOUT 0x40U /* 真头 ch395f.h:269 */
|
||
|
||
typedef enum {
|
||
CH395F_STATUS_OK = 0, /* 真头 ch395f.h:275 */
|
||
CH395F_STATUS_ERROR = -1,
|
||
CH395F_STATUS_TIMEOUT = -2,
|
||
CH395F_STATUS_NOT_DETECTED = -3
|
||
} ch395f_status_t;
|
||
|
||
typedef enum {
|
||
CH395F_RESET_GRACEFUL = 0, /* 真头 :803:最短等待 100ms */
|
||
CH395F_RESET_QUARANTINE /* 真头 :804:最短等待 400ms */
|
||
} ch395f_reset_mode_t;
|
||
|
||
typedef enum {
|
||
CH395F_DONE_OPEN = 0, /* 真头 :826:byte0 变 05H */
|
||
CH395F_DONE_LISTEN, /* 真头 :827:byte0=05H 且 TCP=01H */
|
||
CH395F_DONE_CLOSE /* 真头 :828:byte0=00H */
|
||
} ch395f_done_what_t;
|
||
|
||
/* 复位机阶段(与驱动同名状态的**契约等价**简化,不代表驱动内部实现) */
|
||
#define CH395F_FAKE_RST_IDLE 0
|
||
#define CH395F_FAKE_RST_DRAINED 1 /* 已读空 RX 并发过 CLOSE */
|
||
#define CH395F_FAKE_RST_MINWAIT 2 /* 等最短沉降窗(100/400ms) */
|
||
#define CH395F_FAKE_RST_QUIET 3 /* 排空本 Socket 事件(连续 2 轮无位) */
|
||
#define CH395F_FAKE_RST_WAITCLS 4 /* 等 byte0=00H(含二段 CLOSE 补发) */
|
||
#define CH395F_FAKE_RST_QUIESCENT 2U
|
||
|
||
typedef struct {
|
||
uint8_t open;
|
||
uint8_t tcp_state;
|
||
} ch395f_sock_state_t;
|
||
|
||
/* —— 可预置的芯片侧世界 —— */
|
||
typedef struct {
|
||
uint8_t cached_open[CH395F_FAKE_SOCK_MAX]; /* sock_state_cached().open */
|
||
uint8_t cached_tcp[CH395F_FAKE_SOCK_MAX]; /* sock_state_cached().tcp_state */
|
||
uint8_t status_byte0[CH395F_FAKE_SOCK_MAX]; /* get_socket_status 的 sock 状态 */
|
||
uint8_t status_byte1[CH395F_FAKE_SOCK_MAX]; /* get_socket_status 的 TCP 状态 */
|
||
uint8_t int_status[CH395F_FAKE_SOCK_MAX]; /* 读即清的挂起位图 */
|
||
uint16_t recv_len_q[CH395F_FAKE_SOCK_MAX][CH395F_FAKE_QUEUE_LEN];
|
||
int recv_len_n[CH395F_FAKE_SOCK_MAX];
|
||
int recv_len_i[CH395F_FAKE_SOCK_MAX];
|
||
uint8_t remote[CH395F_FAKE_SOCK_MAX][6]; /* get_remot_ipp 的 6 字节:ip[4]+port(小端) */
|
||
uint16_t link_change; /* link_change_count(链路变更计数) */
|
||
uint8_t link_up; /* link_up_cached */
|
||
uint8_t open_rc[CH395F_FAKE_SOCK_MAX]; /* open_socket 返回码 */
|
||
uint8_t listen_rc[CH395F_FAKE_SOCK_MAX]; /* tcp_listen 返回码 */
|
||
} ch395f_fake_world_t;
|
||
|
||
typedef struct {
|
||
/* 调用计数("不该碰芯片"的断言面) */
|
||
int open_calls;
|
||
int close_calls;
|
||
int listen_calls;
|
||
int int_status_calls;
|
||
int get_status_calls;
|
||
int read_calls;
|
||
int write_calls;
|
||
int set_proto_calls;
|
||
int set_port_calls;
|
||
int cached_calls;
|
||
/* 最近一次入参 */
|
||
uint8_t last_sock;
|
||
uint16_t last_read_len;
|
||
uint16_t last_port;
|
||
uint8_t last_proto;
|
||
uint8_t last_keepalive;
|
||
int keepalive_calls;
|
||
/* 调用顺序日志(短名首字母):
|
||
* 'c'=close 'i'=int_status(读即清) 's'=get_socket_status 'r'=read_recv_buf
|
||
* 'R'=get_recv_len 'o'=open_socket 'l'=tcp_listen 'p'=set_sour_port
|
||
* 'P'=set_proto_type 'w'=write_send_buf
|
||
* 扩展区新增(net_socket 批次):'G'=读全局中断 'v'=sock_events(读即清)
|
||
* 'X'=sock_reset_begin 'x'=sock_reset_poll 'z'=cmd_done 'T'=tcp_connect
|
||
* 'I'=set_ip_addr 'N'=set_gwip 'K'=set_mask 'M'=set_mac 'D'=set_dhcp
|
||
* 'F'=set_fun_para 'Q'=set_tcp_mss 'b'=set_send_buf 'u'=set_recv_buf
|
||
* 'e'=set_des_ip 'q'=set_des_port 'g'=get_phy_status 'E'=check_exist
|
||
* 'Z'=reset 'n'=init */
|
||
char log[CH395F_FAKE_LOG_LEN];
|
||
int log_n;
|
||
} ch395f_fake_obs_t;
|
||
|
||
extern ch395f_fake_world_t g_fake;
|
||
extern ch395f_fake_obs_t g_chip;
|
||
|
||
void ch395f_fake_reset(void); /* 全清并把所有 socket 设为"已关闭" */
|
||
void ch395f_fake_push_recv_len(uint8_t sock, uint16_t v);
|
||
void ch395f_fake_set_listening(uint8_t sock);
|
||
void ch395f_fake_set_peer(uint8_t sock, uint8_t b0, uint8_t b1, uint8_t b2,
|
||
uint8_t b3, uint16_t peer_port); /* 预置对端六元组 */ /* 缓存:open!=CLOSED 且 tcp=LISTEN */
|
||
|
||
/* —— 假芯片实现(签名与真实 ch395f.h 一字不改)—— */
|
||
ch395f_sock_state_t ch395f_sock_state_cached(uint8_t sn);
|
||
ch395f_sock_state_t ch395f_get_sock_state(uint8_t sn);
|
||
void ch395f_get_socket_status(uint8_t sock, uint8_t *status);
|
||
uint8_t ch395f_get_sock_int_status(uint8_t sock);
|
||
uint16_t ch395f_get_recv_len(uint8_t sock);
|
||
void ch395f_read_recv_buf(uint8_t sock, uint8_t *p_data, uint16_t len);
|
||
void ch395f_write_send_buf(uint8_t sock, uint8_t *p_data, uint16_t len);
|
||
uint8_t ch395f_open_socket(uint8_t sock);
|
||
uint8_t ch395f_close_socket(uint8_t sock);
|
||
uint8_t ch395f_tcp_listen(uint8_t sock);
|
||
void ch395f_set_proto_type(uint8_t sock, uint8_t proto);
|
||
void ch395f_set_sour_port(uint8_t sock, uint16_t port);
|
||
void ch395f_get_remot_ipp(uint8_t sock, uint8_t *p_buf);
|
||
void ch395f_set_keepalive_enable(uint8_t sock, uint8_t enable);
|
||
uint8_t ch395f_link_up_cached(void);
|
||
uint16_t ch395f_link_change_count(void);
|
||
|
||
/* ===== 扩展区第二部分:新增状态世界 + 新增假芯片原型 =====
|
||
* ⚠ 刻意**不往既有 ch395f_fake_world_t / ch395f_fake_obs_t 里加字段**,而是另开一份
|
||
* ch395f_fake_ext_t / ch395f_fake_ext_obs_t:既有三套单测的复位与断言面一字不动,
|
||
* 新增状态由 ch395f_fake_reset() 调 ch395f_fake_ext_reset() 一并清零(场景间不残留)。
|
||
*/
|
||
typedef struct {
|
||
/* —— 初始化/参数下发面(net_init 主路)—— */
|
||
int exist_rc; /* ch395f_check_exist 返回(ch395f_status_t)*/
|
||
int reset_rc; /* ch395f_reset 返回 */
|
||
int init_rc; /* ch395f_init 返回 */
|
||
uint8_t version; /* ch395f_get_version(版本门控 0x46 的用点位)*/
|
||
uint8_t dhcp_enable; /* ch395f_set_dhcp */
|
||
uint8_t ping_enable; /* ch395f_ping_enable */
|
||
uint8_t ip[4]; /* ch395f_set_ip_addr */
|
||
uint8_t gw[4]; /* ch395f_set_gwip_addr */
|
||
uint8_t mask[4]; /* ch395f_set_mask_addr */
|
||
uint8_t mac[6]; /* ch395f_set_mac_addr */
|
||
uint32_t fun_para; /* ch395f_set_fun_para 最近一次实发值 */
|
||
uint16_t mss; /* ch395f_set_tcp_mss */
|
||
uint8_t retrans_cnt;
|
||
uint16_t retrans_period;
|
||
uint32_t ka_idle;
|
||
uint32_t ka_intvl;
|
||
uint8_t ka_cnt;
|
||
uint8_t send_blk_start[CH395F_FAKE_SOCK_MAX]; /* ch395f_set_send_buf */
|
||
uint8_t send_blk_cnt[CH395F_FAKE_SOCK_MAX];
|
||
uint8_t recv_blk_start[CH395F_FAKE_SOCK_MAX]; /* ch395f_set_recv_buf */
|
||
uint8_t recv_blk_cnt[CH395F_FAKE_SOCK_MAX];
|
||
uint8_t des_ip[CH395F_FAKE_SOCK_MAX][4]; /* ch395f_set_des_ip */
|
||
uint16_t des_port[CH395F_FAKE_SOCK_MAX]; /* ch395f_set_des_port */
|
||
uint8_t connect_rc[CH395F_FAKE_SOCK_MAX]; /* ch395f_tcp_connect 返回 */
|
||
/* —— 全局中断(0x19,整体读即清;唯一读者应为 net_poll)—— */
|
||
uint16_t glob_q[CH395F_FAKE_GLOB_QUEUE];
|
||
int glob_n;
|
||
int glob_i;
|
||
uint8_t phy_status; /* ch395f_get_phy_status(喂 glob_event_feed)*/
|
||
/* —— sock_reset 复位机(契约等价,见文件头注释 4)—— */
|
||
uint8_t rst_state[CH395F_FAKE_SOCK_MAX];
|
||
uint8_t rst_mode[CH395F_FAKE_SOCK_MAX];
|
||
uint32_t rst_t0[CH395F_FAKE_SOCK_MAX];
|
||
uint8_t rst_quiet[CH395F_FAKE_SOCK_MAX]; /* 连续无事件轮数 */
|
||
/* 1=复位机**不**替芯片把 cached_open 落回 CLOSED(造"永远关不掉"的芯片形态,
|
||
* 用来量上层的复位超时收口)。默认 0 → 与既有行为一致。 */
|
||
uint8_t rst_keep_open[CH395F_FAKE_SOCK_MAX];
|
||
/* GET_RECV_BUF 的**脚本化内容**(默认长度 0 → 与既有"全零交付"逐字相同)。
|
||
* UDP 报文头(长度/源端口/源 IP)只有内容可脚本化才能被断言:net_recvfrom 要
|
||
* 从芯片头里拆出对端地址,全零内容下"拆对了"与"拆反了"看起来一模一样。 */
|
||
uint8_t recv_bytes[128];
|
||
uint16_t recv_bytes_n;
|
||
/* SINT 的**电平型**来源(可脚本化):读即清之后立刻把这个掩码放回 int_status。
|
||
* 默认 0 → 与既有假件行为逐字相同(读一次就没了)。真实芯片的 RECV_OK /
|
||
* SENBUF_FREE 本就是"条件位":只要条件还在(RX 仍非空 / 发送缓冲仍空),下一轮
|
||
* 就还会再报一次。net_socket.c 的多块发送要的就是这个稳态,没有它就只能
|
||
* 造"写完一块就再也等不到空闲"的假死形态。 */
|
||
uint8_t sint_sticky[CH395F_FAKE_SOCK_MAX];
|
||
} ch395f_fake_ext_t;
|
||
|
||
typedef struct {
|
||
int exist_calls;
|
||
int reset_calls;
|
||
int init_calls;
|
||
int set_ip_calls;
|
||
int set_gw_calls;
|
||
int set_mask_calls;
|
||
int set_mac_calls;
|
||
int set_dhcp_calls;
|
||
int ping_calls;
|
||
int set_fun_para_calls;
|
||
int set_mss_calls;
|
||
int set_retrans_calls;
|
||
int set_ka_calls;
|
||
int set_send_buf_calls;
|
||
int set_recv_buf_calls;
|
||
int set_des_ip_calls;
|
||
int set_des_port_calls;
|
||
int connect_calls;
|
||
int glob_calls; /* 读全局中断次数(B3:除 net_poll 外应为 0)*/
|
||
int glob_bits; /* 最近一次读到的 16 位全局位图 */
|
||
int sock_events_calls; /* ch395f_sock_events(只碰本 Socket 的护栏原语)*/
|
||
int rst_begin_calls;
|
||
int rst_begin_reject; /* begin 被拒次数(复位机已在运行)*/
|
||
int rst_poll_calls;
|
||
int rst_done[CH395F_FAKE_SOCK_MAX]; /* 复位机完成计数 */
|
||
int rst_fail[CH395F_FAKE_SOCK_MAX]; /* 复位机失败计数 */
|
||
int cmd_done_calls;
|
||
uint8_t last_cmd_done_what;
|
||
int rst_close_calls; /* 复位机内部发出的 CLOSE 命令(含二段补发)*/
|
||
int rst_rx_discard_calls; /* 复位机 RX 排空事务次数 */
|
||
} ch395f_fake_ext_obs_t;
|
||
|
||
extern ch395f_fake_ext_t g_fx;
|
||
extern ch395f_fake_ext_obs_t g_fxchip;
|
||
|
||
/* 由 ch395f_fake_reset() 自动调用;单独暴露是为了让测试能只清扩展面 */
|
||
void ch395f_fake_ext_reset(void);
|
||
void ch395f_fake_push_glob(uint16_t v); /* 预置全局中断返回序列 */
|
||
void ch395f_fake_set_sint_sticky(uint8_t sock, uint8_t mask);
|
||
/* 预置 GET_RECV_BUF 交付的字节(n=0 撤销预置);p 可为 NULL(表示填 n 个 0xA5) */
|
||
void ch395f_fake_set_recv_bytes(const uint8_t *p, uint16_t n);
|
||
/* 顺序断言辅助:清空调用日志 / 找某个短名第一次出现的位置(-1=没调过)。
|
||
* 刻意提供"清零日志",否则一次长轮询(如 sock_reset 的几十轮 'x')会把 96 格
|
||
* 环形外的顺序信息挤掉,让后续场景的顺序断言失真。 */
|
||
void ch395f_fake_clear_log(void);
|
||
int ch395f_fake_log_find(char c);
|
||
|
||
/* —— 新增假芯片实现(签名与真实 ch395f.h 一字不改)—— */
|
||
ch395f_status_t ch395f_check_exist(void);
|
||
ch395f_status_t ch395f_reset(void);
|
||
ch395f_status_t ch395f_init(void);
|
||
uint8_t ch395f_get_version(void);
|
||
void ch395f_set_fun_para(uint32_t para);
|
||
void ch395f_set_tcp_mss(uint16_t mss);
|
||
void ch395f_set_retrans_count(uint8_t cnt);
|
||
void ch395f_set_retrans_period(uint16_t period);
|
||
void ch395f_set_keepalive_idle(uint32_t time);
|
||
void ch395f_set_keepalive_intvl(uint32_t time);
|
||
void ch395f_set_keepalive_cnt(uint8_t cnt);
|
||
void ch395f_set_dhcp(uint8_t enable);
|
||
void ch395f_ping_enable(uint8_t enable);
|
||
void ch395f_set_ip_addr(uint8_t *p_ip);
|
||
void ch395f_set_gwip_addr(uint8_t *p_gwip);
|
||
void ch395f_set_mask_addr(uint8_t *p_mask);
|
||
void ch395f_set_mac_addr(uint8_t *p_mac);
|
||
void ch395f_set_send_buf(uint8_t sock, uint8_t start_block, uint8_t block_count);
|
||
void ch395f_set_recv_buf(uint8_t sock, uint8_t start_block, uint8_t block_count);
|
||
void ch395f_set_des_ip(uint8_t sock, uint8_t *p_ip);
|
||
void ch395f_set_des_port(uint8_t sock, uint16_t port);
|
||
uint8_t ch395f_tcp_connect(uint8_t sock);
|
||
uint8_t ch395f_get_phy_status(void);
|
||
uint16_t ch395f_get_glob_int_status_all(void);
|
||
void ch395f_glob_event_feed(uint16_t glob_bits);
|
||
uint8_t ch395f_sock_events(uint8_t sn);
|
||
int ch395f_sock_reset_begin(uint8_t sn, ch395f_reset_mode_t mode);
|
||
int ch395f_sock_reset_poll(uint8_t sn);
|
||
int ch395f_cmd_done(uint8_t sn, ch395f_done_what_t what);
|
||
|
||
#endif /* CH395F_FAKE_H */
|