Files
STM32F4-Base/Drivers/BSP/CH395F/ch395f.h
T
wandering1 0054ae629a refactor(编号): F-* 网络设计条目号转语义说明——批次一收尾,代码注释 43 处 + 文档 9 处
批次一(不碰门禁即可清)的最后半批,原派道中途失败且**未留任何改动**(Lead 核实那批文件零 diff 后重派
setpage 执行,14 只文件 / 46 处),测试侧与一张生成器共 9 处由 Lead 收尾。

做法:**逐处先读属主文档 §7 速查表里那条的语义**,再改写成「一句话结论 + §指针」,同号跨文件同一措辞,
无一处机械删号(例:`F-NET-7` → 「唯一读者红线(docs/网络/网络自愈架构设计.md §7 I7)」)。属主登记处
**12 条定义行原样保留**、不删登记族(删了历史行会报未登记前缀),只在该章加停发句。

顺带清掉 **3 处裸形**(`T6` → 「台架实测」、`M4-lite`、`Q1` 语义化)——裸形正是 id-check 校验 2 抓的形态,
属净减。测试侧收尾时两条纪律:主机侧**断言字符串必须保持 ASCII**(`ns_s3_msg.c` 等三处的号在 CHECK 文本
里,改成 `sole reader of the global register` 而不是中文);板端注释可用中文。

生成器 gen_net_instability_svg.py 文案改动 → 同批重跑产物 `docs/images/网络不稳根因总览.svg`:只有那一
行的**框宽随文字自适应**(526 → 551,右缘 1411 未越界),画布 1560x1468 不变,无溢出告警。

⚠ 本笔**只含代码注释面**:该半批的文档面(BSD 函数调用关系 9 处、属主文档 §7 停发句、
生成器与产物那张网络不稳图)已被上一笔 `git add docs tools` 一并收走,两笔合起来才是完整的 F-* 批次。
自证:@build **0 错 0 警**且 Program Size 与改前**逐字节同数**(Code=233900 RO=26104 RW=1
536 ZI=136808,
注释无误伤的机器证据);net_socket 457/457、iec104_serv / net_pending 两套 exit 0;cppchec
k 钩子参数零
发现、coding-standard 0(lftpd_inet.c 那 4 条是存量且该目录本在钩子 exclude 内,用 HEAD 副本对照
甄别过)。
2026-10-27 09:05:27 +08:00

