/* * 模块名称:假 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 /* —— 与真实 ch395f.h 逐字一致的常量(值抄自真实头,勿"顺手改")—— */ #define CH395F_ERR_SUCCESS 0x00U #define CH395F_PROTO_TYPE_TCP 0x03U #define CH395F_SOCKET_CLOSED 0x00U #define CH395F_SOCKET_OPEN 0x01U #define CH395F_TCP_CLOSED 0x00U #define CH395F_TCP_LISTEN 0x01U #define CH395F_TCP_ESTABLISHED 0x05U /* 发送/接收缓冲尺寸宏链:**与真实 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 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 */ 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); #endif /* CH395F_FAKE_H */