/* * 模块名称:假 CH395F 芯片实现(NET 域主机侧单测共享件) * 模块功能:实现 ch395f_fake.h 声明的假芯片。由测试单元 #include 本 .c 使用 * (本仓主机单测的既有做法:生产源与假件都进同一个 TU)。 * 创建日期:2026-10-23 */ #include #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; } }