870 lines
32 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 SPI Ethernet Protocol Stack Driver
* 模块功能:CH395F 以太网协议栈芯片 SPI 驱动,提供网络初始化、Socket 管理、
* 数据收发等功能。命令码参考 CH395 手册 v2.2 Table 5-1
* 适用平台:STM32F4 系列(SPI2 接口)
* 作者:王建锋
* 创建日期:2026-06-06
* 修改记录:
* 2026-06-06 王建锋 创建初始版本,按代码规范重构
*/
#ifndef CH395F_H
#define CH395F_H
/*
* 头文件包含区 - 仅包含本模块必需的头文件
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
/*
* 宏定义区 - SPI 命令码(来自 CH395 手册 v2.2 Table 5-1)
*/
/* 无输入数据,无输出数据 */
#define CH395F_CMD_RESET_ALL 0x05U
/* 无输入数据,1 字节输出 */
#define CH395F_CMD_GET_IC_VER 0x01U
#define CH395F_CMD_GET_CMD_STATUS 0x2CU
#define CH395F_CMD_GET_PHY_STATUS 0x26U
#define CH395F_CMD_GET_DHCP_STATUS 0x42U
/* 无输入数据,多字节输出(§5.16 / §5.14,勿按 1 字节读) */
#define CH395F_CMD_GET_GLOB_INT_STATUS_ALL 0x19U /* 2 字节 */
#define CH395F_CMD_GET_UNREACH_IPPT 0x28U /* 8 字节 */
/* 无输入数据,6 字节输出 */
#define CH395F_CMD_GET_MAC_ADDR 0x40U
/* 无输入数据,20 字节输出 */
#define CH395F_CMD_GET_IP_INF 0x43U
/* 1 字节输入,无输出数据 */
#define CH395F_CMD_SET_PHY 0x20U
#define CH395F_CMD_PING_ENABLE 0x3FU
#define CH395F_CMD_DHCP_ENABLE 0x41U
#define CH395F_CMD_SET_RETRAN_COUNT 0x2AU
/* 1 字节输入,1 字节输出 */
#define CH395F_CMD_CHECK_EXIST 0x06U
/* 4 字节输入,无输出数据(§5.52,勿按 1 字节写) */
#define CH395F_CMD_SET_FUN_PARA 0x55U
/* 2 字节输入(低字节在前),无输出数据 */
#define CH395F_CMD_SET_TTL 0x51U
#define CH395F_CMD_SET_ARP 0x44U
#define CH395F_CMD_SET_RETRAN_PERIOD 0x2BU
/* 3 字节输入,无输出数据 */
#define CH395F_CMD_SET_BAUDRATE 0x02U
/* 4 字节输入,无输出数据 */
#define CH395F_CMD_SET_IP_ADDR 0x22U
#define CH395F_CMD_SET_GWIP_ADDR 0x23U
#define CH395F_CMD_SET_MASK_ADDR 0x24U
/* 6 字节输入,无输出数据 */
#define CH395F_CMD_SET_MAC_ADDR 0x21U
/* 初始化命令(仅写入,执行时间较长) */
#define CH395F_CMD_INIT_CH395 0x27U
/* Socket 命令 */
/* 1 字节输入(socket 索引),无输出数据 */
#define CH395F_CMD_CLOSE_SOCKET_SN 0x3DU
#define CH395F_CMD_OPEN_SOCKET_SN 0x35U
#define CH395F_CMD_TCP_LISTEN_SN 0x36U
#define CH395F_CMD_TCP_CONNECT_SN 0x37U
#define CH395F_CMD_TCP_DISCONNECT_SN 0x38U
#define CH395F_CMD_CLEAR_RECV_BUF_SN 0x2EU
/* 1 字节输入,1 字节输出(socket 索引) */
#define CH395F_CMD_GET_INT_STATUS_SN 0x30U
#define CH395F_CMD_GET_SOCKET_STATUS_SN 0x2FU
/* 1 字节输入,2 字节输出 */
#define CH395F_CMD_GET_RECV_LEN_SN 0x3BU
/* 2 字节输入,无输出数据 */
#define CH395F_CMD_SET_PROTO_TYPE_SN 0x34U
#define CH395F_CMD_SET_IPRAW_PRO_SN 0x3EU
/* 3 字节输入,无输出数据 */
#define CH395F_CMD_SET_DES_PORT_SN 0x32U
#define CH395F_CMD_SET_SOUR_PORT_SN 0x33U
/* 5 字节输入,无输出数据(socket + 4 字节 IP) */
#define CH395F_CMD_SET_IP_ADDR_SN 0x31U
/* 1 字节输入,6 字节输出(socket 索引 -> 远程 IP + 端口) */
#define CH395F_CMD_GET_REMOT_IPP_SN 0x2DU
/* 3 字节输入 + 数据输出(socket + 长度) */
#define CH395F_CMD_READ_RECV_BUF_SN 0x3CU
/* 3 字节输入 + 数据输入(socket + 长度 + 数据) */
#define CH395F_CMD_WRITE_SEND_BUF_SN 0x39U
/*
* TCP MSS(CH395F_CMD_SET_TCP_MSS 参数)
* 由 net_init 经 ch395f_set_tcp_mss() 下发(须在 ch395f_init 之前);此处为单一真值源。
* 维持 1024:8 Socket 共享 24KB 缓冲时,单 Socket 接收缓冲 = 2×MSS = 2KB(手册 §9.2.8
* 满足上限的最大值)。MSS=512 裕量方案未采纳;当年支撑该决策的台架判据不可信,
* 已随 TC-NET-604 结案为非缺陷一并撤回(2026-09-23)——维持 1024 的
* 现有理由 = 手册允许的最大值、满缓冲周期段数少。MSS 只影响芯片分包与窗口动态,
* 与下方缓冲块布局解耦。
*/
#define CH395F_TCP_MSS 1024U
/* 内部缓冲 RAM 每块字节数(手册 §5.45:48 块 × 512B = 24KB) */
#define CH395F_RAM_BLOCK_SIZE 512U
/* 单 Socket 缓冲块数:固定布局(2026-09-22 与 MSS 解耦;此前由 MSS 推导,改 MSS 会
* 连带静默缩小布局):接收 4 块=2KB、发送 2 块=1KB,8 Socket × 6 块 = 48 块恰好用满。
* 布局满足手册 §9.2.8:接收 2KB = 2×MSS(1024)(建议下沿,零裕量——用满 48 块的代价)/
* ≥ MSS(必须)/ ≤ 6×MSS(建议);
* 发送 1KB = MSS(WCH FAQ 要求"发送缓冲 > MSS",此处取等值——生产实测(FTP 大文件
* 上传/下载 + UI 推流)在缓冲边界可正常成包)。 */
#define CH395F_RECV_BLOCKS 4U
#define CH395F_SEND_BLOCKS 2U
/* 单 Socket 硬件收发缓冲字节数(= 块数 × 块大小)。写入发送 FIFO 的单次长度严禁超过此值,
* 否则会写穿有限的发送缓冲(见 TRAP-NET-16)。 */
#define CH395F_SEND_BUF_SIZE_BYTES (CH395F_SEND_BLOCKS * CH395F_RAM_BLOCK_SIZE)
#define CH395F_RECV_BUF_SIZE_BYTES (CH395F_RECV_BLOCKS * CH395F_RAM_BLOCK_SIZE)
/*
* SPI DMA 事务限制
* CH395F_SPI_DMA_MAX_PAYLOAD: 单次 DMA 事务最大有效载荷(总缓冲 - 4 字节命令头)
* 缓冲按"一条命令读空整个 Socket 接收缓冲(2KB)"定容——排空契约(TRAP-NET-20,
* bit3=1 残数据由 MCU 读出)的形态本身就是整缓冲单读。
* (旧解释"部分读致 recv_len 归零、剩余数据不可见"未证实且与手册 §5.34 相左,
* 定容不依赖该解释;结案见 `CH395F_Trap_Records.md` 台架纪律。)
* 2026-09-22:与 MSS 解耦(此前 = 2×MSS+4,MSS 下调会把 DMA 缓冲缩到装不下整缓冲
* → 整缓冲读会被截断丢弃)。
*/
#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_CMD_SET_TCP_MSS 0x50U
#define CH395F_CMD_SET_RECV_BUF 0x52U
#define CH395F_CMD_SET_SEND_BUF 0x53U
#define CH395F_CMD_SET_KEEPALIVE_IDLE 0x56U
#define CH395F_CMD_SET_KEEPALIVE_INTVL 0x57U
#define CH395F_CMD_SET_KEEPALIVE_CNT 0x58U
#define CH395F_CMD_SET_KEEPALIVE_SN 0x59U
/* EEPROM(0xE9..0xEB)/GPIO(0xEC/0xED)/SLEEP(0x03) 命令宏与
* GET_GLOB_INT_STATUS(0x29,只有 2 字节版 0x19 有实现) 死声明已删除——
* 全仓零引用已核实;需要时按手册 §5.x 重新登记 */
/*
* CH395 命令执行状态码(CMD_GET_CMD_STATUS 返回值,与芯片手册一致)
*/
#define CH395F_ERR_SUCCESS 0x00U /* 成功 */
#define CH395F_ERR_BUSY 0x10U /* 忙,命令正在执行 */
#define CH395F_ERR_MEM 0x11U /* 内存管理错误 */
#define CH395F_ERR_BUF 0x12U /* 缓冲区错误 */
#define CH395F_ERR_TIMEOUT 0x13U /* 超时 */
#define CH395F_ERR_RTE 0x14U /* 路由错误 */
#define CH395F_ERR_ABRT 0x15U /* 连接中止 */
#define CH395F_ERR_RST 0x16U /* 连接复位 */
#define CH395F_ERR_CLSD 0x17U /* 连接关闭 */
#define CH395F_ERR_CONN 0x18U /* 无连接 */
#define CH395F_ERR_VAL 0x19U /* 值错误 */
#define CH395F_ERR_ARG 0x1AH /* 参数错误 */
#define CH395F_ERR_USE 0x1BH /* 已被使用 */
#define CH395F_ERR_IF 0x1CH /* MAC 错误 */
#define CH395F_ERR_ISCONN 0x1DH /* 已连接 */
#define CH395F_ERR_OPEN 0x20U /* 已打开 */
#define CH395F_CMD_RET_ABORT 0x5FU /* 命令中止(来自官方库) */
#define CH395F_ERR_UNKNOW 0xFAU /* 未知错误」 */
/*
* PHY 状态码
*/
#define CH395F_PHY_DISCONN 0x01U /* PHY 断开连接 */
#define CH395F_PHY_10M_FULL 0x02U /* 10M 全双工 */
#define CH395F_PHY_10M_HALF 0x04U /* 10M 半双工 */
#define CH395F_PHY_100M_FULL 0x08U /* 100M 全双工 */
#define CH395F_PHY_100M_HALF 0x10U /* 100M 半双工 */
#define CH395F_PHY_AUTO_NEGOTIATE 0x20U /* 自动协商 */
/*
* 功能参数标志位(CMD_SET_FUN_PARA,§5.52 表)
* bit3 SOCKET_CLOSE 需芯片版本 ≥0x46(版本门控见 net_init);
* bit1 TCP_SERVER 多连接模式——本项目单连接模型不用(红线,勿置 1);
* bit0 保留必须为 0(TRAP-NET-15 定案更正:0x09→0x08)
*/
#define CH395F_FUN_PARA_TCP_SERVER (1UL << 1) /* TCP Server 多连接模式 */
#define CH395F_FUN_PARA_SOCKET_CLOSE (1UL << 3) /* Socket 关闭控制(0=芯片自动,1=外部控制;TRAP-NET-20 排空契约) */
#define CH395F_FUN_PARA_DISABLE_SEND_OK (1UL << 4) /* 禁用 SEND_OK 中断 */
/*
* 协议类型
*/
#define CH395F_PROTO_TYPE_IP_RAW 0x00U
#define CH395F_PROTO_TYPE_MAC_RAW 0x01U
#define CH395F_PROTO_TYPE_UDP 0x02U
#define CH395F_PROTO_TYPE_TCP 0x03U
/*
* Socket 状态
*/
#define CH395F_SOCKET_CLOSED 0x00U
#define CH395F_SOCKET_OPEN 0x05U
/*
* TCP 状态
*/
#define CH395F_TCP_CLOSED 0x00U
#define CH395F_TCP_LISTEN 0x01U
#define CH395F_TCP_SYN_SENT 0x02U
#define CH395F_TCP_SYN_RCVD 0x03U
#define CH395F_TCP_ESTABLISHED 0x04U
#define CH395F_TCP_FIN_WAIT_1 0x05U
#define CH395F_TCP_FIN_WAIT_2 0x06U
#define CH395F_TCP_CLOSE_WAIT 0x07U
#define CH395F_TCP_CLOSING 0x08U
#define CH395F_TCP_LAST_ACK 0x09U
#define CH395F_TCP_TIME_WAIT 0x0AU
/*
* 全局中断状态位低字节(bit0~3 全局事件;§5.16——2 字节版
* GET_GLOB_INT_STATUS_ALL 低字节同语义。Socket 事件位(bit4 起)由
* net_poll 按 1U<<(i+4) 计算,旧 SOCK0..3 单列宏已删(
* 全仓零引用;1 字节版命令 0x29 亦已随死声明清理)
*/
#define CH395F_GINT_STAT_UNREACH 0x01U
#define CH395F_GINT_STAT_IP_CONFLI 0x02U
#define CH395F_GINT_STAT_PHY_CHANGE 0x04U
#define CH395F_GINT_STAT_DHCP 0x08U
/*
* 全局中断状态位(CMD_GET_GLOB_INT_STATUS_ALL 2字节版,支持Socket 0~7)
* 低字节高字节分别定义
*/
#define CH395F_GINT_STAT_SOCK4 0x0100U
#define CH395F_GINT_STAT_SOCK5 0x0200U
#define CH395F_GINT_STAT_SOCK6 0x0400U
#define CH395F_GINT_STAT_SOCK7 0x0800U
/* bit12 DHCPv6:官方 SDK 定义为 (1<<12),但 §5.16 明确 CH395F 的 [12:15] 为
* 保留位(仅 CH395X 系列产生)——本芯片上恒为 0,勿用作判据 */
#define CH395F_GINT_STAT_DHCPV6 0x1000U
/*
* Socket 中断状态位(CMD_GET_INT_STATUS_SN 返回值,来自手册表5-x)
*/
#define CH395F_SINT_STAT_SENBUF_FREE 0x01U /* bit0: 发送缓冲区空闲 */
#define CH395F_SINT_STAT_SEND_OK 0x02U /* bit1: 发送成功 */
#define CH395F_SINT_STAT_RECV_OK 0x04U /* bit2: 接收缓冲区非空 */
#define CH395F_SINT_STAT_CONNECT 0x08U /* bit3: TCP 连接成功 */
#define CH395F_SINT_STAT_DISCONNECT 0x10U /* bit4: TCP 连接断开 */
#define CH395F_SINT_STAT_DISCARD 0x20U /* bit5: 保留 */
#define CH395F_SINT_STAT_SOCK_TIMEOUT 0x40U /* bit6: 超时 */
/*
* 类型定义区 - 驱动返回码
*/
typedef enum {
CH395F_STATUS_OK = 0,
CH395F_STATUS_ERROR = -1,
CH395F_STATUS_TIMEOUT = -2,
CH395F_STATUS_NOT_DETECTED = -3
} ch395f_status_t;
/*
* 函数声明区 - SPI 基础事务层
*/
/*
* 函数功能:向 CH395 写入命令字节
* 入口参数:cmd - 命令码 uint8_t 0x00 - 0xFF
* 返回值:命令码回显值 uint8_t
* 限定条件:需在 ch395f_spi_begin() 和 ch395f_spi_end() 之间调用
* 函数说明:SPI 模式下命令与数据之间无需间隔
*/
uint8_t ch395f_write_cmd(uint8_t cmd);
/*
* 函数功能:向 CH395 写入数据字节
* 入口参数:data - 数据字节 uint8_t 0x00 - 0xFF
* 返回值:数据回显值 uint8_t
* 限定条件:需在 ch395f_spi_begin() 和 ch395f_spi_end() 之间调用
*/
uint8_t ch395f_write_data(uint8_t data);
/*
* 函数功能:从 CH395 读取数据字节
* 返回值:接收到的数据字节 uint8_t
* 限定条件:需在 ch395f_spi_begin() 和 ch395f_spi_end() 之间调用
*/
uint8_t ch395f_read_data(void);
/*
* 函数功能:查询 SPI 通道故障锁存
* 返回值:0 - 正常 1 - 曾发生 SPI 超时/错误(字节级或 DMA 级)
* 限定条件:无
* 函数说明:锁存式(MCU 复位前一直有效);上层据此判定"SPI 通道异常"
* (区别于"无芯片"/"PHY 未链接");仅首条故障记日志
*/
uint8_t ch395f_spi_byte_fault(void);
/*
* 函数声明区 - 芯片检测与版本
*/
/*
* 函数功能:检测 CH395 芯片是否存在且通信正常
* 返回值:CH395F_STATUS_OK - 检测到芯片,CH395F_STATUS_NOT_DETECTED - 未检测到
* 限定条件:SPI2 已正确初始化
* 函数说明:发送 CMD_CHECK_EXIST (0x06) 及测试字节 0x57,
* 芯片应返回按位取反值 0xA8
*/
ch395f_status_t ch395f_check_exist(void);
/*
* 函数功能:读取 CH395 芯片版本号
* 返回值:版本字节(bit5:0 为版本号)uint8_t
* 限定条件:芯片已通过 ch395f_check_exist() 检测
*/
uint8_t ch395f_get_version(void);
/*
* 函数声明区 - 初始化
*/
/*
* 函数功能:软件复位 CH395
* 返回值:CH395F_STATUS_OK
* 限定条件:SPI2 已正确初始化
* 函数说明:复位耗时约 15ms(TE0),函数内部已包含延时
*/
ch395f_status_t ch395f_reset(void);
/*
* 函数功能:查询命令执行状态
* 返回值:状态字节(CH395F_ERR_SUCCESS / CH395F_ERR_BUSY / ...)uint8_t
* 限定条件:仅在长执行命令(如初始化)后调用
*/
uint8_t ch395f_get_cmd_status(void);
/*
* 函数功能:轮询等待命令执行完成
* 入口参数:timeout_ms - 超时时间(毫秒) uint32_t
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 或 CH395F_CMD_RET_ABORT)
* 限定条件:在发送长执行命令(OPEN/TCP_LISTEN/CONNECT/DISCONNECT/CLOSE/DHCP)后调用
* 函数说明:每 20ms 查询一次,直到命令完成或超时
*/
uint8_t ch395f_poll_cmd_status(uint32_t timeout_ms);
/*
* 函数功能:初始化 CH395(包含 MAC、PHY、TCP/IP 协议栈)
* 返回值:CH395F_STATUS_OK - 成功,CH395F_STATUS_TIMEOUT - 超时失败
* 限定条件:芯片已通过 ch395f_reset() 复位
* 函数说明:阻塞等待初始化完成或超时(典型 5ms,TE1)
*/
ch395f_status_t ch395f_init(void);
/*
* 函数声明区 - 网络参数配置
*/
/*
* 函数功能:设置 CH395 IP 地址(点分十进制序:p_ip[0]=第一段,如 192;
* 字节序曾误注为"低字节在前"——调用方 parse_ip_string 产出
* 点分数组直传、芯片按首段在前接受,台架多年 IP 生效实证)
* 入口参数:p_ip - 4 字节 IP 地址指针 uint8_t*
* 限定条件:指针非空,芯片已初始化
*/
void ch395f_set_ip_addr(uint8_t *p_ip);
/*
* 函数功能:设置网关 IP 地址(点分十进制序,同 ch395f_set_ip_addr)
* 入口参数:p_gwip - 4 字节网关 IP 指针 uint8_t*
* 限定条件:指针非空,芯片已初始化
*/
void ch395f_set_gwip_addr(uint8_t *p_gwip);
/*
* 函数功能:设置子网掩码(点分十进制序,同 ch395f_set_ip_addr)
* 入口参数:p_mask - 4 字节子网掩码指针 uint8_t*
* 限定条件:指针非空,芯片已初始化
*/
void ch395f_set_mask_addr(uint8_t *p_mask);
/*
* 函数功能:设置 MAC 地址(低字节在前,存储于 EEPROM)
* 入口参数:p_mac - 6 字节 MAC 地址指针 uint8_t*
* 限定条件:指针非空,芯片已初始化
* 函数说明:执行耗时约 30us(TE5)
*/
void ch395f_set_mac_addr(uint8_t *p_mac);
/*
* 函数功能:从 CH395 读取 MAC 地址
* 出口参数:p_mac - 6 字节 MAC 地址缓冲区指针 uint8_t*
* 限定条件:指针非空
*/
void ch395f_get_mac_addr(uint8_t *p_mac);
/*
* 函数功能:读取 IP 信息(IP + 掩码 + DNS,共 20 字节)
* 出口参数:p_buf - 20 字节缓冲区指针 uint8_t*
* 限定条件:指针非空
*/
void ch395f_get_ip_inf(uint8_t *p_buf);
/*
* 函数声明区 - PHY 管理
*/
/*
* 函数功能:获取 PHY 连接状态
* 返回值:PHY 状态码(CH395F_PHY_DISCONN、CH395F_PHY_10M_FULL 等)uint8_t
* 限定条件:芯片已初始化
*/
uint8_t ch395f_get_phy_status(void);
/*
* 函数功能:设置 PHY 连接模式
* 入口参数:phystat - 连接模式码 uint8_t 0x20 = 自动协商
* 限定条件:芯片已初始化
*/
void ch395f_set_phy(uint8_t phystat);
/*
* 函数功能:使能/关闭 CH395 响应 PING
* 入口参数:enable - 1 使能 PING 响应,0 关闭
* 限定条件:芯片已初始化
* 函数说明:手册 5.37 CMD_PING_ENABLE,默认关闭
*/
void ch395f_ping_enable(uint8_t enable);
/*
* 函数声明区 - DHCP
*/
/*
* 函数功能:启用/禁用 DHCP
* 入口参数:enable - 1 启用,0 禁用 uint8_t
* 限定条件:芯片已初始化
*/
void ch395f_set_dhcp(uint8_t enable);
/*
* 函数功能:获取 DHCP 状态
* 返回值:0 = 成功,非零 = 错误/超时 uint8_t
* 限定条件:芯片已初始化且 DHCP 已启用
*/
uint8_t ch395f_get_dhcp_status(void);
/*
* 函数声明区 - Socket 管理
*/
/*
* 函数功能:设置 Socket 协议类型
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
* proto - 协议类型 uint8_t CH395F_PROTO_TYPE_xxx
* 限定条件:Socket 未打开
*/
void ch395f_set_proto_type(uint8_t sock, uint8_t proto);
/*
* 函数功能:设置 Socket 目标 IP 地址
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
* p_ip - 4 字节目标 IP 指针 uint8_t*
* 限定条件:指针非空
* 函数说明:字节序与 ch395f_get_remot_ipp 输出一致(net_connect 直传其输出,
* 台架出站连接往返实证)
*/
void ch395f_set_des_ip(uint8_t sock, uint8_t *p_ip);
/*
* 函数功能:设置 Socket 目标端口(小端序)
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
* port - 目标端口 uint16_t
* 限定条件:无
*/
void ch395f_set_des_port(uint8_t sock, uint16_t port);
/*
* 函数功能:设置 Socket 源端口(小端序)
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
* port - 源端口 uint16_t
* 限定条件:无
*/
void ch395f_set_sour_port(uint8_t sock, uint16_t port);
/*
* 函数功能:打开 Socket
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t
* 限定条件:协议类型、目标 IP、端口已设置
*/
uint8_t ch395f_open_socket(uint8_t sock);
/*
* 函数功能:关闭 Socket
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t
* 限定条件:Socket 已打开
*/
uint8_t ch395f_close_socket(uint8_t sock);
/*
* 函数功能:启动 TCP 监听模式
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t
* 限定条件:Socket 已打开且协议类型为 TCP
*/
uint8_t ch395f_tcp_listen(uint8_t sock);
/*
* 函数功能:启动 TCP 连接
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t
* 限定条件:Socket 已打开且协议类型为 TCP
*/
uint8_t ch395f_tcp_connect(uint8_t sock);
/*
* 函数功能:断开 TCP 连接
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t
* 限定条件:TCP 已建立连接
*/
uint8_t ch395f_tcp_disconnect(uint8_t sock);
/*
* 函数声明区 - Socket 数据传输
*/
/*
* 函数功能:向 Socket 发送缓冲区写入数据
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
* p_data - 数据指针 uint8_t*
* len - 数据长度 uint16_t
* 限定条件:指针非空,长度大于 0,TCP 已连接或 UDP 已打开
*/
void ch395f_write_send_buf(uint8_t sock, uint8_t *p_data, uint16_t len);
/*
* 函数功能:从 Socket 接收缓冲区读取数据
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
* p_data - 输出缓冲区指针 uint8_t*
* len - 待读取数据长度 uint16_t
* 限定条件:指针非空,长度大于 0,接收缓冲区有数据
*/
void ch395f_read_recv_buf(uint8_t sock, uint8_t *p_data, uint16_t len);
/*
* 函数功能:获取 Socket 接收缓冲区数据长度
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
* 返回值:接收数据长度 uint16_t
* 限定条件:Socket 已打开
*/
uint16_t ch395f_get_recv_len(uint8_t sock);
/*
* 函数声明区 - 中断状态
*/
/*
* 函数功能:获取全局中断状态(2 字节版,支持 Socket 0~7)
* 返回值:中断状态 uint16_t(低字节=Socket 0~3 + PHY/DHCP,高字节=Socket 4~7 + DHCPv6)
* 限定条件:芯片已初始化
* ⚠ 护栏(唯一读者红线,docs/网络/网络自愈架构设计.md §4.10;I7 不变量):
* 本寄存器**读即清**且含全部 Socket 事件位——
* 任何未配对 SINT 消费的读取都会吞掉其它 Socket 的事件通知。
* **唯一读者 = net_poll(net_socket.c);测试/台架代码同样禁自行读取**
* (用户裁定 2026-10-13)——等事件一律直读本 Socket ch395f_get_sock_int_status()。
* 唯一例外:被测对象就是本 API 的板级用例(寄存器断言 / Phase 12 L1
* 时延基准,硬件层独占上下文、无并发消费者)。
*/
uint16_t ch395f_get_glob_int_status_all(void);
/*
* 函数功能:获取 Socket 中断状态
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
* 返回值:Socket 中断状态字节 uint8_t
* 限定条件:芯片已初始化
*/
uint8_t ch395f_get_sock_int_status(uint8_t sock);
/*
* 函数功能:获取 Socket 状态(2 字节输出)
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
* status - 2 字节输出缓冲区 [0]=Socket状态, [1]=TCP状态
* 限定条件:芯片已初始化
* 函数说明:Socket 状态: 00H=CLOSED, 05H=OPEN
* TCP 状态: 00H=CLOSED, 01H=LISTEN, 02H=SYN_SENT, 03H=SYN_RCVD, 04H=ESTABLISHED
* ⚠ 必须给 **2 字节**缓冲:只给 1 字节会栈越界 1 字节(2026-09-22 实测
* net_socket.c 两处调用曾如此,已修)。
*/
void ch395f_get_socket_status(uint8_t sock, uint8_t *status);
/*
* 函数声明区 - Socket 远端信息
*/
/*
* 函数功能:获取远端 IP 和端口
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
* p_buf - 6 字节输出缓冲区(4字节IP + 2字节端口)
* 限定条件:TCP Server 模式下连接建立后调用
* 函数说明:IP 低字节在前,端口低字节在前
*/
void ch395f_get_remot_ipp(uint8_t sock, uint8_t *p_buf);
/*
* 函数声明区 - 功能参数设置
*/
/*
* 函数功能:设置 CH395 功能参数
* 入口参数:para - 4 字节功能参数 uint32_t
* bit0: 未使用,必须为 0
* bit1: TCP Server 多连接模式使能
* bit2: 低功耗模式
* bit3: Socket 关闭控制(0=芯片自动关闭,1=外部关闭)
* bit4: 禁用 SEND_OK 中断
* 限定条件:必须在 ch395f_init() 之前调用
*/
void ch395f_set_fun_para(uint32_t para);
/*
* 函数声明区 - TCP MSS 设置
*/
/*
* 函数功能:设置 TCP MSS
* 入口参数:mss - MSS 值 uint16_t 60~1460
* 限定条件:必须在 ch395f_init() 之前调用
*/
void ch395f_set_tcp_mss(uint16_t mss);
/*
* 函数声明区 - Socket 缓冲区设置
*/
/*
* 函数功能:设置 Socket 接收缓冲区
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
* start_block - 起始块地址 uint8_t
* block_count - 块个数 uint8_t
* 限定条件:必须在 OPEN_SOCKET_SN 之前调用
*/
void ch395f_set_recv_buf(uint8_t sock, uint8_t start_block, uint8_t block_count);
/*
* 函数功能:设置 Socket 发送缓冲区
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
* start_block - 起始块地址 uint8_t
* block_count - 块个数 uint8_t
* 限定条件:必须在 OPEN_SOCKET_SN 之前调用
*/
void ch395f_set_send_buf(uint8_t sock, uint8_t start_block, uint8_t block_count);
/*
* 函数功能:清空 Socket 接收缓冲区
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
* 限定条件:Socket 已打开
*/
void ch395f_clear_recv_buf(uint8_t sock);
/*
* 函数功能:设置 TCP KeepAlive 空闲时间
* 入口参数:time - 空闲时间(毫秒,必须为 500 的倍数) uint32_t
* 限定条件:必须在 ch395f_init() 之前调用
*/
void ch395f_set_keepalive_idle(uint32_t time);
/*
* 函数功能:设置 TCP KeepAlive 探测间隔
* 入口参数:time - 间隔时间(毫秒,必须为 500 的倍数) uint32_t
* 限定条件:必须在 ch395f_init() 之前调用
*/
void ch395f_set_keepalive_intvl(uint32_t time);
/*
* 函数功能:设置 TCP KeepAlive 探测次数
* 入口参数:cnt - 探测次数 uint8_t
* 限定条件:必须在 ch395f_init() 之前调用
*/
void ch395f_set_keepalive_cnt(uint8_t cnt);
/*
* 函数功能:启用/禁用指定 Socket 的 KeepAlive
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
* enable - 1 启用,0 禁用 uint8_t
* 限定条件:Socket 已打开
*/
void ch395f_set_keepalive_enable(uint8_t sock, uint8_t enable);
/*
* 函数声明区 - TCP 重传参数设置
*/
/*
* 函数功能:设置 TCP 重传次数
* 入口参数:cnt - 重传次数 uint8_t(§5.17:默认 12 次,最大 20,>20 按 20 处理;无 0=默认语义)
* 限定条件:必须在 ch395f_init() 之前调用
*/
void ch395f_set_retrans_count(uint8_t cnt);
/*
* 函数功能:设置 TCP 重传周期
* 入口参数:period - 重传周期(毫秒) uint16_t
* 限定条件:必须在 ch395f_init() 之前调用
*/
void ch395f_set_retrans_period(uint16_t period);
/*
* 函数声明区 - ARP / TTL / 不可达信息
*/
/*
* 函数功能:设置 ARP 重传参数
* 入口参数:period_100ms - ARP 重传周期(单位 100ms,0=默认值=10即1秒) uint8_t
* cnt - ARP 重传次数(0=默认值=3,255=无限重传) uint8_t
* 限定条件:应在 ch395f_init() 之后调用
*/
void ch395f_set_arp(uint8_t period_100ms, uint8_t cnt);
/*
* 函数功能:设置 Socket TTL
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
* ttl - TTL 值 uint8_t 最大 128
* 限定条件:Socket 已打开,TCP Server 模式下不生效
*/
void ch395f_set_ttl(uint8_t sock, uint8_t ttl);
/*
* 函数功能:获取不可达信息(用于调试连接失败原因)
* 出口参数:p_buf - 8 字节输出缓冲区(类型+协议码+端口+IP)
* 限定条件:收到 GINT_STAT_UNREACH 中断后调用
*/
void ch395f_get_unreach_info(uint8_t *p_buf);
/*
* 函数声明区 - 自愈驱动原语(设计 docs/网络/网络自愈架构设计.md §4.4;
* 形态定案锚点 同文档 §5.2 E2/E3/E4)
* E2 实测:单次状态回读 18.1us;LISTEN 可见延迟 100% <=10ms。
*/
/* 类型化状态回读 + 每 Socket 缓存 = 单一事实源(docs/网络/网络自愈架构设计.md §4.4) */
#define CH395F_SOCK_STATE_NONE 0xFFU /* open=CLOSED 时 tcp_state 哨兵("无意义") */
typedef struct {
uint8_t open; /* byte0:CH395F_SOCKET_CLOSED / CH395F_SOCKET_OPEN */
uint8_t tcp_state; /* byte1:CH395F_TCP_*;open=CLOSED 时为 CH395F_SOCK_STATE_NONE */
} ch395f_sock_state_t;
/*
* 函数功能:主动回读本 Socket 状态并刷新驱动缓存(缓存刷新点之一,另一个
* 是 net_poll 每轮全量刷新)
* 入口参数:sn - Socket 索引 uint8_t 0 - 7
* 返回值:类型化状态;sn>7 返回 {CLOSED, 哨兵} 并计一次边界 fault uint8_t×2
* 限定条件:芯片已初始化;netTask 上下文(与其它 CH395F 事务串行)
*/
ch395f_sock_state_t ch395f_get_sock_state(uint8_t sn);
/*
* 函数功能:读驱动缓存(零 SPI 成本;数据新鲜度取决于刷新点,见上)
* 入口参数:sn - Socket 索引 uint8_t 0 - 7
* 返回值:最近一次刷新的状态;sn>7 返回 {CLOSED, 哨兵}
*/
ch395f_sock_state_t ch395f_sock_state_cached(uint8_t sn);
/*
* 函数功能:判"本 Socket 正在监听"(读缓存:open=OPEN 且 TCP=LISTEN)
* 入口参数:sn - Socket 索引 uint8_t 0 - 7
* 返回值:1=在听 0=不在 int
*/
int ch395f_sock_is_listening(uint8_t sn);
/*
* 函数功能:事件护栏——只读本 Socket SINT(0x30,读即清),永不触碰全局寄存器
* (唯一读者红线收窄,docs/网络/网络自愈架构设计.md §4.10:两级预清
* "先读全局再读本 socket"会清掉其它 Socket 的
* 事件位;全局寄存器唯一读者=net_poll 写成驱动侧契约)
* 入口参数:sn - Socket 索引 uint8_t 0 - 7
* 返回值:SINT 位图;sn>7 返回 0 uint8_t
*/
uint8_t ch395f_sock_events(uint8_t sn);
/* 复合复位模式(两套同构变体的统一原语,docs/网络/网络自愈架构设计.md §4.4;
* 两模式都必须排 RX——E4 定案,差异只剩最短等待) */
typedef enum {
CH395F_RESET_GRACEFUL = 0, /* 最短等待 100ms(TRAP-NET-18 二阶段实测值) */
CH395F_RESET_QUARANTINE /* 最短等待 400ms */
} ch395f_reset_mode_t;
/*
* 函数功能:启动 Socket 复合复位(非阻塞状态机,每 net_poll 步进;内部序列
* E4 定案:读空 RX -> CLOSE -> 排空事件(quiescent) -> 轮询 byte0=00H)
* 入口参数:sn - Socket 索引 uint8_t 0 - 7
* mode - 复位模式 ch395f_reset_mode_t
* 返回值:0=已启动 -1=参数错或已在运行(调用方逻辑错误) int
* 限定条件:netTask 上下文;调用前本层已放弃该会话(复位会丢弃 RX 残渣)
*/
int ch395f_sock_reset_begin(uint8_t sn, ch395f_reset_mode_t mode);
/*
* 函数功能:复位状态机步进(在 net_poll 或测试循环里周期调用,禁忙等复制)
* 入口参数:sn - Socket 索引 uint8_t 0 - 7
* 返回值:0=完成(含未启动,幂等) 1=进行中 -1=失败(超时/参数,槽位已复位可重开) int
*/
int ch395f_sock_reset_poll(uint8_t sn);
/* 命令完成判据(阻塞等待的非阻塞化,docs/网络/网络自愈架构设计.md §4.4;
* E3 定案=状态回读,GET_CMD_STATUS 对这三条无判别力) */
typedef enum {
CH395F_DONE_OPEN = 0, /* open 完成 = byte0 变 05H */
CH395F_DONE_LISTEN, /* listen 完成 = byte0=05H 且 TCP=01H(E2:<=10ms 可见) */
CH395F_DONE_CLOSE /* close 完成 = byte0=00H */
} ch395f_done_what_t;
/*
* 函数功能:非阻塞命令完成查询(单次主动回读 18.1us,E2 背书;勿复制
* poll_cmd_status 式忙等——E3 实证其对 OPEN/LISTEN/CLOSE 恒白等且无判别力)
* 入口参数:sn - Socket 索引 uint8_t 0 - 7
* what - 完成判据 ch395f_done_what_t
* 返回值:1=已完成 0=未完成 -1=参数错 int
*/
int ch395f_cmd_done(uint8_t sn, ch395f_done_what_t what);
/* 链路态缓存(拔网线不再静默,docs/网络/网络自愈架构设计.md §4.4;net_poll 读全局后喂 bit0~3) */
/*
* 函数功能:喂全局中断位(net_poll 读 GET_GLOB_INT_STATUS_ALL 后调用;
* bit2 PHY_CHANGE 置位时驱动重读 PHY 更新 link_up 缓存 + 变化计数)
* 入口参数:glob_bits - 全局中断状态低字节语义位图 uint16_t
*/
void ch395f_glob_event_feed(uint16_t glob_bits);
/*
* 函数功能:读链路态缓存(首次查询惰性读 PHY 建档)
* 返回值:1=link up 0=down uint8_t(判据 B9:PHY != DISCONN 即 up)
*/
uint8_t ch395f_link_up_cached(void);
/*
* 函数功能:读链路变化计数(net 层订阅用:计数变化 -> 日志/可选重配)
* 返回值:自建档以来的 PHY 连接状态翻转次数 uint16_t
*/
uint16_t ch395f_link_change_count(void);
#ifdef __cplusplus
}
#endif
#endif /* CH395F_H */