Files
STM32F4-Base/Drivers/BSP/NET/net_socket.c
T
2026-08-24 16:16:18 +08:00

1644 lines
58 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.
/*
* 模块名称:Network Socket Core
* 模块功能:BSD Socket API 核心实现,包含 Socket 管理、状态机、消息队列(线程安全)、事件处理、数据收发等功能,底层调用 CH395F 驱动
* 适用平台:STM32F407ZGTx + CH395F 以太网芯片
* 作者:王建锋
* 创建日期:2026-07-18
* 修改记录:
* 2026-07-18 王建锋 创建初始版本
* 2026-07-19 王建锋 添加消息队列线程安全机制,替换 xQueueCreate 为 CubeMX osMessageQueue
*/
#include <string.h>
#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"
#include "cmsis_os.h"
#include "net_socket.h"
#include "ch395f.h"
#include "main.h"
/*
* 调试输出配置
*/
#define DBG_TAG "[NET]"
#include "dbg_log.h"
/*
* 私有宏定义区
*/
#define NET_PHY_CHECK_INTERVAL_MS 5000U /* PHY 状态定期检查间隔(ms) */
/*
* 全局变量定义区 - 尽量避免使用全局变量
*/
static net_sock_t s_net_socks[NET_MAX_SOCKETS]; /* Socket 控制块数组 */
static int s_net_errno = 0; /* 最后错误码 */
static uint8_t s_net_initialized = 0; /* 初始化标志 */
static uint8_t s_local_ip[4]; /* 本机 IP 缓存(网络序,net_getsockname 用) */
static uint16_t s_dynamic_port = 49152; /* 动态端口分配起始值 */
/*
* 消息队列 - 线程安全核心
* 外部任务通过 net_send/net_recv/net_close 等 API 将请求放入队列,
* netTask 调用 net_process_messages() 串行处理所有 CH395F 操作
* 由 CubeMX 在 MX_FREERTOS_Init()(osKernelInitialize 之后)中创建
*/
extern osMessageQueueId_t netMsgQueueHandle; /* CubeMX 生成的消息队列句柄 */
/*
* 私有函数声明区
*/
static int alloc_socket(void);
static void handle_connect_event(net_sock_t *p_sock);
static void handle_disconnect_event(net_sock_t *p_sock);
static void handle_recv_event(net_sock_t *p_sock);
static void handle_send_event(net_sock_t *p_sock);
static void handle_timeout_event(net_sock_t *p_sock);
static void fire_event(net_sock_t *p_sock, net_event_t event);
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_accept_locked(int sockfd, struct net_sockaddr *addr, int *addrlen);
/*
* 函数功能:网络子系统初始化(配置 CH395F + 启用多连接模式)
* 入口参数:ip - IP 地址字符串 "192.168.1.100",NULL 使用 DHCP 自动获取 const char *
* mask - 子网掩码字符串 "255.255.255.0",NULL 使用默认值 const char *
* gateway - 网关地址字符串 "192.168.1.1",NULL 使用默认值 const char *
* 返回值:0 - 初始化成功 int
* -1 - 初始化失败(芯片检测/复位/协议栈初始化失败) int
* 限定条件:SPI2 已正确初始化;netTask 尚未启动
* 函数说明:1. 检查 CH395F 芯片是否存在并复位
* 2. 启用 TCP Server 多连接模式(bit1=1),设置 TCP MSS、重传参数、KeepAlive 参数
* 3. 配置 IP/网关/子网掩码,或启用 DHCP
* 4. 初始化 CH395F 协议栈并使能 PING 响应
*/
int net_init(const char *ip, const char *mask, const char *gateway) {
ch395f_status_t ret;
DBG_INFO("net_init: start");
/* 清零 Socket 控制块 */
memset(s_net_socks, 0, sizeof(s_net_socks));
s_net_errno = 0;
s_net_initialized = 0;
DBG_INFO("net_init: queue=%p", (void *)netMsgQueueHandle);
DBG_INFO("net_init: check_exist...");
/* 检查 CH395F 芯片 */
if (ch395f_check_exist() != CH395F_STATUS_OK) {
DBG_ERROR("net_init: ch395f_check_exist FAILED");
s_net_errno = NET_ERR;
return -1;
}
DBG_INFO("net_init: reset...");
/* 复位芯片 */
ch395f_reset();
DBG_INFO("net_init: set_fun_para...");
/* 启用单连接模式 + 手动关闭 Socket(bit3=1, bit1=0)
* bit3=1: DISCONNECT/TIMEOUT 时不自动清空缓冲区,由软件排空数据后手动关闭 */
ch395f_set_fun_para(0x08);
DBG_INFO("net_init: set_tcp_mss...");
/* 设置 TCP MSS */
ch395f_set_tcp_mss(1460);
/* 设置 TCP 重传参数(必须在 INIT_CH395 之前�?*/
ch395f_set_retrans_count(8); /* 重传 8 �?*/
ch395f_set_retrans_period(500); /* 每次间隔 500ms,总计 4s 重传窗口 */
/* 设置 TCP KeepAlive 参数(必须在 INIT_CH395 之前,单�?ms,必须为 500 的倍数,IDLE > INTVL�?*/
ch395f_set_keepalive_idle(60000); /* 空闲 60 秒后开始探�?*/
ch395f_set_keepalive_intvl(5000); /* �?5 秒探测一�?*/
ch395f_set_keepalive_cnt(3); /* 最多探�?3 �?*/
/* 设置网络参数(必须在 INIT_CH395 之前�?*/
if (ip != NULL) {
uint8_t ip_arr[4];
uint8_t mask_arr[4];
uint8_t gw_arr[4];
parse_ip_string(ip, ip_arr);
parse_ip_string(mask, mask_arr);
parse_ip_string(gateway, gw_arr);
memcpy(s_local_ip, ip_arr, 4);
ch395f_set_ip_addr(ip_arr);
ch395f_set_gwip_addr(gw_arr);
ch395f_set_mask_addr(mask_arr);
} else {
/* 启用 DHCP */
ch395f_set_dhcp(1);
}
/* 初始�?CH395F 协议栈(先不配置 buffer,测试默认值是否工作) */
ret = ch395f_init();
if (ret != CH395F_STATUS_OK) {
s_net_errno = NET_ERR;
return -1;
}
/* 使能 PING 响应 */
ch395f_ping_enable(1);
s_net_initialized = 1;
return 0;
}
/*
* 函数功能:轮询 CH395F 中断状态,更新 Socket 连接状态并处理事件
* 返回值:本次轮询中发生事件的 Socket 数量 int >= 0
* 限定条件:s_net_initialized == 1;必须在 netTask 上下文中调用
* 函数说明:1. GPIO 轮询 CH395F INT# 引脚电平(低电平有效),无需 EXTI 中断
* 2. 读取 GET_GLOB_INT_STATUS_ALL(2 字节版)获取所有 Socket 的中断状态
* 3. 处理连接/断开/数据接收/发送完成/超时等事件,更新 Socket 状态机
* 4. RECV 中断为电平触发,每次 net_poll() 只处理一批中断,避免主循环饿死
*/
int net_poll(void) {
int event_count = 0;
int i;
uint16_t int_status;
if (!s_net_initialized) {
return 0;
}
/*
* GPIO 轮询模式:仅当 INT# 有效(低电平)时读取中断状态。
* 读取 GET_GLOB_INT_STATUS_ALL,CH395F 拉高 INT#;若仍有中断则再次拉低。
*/
do
{
if (HAL_GPIO_ReadPin(CH395_INT_GPIO_Port, CH395_INT_Pin) == GPIO_PIN_SET) {
break;
}
int_status = ch395f_get_glob_int_status_all();
if (int_status == 0) {
break;
}
/* 诊断:每 3 秒打印一次全局中断状态和 Socket 状态。
* 注意:使用已读取的 int_status,不要再读 GINT(读即清除)。 */
// static uint32_t s_last_diag = 0;
// uint32_t now_diag = HAL_GetTick();
// if ((now_diag - s_last_diag >= 3000) || s_last_diag == 0) {
// s_last_diag = now_diag;
// DBG_INFO("GINT=0x%04X", int_status);
// for (int di = 0; di < NET_MAX_SOCKETS; di++) {
// DBG_INFO(" s%d: in_use=%d state=%d",
// di, s_net_socks[di].in_use, s_net_socks[di].state);
// }
// }
if (int_status & CH395F_GINT_STAT_PHY_CHANGE) {
uint8_t phy = ch395f_get_phy_status();
DBG_INFO("PHY_CHANGE: 0x%02X", phy);
if (phy == CH395F_PHY_DISCONN) {
DBG_ERROR("PHY disconnected, sockets may need recovery");
}
}
/* 处理每个 Socket */
for (i = 0; i < NET_MAX_SOCKETS; i++) {
net_sock_t *p_sock = &s_net_socks[i];
/* 检查该 Socket 是否有中断(全局中断状�?bit4~bit11 对应 socket0~7�?*/
if (!(int_status & (1U << (i + 4)))) {
continue;
}
/* 读取 Socket 中断状�?*/
uint8_t sock_int = ch395f_get_sock_int_status(i);
//DBG_INFO("s%d int=0x%02X", i, sock_int);
/* 连接事件 */
if (sock_int & CH395F_SINT_STAT_CONNECT) {
handle_connect_event(p_sock);
event_count++;
}
/* 断开事件 */
if (sock_int & CH395F_SINT_STAT_DISCONNECT) {
handle_disconnect_event(p_sock);
event_count++;
}
/* 数据接收事件 */
if (sock_int & CH395F_SINT_STAT_RECV_OK) {
handle_recv_event(p_sock);
event_count++;
}
/* 发送完成事�?*/
if (sock_int & CH395F_SINT_STAT_SEND_OK) {
handle_send_event(p_sock);
event_count++;
}
/* 发送缓冲区空闲 */
if (sock_int & CH395F_SINT_STAT_SENBUF_FREE) {
p_sock->send_ready = 1;
}
/* 超时事件 */
if (sock_int & CH395F_SINT_STAT_SOCK_TIMEOUT) {
handle_timeout_event(p_sock);
event_count++;
}
}
/*
* 处理完毕后检查 INT# 是否仍为低电平。如果是,说明在处理期间有新中断产生,需要再次读取。
* 注意:CH395F 的 RECV 中断是电平触发的(只要接收缓冲区有数据就保持低电平)。
* 如果不跳出循环,net_poll() 会无限循环处理 RECV 中断,导致主循环中的应用代码(如 echo)永远无法执行。
* 因此每次 net_poll() 调用只处理一批中断,由主循环负责读取数据。 */
} while (0);
// /* 2 秒打印一次诊断信息(调试用) */
// {
// static uint32_t s_last_dbg = 0;
// uint32_t now = HAL_GetTick();
// if (now - s_last_dbg >= 2000) {
// s_last_dbg = now;
// uint8_t int_level = (HAL_GPIO_ReadPin(CH395_INT_GPIO_Port, CH395_INT_Pin) == GPIO_PIN_RESET) ? 1 : 0;
// DBG_DEBUG("INT#=%d", int_level);
// for (i = 0; i < NET_MAX_SOCKETS; i++) {
// if (s_net_socks[i].in_use) {
// uint8_t st[2];
// ch395f_get_socket_status((uint8_t)i, st);
// uint16_t rl = ch395f_get_recv_len((uint8_t)i);
// DBG_DEBUG(" s%d:sw%d/tcp%d rl%d", i, st[0], st[1], rl);
// }
// }
// }
// }
return event_count;
}
/*
* 函数功能:处理消息队列中的请求
* 限定条件:必须在 netTask 上下文中调用(独占 CH395F 和 s_net_socks 访问权)
* 函数说明:每次调用处理一条消息。处理 send/recv 时内部会调用 net_poll()
* 等待操作完成。处理完毕后通知调用方任务。
*/
void net_process_messages(void) {
net_msg_t msg;
if (netMsgQueueHandle == NULL) {
return;
}
while (osMessageQueueGet(netMsgQueueHandle, &msg, NULL, 0) == osOK) {
switch (msg.type) {
case NET_MSG_SEND: {
net_sock_t *p_sock = net_get_sock(msg.sockfd);
if (p_sock == NULL || p_sock->state != NET_SOCK_STATE_ESTABLISHED) {
msg.result = -1;
} else {
msg.result = net_send_locked(p_sock, msg.buf, msg.len);
}
break;
}
case NET_MSG_RECV: {
net_sock_t *p_sock = net_get_sock(msg.sockfd);
if (p_sock == NULL) {
msg.result = -1;
} else {
msg.result = net_recv_locked(p_sock, msg.buf, msg.len, msg.flags);
}
break;
}
case NET_MSG_CLOSE: {
net_sock_t *p_sock = net_get_sock(msg.sockfd);
if (p_sock == NULL) {
msg.result = -1;
} else {
msg.result = net_close_locked(p_sock);
}
break;
}
case NET_MSG_CONNECT: {
msg.result = net_connect(msg.sockfd,
(const struct net_sockaddr *)&msg.addr,
msg.addrlen);
break;
}
case NET_MSG_LISTEN: {
msg.result = net_listen_locked(msg.sockfd, msg.flags);
break;
}
case NET_MSG_ACCEPT: {
struct net_sockaddr *p_addr = (struct net_sockaddr *)msg.buf;
int addrlen = msg.len;
int *p_addrlen = (p_addr != NULL && addrlen > 0) ? &addrlen : NULL;
msg.result = net_accept_locked(msg.sockfd, p_addr, p_addrlen);
break;
}
default:
msg.result = -1;
break;
}
xTaskNotify(msg.caller, (uint32_t)msg.result, eSetValueWithOverwrite);
}
}
/*
* 函数功能:创建 Socket,分配空闲 Socket 控制块并初始化状态
* 入口参数:domain - 地址族,仅支持 NET_AF_INET int
* type - SOCK_STREAM(TCP) 或 SOCK_DGRAM(UDP) int
* protocol - 通常为 0 int
* 返回值:Socket 描述符 (0~7),失败返回 -1 int
* 限定条件:net_init() 已调用成功;s_net_initialized == 1
* 函数说明:自动分配一个空闲的 Socket 控制块(in_use=0),初始化为 CREATED 状态
*/
int net_socket(int domain, int type, int protocol) {
int sockfd;
net_sock_t *p_sock;
/* 参数检查*/
if (domain != NET_AF_INET) {
s_net_errno = NET_ERR_INVAL;
return -1;
}
/* 分配空闲 Socket */
sockfd = alloc_socket();
if (sockfd < 0) {
s_net_errno = NET_ERR_NOMEM;
return -1;
}
p_sock = &s_net_socks[sockfd];
p_sock->ch395_sock = (uint8_t)sockfd;
p_sock->type = (uint8_t)type;
p_sock->state = NET_SOCK_STATE_CREATED;
p_sock->in_use = 1;
p_sock->send_ready = 1;
return sockfd;
}
/*
* 函数功能:绑定 Socket 到本地 IP 地址和端口号
* 入口参数:sockfd - Socket 描述符 (0~7) int
* addr - 本地地址结构体指针 const struct net_sockaddr *
* addrlen - 地址结构体长度 int >= sizeof(struct net_sockaddr_in)
* 返回值:0 - 绑定成功 int
* -1 - 绑定失败(参数无效、Socket 未使用等) int
* 限定条件:Socket 已通过 net_socket() 创建且未被其他操作占用;net_init() 已调用
* 函数说明:1. TCP Socket 仅记录本地端口,进入 BOUND 状态等待 listen
* 2. UDP Socket(SOCK_DGRAM)立即打开 CH395F Socket 并配置为 Server 模式
* - Socket 4~7 需显式分配收发缓冲区
*/
int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen) {
net_sock_t *p_sock;
const struct net_sockaddr_in *p_addr_in;
/* 参数检�?*/
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) {
s_net_errno = NET_ERR_BADF;
return -1;
}
p_sock = &s_net_socks[sockfd];
if (!p_sock->in_use) {
s_net_errno = NET_ERR_BADF;
return -1;
}
if (addr == NULL || addrlen < (int)sizeof(struct net_sockaddr_in)) {
s_net_errno = NET_ERR_INVAL;
return -1;
}
p_addr_in = (const struct net_sockaddr_in *)addr;
/* 设置本地端口(转换为主机序) */
p_sock->local_port = net_ntohs(p_addr_in->sin_port);
/* port=0 时自动分配动态端口(49152~65535) */
if (p_sock->local_port == 0) {
p_sock->local_port = s_dynamic_port;
s_dynamic_port++;
if (s_dynamic_port > 65535) {
s_dynamic_port = 49152;
}
}
/* UDP (SOCK_DGRAM): 直接在此打开 CH395F Socket */
if (p_sock->type == NET_SOCK_DGRAM) {
uint8_t status;
/* Socket 4-7 默认无收发缓冲,需显式分配 */
if (sockfd >= 4) {
ch395f_set_send_buf((uint8_t)sockfd, 28, 2);
ch395f_set_recv_buf((uint8_t)sockfd, 30, 2);
}
ch395f_set_proto_type((uint8_t)sockfd, CH395F_PROTO_TYPE_UDP);
ch395f_set_sour_port((uint8_t)sockfd, p_sock->local_port);
/* DesIP=0xFFFFFFFF �?UDP Server 模式(接受任意来源) */
{
uint8_t broadcast[4] = {0xFF, 0xFF, 0xFF, 0xFF};
ch395f_set_des_ip((uint8_t)sockfd, broadcast);
}
ch395f_set_des_port((uint8_t)sockfd, 0);
status = ch395f_open_socket((uint8_t)sockfd);
if (status != CH395F_ERR_SUCCESS) {
DBG_ERROR("sock%d open_socket FAIL: status=0x%02X (expected 0x00)", sockfd, status);
s_net_errno = NET_ERR_BUSY;
return -1;
}
p_sock->state = NET_SOCK_STATE_UDP_OPEN;
} else {
p_sock->state = NET_SOCK_STATE_BOUND;
}
return 0;
}
/*
* 函数功能:启动 TCP Server 监听(内部版本,必须在 netTask 上下文调用)
* 入口参数:sockfd - Socket 描述符 (0~7) int
* backlog - 数据 Socket 数量(0=单连接模式) int
* 返回值:0 - 成功,-1 - 失败 int
* 限定条件:sockfd 已绑定且为 TCP;netTask 上下文
*/
int net_listen_locked(int sockfd, int backlog) {
net_sock_t *p_sock = &s_net_socks[sockfd];
uint8_t status;
if (!p_sock->in_use || p_sock->type != NET_SOCK_STREAM) {
s_net_errno = NET_ERR_INVAL;
return -1;
}
if (p_sock->state != NET_SOCK_STATE_BOUND &&
p_sock->state != NET_SOCK_STATE_CREATED) {
s_net_errno = NET_ERR_INVAL;
return -1;
}
/* 多连接模式:按 backlog 分配数据 Socket */
if (backlog > 0) {
int max_ds = NET_TCP_SERVER_DATA_SOCK_START + backlog;
if (max_ds > NET_MAX_SOCKETS) {
max_ds = NET_MAX_SOCKETS;
}
for (int ds = NET_TCP_SERVER_DATA_SOCK_START; ds < max_ds; ds++) {
uint8_t base = (uint8_t)(ds * 4);
ch395f_set_send_buf((uint8_t)ds, base, 2);
ch395f_set_recv_buf((uint8_t)ds, base + 2, 2);
ch395f_set_sour_port((uint8_t)ds, p_sock->local_port);
ch395f_set_proto_type((uint8_t)ds, CH395F_PROTO_TYPE_TCP);
s_net_socks[ds].in_use = 1;
s_net_socks[ds].state = NET_SOCK_STATE_TCP_ACCEPT;
s_net_socks[ds].type = NET_SOCK_STREAM;
s_net_socks[ds].ch395_sock = (uint8_t)ds;
s_net_socks[ds].send_ready = 1;
p_sock->data_socks[p_sock->data_sock_count++] = ds;
}
}
/* 配置监听 Socket:单连接模式使用 CH395F 默认缓冲区(socket 0-3 已互不重叠),
* 多连接模式显式分配(socket 4-7 默认无缓冲区)*/
if (backlog > 0) {
uint8_t base = (uint8_t)(sockfd * 4);
ch395f_set_send_buf((uint8_t)sockfd, base, 2);
ch395f_set_recv_buf((uint8_t)sockfd, base + 2, 2);
}
ch395f_set_proto_type(sockfd, CH395F_PROTO_TYPE_TCP);
ch395f_set_sour_port(sockfd, p_sock->local_port);
/* CH395F 关 socket 后需要时间才能重新打开,重试 3 次(Trap 09) */
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;
}
ch395f_tcp_listen(sockfd);
p_sock->state = NET_SOCK_STATE_LISTENING;
if (backlog == 0) {
p_sock->standalone_accept = 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();
return 0;
}
/*
* 函数功能:启动 TCP Server 监听(线程安全版本,通过消息队列委托给 netTask)
* 入口参数:sockfd - Socket 描述符 int
* backlog - 数据 Socket 数量 int
* 返回值:0 - 成功,-1 - 失败 int
* 限定条件:net_init() + MX_FREERTOS_Init() 已执行;必须在任务上下文中调用
* 函数说明:通过消息队列委托给 netTask,确保 SPI 串行化
*/
int net_listen(int sockfd, int backlog) {
net_msg_t msg;
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) {
s_net_errno = NET_ERR_BADF;
return -1;
}
if (netMsgQueueHandle == NULL) {
s_net_errno = NET_ERR;
return -1;
}
msg.type = NET_MSG_LISTEN;
msg.sockfd = sockfd;
msg.flags = backlog;
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 Server 接受新连接(内部版本,必须在 netTask 上下文调用)
* 入口参数:sockfd - 监听 Socket 描述符 int
* addr - 输出:客户端地址结构体指针 struct net_sockaddr *(可为 NULL)
* addrlen - 输入输出:地址结构体长度 int *(可为 NULL)
* 返回值:新连接的 Socket 描述符,失败返回 -1 int
* 限定条件:Socket 处于 LISTENING 状态
* 函数说明:先查 data_socks[] 多连接数据 Socket,再查 standalone_accept 单连接 Socket
*/
static int net_accept_locked(int sockfd, struct net_sockaddr *addr, int *addrlen) {
net_sock_t *p_listen_sock;
int i;
p_listen_sock = &s_net_socks[sockfd];
if (!p_listen_sock->in_use) {
s_net_errno = NET_ERR_INVAL;
return -1;
}
if (p_listen_sock->state != NET_SOCK_STATE_LISTENING &&
!(p_listen_sock->standalone_accept && p_listen_sock->state == NET_SOCK_STATE_ESTABLISHED)) {
s_net_errno = NET_ERR_INVAL;
return -1;
}
net_poll();
/* 多连接模式:查 data_socks */
for (i = 0; i < p_listen_sock->data_sock_count; i++) {
int data_sock = p_listen_sock->data_socks[i];
net_sock_t *p_data_cb = &s_net_socks[data_sock];
if (p_data_cb->state == NET_SOCK_STATE_ESTABLISHED) {
if (addr != NULL && addrlen != NULL) {
struct net_sockaddr_in *p_addr_in = (struct net_sockaddr_in *)addr;
p_addr_in->sin_family = NET_AF_INET;
p_addr_in->sin_port = net_htons(p_data_cb->remote_port);
p_addr_in->sin_addr.s_addr = p_data_cb->remote_ip;
*addrlen = sizeof(struct net_sockaddr_in);
}
return data_sock;
}
}
/* 单连接模式(PASV):查 standalone 监听者是否已 ESTABLISHED */
if (p_listen_sock->standalone_accept &&
p_listen_sock->state == NET_SOCK_STATE_ESTABLISHED) {
if (addr != NULL && addrlen != NULL) {
struct net_sockaddr_in *p_addr_in = (struct net_sockaddr_in *)addr;
p_addr_in->sin_family = NET_AF_INET;
p_addr_in->sin_port = net_htons(p_listen_sock->remote_port);
p_addr_in->sin_addr.s_addr = p_listen_sock->remote_ip;
*addrlen = sizeof(struct net_sockaddr_in);
}
return sockfd;
}
s_net_errno = NET_ERR_WOULDBLOCK;
return -1;
}
/*
* 函数功能:TCP Server 接受新连接(线程安全版本,通过消息队列委托给 netTask)
* 入口参数:sockfd - 监听 Socket 描述符 int
* addr - 输出:客户端地址结构体指针 struct net_sockaddr *(可为 NULL)
* addrlen - 输入输出:地址结构体长度 int *(可为 NULL)
* 返回值:新连接的 Socket 描述符,失败返回 -1 int
* 限定条件:Socket 处于 LISTENING 状态;net_init() + MX_FREERTOS_Init() 已执行;非 netTask 上下文
* 函数说明:将接受请求放入消息队列,阻塞等待 netTask 处理完毕
*/
int net_accept(int sockfd, 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 (netMsgQueueHandle == NULL) {
s_net_errno = NET_ERR;
return -1;
}
msg.type = NET_MSG_ACCEPT;
msg.sockfd = sockfd;
msg.buf = (void *)addr;
msg.len = (addrlen != NULL) ? *addrlen : 0;
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 (addrlen != NULL && addr != NULL) {
*addrlen = sizeof(struct net_sockaddr_in);
}
if (msg.result < 0) {
s_net_errno = NET_ERR;
}
return msg.result;
}
/*
* 函数功能:TCP Client 发起与服务器的连接
* 入口参数: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
*/
int net_connect(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;
/* 参数检�?*/
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) {
s_net_errno = NET_ERR_BADF;
return -1;
}
p_sock = &s_net_socks[sockfd];
if (!p_sock->in_use || p_sock->type != NET_SOCK_STREAM) {
s_net_errno = NET_ERR_INVAL;
return -1;
}
if (addr == NULL || addrlen < (int)sizeof(struct net_sockaddr_in)) {
s_net_errno = NET_ERR_INVAL;
return -1;
}
p_addr_in = (const struct net_sockaddr_in *)addr;
/* 保存远端地址 */
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);
/* 配置 CH395F Socket */
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);
if (status != CH395F_ERR_SUCCESS) {
s_net_errno = NET_ERR_BUSY;
return -1;
}
/* 发起 TCP 连接 */
ch395f_tcp_connect(sockfd);
p_sock->state = NET_SOCK_STATE_CONNECTING;
return 0;
}
/*
* SPI DMA 单次事务最大有效载荷(取 CH395F 驱动公开常量)
*/
#define NET_DMA_MAX_PAYLOAD ((int)CH395F_SPI_DMA_MAX_PAYLOAD)
/*
* 函数功能:发送数据(内部锁定版本,必须在 netTask 上下文调用)
*/
static int net_send_locked(net_sock_t *p_sock, const void *buf, int len) {
int sent = 0;
uint32_t tick_start;
int sockfd = (int)(p_sock - s_net_socks);
if (buf == NULL || len <= 0) {
s_net_errno = NET_ERR_INVAL;
return -1;
}
if (p_sock->state != NET_SOCK_STATE_ESTABLISHED) {
s_net_errno = NET_ERR_NOTCONN;
return -1;
}
tick_start = HAL_GetTick();
while (sent < len) {
int chunk = len - sent;
if (chunk > NET_DMA_MAX_PAYLOAD) {
chunk = NET_DMA_MAX_PAYLOAD;
}
if (!p_sock->send_ready) {
if (NET_SEND_TIMEOUT_MS > 0 &&
(HAL_GetTick() - tick_start) >= NET_SEND_TIMEOUT_MS) {
s_net_errno = NET_ERR_TIMEDOUT;
break;
}
net_poll();
continue;
}
ch395f_write_send_buf(sockfd, (uint8_t *)buf + sent, (uint16_t)chunk);
p_sock->send_ready = 0;
sent += chunk;
p_sock->send_bytes += (uint32_t)chunk;
tick_start = HAL_GetTick();
while (!p_sock->send_ready) {
net_poll();
if (NET_SEND_TIMEOUT_MS > 0 &&
(HAL_GetTick() - tick_start) >= NET_SEND_TIMEOUT_MS) {
break;
}
}
}
return sent;
}
/*
* 函数功能:接收数据(内部锁定版本,必须在 netTask 上下文调用)
*/
static int net_recv_locked(net_sock_t *p_sock, void *buf, int len, int flags) {
uint16_t recv_len;
uint32_t tick_start;
int sockfd = (int)(p_sock - s_net_socks);
if (buf == NULL || len <= 0) {
s_net_errno = NET_ERR_INVAL;
return -1;
}
tick_start = HAL_GetTick();
while (1) {
net_poll();
recv_len = ch395f_get_recv_len(sockfd);
if (recv_len > 0) {
int read_len = (recv_len > (uint16_t)len) ? len : (int)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;
HAL_Delay(1); /* 等待 CH395F 刷新 recv_len 寄存器 */
return read_len;
}
if (flags & NET_MSG_DONTWAIT) {
s_net_errno = NET_ERR_WOULDBLOCK;
return -1;
}
if (NET_RECV_TIMEOUT_MS > 0 &&
(HAL_GetTick() - tick_start) >= NET_RECV_TIMEOUT_MS) {
s_net_errno = NET_ERR_TIMEDOUT;
return -1;
}
if (p_sock->state == NET_SOCK_STATE_TCP_ACCEPT) {
return 0;
}
if (p_sock->state == NET_SOCK_STATE_CLOSED) {
/* 断开前尝试排空 CH395F 接收缓冲区(Trap 13:FIN 可能比数据先到) */
uint16_t rem = ch395f_get_recv_len(sockfd);
if (rem > 0) {
int rd = (rem > (uint16_t)len) ? len : (int)rem;
ch395f_read_recv_buf(sockfd, (uint8_t *)buf, (uint16_t)rd);
p_sock->recv_bytes += (uint32_t)rd;
return rd;
}
return 0;
}
}
}
/*
* 函数功能:关闭 socket(内部锁定版本,必须在 netTask 上下文调用)
*/
static int net_close_locked(net_sock_t *p_sock) {
int sockfd = (int)(p_sock - s_net_socks);
ch395f_close_socket(sockfd);
memset(p_sock, 0, sizeof(net_sock_t));
return 0;
}
/*
* 函数功能:发送数据(线程安全版本,通过消息队列委托给 netTask)
* 入口参数:sockfd - Socket 描述符 int >= 0 && < NET_MAX_SOCKETS
* buf - 待发送数据缓冲区指针 const void *
* len - 数据长度 int > 0
* flags - 标志位,通常为 0 int
* 返回值:实际发送字节数 int >= 0 || -1
* -1 - 发送失败(参数无效、队列满等) int
* 限定条件:Socket 处于 ESTABLISHED 状态;net_init() + MX_FREERTOS_Init() 已执行;非 netTask 上下文
* 函数说明:将发送请求放入消息队列,阻塞等待 netTask 处理完毕并返回结果。netTask 内请使用 net_send_sock()
*/
int net_send(int sockfd, const void *buf, int len, int flags) {
(void)flags;
net_msg_t msg;
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) {
s_net_errno = NET_ERR_BADF;
return -1;
}
if (netMsgQueueHandle == NULL) {
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;
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;
}
/*
* 函数功能:接收数据(线程安全版本,通过消息队列委托给 netTask)
* 入口参数:sockfd - Socket 描述符 int >= 0 && < NET_MAX_SOCKETS
* buf - 接收缓冲区指针 void *
* len - 缓冲区大小 int > 0
* flags - 标志位,0=阻塞,NET_MSG_DONTWAIT=非阻塞 int
* 返回值:实际接收字节数 int >= 0 || 0 || -1
* 0 - 对端关闭连接 int
* -1 - 接收失败(参数无效、队列满等) int
* 限定条件:Socket 处于 ESTABLISHED 状态;net_init() + MX_FREERTOS_Init() 已执行;非 netTask 上下文
* 函数说明:将接收请求放入消息队列,阻塞等待 netTask 处理完毕并返回结果。netTask 内请使用 net_recv_sock()
*/
int net_recv(int sockfd, void *buf, int len, int flags) {
net_msg_t msg;
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) {
s_net_errno = NET_ERR_BADF;
return -1;
}
if (netMsgQueueHandle == NULL) {
s_net_errno = NET_ERR;
return -1;
}
msg.type = NET_MSG_RECV;
msg.sockfd = sockfd;
msg.buf = buf;
msg.len = len;
msg.flags = flags;
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;
}
/*
* 函数功能:关闭 Socket(线程安全版本,通过消息队列委托给 netTask)
* 入口参数:sockfd - Socket 描述符 int >= 0 && < NET_MAX_SOCKETS
* 返回值:0 - 关闭成功 int
* -1 - 关闭失败 int
* 限定条件:Socket 已创建且处于非 CLOSED 状态;net_init() + MX_FREERTOS_Init() 已执行;非 netTask 上下文
* 函数说明:将关闭请求放入消息队列,阻塞等待 netTask 处理完毕。TCP Socket 先断开连接再释放控制块。
* netTask 内请使用 net_close_sock()
*/
int net_close(int sockfd) {
net_msg_t msg;
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) {
s_net_errno = NET_ERR_BADF;
return -1;
}
if (netMsgQueueHandle == NULL) {
s_net_errno = NET_ERR;
return -1;
}
msg.type = NET_MSG_CLOSE;
msg.sockfd = sockfd;
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;
}
/*
* 函数功能:发送 UDP 数据报(含目标地址)
* 入口参数:sockfd - Socket 描述符 int >= 0 && < NET_MAX_SOCKETS
* buf - 待发送数据缓冲区指针 const void *
* len - 数据长度 int > 0
* flags - 标志位,通常为 0 int
* dest_addr - 目标地址结构体指针 const struct net_sockaddr *
* addrlen - 目标地址结构体长度 int >= sizeof(struct net_sockaddr_in)
* 返回值:实际发送字节数 int > 0 || -1
* -1 - 发送失败 int
* 限定条件:Socket 已创建且为 UDP 类型(SOCK_DGRAM);net_init() 已调用
*/
int net_sendto(int sockfd, const void *buf, int len, int flags,
const struct net_sockaddr *dest_addr, int addrlen) {
net_sock_t *p_sock;
const struct net_sockaddr_in *p_addr_in;
int sent = 0;
uint32_t tick_start;
/* 参数检�?*/
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) {
s_net_errno = NET_ERR_BADF;
return -1;
}
p_sock = &s_net_socks[sockfd];
if (!p_sock->in_use) {
s_net_errno = NET_ERR_BADF;
return -1;
}
if (buf == NULL || len <= 0) {
s_net_errno = NET_ERR_INVAL;
return -1;
}
/* UDP 模式:设置目标地址 */
if (dest_addr != NULL && addrlen >= (int)sizeof(struct net_sockaddr_in)) {
p_addr_in = (const struct net_sockaddr_in *)dest_addr;
/* 转换 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);
ch395f_set_des_ip(sockfd, ip_arr);
ch395f_set_des_port(sockfd, net_ntohs(p_addr_in->sin_port));
}
tick_start = HAL_GetTick();
/* 发送数�?*/
while (sent < len) {
int chunk = len - sent;
if (chunk > NET_SEND_BUF_SIZE) {
chunk = NET_SEND_BUF_SIZE;
}
/* 检查发送缓冲区 */
if (!p_sock->send_ready) {
if (NET_SEND_TIMEOUT_MS > 0 &&
(HAL_GetTick() - tick_start) >= NET_SEND_TIMEOUT_MS) {
s_net_errno = NET_ERR_TIMEDOUT;
break;
}
net_poll();
continue;
}
ch395f_write_send_buf(sockfd, (uint8_t *)buf + sent, (uint16_t)chunk);
p_sock->send_ready = 0;
sent += chunk;
p_sock->send_bytes += (uint32_t)chunk;
/* 等待发送完�?*/
tick_start = HAL_GetTick();
while (!p_sock->send_ready) {
net_poll();
if (NET_SEND_TIMEOUT_MS > 0 &&
(HAL_GetTick() - tick_start) >= NET_SEND_TIMEOUT_MS) {
break;
}
}
}
return sent;
}
/*
* 函数功能:接收 UDP 数据报(含源地址)
* 入口参数:sockfd - Socket 描述符 int >= 0 && < NET_MAX_SOCKETS
* buf - 接收缓冲区指针 void *
* len - 缓冲区大小 int > 0
* flags - 标志位,通常为 0 int
* src_addr - 输出:发送方地址结构体指针 struct net_sockaddr *(可为 NULL)
* addrlen - 输入输出:源地址长度 int *(可为 NULL)
* 返回值:实际接收字节数 int >= 0 || -1
* -1 - 接收失败 int
* 限定条件:Socket 已创建且为 UDP 类型(SOCK_DGRAM);net_init() 已调用;有数据可用
*/
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;
uint32_t tick_start;
/* 参数检�?*/
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) {
s_net_errno = NET_ERR_BADF;
return -1;
}
p_sock = &s_net_socks[sockfd];
if (!p_sock->in_use) {
s_net_errno = NET_ERR_BADF;
return -1;
}
if (buf == NULL || len <= 0) {
s_net_errno = NET_ERR_INVAL;
return -1;
}
tick_start = HAL_GetTick();
while (1) {
net_poll();
recv_len = ch395f_get_recv_len(sockfd);
if (recv_len > 0) {
/* UDP Server 模式:前 8 字节为固定格式(IP + 端口 + 长度�?*/
if (p_sock->type == NET_SOCK_DGRAM && recv_len >= 8) {
uint8_t header[8];
ch395f_read_recv_buf(sockfd, header, 8);
recv_len -= 8;
/* 填充来源地址 */
if (src_addr != NULL && addrlen != NULL &&
*addrlen >= (int)sizeof(struct net_sockaddr_in)) {
struct net_sockaddr_in *p_addr_in = (struct net_sockaddr_in *)src_addr;
p_addr_in->sin_family = NET_AF_INET;
/* CH395F UDP �? [0-1] reserved [2-3] src_port(LE) [4-7] src_ip */
p_addr_in->sin_port = net_htons((uint16_t)(header[2] | (header[3] << 8)));
p_addr_in->sin_addr.s_addr = ((uint32_t)header[4]) |
((uint32_t)header[5] << 8) |
((uint32_t)header[6] << 16) |
((uint32_t)header[7] << 24);
*addrlen = sizeof(struct net_sockaddr_in);
}
}
/* 读取数据 */
if (recv_len > 0) {
int read_len = (recv_len > (uint16_t)len) ? len : (int)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;
}
}
/* 非阻塞模式检�?*/
if (flags & NET_MSG_DONTWAIT) {
s_net_errno = NET_ERR_WOULDBLOCK;
return -1;
}
/* 超时检�?*/
if (NET_RECV_TIMEOUT_MS > 0 &&
(HAL_GetTick() - tick_start) >= NET_RECV_TIMEOUT_MS) {
s_net_errno = NET_ERR_TIMEDOUT;
return -1;
}
}
}
/*
* 函数功能:发送数据(内部版本,绕过消息队列,供 netTask 直接使用)
*/
int net_send_sock(net_sock_t *p_sock, const void *buf, int len) {
if (p_sock == NULL) {
s_net_errno = NET_ERR_BADF;
return -1;
}
return net_send_locked(p_sock, buf, len);
}
/*
* 函数功能:接收数据(内部版本,绕过消息队列,供 netTask 直接使用)
* 入口参数:p_sock - Socket 控制块指针 net_sock_t *
* buf - 接收缓冲区指针 void *
* len - 缓冲区大小 int > 0
* flags - 标志位,NET_MSG_DONTWAIT=非阻塞 int
* 返回值:实际接收字节数 int >= 0 || 0 || -1
* 0 - 对端关闭连接 int
* -1 - 接收失败 int
* 限定条件:必须在 netTask 上下文中调用;p_sock->in_use == 1
* 函数说明:直接操作 Socket 控制块,不经过消息队列。避免 netTask 向自身发送消息造成死锁
*/
int net_recv_sock(net_sock_t *p_sock, void *buf, int len, int flags) {
if (p_sock == NULL) {
s_net_errno = NET_ERR_BADF;
return -1;
}
return net_recv_locked(p_sock, buf, len, flags);
}
/*
* 函数功能:关闭 Socket(内部版本,绕过消息队列,供 netTask 直接使用)
* 入口参数:p_sock - Socket 控制块指针 net_sock_t *
* 返回值:0 - 关闭成功 int
* -1 - 关闭失败 int
* 限定条件:必须在 netTask 上下文中调用;p_sock->in_use == 1
* 函数说明:直接操作 Socket 控制块,不经过消息队列。TCP Socket 先断开连接再释放控制块
*/
int net_close_sock(net_sock_t *p_sock) {
if (p_sock == NULL) {
s_net_errno = NET_ERR_BADF;
return -1;
}
return net_close_locked(p_sock);
}
/*
* 函数功能:注册 Socket 事件回调函数
* 入口参数:sockfd - Socket 描述符 int >= 0 && < NET_MAX_SOCKETS
* cb - 回调函数指针 net_event_cb_t(可为 NULL 取消注册)
* arg - 用户自定义参数指针 void *
* 返回值:0 - 注册成功 int
* -1 - 注册失败 int
* 限定条件:Socket 已创建且 in_use == 1;net_init() 已调用
*/
int net_set_event_cb(int sockfd, net_event_cb_t cb, void *arg) {
net_sock_t *p_sock;
/* 参数检�?*/
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) {
s_net_errno = NET_ERR_BADF;
return -1;
}
p_sock = &s_net_socks[sockfd];
if (!p_sock->in_use) {
s_net_errno = NET_ERR_BADF;
return -1;
}
p_sock->event_cb = cb;
p_sock->event_arg = arg;
return 0;
}
/*
* 函数功能:获取 Socket 最后一次操作返回的错误码
* 返回值:当前错误码值(NET_OK=0, NET_ERR_xxx=-N) int
* 限定条件:无
* 函数说明:每次 net_*() API 调用失败后,错误码被设置。调用成功时不自动清零
*/
int net_get_errno(void) {
return s_net_errno;
}
/*
* 函数功能:将 IP 地址字符串转为网络字节序
*/
uint32_t net_inet_addr(const char *cp) {
uint32_t addr = 0;
uint32_t val;
int i;
if (cp == NULL) {
return 0;
}
for (i = 0; i < 4; i++) {
val = 0;
while (*cp >= '0' && *cp <= '9') {
val = val * 10 + (*cp - '0');
cp++;
}
addr |= (val << (i * 8));
if (*cp == '.') {
cp++;
}
}
return NET_htonl(addr);
}
/*
* 函数功能:将网络字节�?IP 转为字符�? */
char *net_inet_ntoa(uint32_t addr, char *buf) {
uint32_t naddr = NET_ntohl(addr);
if (buf == NULL) {
return NULL;
}
sprintf(buf, "%lu.%lu.%lu.%lu",
(unsigned long)(naddr & 0xFF),
(unsigned long)((naddr >> 8) & 0xFF),
(unsigned long)((naddr >> 16) & 0xFF),
(unsigned long)((naddr >> 24) & 0xFF));
return buf;
}
/*
* 函数功能:端口字节序转换(主机序 -> 网络序)
*/
uint16_t net_htons(uint16_t hostshort) {
return NET_htons(hostshort);
}
/*
* 函数功能:端口字节序转换(网络序 -> 主机序)
*/
uint16_t net_ntohs(uint16_t netshort) {
return NET_ntohs(netshort);
}
/*
* 函数功能:IP 地址字节序转换(主机�?-> 网络序)
*/
uint32_t net_htonl(uint32_t hostlong) {
return NET_htonl(hostlong);
}
/*
* 函数功能:IP 地址字节序转换(网络�?-> 主机序)
*/
uint32_t net_ntohl(uint32_t netlong) {
return NET_ntohl(netlong);
}
/*
* 私有函数实现�? */
/*
* 函数功能:分配空�?Socket
* 返回值:Socket 索引,失败返�?-1
*/
static int alloc_socket(void) {
int i;
for (i = 0; i < NET_MAX_SOCKETS; i++) {
if (!s_net_socks[i].in_use) {
return i;
}
}
return -1;
}
/*
* 函数功能:处理连接事�? */
static void handle_connect_event(net_sock_t *p_sock) {
if (p_sock->state == NET_SOCK_STATE_LISTENING) {
if (p_sock->standalone_accept) {
/* 独立监听模式(PASV):收到 CONNECT 中断 = 自身有连接到达,转为 ESTABLISHED */
DBG_INFO("sock%d standalone accept", p_sock->ch395_sock);
uint8_t remote[6];
ch395f_get_remot_ipp(p_sock->ch395_sock, remote);
memcpy(p_sock->remote_ip_arr, remote, 4);
p_sock->remote_ip = ((uint32_t)remote[0]) |
((uint32_t)remote[1] << 8) |
((uint32_t)remote[2] << 16) |
((uint32_t)remote[3] << 24);
p_sock->remote_port = (uint16_t)(remote[4] | (remote[5] << 8));
p_sock->state = NET_SOCK_STATE_ESTABLISHED;
p_sock->send_ready = 1;
/* 清除残留的 TIMEOUT 中断标志 */
(void)ch395f_get_sock_int_status(p_sock->ch395_sock);
fire_event(p_sock, NET_EVENT_CONNECTED);
} else {
/* 多连接模式:监听 Socket 收到 CONNECT 中断 = 有新连接被分配到数据 Socket
* Socket 0 自身保持 LISTENING,不需要改变状态 */
fire_event(p_sock, NET_EVENT_CONNECTED);
}
}
else if (!p_sock->in_use) {
/* CH395F 自动打开的数�?Socket(多连接模式),首次收到 CONNECT 中断 */
int sock_idx = (int)(p_sock - s_net_socks);
p_sock->ch395_sock = (uint8_t)sock_idx;
DBG_INFO("sock%d AUTO-OPENED, CONNECTED", p_sock->ch395_sock);
uint8_t remote[6];
ch395f_get_remot_ipp(p_sock->ch395_sock, remote);
memcpy(p_sock->remote_ip_arr, remote, 4);
p_sock->remote_ip = ((uint32_t)remote[0]) |
((uint32_t)remote[1] << 8) |
((uint32_t)remote[2] << 16) |
((uint32_t)remote[3] << 24);
p_sock->remote_port = (uint16_t)(remote[4] | (remote[5] << 8));
p_sock->in_use = 1;
p_sock->state = NET_SOCK_STATE_ESTABLISHED;
p_sock->send_ready = 1;
ch395f_set_keepalive_enable(p_sock->ch395_sock, 1);
fire_event(p_sock, NET_EVENT_CONNECTED);
}
else if (p_sock->state == NET_SOCK_STATE_CONNECTING) {
/* TCP Client 连接成功 */
uint8_t remote[6];
ch395f_get_remot_ipp(p_sock->ch395_sock, remote);
memcpy(p_sock->remote_ip_arr, remote, 4);
p_sock->remote_ip = ((uint32_t)remote[0]) |
((uint32_t)remote[1] << 8) |
((uint32_t)remote[2] << 16) |
((uint32_t)remote[3] << 24);
p_sock->remote_port = (uint16_t)(remote[4] | (remote[5] << 8));
p_sock->state = NET_SOCK_STATE_ESTABLISHED;
ch395f_set_keepalive_enable(p_sock->ch395_sock, 1);
fire_event(p_sock, NET_EVENT_CONNECTED);
}
else if (p_sock->state == NET_SOCK_STATE_TCP_ACCEPT) {
/* 数据 Socket 被分配了连接 */
DBG_INFO("data sock%d TCP_ACCEPT -> CONNECTED", p_sock->ch395_sock);
uint8_t remote[6];
ch395f_get_remot_ipp(p_sock->ch395_sock, remote);
memcpy(p_sock->remote_ip_arr, remote, 4);
p_sock->remote_ip = ((uint32_t)remote[0]) |
((uint32_t)remote[1] << 8) |
((uint32_t)remote[2] << 16) |
((uint32_t)remote[3] << 24);
p_sock->remote_port = (uint16_t)(remote[4] | (remote[5] << 8));
p_sock->state = NET_SOCK_STATE_ESTABLISHED;
p_sock->send_ready = 1;
ch395f_set_keepalive_enable(p_sock->ch395_sock, 1);
fire_event(p_sock, NET_EVENT_CONNECTED);
}
}
/*
* 函数功能:处理断开事件
* 函数说明:CH395F �?DISCONNECT 中断后自动关�?Socket(默�?FUN_PARA_FLAG_SOCKET_CLOSE=0),
* 必须重新 OPEN_SOCKET + TCP_LISTEN 才能接受新连�? */
static void handle_disconnect_event(net_sock_t *p_sock) {
if (p_sock->state == NET_SOCK_STATE_LISTENING) {
DBG_ERROR("WARNING: listen sock%d got disconnect", p_sock->ch395_sock);
}
else if (p_sock->state == NET_SOCK_STATE_ESTABLISHED) {
if (p_sock->standalone_accept) {
/* 独立监听模式:先不关 CH395F Socket,
* 留给 net_recv_locked 把剩余数据读出来再关 */
DBG_INFO("sock%d DISCONNECTED, releasing", p_sock->ch395_sock);
p_sock->state = NET_SOCK_STATE_CLOSED;
fire_event(p_sock, NET_EVENT_DISCONNECTED);
} else {
DBG_INFO("sock%d DISCONNECTED, back to idle", p_sock->ch395_sock);
memset(p_sock->remote_ip_arr, 0, 4);
p_sock->remote_port = 0;
p_sock->send_ready = 1;
p_sock->state = NET_SOCK_STATE_TCP_ACCEPT;
fire_event(p_sock, NET_EVENT_DISCONNECTED);
}
} else if (p_sock->state == NET_SOCK_STATE_TCP_ACCEPT) {
memset(p_sock->remote_ip_arr, 0, 4);
p_sock->remote_port = 0;
p_sock->send_ready = 1;
} else if (p_sock->state != NET_SOCK_STATE_CLOSED &&
p_sock->state != NET_SOCK_STATE_BOUND &&
p_sock->state != NET_SOCK_STATE_CREATED) {
/* 未预期的断开 */
DBG_ERROR("sock%d disconnect in state %d", p_sock->ch395_sock, p_sock->state);
fire_event(p_sock, NET_EVENT_DISCONNECTED);
}
}
/*
* 函数功能:处理数据接收事�? */
static void handle_recv_event(net_sock_t *p_sock) {
/* RECV_OK 中断已触发,直接通知上层。不在此读 recv_len,
* 避免和 net_recv_locked 里面的 ch395f_get_recv_len 冲突(Trap 13) */
fire_event(p_sock, NET_EVENT_DATA_RECEIVED);
}
/*
* 函数功能:处理发送完成事�? */
static void handle_send_event(net_sock_t *p_sock) {
fire_event(p_sock, NET_EVENT_SEND_COMPLETE);
}
/*
* 函数功能:处理超时事�? * 函数说明:CH395F �?TIMEOUT 中断后同样自动关�?Socket�? * 需要重新打开并恢复监�? */
static void handle_timeout_event(net_sock_t *p_sock) {
if (p_sock->state == NET_SOCK_STATE_CONNECTING) {
/* TCP Client 连接超时 */
DBG_ERROR("sock%d CONNECT TIMEOUT", p_sock->ch395_sock);
p_sock->state = NET_SOCK_STATE_CREATED;
}
else if (p_sock->state == NET_SOCK_STATE_ESTABLISHED) {
DBG_ERROR("sock%d TIMEOUT", p_sock->ch395_sock);
p_sock->state = p_sock->standalone_accept ? NET_SOCK_STATE_CLOSED : NET_SOCK_STATE_TCP_ACCEPT;
}
else if (p_sock->state == NET_SOCK_STATE_LISTENING) {
/* 监听超时(异常情况) */
DBG_ERROR("sock%d LISTEN TIMEOUT", p_sock->ch395_sock);
}
fire_event(p_sock, NET_EVENT_TIMEOUT);
}
/*
* 函数功能:触发事件回�? */
static void fire_event(net_sock_t *p_sock, net_event_t event) {
if (p_sock->event_cb != NULL) {
p_sock->event_cb(p_sock->ch395_sock, event, p_sock->event_arg);
}
}
/*
* 函数功能:解�?IP 地址字符串为数组
*/
static void parse_ip_string(const char *str, uint8_t *ip_arr) {
uint32_t val;
int i;
if (str == NULL || ip_arr == NULL) {
return;
}
for (i = 0; i < 4; i++) {
val = 0;
while (*str >= '0' && *str <= '9') {
val = val * 10 + (*str - '0');
str++;
}
ip_arr[i] = (uint8_t)val;
if (*str == '.') {
str++;
}
}
}
/*
* 函数功能:获�?Socket 控制块指针(内部使用�? */
net_sock_t *net_get_sock(int sockfd) {
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) {
return NULL;
}
if (!s_net_socks[sockfd].in_use) {
return NULL;
}
return &s_net_socks[sockfd];
}
/*
* 函数功能:获取 Socket 本地地址(IP + Port)
* 入口参数:sockfd - socket 描述符 int
* addr - 输出:本地地址 struct net_sockaddr *
* addrlen - 输入输出:地址结构体长度 int *
* 返回值:0 - 成功,-1 - 失败 int
* 限定条件:socket 已创建或已绑定
* 函数说明:返回 sin_family + sin_port(网络序)+ sin_addr(网络序,从 net_init 缓存的 s_local_ip)
*/
int net_getsockname(int sockfd, struct net_sockaddr *addr, int *addrlen) {
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) {
s_net_errno = NET_ERR_BADF;
return -1;
}
net_sock_t *p_sock = &s_net_socks[sockfd];
if (!p_sock->in_use && p_sock->state == NET_SOCK_STATE_CLOSED) {
s_net_errno = NET_ERR_BADF;
return -1;
}
if (addr == NULL || addrlen == NULL || *addrlen < (int)sizeof(struct net_sockaddr_in)) {
s_net_errno = NET_ERR_INVAL;
return -1;
}
struct net_sockaddr_in *p_addr_in = (struct net_sockaddr_in *)addr;
memset(p_addr_in, 0, sizeof(struct net_sockaddr_in));
p_addr_in->sin_family = NET_AF_INET;
p_addr_in->sin_port = net_htons(p_sock->local_port);
p_addr_in->sin_addr.s_addr = ((uint32_t)s_local_ip[0]) |
((uint32_t)s_local_ip[1] << 8) |
((uint32_t)s_local_ip[2] << 16) |
((uint32_t)s_local_ip[3] << 24);
*addrlen = sizeof(struct net_sockaddr_in);
return 0;
}