网络主要内容测试完成
This commit is contained in:
@@ -925,7 +925,7 @@ uint8_t ch395f_get_dhcp_status(void) {
|
||||
|
||||
/*
|
||||
* 函数功能:设置Socket协议类型
|
||||
* 入口参数:sock - Socket索引 uint8_t 0 - 3
|
||||
* 入口参数:sock - Socket索引 uint8_t 0 - 7
|
||||
* proto - 协议类型 uint8_t CH395F_PROTO_TYPE_xxx
|
||||
* 限定条件:Socket必须处于关闭状态
|
||||
*/
|
||||
@@ -948,7 +948,7 @@ void ch395f_set_proto_type(uint8_t sock, uint8_t proto) {
|
||||
|
||||
/*
|
||||
* 函数功能:设置Socket目标IP地址
|
||||
* 入口参数:sock - Socket索引 uint8_t 0 - 3
|
||||
* 入口参数:sock - Socket索引 uint8_t 0 - 7
|
||||
* p_ip - 4字节目标IP指针 uint8_t*
|
||||
* 限定条件:p_ip不可为NULL
|
||||
*/
|
||||
@@ -980,7 +980,7 @@ void ch395f_set_des_ip(uint8_t sock, uint8_t *p_ip) {
|
||||
|
||||
/*
|
||||
* 函数功能:设置Socket目标端口(小端格式)
|
||||
* 入口参数:sock - Socket索引 uint8_t 0 - 3
|
||||
* 入口参数:sock - Socket索引 uint8_t 0 - 7
|
||||
* port - 目标端口号 uint16_t
|
||||
*/
|
||||
void ch395f_set_des_port(uint8_t sock, uint16_t port) {
|
||||
@@ -1005,7 +1005,7 @@ void ch395f_set_des_port(uint8_t sock, uint16_t port) {
|
||||
|
||||
/*
|
||||
* 函数功能:设置Socket源端口(小端格式)
|
||||
* 入口参数:sock - Socket索引 uint8_t 0 - 3
|
||||
* 入口参数:sock - Socket索引 uint8_t 0 - 7
|
||||
* port - 源端口号 uint16_t
|
||||
*/
|
||||
void ch395f_set_sour_port(uint8_t sock, uint16_t port) {
|
||||
@@ -1105,7 +1105,7 @@ uint8_t ch395f_tcp_disconnect(uint8_t sock) {
|
||||
|
||||
/*
|
||||
* 函数功能:向Socket发送缓冲区写入数据(DMA批量传输)
|
||||
* 入口参数:sock - Socket索引 uint8_t 0 - 3
|
||||
* 入口参数:sock - Socket索引 uint8_t 0 - 7
|
||||
* p_data - 数据指针 uint8_t*
|
||||
* len - 数据长度 uint16_t
|
||||
* 限定条件:1. p_data不可为NULL
|
||||
@@ -1149,7 +1149,7 @@ void ch395f_write_send_buf(uint8_t sock, uint8_t *p_data, uint16_t len) {
|
||||
|
||||
/*
|
||||
* 函数功能:从Socket接收缓冲区读取数据(DMA批量传输)
|
||||
* 入口参数:sock - Socket索引 uint8_t 0 - 3
|
||||
* 入口参数:sock - Socket索引 uint8_t 0 - 7
|
||||
* p_data - 输出缓冲区指针 uint8_t*
|
||||
* len - 待读取数据长度 uint16_t
|
||||
* 限定条件:1. p_data不可为NULL
|
||||
@@ -1193,8 +1193,8 @@ void ch395f_read_recv_buf(uint8_t sock, uint8_t *p_data, uint16_t len) {
|
||||
|
||||
/*
|
||||
* 函数功能:获取Socket接收缓冲区中数据长度
|
||||
* 入口参数:sock - Socket索引 uint8_t 0 - 3
|
||||
* 返回值:接收数据长度 uint16_t
|
||||
* 入口参数:sock - Socket索引 uint8_t 0 - 7
|
||||
* 返回值:接收数据长度 uint16_t,实际上 ch395F 接收缓冲区最大也就 8192
|
||||
* 限定条件:Socket必须已打开
|
||||
*/
|
||||
uint16_t ch395f_get_recv_len(uint8_t sock) {
|
||||
|
||||
@@ -110,12 +110,31 @@ extern "C" {
|
||||
/* 3 字节输入 + 数据输入(socket + 长度 + 数据) */
|
||||
#define CH395F_CMD_WRITE_SEND_BUF_SN 0x39U
|
||||
|
||||
/*
|
||||
* TCP MSS(CH395F_CMD_SET_TCP_MSS 参数)
|
||||
* 由 net_init 经 ch395f_set_tcp_mss() 下发;此处作为单一真值源,
|
||||
* DMA 缓冲大小亦由此推导(见下)。当前选取依据:8 Socket 共享 24KB 缓冲时,
|
||||
* 各 Socket 接收缓冲 = 2×MSS,故 MSS 取 1024 为最大值(详见 net_socket.c 分配注释)。
|
||||
*/
|
||||
#define CH395F_TCP_MSS 1024U
|
||||
|
||||
/* 内部缓冲 RAM 每块字节数(手册 §5.45:48 块 × 512B = 24KB) */
|
||||
#define CH395F_RAM_BLOCK_SIZE 512U
|
||||
/* 单 Socket 缓冲块数由 MSS 推导:接收 = 2×MSS(满足手册 §9.2.8 接收 ≥ 2×MSS),发送 = 1×MSS;向上取整 */
|
||||
#define CH395F_RECV_BLOCKS ((2U * CH395F_TCP_MSS + CH395F_RAM_BLOCK_SIZE - 1U) / CH395F_RAM_BLOCK_SIZE)
|
||||
#define CH395F_SEND_BLOCKS ((CH395F_TCP_MSS + CH395F_RAM_BLOCK_SIZE - 1U) / CH395F_RAM_BLOCK_SIZE)
|
||||
/* 单 Socket 硬件收发缓冲字节数(= 块数 × 块大小)。写入发送 FIFO 的单次长度严禁超过此值,
|
||||
* 否则会写穿有限的发送缓冲(见 Trap 20)。 */
|
||||
#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 字节命令头)
|
||||
* 注意: CH395F 内部 socket 接收缓冲默认 4096B,DMA 缓冲需至少 4100 以一次性读空
|
||||
* 接收方向需一次性读空整个 Socket 接收缓冲(= 2×MSS,避免 Trap 13 部分读导致数据不可见),
|
||||
* 故总缓冲 = 2×MSS + 4(4 为命令头开销),有效载荷 = 2×MSS。
|
||||
*/
|
||||
#define CH395F_SPI_DMA_BUF_SIZE 4100U
|
||||
#define CH395F_SPI_DMA_BUF_SIZE (CH395F_TCP_MSS * 2U + 4U)
|
||||
#define CH395F_SPI_DMA_MAX_PAYLOAD (CH395F_SPI_DMA_BUF_SIZE - 4U)
|
||||
|
||||
/* 其他命令 */
|
||||
|
||||
@@ -41,13 +41,16 @@ static int check_socket_error(int sockfd);
|
||||
* timeout - 超时时间结构体指针 net_timeval *(NULL=无限等待)
|
||||
* 出口参数:readfds/writefds/exceptfds - 仅保留就绪的 Socket 位 net_fd_set *
|
||||
* 返回值:就绪的 Socket 数量(>= 0);-1 表示参数无效 int
|
||||
* 限定条件:net_init() + MX_FREERTOS_Init() 已执行;必须在 netTask 上下文中调用
|
||||
* 函数说明:1. 轮询所有 Socket,检查读/写/异常事件是否就绪
|
||||
* 2. 阻塞等待直到有事件就绪或超时
|
||||
* 3. 通过 osDelay(1) 让出 CPU,平衡实时性与 CPU 利用率
|
||||
* 限定条件:net_init() + MX_FREERTOS_Init() 已执行;可在任意任务上下文调用
|
||||
* 函数说明:1. 轮询 Socket 控制块(RAM)中的读/写/异常状态,判断事件是否就绪
|
||||
* 2. 不在此直接访问 CH395F SPI——所有 ch395f 事务统一由 netTask 的 net_poll()
|
||||
* 每 10ms 串行执行并刷新控制块状态(send_ready / readable),本函数仅做
|
||||
* RAM 读取,避免与应用任务发起的 SPI 访问竞争(见 Trap 16)
|
||||
* 3. 阻塞等待直到有事件就绪或超时
|
||||
* 4. 通过 osDelay(1) 让出 CPU,平衡实时性与 CPU 利用率(状态刷新延迟 <=10ms)
|
||||
*/
|
||||
int net_select(int nfds, net_fd_set *readfds, net_fd_set *writefds,
|
||||
net_fd_set *exceptfds, net_timeval *timeout) {
|
||||
net_fd_set *exceptfds, net_timeval *timeout) {
|
||||
uint32_t start_tick;
|
||||
uint32_t timeout_ms = 0;
|
||||
net_fd_set result_read = {0};
|
||||
@@ -70,9 +73,7 @@ int net_select(int nfds, net_fd_set *readfds, net_fd_set *writefds,
|
||||
start_tick = HAL_GetTick();
|
||||
|
||||
while (1) {
|
||||
/* 轮询所有 Socket */
|
||||
net_poll();
|
||||
|
||||
/* 仅读取 netTask 的 net_poll() 已刷新的控制块状态(无 CH395F SPI 访问) */
|
||||
ready_count = 0;
|
||||
|
||||
/* 检查哪个 Socket 有事件 */
|
||||
@@ -146,10 +147,11 @@ int net_select(int nfds, net_fd_set *readfds, net_fd_set *writefds,
|
||||
* timeout - 超时时间(毫秒) int >= 0(-1=无限等待,但本实现按 >=0 处理)
|
||||
* 出口参数:fds[i].revents - 填充实际发生的事件掩码 short
|
||||
* 返回值:就绪的 fd 数量(>= 0);-1 表示参数无效 int
|
||||
* 限定条件:net_init() + MX_FREERTOS_Init() 已执行;必须在 netTask 上下文中调用
|
||||
* 函数说明:1. 轮询所有 Socket,检查读/写/错误/挂起事件是否就绪
|
||||
* 2. 阻塞等待直到有事件就绪或超时
|
||||
* 3. 通过 osDelay(1) 让出 CPU,平衡实时性与 CPU 利用率
|
||||
* 限定条件:net_init() + MX_FREERTOS_Init() 已执行;可在任意任务上下文调用
|
||||
* 函数说明:1. 轮询 Socket 控制块(RAM)中的读/写/错误/挂起状态,判断事件是否就绪
|
||||
* 2. 不在此直接访问 CH395F SPI——状态由 netTask 的 net_poll() 每 10ms 刷新
|
||||
* 3. 阻塞等待直到有事件就绪或超时
|
||||
* 4. 通过 osDelay(1) 让出 CPU,平衡实时性与 CPU 利用率(状态刷新延迟 <=10ms)
|
||||
*/
|
||||
int net_poll_events(net_pollfd *fds, int nfds, int timeout) {
|
||||
uint32_t start_tick;
|
||||
@@ -163,9 +165,7 @@ int net_poll_events(net_pollfd *fds, int nfds, int timeout) {
|
||||
start_tick = HAL_GetTick();
|
||||
|
||||
while (1) {
|
||||
/* 轮询 */
|
||||
net_poll();
|
||||
|
||||
/* 仅读取 netTask 的 net_poll() 已刷新的控制块状态(无 CH395F SPI 访问) */
|
||||
ready = 0;
|
||||
|
||||
for (i = 0; i < nfds; i++) {
|
||||
@@ -248,7 +248,6 @@ int net_poll_events(net_pollfd *fds, int nfds, int timeout) {
|
||||
*/
|
||||
static int check_socket_readable(int sockfd) {
|
||||
net_sock_t *p_sock;
|
||||
uint16_t recv_len;
|
||||
|
||||
p_sock = net_get_sock(sockfd);
|
||||
if (NULL == p_sock) {
|
||||
@@ -260,12 +259,10 @@ static int check_socket_readable(int sockfd) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 已建立连接的 Socket 有数据可读 */
|
||||
if (NET_SOCK_STATE_ESTABLISHED == p_sock->state) {
|
||||
recv_len = ch395f_get_recv_len(sockfd);
|
||||
if (0 < recv_len) {
|
||||
return 1;
|
||||
}
|
||||
/* 已建立连接或 UDP 等有数据可读:readable 由 net_poll 在 RECV_OK 时置位、
|
||||
* net_recv_locked 读空后清零。避免应用任务直接访问 CH395F SPI(见 Trap 16) */
|
||||
if (p_sock->readable) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -65,7 +65,9 @@ static void parse_ip_string(const char *str, uint8_t *ip_arr);
|
||||
static int net_send_locked(net_sock_t *p_sock, const void *buf, int len);
|
||||
static int net_recv_locked(net_sock_t *p_sock, void *buf, int len, int flags);
|
||||
static int net_close_locked(net_sock_t *p_sock);
|
||||
static int net_relisten_locked(net_sock_t *p_sock);
|
||||
static int net_accept_locked(int sockfd, struct net_sockaddr *addr, int *addrlen);
|
||||
static int net_connect_locked(int sockfd, const struct net_sockaddr *addr, int addrlen);
|
||||
|
||||
/*
|
||||
* 函数功能:网络子系统初始化(配置 CH395F + 启用多连接模式)
|
||||
@@ -104,13 +106,18 @@ int net_init(const char *ip, const char *mask, const char *gateway) {
|
||||
ch395f_reset();
|
||||
DBG_INFO("net_init: set_fun_para...");
|
||||
|
||||
/* 启用单连接模式 + 手动关闭 Socket(bit3=1, bit1=0)
|
||||
/* 多 Socket 模式 + TCP Server 单连接 + 手动关闭 Socket(bit0=1, bit1=0, bit3=1)
|
||||
* bit0=1: 多 Socket 模式,启用 Socket 0~7(单 Socket 模式下 1~7 被禁用)
|
||||
* bit1=0: TCP Server 单连接,监听 Socket 0 仅接受 1 个客户端(连接停留在 Socket 0 本身)
|
||||
* bit3=1: DISCONNECT/TIMEOUT 时不自动清空缓冲区,由软件排空数据后手动关闭 */
|
||||
ch395f_set_fun_para(0x08);
|
||||
ch395f_set_fun_para(0x09);
|
||||
DBG_INFO("net_init: set_tcp_mss...");
|
||||
|
||||
/* 设置 TCP MSS */
|
||||
ch395f_set_tcp_mss(1460);
|
||||
/* 设置 TCP MSS
|
||||
* 手册(§5.45):CH395F 内部缓冲共 48 块 × 512B = 24KB。下方为 8 个 Socket 各分配 6 块
|
||||
* (接收 4 块=2KB + 发送 2 块=1KB),按手册 §9.2.8(接收 ≥ 2×MSS 建议)取 MSS=1024,用满 48 块。
|
||||
* MSS 真值源为 ch395f.h 的 CH395F_TCP_MSS,DMA 缓冲大小亦由其推导。 */
|
||||
ch395f_set_tcp_mss(CH395F_TCP_MSS);
|
||||
|
||||
/* 设置 TCP 重传参数(必须在 INIT_CH395 之前调用*/
|
||||
ch395f_set_retrans_count(8); /* 重传 8 次*/
|
||||
@@ -141,13 +148,31 @@ int net_init(const char *ip, const char *mask, const char *gateway) {
|
||||
ch395f_set_dhcp(1);
|
||||
}
|
||||
|
||||
/* 初始化 CH395F 协议栈(先不配置 buffer,测试默认值是否工作) */
|
||||
/* 初始化 CH395F 协议栈 */
|
||||
ret = ch395f_init();
|
||||
if (ret != CH395F_STATUS_OK) {
|
||||
s_net_errno = NET_ERR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 多 Socket 模式:为 Socket 0~7 各分配独立收发缓冲(必须在 OPEN_SOCKET 之前)
|
||||
* 手册(§5.45):CH395F 内部缓冲共 48 块 × 512B = 24KB;芯片上电默认仅给 Socket 0~3
|
||||
* 分配(每 Socket 接收 8 块/发送 4 块),Socket 4~7 为 NULL,故用到 8 个 Socket 必须重分配。
|
||||
* 单 Socket 块数由 MSS 推导(ch395f.h):接收 CH395F_RECV_BLOCKS(=2×MSS/512=4 块=2KB)、
|
||||
* 发送 CH395F_SEND_BLOCKS(=1×MSS/512=2 块=1KB),每 Socket 共 6 块,MSS=1024 用满 48 块:
|
||||
* blocks_per_socket = CH395F_RECV_BLOCKS + CH395F_SEND_BLOCKS
|
||||
* recv_start = i * blocks_per_socket, send_start = recv_start + CH395F_RECV_BLOCKS
|
||||
* Socket 7 占块 42~47,恰好用尽 0~47,互不重叠。
|
||||
* 注:此布局以手册 §5.45(48×512B)为准;若实际芯片为其它缓冲规格需重新核算。
|
||||
* Trap 01:先配数据 Socket 1~7,再配监听 Socket 0。 */
|
||||
uint8_t blocks_per_socket = (uint8_t)(CH395F_RECV_BLOCKS + CH395F_SEND_BLOCKS);
|
||||
for (int i = NET_MAX_SOCKETS - 1; i >= 0; i--) {
|
||||
uint8_t recv_start = (uint8_t)(i * blocks_per_socket);
|
||||
uint8_t send_start = (uint8_t)(recv_start + CH395F_RECV_BLOCKS);
|
||||
ch395f_set_send_buf((uint8_t)i, send_start, (uint8_t)CH395F_SEND_BLOCKS);
|
||||
ch395f_set_recv_buf((uint8_t)i, recv_start, (uint8_t)CH395F_RECV_BLOCKS);
|
||||
}
|
||||
|
||||
/* 使能 PING 响应 */
|
||||
ch395f_ping_enable(1);
|
||||
|
||||
@@ -207,9 +232,10 @@ int net_poll(void) {
|
||||
/* 取本 Socket 控制块(直接用数组下标,无需 net_get_sock 的越界判断) */
|
||||
net_sock_t *p_sock = &s_net_socks[i];
|
||||
|
||||
/* 全局中断状态 bit4~bit11 分别对应 socket0~socket7 的中断标志,
|
||||
* 对应位为 0 说明该 Socket 无中断,跳过以节省时间 */
|
||||
if (!(int_status & (1U << (i + 4)))) {
|
||||
/* 全局中断状态(GET_GLOB_INT_STATUS_ALL 16 位):Socket n 的中断位即 bit(n+4)。
|
||||
* Socket 0~3 在低位字节 bit4~bit7;Socket 4~7 在高位字节的 bit0~3
|
||||
* (即 16 位值的 bit8~bit11)。对应位为 0 说明该 Socket 无中断,跳过以节省时间。 */
|
||||
if (!(int_status & (1U << (i + 4U)))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -307,7 +333,7 @@ void net_process_messages(void) {
|
||||
break;
|
||||
}
|
||||
case NET_MSG_CONNECT: {
|
||||
msg.result = net_connect(msg.sockfd,
|
||||
msg.result = net_connect_locked(msg.sockfd,
|
||||
(const struct net_sockaddr *)&msg.addr,
|
||||
msg.addrlen);
|
||||
break;
|
||||
@@ -364,6 +390,7 @@ int net_socket(int domain, int type, int protocol) {
|
||||
p_sock->state = NET_SOCK_STATE_CREATED;
|
||||
p_sock->in_use = 1;
|
||||
p_sock->send_ready = 1;
|
||||
p_sock->readable = 0;
|
||||
|
||||
return sockfd;
|
||||
}
|
||||
@@ -419,10 +446,14 @@ int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen) {
|
||||
if (p_sock->type == NET_SOCK_DGRAM) {
|
||||
uint8_t status;
|
||||
|
||||
/* Socket 4-7 默认无收发缓冲,需显式分配 */
|
||||
/* net_init 已为全部 8 个 Socket 分配缓冲;此处仅对 Socket 4~7 兜底重设,
|
||||
* 使用与 net_init 相同的布局(由 MSS 推导,见 net_init) */
|
||||
if (sockfd >= 4) {
|
||||
ch395f_set_send_buf((uint8_t)sockfd, 28, 2);
|
||||
ch395f_set_recv_buf((uint8_t)sockfd, 30, 2);
|
||||
uint8_t blocks_per_socket = (uint8_t)(CH395F_RECV_BLOCKS + CH395F_SEND_BLOCKS);
|
||||
uint8_t recv_start = (uint8_t)(sockfd * blocks_per_socket);
|
||||
uint8_t send_start = (uint8_t)(recv_start + CH395F_RECV_BLOCKS);
|
||||
ch395f_set_send_buf((uint8_t)sockfd, send_start, (uint8_t)CH395F_SEND_BLOCKS);
|
||||
ch395f_set_recv_buf((uint8_t)sockfd, recv_start, (uint8_t)CH395F_RECV_BLOCKS);
|
||||
}
|
||||
|
||||
ch395f_set_proto_type((uint8_t)sockfd, CH395F_PROTO_TYPE_UDP);
|
||||
@@ -505,6 +536,8 @@ int net_listen_locked(int sockfd) {
|
||||
|
||||
/* 监听 Socket 进入 LISTENING 态 */
|
||||
p_sock->state = NET_SOCK_STATE_LISTENING;
|
||||
/* 单连接模式:连接断开后由 net 层自动回到 LISTEN(模拟 BSD 监听常驻) */
|
||||
p_sock->auto_relisten = 1;
|
||||
/* 单连接:CONNECT 中断直接作用于本 Socket 自身 */
|
||||
|
||||
/*
|
||||
@@ -584,6 +617,11 @@ static int net_accept_locked(int sockfd, struct net_sockaddr *addr, int *addrlen
|
||||
/* 单连接:本 Socket 自身在 CONNECT 后已转为 ESTABLISHED,
|
||||
* 只有处于 ESTABLISHED 才表示有可接受的连接;否则尚无连接 */
|
||||
if (p_listen_sock->state != NET_SOCK_STATE_ESTABLISHED) {
|
||||
/* 连接已断开(CLOSED)且启用自动重监听:先把 Socket 重新置回 LISTEN,
|
||||
* 下一次 accept 即可等待新连接(BSD 风格监听常驻) */
|
||||
if (p_listen_sock->state == NET_SOCK_STATE_CLOSED && p_listen_sock->auto_relisten) {
|
||||
net_relisten_locked(p_listen_sock);
|
||||
}
|
||||
s_net_errno = NET_ERR_WOULDBLOCK;
|
||||
return -1;
|
||||
}
|
||||
@@ -652,22 +690,72 @@ int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen) {
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:TCP Client 发起与服务器的连接
|
||||
* 函数功能:TCP Client 发起与服务器的连接(线程安全版本,通过消息队列委托给 netTask)
|
||||
* 入口参数:sockfd - Socket 描述符 (0~7),必须为已创建的 TCP Socket int
|
||||
* addr - 服务器地址结构体指针 const struct net_sockaddr *
|
||||
* addrlen - 地址结构体长度 int >= sizeof(struct net_sockaddr_in)
|
||||
* 返回值:0 - 连接请求发送成功(异步,需等待 ESTABLISHED) int
|
||||
* -1 - 连接失败(参数无效、状态错误等) int
|
||||
* 限定条件:Socket 已通过 net_socket() 创建且 type == NET_SOCK_STREAM;尚未连接
|
||||
* 函数说明:设置目标 IP 和端口后打开 CH395F Socket,进入 CONNECTING 状态。连接建立需等待
|
||||
* net_poll() 检测到 CONNECT 事件并将状态更新为 ESTABLISHED
|
||||
* 函数说明:将连接请求放入消息队列,阻塞等待 netTask 处理完毕。实际的 SPI 操作在 netTask
|
||||
* 上下文中执行,避免与 net_poll() 的 SPI 访问产生竞争(否则会破坏 CH395F 寄存器)。
|
||||
* 连接建立需等待 net_poll() 检测到 CONNECT 事件并将状态更新为 ESTABLISHED
|
||||
*/
|
||||
int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen) {
|
||||
net_msg_t msg;
|
||||
|
||||
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) {
|
||||
s_net_errno = NET_ERR_BADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NULL == netMsgQueueHandle) {
|
||||
s_net_errno = NET_ERR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NULL == addr || addrlen < (int)sizeof(struct net_sockaddr_in)) {
|
||||
s_net_errno = NET_ERR_INVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
msg.type = NET_MSG_CONNECT;
|
||||
msg.sockfd = sockfd;
|
||||
msg.buf = NULL;
|
||||
msg.len = 0;
|
||||
msg.flags = 0;
|
||||
memcpy(&msg.addr, addr, sizeof(struct net_sockaddr_in));
|
||||
msg.addrlen = addrlen;
|
||||
msg.caller = xTaskGetCurrentTaskHandle();
|
||||
msg.result = -1;
|
||||
|
||||
if (osMessageQueuePut(netMsgQueueHandle, &msg, 0, osWaitForever) != osOK) {
|
||||
s_net_errno = NET_ERR_BUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
{
|
||||
uint32_t s_notified;
|
||||
xTaskNotifyWait(0, 0, &s_notified, portMAX_DELAY);
|
||||
msg.result = (int)s_notified;
|
||||
}
|
||||
|
||||
if (msg.result < 0) {
|
||||
s_net_errno = NET_ERR;
|
||||
}
|
||||
return msg.result;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:TCP Client 发起连接(netTask 内部锁定版本,由消息队列委托执行)
|
||||
* 限定条件:net_init() 已调用;必须在 netTask 上下文中调用
|
||||
*/
|
||||
static int net_connect_locked(int sockfd, const struct net_sockaddr *addr, int addrlen) {
|
||||
net_sock_t *p_sock;
|
||||
const struct net_sockaddr_in *p_addr_in;
|
||||
uint8_t status;
|
||||
|
||||
/* 参数检<EFBFBD>?*/
|
||||
/* 参数检查 */
|
||||
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) {
|
||||
s_net_errno = NET_ERR_BADF;
|
||||
return -1;
|
||||
@@ -690,24 +778,56 @@ int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen) {
|
||||
p_sock->remote_ip = p_addr_in->sin_addr.s_addr;
|
||||
p_sock->remote_port = net_ntohs(p_addr_in->sin_port);
|
||||
|
||||
/* 转换 IP 为数组格式(低字节在前) */
|
||||
p_sock->remote_ip_arr[0] = (uint8_t)(p_sock->remote_ip);
|
||||
p_sock->remote_ip_arr[1] = (uint8_t)(p_sock->remote_ip >> 8);
|
||||
p_sock->remote_ip_arr[2] = (uint8_t)(p_sock->remote_ip >> 16);
|
||||
p_sock->remote_ip_arr[3] = (uint8_t)(p_sock->remote_ip >> 24);
|
||||
/* 转换 IP 为数组格式(大端/网络字节序,与 ch395f set_des_ip 期望一致,
|
||||
* 同 Phase2 phase2_tc201 的 test_parse_ip 结果 [192,168,1,2]) */
|
||||
p_sock->remote_ip_arr[0] = (uint8_t)(p_sock->remote_ip >> 24);
|
||||
p_sock->remote_ip_arr[1] = (uint8_t)(p_sock->remote_ip >> 16);
|
||||
p_sock->remote_ip_arr[2] = (uint8_t)(p_sock->remote_ip >> 8);
|
||||
p_sock->remote_ip_arr[3] = (uint8_t)(p_sock->remote_ip);
|
||||
|
||||
/* 配置 CH395F Socket */
|
||||
/* 配置 CH395F Socket:先 OPEN 再写源/目的端口(避免 open 复位寄存器) */
|
||||
ch395f_set_proto_type(sockfd, CH395F_PROTO_TYPE_TCP);
|
||||
ch395f_set_sour_port(sockfd, p_sock->local_port);
|
||||
ch395f_set_des_ip(sockfd, p_sock->remote_ip_arr);
|
||||
ch395f_set_des_port(sockfd, p_sock->remote_port);
|
||||
status = ch395f_open_socket(sockfd);
|
||||
|
||||
/* CH395F 关闭 Socket 后需延时才能重新打开(Trap 09),故失败重试最多 3 次 */
|
||||
for (int open_try = 0; open_try < 3; open_try++) {
|
||||
status = ch395f_open_socket(sockfd);
|
||||
if (status == CH395F_ERR_SUCCESS) {
|
||||
break; /* 打开成功,退出重试 */
|
||||
}
|
||||
ch395f_close_socket(sockfd); /* 打开失败先关闭,再延时后重试 */
|
||||
HAL_Delay(500);
|
||||
}
|
||||
|
||||
if (status != CH395F_ERR_SUCCESS) {
|
||||
s_net_errno = NET_ERR_BUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 清掉本 Socket 可能残留的中断状态,丢弃上一条连接遗留的 DISCONNECT */
|
||||
(void)ch395f_get_sock_int_status((uint8_t)sockfd);
|
||||
(void)ch395f_get_glob_int_status_all();
|
||||
|
||||
ch395f_set_sour_port(sockfd, p_sock->local_port);
|
||||
ch395f_set_des_ip(sockfd, p_sock->remote_ip_arr);
|
||||
ch395f_set_des_port(sockfd, p_sock->remote_port);
|
||||
|
||||
/* 诊断:回读目的 IP/端口与 Socket 状态(GET_REMOT_IPP 为小端,故需按小端解析) */
|
||||
{
|
||||
uint8_t rip[6];
|
||||
uint8_t st = 0;
|
||||
uint32_t dip;
|
||||
uint16_t dp;
|
||||
ch395f_get_remot_ipp((uint8_t)sockfd, rip);
|
||||
ch395f_get_socket_status((uint8_t)sockfd, &st);
|
||||
dip = ((uint32_t)rip[3] << 24) | ((uint32_t)rip[2] << 16) |
|
||||
((uint32_t)rip[1] << 8) | rip[0];
|
||||
dp = ((uint16_t)rip[5] << 8) | rip[4];
|
||||
DBG_INFO("[CONN] sock%d openOK dest=%d.%d.%d.%d:%d status=0x%02X",
|
||||
sockfd,
|
||||
(dip >> 24) & 0xFF, (dip >> 16) & 0xFF,
|
||||
(dip >> 8) & 0xFF, dip & 0xFF, dp, st);
|
||||
}
|
||||
|
||||
/* 发起 TCP 连接 */
|
||||
ch395f_tcp_connect(sockfd);
|
||||
p_sock->state = NET_SOCK_STATE_CONNECTING;
|
||||
@@ -719,6 +839,11 @@ int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen) {
|
||||
* SPI DMA 单次事务最大有效载荷(取 CH395F 驱动公开常量)
|
||||
*/
|
||||
#define NET_DMA_MAX_PAYLOAD ((int)CH395F_SPI_DMA_MAX_PAYLOAD)
|
||||
/* 单次写入 CH395F 发送 FIFO 的最大字节数:受硬件发送缓冲(CH395F_SEND_BUF_SIZE_BYTES=1KB)
|
||||
* 与 SPI DMA 载荷(NET_DMA_MAX_PAYLOAD=2KB) 双重限制,以硬件发送缓冲为硬上限(见 Trap 20),
|
||||
* 否则单次写 2KB/4KB 会写穿 1KB 发送 FIFO。 */
|
||||
#define NET_SEND_CHUNK_MAX ((int)CH395F_SEND_BUF_SIZE_BYTES < NET_DMA_MAX_PAYLOAD ? \
|
||||
(int)CH395F_SEND_BUF_SIZE_BYTES : NET_DMA_MAX_PAYLOAD)
|
||||
|
||||
/*
|
||||
* 函数功能:发送数据(内部锁定版本,必须在 netTask 上下文调用)
|
||||
@@ -731,7 +856,7 @@ int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen) {
|
||||
* 出口参数:无
|
||||
* 返回值:实际发送字节数(>= 0);-1 表示参数无效或 Socket 未连接 int
|
||||
* 限定条件:p_sock 非空;Socket 处于 ESTABLISHED 状态;netTask 上下文
|
||||
* 函数说明:1. 按 NET_DMA_MAX_PAYLOAD 分块写入 CH395F 发送缓冲区
|
||||
* 函数说明:1. 按 NET_SEND_CHUNK_MAX(硬件发送缓冲上限,见 Trap 20)分块写入 CH395F 发送 FIFO
|
||||
* 2. 发送前等待 send_ready 置位,超时返回已发送字节数
|
||||
* 3. 每写完一块等待 SEND_OK 中断(send_ready 清零后重新置位)
|
||||
*/
|
||||
@@ -754,8 +879,8 @@ static int net_send_locked(net_sock_t *p_sock, const void *buf, int len) {
|
||||
|
||||
while (sent < len) {
|
||||
int chunk = len - sent;
|
||||
if (chunk > NET_DMA_MAX_PAYLOAD) {
|
||||
chunk = NET_DMA_MAX_PAYLOAD;
|
||||
if (chunk > NET_SEND_CHUNK_MAX) {
|
||||
chunk = NET_SEND_CHUNK_MAX;
|
||||
}
|
||||
|
||||
if (!p_sock->send_ready) {
|
||||
@@ -786,9 +911,6 @@ static int net_send_locked(net_sock_t *p_sock, const void *buf, int len) {
|
||||
return sent;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:接收数据(内部锁定版本,必须在 netTask 上下文调用)
|
||||
*/
|
||||
/*
|
||||
* 函数功能:接收数据(内部锁定版本,必须在 netTask 上下文调用)
|
||||
* 入口参数:p_sock - Socket 控制块指针 net_sock_t *
|
||||
@@ -803,7 +925,7 @@ static int net_send_locked(net_sock_t *p_sock, const void *buf, int len) {
|
||||
* 3. CLOSED 状态尝试排空接收缓冲区残余数据(Trap 13:FIN 可能先于数据到达)
|
||||
*/
|
||||
static int net_recv_locked(net_sock_t *p_sock, void *buf, int len, int flags) {
|
||||
uint16_t recv_len;
|
||||
int recv_len;
|
||||
uint32_t tick_start;
|
||||
int sockfd = (int)(p_sock - s_net_socks);
|
||||
|
||||
@@ -819,15 +941,24 @@ static int net_recv_locked(net_sock_t *p_sock, void *buf, int len, int flags) {
|
||||
|
||||
recv_len = ch395f_get_recv_len(sockfd);
|
||||
if (recv_len > 0) {
|
||||
int read_len = (recv_len > (uint16_t)len) ? len : (int)recv_len;
|
||||
int read_len = (recv_len > len) ? len : recv_len;
|
||||
DBG_INFO("recv sock%d len=%d", sockfd, recv_len);
|
||||
ch395f_read_recv_buf(sockfd, (uint8_t *)buf, (uint16_t)read_len);
|
||||
p_sock->recv_bytes += (uint32_t)read_len;
|
||||
p_sock->readable = 0; /* 已消费数据(注:部分读受 Trap 13 限制,下一次 RECV_OK 会重新置位) */
|
||||
HAL_Delay(1); /* 等待 CH395F 刷新 recv_len 寄存器 */
|
||||
return read_len;
|
||||
}
|
||||
|
||||
if (flags & NET_MSG_DONTWAIT) {
|
||||
/* 非阻塞且当前无数据:若连接已断开则视为 EOF(0) 并自动重监听,
|
||||
* 否则返回 WOULDBLOCK(-1) 表示暂时无数据 */
|
||||
if (p_sock->state == NET_SOCK_STATE_CLOSED) {
|
||||
if (p_sock->auto_relisten) {
|
||||
net_relisten_locked(p_sock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
s_net_errno = NET_ERR_WOULDBLOCK;
|
||||
return -1;
|
||||
}
|
||||
@@ -840,13 +971,18 @@ static int net_recv_locked(net_sock_t *p_sock, void *buf, int len, int flags) {
|
||||
|
||||
if (p_sock->state == NET_SOCK_STATE_CLOSED) {
|
||||
/* 断开前尝试排空 CH395F 接收缓冲区(Trap 13:FIN 可能比数据先到) */
|
||||
uint16_t rem = ch395f_get_recv_len(sockfd);
|
||||
int rem = ch395f_get_recv_len(sockfd);
|
||||
if (rem > 0) {
|
||||
int rd = (rem > (uint16_t)len) ? len : (int)rem;
|
||||
int rd = (rem > len) ? len : rem;
|
||||
ch395f_read_recv_buf(sockfd, (uint8_t *)buf, (uint16_t)rd);
|
||||
p_sock->recv_bytes += (uint32_t)rd;
|
||||
p_sock->readable = 0;
|
||||
return rd;
|
||||
}
|
||||
/* EOF:单连接模式自动回到 LISTEN,应用下次 net_accept 即接到新连接 */
|
||||
if (p_sock->auto_relisten) {
|
||||
net_relisten_locked(p_sock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -864,10 +1000,82 @@ static int net_recv_locked(net_sock_t *p_sock, void *buf, int len, int flags) {
|
||||
* 函数说明:1. 调用 ch395f_close_socket 关闭 CH395F 硬件 Socket
|
||||
* 2. 清空整个控制块(memset 0),释放该 Socket 资源
|
||||
*/
|
||||
static int net_close_locked(net_sock_t *p_sock) {
|
||||
/*
|
||||
* 函数功能:单连接模式断连后自动重新进入 LISTEN(不清空控制块,保留 fd)
|
||||
* 入口参数:p_sock - 已断开(CLOSED)的 TCP 监听型 Socket 控制块 net_sock_t *
|
||||
* 返回值:0 - 成功,-1 - 失败
|
||||
* 限定条件:netTask 上下文;p_sock->in_use == 1;保留 local_port/auto_relisten
|
||||
* 函数说明:1. 复用原本地端口与协议,重新 OPEN + TCP_LISTEN(Trap 09 重试)
|
||||
* 2. 仅将 state 置回 LISTENING,不 memset(fd 与 auto_relisten 保持不变)
|
||||
* 3. 实现 BSD 风格"监听 Socket 常驻",应用层无需手动重监听
|
||||
*/
|
||||
static int net_relisten_locked(net_sock_t *p_sock) {
|
||||
uint8_t status;
|
||||
int sockfd = (int)(p_sock - s_net_socks);
|
||||
|
||||
ch395f_set_proto_type((uint8_t)sockfd, CH395F_PROTO_TYPE_TCP);
|
||||
ch395f_set_sour_port((uint8_t)sockfd, p_sock->local_port);
|
||||
|
||||
for (int open_try = 0; open_try < 3; open_try++) {
|
||||
status = ch395f_open_socket((uint8_t)sockfd);
|
||||
if (status == CH395F_ERR_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
ch395f_close_socket((uint8_t)sockfd); /* 打开失败先关闭,再延时后重试 */
|
||||
HAL_Delay(500);
|
||||
}
|
||||
if (status != CH395F_ERR_SUCCESS) {
|
||||
s_net_errno = NET_ERR_BUSY;
|
||||
return -1;
|
||||
}
|
||||
status = ch395f_tcp_listen((uint8_t)sockfd);
|
||||
if (status != CH395F_ERR_SUCCESS) {
|
||||
s_net_errno = NET_ERR_BUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
p_sock->state = NET_SOCK_STATE_LISTENING;
|
||||
p_sock->remote_port = 0;
|
||||
p_sock->remote_ip = 0;
|
||||
memset(p_sock->remote_ip_arr, 0, sizeof(p_sock->remote_ip_arr));
|
||||
p_sock->send_ready = 0;
|
||||
p_sock->recv_bytes = 0;
|
||||
/* auto_relisten 保持为 1,下次断连仍自动重监听 */
|
||||
|
||||
for (int j = 0; j < NET_MAX_SOCKETS; j++) {
|
||||
(void)ch395f_get_sock_int_status((uint8_t)j);
|
||||
}
|
||||
(void)ch395f_get_glob_int_status_all();
|
||||
|
||||
DBG_INFO("sock%d auto-relisten ok", sockfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int net_close_locked(net_sock_t *p_sock) {
|
||||
int sockfd = (int)(p_sock - s_net_socks);
|
||||
uint32_t tick = HAL_GetTick();
|
||||
|
||||
ch395f_close_socket(sockfd);
|
||||
|
||||
/* 排空上一条连接残留的 DISCONNECT 中断(单连接模式仅有 Socket 0,
|
||||
* 复用同一 Socket 时,旧连接的 DISCONNECT 在 FIN/ACK 完成后才上报,
|
||||
* 若不清除会被下一连接误判为"刚建立就断开")。等待芯片回到 CLOSED
|
||||
* 并清掉 Socket/全局中断状态,避免事件串扰。
|
||||
*/
|
||||
do {
|
||||
uint8_t st = 0;
|
||||
ch395f_get_socket_status((uint8_t)sockfd, &st);
|
||||
(void)ch395f_get_sock_int_status((uint8_t)sockfd);
|
||||
(void)ch395f_get_glob_int_status_all();
|
||||
if (st == CH395F_SOCKET_CLOSED) {
|
||||
break;
|
||||
}
|
||||
if (HAL_GetTick() - tick > 500) {
|
||||
break;
|
||||
}
|
||||
osDelay(5);
|
||||
} while (1);
|
||||
|
||||
memset(p_sock, 0, sizeof(net_sock_t));
|
||||
|
||||
return 0;
|
||||
@@ -876,47 +1084,61 @@ static int net_close_locked(net_sock_t *p_sock) {
|
||||
/*
|
||||
* 函数功能:发送数据(线程安全版本,通过消息队列委托给 netTask)
|
||||
* 入口参数:sockfd - Socket 描述符 int >= 0 && < NET_MAX_SOCKETS
|
||||
* buf - 待发送数据缓冲区指针 const void *
|
||||
* len - 数据长度 int > 0
|
||||
* flags - 标志位,通常为 0 int
|
||||
* buf - 待发送数据缓冲区指针(调用返回前须保持有效,本函数不拷贝数据) const void *
|
||||
* len - 数据长度(字节),> 0 int
|
||||
* flags - 标志位,当前实现忽略(保留 BSD send 接口兼容) int
|
||||
* 返回值:实际发送字节数 int >= 0 || -1
|
||||
* -1 - 发送失败(参数无效、队列满等) int
|
||||
* 限定条件:Socket 处于 ESTABLISHED 状态;net_init() + MX_FREERTOS_Init() 已执行;非 netTask 上下文
|
||||
* 函数说明:将发送请求放入消息队列,阻塞等待 netTask 处理完毕并返回结果。netTask 内请使用 net_send_sock()
|
||||
* -1 - 发送失败(参数非法 / 消息队列入队失败 / netTask 侧发送错误) int
|
||||
* 限定条件:1. 必须在【非 netTask】上下文中调用(应用/测试任务);若在 netTask 内调用会自己等自己
|
||||
* (netTask 阻塞在 xTaskNotifyWait 而无人处理消息)→ 死锁。netTask 内请直接用 net_send_locked()。
|
||||
* 2. Socket 须处于 ESTABLISHED 状态;net_init() + MX_FREERTOS_Init() 已执行;
|
||||
* netMsgQueueHandle 已由 net_init 创建。
|
||||
* 函数说明:所有 CH395F SPI 访问只允许在 netTask 内串行执行(见 Trap 16)。本函数作为应用侧 API,
|
||||
* 自身不直接触碰 SPI,而是把发送请求打包成 net_msg_t 投递到 netMsgQueueHandle,由 netTask
|
||||
* 的 net_process_messages() 取出并在 netTask 上下文调用 net_send_locked() 真正写 CH395F。
|
||||
* 调用方通过 FreeRTOS TaskNotify 阻塞等待处理结果,从而对外呈现"同步发送"语义:
|
||||
* 函数返回即代表本次发送已被 netTask 处理完毕(成功或失败)。
|
||||
*/
|
||||
int net_send(int sockfd, const void *buf, int len, int flags) {
|
||||
(void)flags;
|
||||
net_msg_t msg;
|
||||
(void)flags; /* flags 当前未使用,显式 void 以消除未用参数告警 */
|
||||
net_msg_t msg; /* 一次性消息结构体;入队后由 netTask 取出处理(注意只传指针不拷贝数据) */
|
||||
|
||||
/* ---- 1. 参数合法性检查 ---- */
|
||||
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) {
|
||||
s_net_errno = NET_ERR_BADF;
|
||||
s_net_errno = NET_ERR_BADF; /* 描述符越界 */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ---- 2. 运行环境检查:消息队列须已创建(网络层已初始化) ---- */
|
||||
if (NULL == netMsgQueueHandle) {
|
||||
s_net_errno = NET_ERR;
|
||||
s_net_errno = NET_ERR; /* 网络层未初始化 */
|
||||
return -1;
|
||||
}
|
||||
|
||||
msg.type = NET_MSG_SEND;
|
||||
msg.sockfd = sockfd;
|
||||
msg.buf = (void *)buf;
|
||||
msg.len = len;
|
||||
msg.flags = 0;
|
||||
msg.caller = xTaskGetCurrentTaskHandle();
|
||||
msg.result = -1;
|
||||
/* ---- 3. 组装消息:把本次 send 的全部上下文填入 msg ---- */
|
||||
msg.type = NET_MSG_SEND; /* 消息类型,netTask 据此分派到 net_send_locked */
|
||||
msg.sockfd = sockfd; /* 目标 Socket */
|
||||
msg.buf = (void *)buf; /* 数据缓冲(队列仅拷贝指针,buf 须有效至函数返回) */
|
||||
msg.len = len; /* 待发送字节数 */
|
||||
msg.flags = 0; /* 实际标志位(忽略入参 flags) */
|
||||
msg.caller = xTaskGetCurrentTaskHandle(); /* 记录调用任务句柄,供 netTask 回执时精准通知 */
|
||||
msg.result = -1; /* 预置失败;netTask 处理成功后会改写为实际发送字节数 */
|
||||
|
||||
/* ---- 4. 入队:将消息投递给 netTask,osWaitForever 表示队列满时阻塞调用方 ---- */
|
||||
if (osMessageQueuePut(netMsgQueueHandle, &msg, 0, osWaitForever) != osOK) {
|
||||
s_net_errno = NET_ERR_BUSY;
|
||||
s_net_errno = NET_ERR_BUSY; /* 入队失败(队列异常等极端情况) */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ---- 5. 阻塞等待 netTask 处理完毕:netTask 调 net_send_locked 后通过
|
||||
* xTaskNotify() 唤醒本任务,并把结果(实际发送字节数或 -1)作为通知值传回 ---- */
|
||||
{
|
||||
uint32_t s_notified;
|
||||
xTaskNotifyWait(0, 0, &s_notified, portMAX_DELAY);
|
||||
msg.result = (int)s_notified;
|
||||
xTaskNotifyWait(0, 0, &s_notified, portMAX_DELAY); /* 一直阻塞直到被 netTask 通知 */
|
||||
msg.result = (int)s_notified; /* 取回 netTask 写入的结果 */
|
||||
}
|
||||
|
||||
/* ---- 6. 结果回传:负数视为错误并设置线程级错误码;否则返回实际发送字节数 ---- */
|
||||
if (msg.result < 0) {
|
||||
s_net_errno = NET_ERR;
|
||||
}
|
||||
@@ -1057,13 +1279,13 @@ int net_sendto(int sockfd, const void *buf, int len, int flags,
|
||||
if (NULL != dest_addr && addrlen >= (int)sizeof(struct net_sockaddr_in)) {
|
||||
p_addr_in = (const struct net_sockaddr_in *)dest_addr;
|
||||
|
||||
/* 转换 IP 为数组格<EFBFBD>?*/
|
||||
/* 转换 IP 为大端数组(同 TCP 客户端,set_des_ip 期望大端) */
|
||||
uint8_t ip_arr[4];
|
||||
uint32_t ip = p_addr_in->sin_addr.s_addr;
|
||||
ip_arr[0] = (uint8_t)(ip);
|
||||
ip_arr[1] = (uint8_t)(ip >> 8);
|
||||
ip_arr[2] = (uint8_t)(ip >> 16);
|
||||
ip_arr[3] = (uint8_t)(ip >> 24);
|
||||
ip_arr[0] = (uint8_t)(ip >> 24);
|
||||
ip_arr[1] = (uint8_t)(ip >> 16);
|
||||
ip_arr[2] = (uint8_t)(ip >> 8);
|
||||
ip_arr[3] = (uint8_t)(ip);
|
||||
|
||||
ch395f_set_des_ip(sockfd, ip_arr);
|
||||
ch395f_set_des_port(sockfd, net_ntohs(p_addr_in->sin_port));
|
||||
@@ -1074,8 +1296,8 @@ int net_sendto(int sockfd, const void *buf, int len, int flags,
|
||||
/* 发送数<E98081>?*/
|
||||
while (sent < len) {
|
||||
int chunk = len - sent;
|
||||
if (chunk > NET_SEND_BUF_SIZE) {
|
||||
chunk = NET_SEND_BUF_SIZE;
|
||||
if (chunk > NET_SEND_CHUNK_MAX) {
|
||||
chunk = NET_SEND_CHUNK_MAX;
|
||||
}
|
||||
|
||||
/* 检查发送缓冲区 */
|
||||
@@ -1122,7 +1344,7 @@ int net_sendto(int sockfd, const void *buf, int len, int flags,
|
||||
int net_recvfrom(int sockfd, void *buf, int len, int flags,
|
||||
struct net_sockaddr *src_addr, int *addrlen) {
|
||||
net_sock_t *p_sock;
|
||||
uint16_t recv_len;
|
||||
int recv_len;
|
||||
uint32_t tick_start;
|
||||
|
||||
/* 参数检<E695B0>?*/
|
||||
@@ -1172,7 +1394,7 @@ int net_recvfrom(int sockfd, void *buf, int len, int flags,
|
||||
|
||||
/* 读取数据 */
|
||||
if (recv_len > 0) {
|
||||
int read_len = (recv_len > (uint16_t)len) ? len : (int)recv_len;
|
||||
int read_len = (recv_len > len) ? len : recv_len;
|
||||
ch395f_read_recv_buf(sockfd, (uint8_t *)buf, (uint16_t)read_len);
|
||||
p_sock->recv_bytes += (uint32_t)read_len;
|
||||
return read_len;
|
||||
@@ -1505,6 +1727,7 @@ static void handle_disconnect_event(net_sock_t *p_sock) {
|
||||
static void handle_recv_event(net_sock_t *p_sock) {
|
||||
/* RECV_OK 中断已触发,直接通知上层。不在此读 recv_len,
|
||||
* 避免和 net_recv_locked 里面的 ch395f_get_recv_len 冲突(Trap 13) */
|
||||
p_sock->readable = 1; /* 置可读标志,供 net_select 在无 SPI 访问下判读 */
|
||||
fire_event(p_sock, NET_EVENT_DATA_RECEIVED);
|
||||
}
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ typedef struct {
|
||||
uint16_t local_port; /* 本地端口(主机序) */
|
||||
uint16_t remote_port; /* 远端端口(主机序) */
|
||||
uint32_t remote_ip; /* 远端 IP(网络字节序) */
|
||||
uint8_t remote_ip_arr[4]; /* 远端 IP 数组(低字节在前) */
|
||||
uint8_t remote_ip_arr[4]; /* 远端 IP 数组(大端/网络字节序) */
|
||||
|
||||
/* 事件回调(可选) */
|
||||
net_event_cb_t event_cb;
|
||||
@@ -158,6 +158,14 @@ typedef struct {
|
||||
/* 发送就绪标志 */
|
||||
uint8_t send_ready;
|
||||
|
||||
/* 接收可读标志:net_poll 检测到 RECV_OK 时置 1,net_recv_locked 读空后清零。
|
||||
* net_select 据此判断可读性,从而无需在应用/测试任务上下文直接访问 CH395F SPI
|
||||
* (所有 ch395f 事务统一由 netTask 串行执行,避免与 net_poll 竞争,见 Trap 16)。 */
|
||||
uint8_t readable;
|
||||
|
||||
/* 单连接模式自动重监听:连接断开后由 net 层自动回到 LISTEN(BSD 风格监听常驻) */
|
||||
uint8_t auto_relisten;
|
||||
|
||||
/* 统计信息 */
|
||||
uint32_t recv_bytes; /* 累计接收字节数 */
|
||||
uint32_t send_bytes; /* 累计发送字节数 */
|
||||
|
||||
Reference in New Issue
Block a user