增加文件系统

This commit is contained in:
2026-07-21 00:30:59 +08:00
parent e06d849007
commit fbe0726991
50 changed files with 12921 additions and 893 deletions

View File

@@ -1,12 +1,21 @@
/*
* 模块名称Network Socket Core
* 模块功能BSD Socket API 核心实现,包<EFBFBD>?Socket 管理、状态机<EFBFBD>? * 事件处理、数据收发等功能,底层调<EFBFBD>?CH395F 驱动
* 适用平台STM32F4 系列(CH395F 以太网芯片
* 作者:王建<EFBFBD>? * 创建日期<E697A5>?026-07-18
* 修改记录<EFBFBD>? */
* 模块功能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"
@@ -20,21 +29,32 @@
/*
* 私有宏定义区
*/
#define NET_PHY_CHECK_INTERVAL_MS 5000U /* PHY 状态定期检查间隔ms */
/*
* 私有变量<EFBFBD>? */
static net_sock_t s_net_socks[NET_MAX_SOCKETS]; /* Socket 控制块数<E59D97>?*/
static int s_net_errno = 0; /* 最后错误码 */
static uint8_t s_net_initialized = 0; /* 初始化标<E58C96>?*/
/*
* 私有宏定义区 - 补充
* 全局变量定义区 - 尽量避免使用全局变量
*/
#define NET_PHY_CHECK_INTERVAL_MS 5000U /* PHY 状态定期检查间隔ms<6D>?*/
static net_sock_t s_net_socks[NET_MAX_SOCKETS]; /* Socket 控制块数组 */
static int s_net_errno = 0; /* 最后错误码 */
static uint8_t s_net_initialized = 0; /* 初始化标志 */
/*
* 私有函数声明<EFBFBD>? */
* 消息队列 - 线程安全核心
* 外部任务通过 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);
@@ -43,31 +63,50 @@ 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);
/*
* 公共函数实现<EFBFBD>? */
/*
* 函数功能网络子系统初始<EFBFBD>? */
* 函数功能:网络子系统初始化(配置 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;
/* 清零 Socket 控制<E68EA7>?*/
DBG_INFO("net_init: start");
/* 清零 Socket 控制块 */
memset(s_net_socks, 0, sizeof(s_net_socks));
s_net_errno = 0;
s_net_initialized = 0;
/* 检<>?CH395F 芯片 */
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...");
/* 启用 TCP Server 多连接模式bit1=1<EFBFBD>? * Socket 0 专职监听Socket 1~7 自动分配给新连接 */
/* 启用 TCP Server 多连接模式bit1=1 */
ch395f_set_fun_para(0x02);
DBG_INFO("net_init: set_tcp_mss...");
/* 设置 TCP MSS */
ch395f_set_tcp_mss(1460);
@@ -115,7 +154,14 @@ int net_init(const char *ip, const char *mask, const char *gateway) {
}
/*
* 函数功能:轮询<EFBFBD>?Socket 状<>? */
* 函数功能:轮询 CH395F 中断状态,更新 Socket 连接状态并处理事件
* 返回值:本次轮询中发生事件的 Socket 数量 int >= 0
* 限定条件s_net_initialized == 1必须在 netTask 上下文中调用
* 函数说明1. GPIO 轮询 CH395F INT# 引脚电平(低电平有效),无需 EXTI 中断
* 2. 读取 GET_GLOB_INT_STATUS_ALL2 字节版)获取所有 Socket 的中断状态
* 3. 处理连接/断开/数据接收/发送完成/超时等事件,更新 Socket 状态机
* 4. RECV 中断为电平触发,每次 net_poll() 只处理一批中断,避免主循环饿死
*/
int net_poll(void) {
int event_count = 0;
int i;
@@ -126,7 +172,9 @@ int net_poll(void) {
}
/*
* GPIO 轮询模式:仅<EFBFBD>?INT# 有效(低电平)时读取中断状<EFBFBD>? * 读取 GET_GLOB_INT_STATUS_ALL <20>?CH395F 拉高 INT#若仍有中断则再次拉<E6ACA1>? */
* GPIO 轮询模式:仅INT# 有效(低电平)时读取中断状态。
* 读取 GET_GLOB_INT_STATUS_ALLCH395F 拉高 INT#;若仍有中断则再次拉低。
*/
do
{
if (HAL_GPIO_ReadPin(CH395_INT_GPIO_Port, CH395_INT_Pin) == GPIO_PIN_SET) {
@@ -139,7 +187,8 @@ int net_poll(void) {
break;
}
/* 诊断:每 3 秒打印一次全局中断状态和 Socket 状<EFBFBD>? * 注意:使用已读取的 int_status不要再读 GINT读即清除<E6B885>?*/
/* 诊断:每 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) {
@@ -208,11 +257,13 @@ int net_poll(void) {
}
/*
* 处理完毕后检<EFBFBD>?INT# 是否仍为低电<EFBFBD>? * 如果是,说明在处理期间有新中断产生,需要再次读<EFBFBD>? *
* 注意CH395F <EFBFBD>?RECV 中断是电平触发的(只要接收缓冲区有数据就保持低电平)<EFBFBD>? * 如果不跳出循环net_poll() 会无限循环处<E78EAF>?RECV 中断<E4B8AD>? * 导致主循环中的应用代码<E7A081>?echo永远无法执行<E689A7>? * 因此每次 net_poll() 调用只处理一批中断由主循环负责读取数据<E695B0>? */
* 处理完毕后检INT# 是否仍为低电平。如果是,说明在处理期间有新中断产生,需要再次读取。
* 注意CH395F RECV 中断是电平触发的(只要接收缓冲区有数据就保持低电平)
* 如果不跳出循环net_poll() 会无限循环处理 RECV 中断,导致主循环中的应用代码(如 echo永远无法执行。
* 因此每次 net_poll() 调用只处理一批中断,由主循环负责读取数据。 */
} while (0);
/* <EFBFBD>?2 秒打印一次诊断信息(调试用) */
/* 2 秒打印一次诊断信息(调试用) */
{
static uint32_t s_last_dbg = 0;
uint32_t now = HAL_GetTick();
@@ -235,13 +286,76 @@ int net_poll(void) {
}
/*
* 函数功能:<EFBFBD>?socket
* 函数功能:处理消息队列中的请求
* 限定条件:必须在 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;
}
default:
msg.result = -1;
break;
}
xTaskNotifyGive(msg.caller);
}
}
/*
* 函数功能:创建 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;
/* 参数检<EFBFBD>?*/
/* 参数检*/
if (domain != NET_AF_INET) {
s_net_errno = NET_ERR_INVAL;
return -1;
@@ -265,7 +379,17 @@ int net_socket(int domain, int type, int protocol) {
}
/*
* 函数功能:绑定本地地址和端<EFBFBD>? */
* 函数功能:绑定 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 SocketSOCK_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;
@@ -327,7 +451,15 @@ int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen) {
}
/*
* 函数功能TCP Server 监听
* 函数功能:启动 TCP Server 监听(多连接模式)
* 入口参数sockfd - Socket 描述符 (0~7),必须为已绑定的 TCP Socket int
* backlog - 最大并发数据 Socket 数量 int >= 1
* 返回值0 - 监听启动成功 int
* -1 - 监听失败(参数无效、状态错误等) int
* 限定条件Socket 已通过 net_socket() + net_bind() 创建并绑定type == NET_SOCK_STREAM
* 函数说明1. 多连接模式下,先为数据 SocketNET_TCP_SERVER_DATA_SOCK_START ~ 7配置协议类型、源端口和独立缓冲区
* 2. CH395F 根据源端口匹配、协议类型为 TCP、状态为 CLOSED 查找可用 Socket 进行自动分配
* 3. 最后配置监听 Socket 并启动 TCP_LISTEN
*/
int net_listen(int sockfd, int backlog) {
net_sock_t *p_sock;
@@ -351,8 +483,10 @@ int net_listen(int sockfd, int backlog) {
return -1;
}
/* 多连接模式:先为数据 Socket 设置协议类型、源端口和独立缓冲区<EFBFBD>? * 必须在监听话<E590AC>?Socket OPEN+LISTEN 之前配置<EFBC8C>?CH395F <20>? * 自动分配机制能扫描到所有可<E69C89>?Socket
* CH395F 根据源端口匹配、协议类<E8AEAE>?TCP、状<E38081>?CLOSED 查找可用 Socket */
/* 多连接模式:先为数据 Socket 设置协议类型、源端口和独立缓冲区
* 必须在监听 Socket OPEN+LISTEN 之前配置,确保 CH395F
* 自动分配机制能扫描到所有可用 Socket。
* CH395F 根据源端口匹配、协议类型为 TCP、状态为 CLOSED 查找可用 Socket。 */
for (int ds = NET_TCP_SERVER_DATA_SOCK_START; ds < NET_MAX_SOCKETS; ds++) {
uint8_t base = (uint8_t)(ds * 4);
ch395f_set_send_buf((uint8_t)ds, base, 2);
@@ -393,7 +527,13 @@ int net_listen(int sockfd, int backlog) {
}
/*
* 函数功能TCP Server 接受连接
* 函数功能TCP Server 接受连接,返回已建立连接的 Socket 描述符
* 入口参数sockfd - 监听 Socket 描述符 int
* addr - 输出:客户端地址结构体指针 struct net_sockaddr *(可为 NULL
* addrlen - 输入输出:地址结构体长度 int *(可为 NULL
* 返回值:新连接的 Socket 描述符 (1~7),失败返回 -1 int >= 0 || -1
* 限定条件Socket 处于 LISTENING 状态net_poll() 已检测到 CONNECT 事件
* 函数说明:遍历所有数据 Socket查找与客户端地址匹配且已建立连接ESTABLISHED的 Socket
*/
int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen) {
net_sock_t *p_listen_sock;
@@ -438,7 +578,15 @@ int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen) {
}
/*
* 函数功能TCP Client 发起连接
* 函数功能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;
@@ -494,47 +642,37 @@ int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen) {
}
/*
* 函数功能:发送数据(TCP<EFBFBD>? */
int net_send(int sockfd, const void *buf, int len, int flags) {
net_sock_t *p_sock;
* 函数功能:发送数据(内部锁定版本,必须在 netTask 上下文调用)
*/
static int net_send_locked(net_sock_t *p_sock, const void *buf, int len) {
int sent = 0;
uint32_t tick_start;
/* 参数检<E695B0>?*/
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->state != NET_SOCK_STATE_ESTABLISHED) {
s_net_errno = NET_ERR_NOTCONN;
return -1;
}
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();
/* 分块发<E59D97>?*/
while (sent < len) {
int chunk = len - sent;
if (chunk > NET_SEND_BUF_SIZE) {
chunk = NET_SEND_BUF_SIZE;
}
/* 检查发送缓冲区是否空闲 */
if (!p_sock->send_ready) {
/* 超时检<E697B6>?*/
if (NET_SEND_TIMEOUT_MS > 0 &&
(HAL_GetTick() - tick_start) >= NET_SEND_TIMEOUT_MS) {
s_net_errno = NET_ERR_TIMEDOUT;
break;
}
/* 继续轮询 */
net_poll();
continue;
}
@@ -544,7 +682,6 @@ int net_send(int sockfd, const void *buf, int len, int flags) {
sent += chunk;
p_sock->send_bytes += (uint32_t)chunk;
/* 短暂延时等待发送完<E98081>?*/
tick_start = HAL_GetTick();
while (!p_sock->send_ready) {
net_poll();
@@ -559,30 +696,12 @@ int net_send(int sockfd, const void *buf, int len, int flags) {
}
/*
* 函数功能:接收数据(TCP<EFBFBD>? */
int net_recv(int sockfd, void *buf, int len, int flags) {
net_sock_t *p_sock;
* 函数功能:接收数据(内部锁定版本,必须在 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;
/* 参数检<E695B0>?*/
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;
}
/* 检查连接状<E68EA5>?*/
if (p_sock->type == NET_SOCK_STREAM &&
p_sock->state != NET_SOCK_STATE_ESTABLISHED) {
s_net_errno = NET_ERR_NOTCONN;
return -1;
}
int sockfd = (int)(p_sock - s_net_socks);
if (buf == NULL || len <= 0) {
s_net_errno = NET_ERR_INVAL;
@@ -596,35 +715,183 @@ int net_recv(int sockfd, void *buf, int len, int flags) {
recv_len = ch395f_get_recv_len(sockfd);
if (recv_len > 0) {
/* 有数据可<E68DAE>?*/
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;
}
/* 非阻塞模式检<E5BC8F>?*/
if (flags & NET_MSG_DONTWAIT) {
s_net_errno = NET_ERR_WOULDBLOCK;
return -1;
}
/* 超时检<E697B6>?*/
if (NET_RECV_TIMEOUT_MS > 0 &&
(HAL_GetTick() - tick_start) >= NET_RECV_TIMEOUT_MS) {
s_net_errno = NET_ERR_TIMEDOUT;
return -1;
}
/* 连接已断开检<E5BC80>?*/
if (p_sock->state == NET_SOCK_STATE_TCP_ACCEPT) {
return 0; /* 对端关闭 */
return 0;
}
}
}
/*
* 函数功能:<EFBFBD>?UDP 数据
* 函数功能:关闭 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;
}
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
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;
}
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
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;
}
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
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_DGRAMnet_init() 已调用
*/
int net_sendto(int sockfd, const void *buf, int len, int flags,
const struct net_sockaddr *dest_addr, int addrlen) {
@@ -704,9 +971,17 @@ int net_sendto(int sockfd, const void *buf, int len, int flags,
return sent;
}
/*
* 函数功能:接<EFBFBD>?UDP 数据
* 函数功能:接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_DGRAMnet_init() 已调用;有数据可用
*/
int net_recvfrom(int sockfd, void *buf, int len, int flags,
struct net_sockaddr *src_addr, int *addrlen) {
@@ -784,34 +1059,59 @@ int net_recvfrom(int sockfd, void *buf, int len, int flags,
}
/*
* 函数功能:<EFBFBD>?socket
* 函数功能:发送数据(内部版本,绕过消息队列,供 netTask 直接使用)
*/
int net_close(int sockfd) {
net_sock_t *p_sock;
/* 参数检<E695B0>?*/
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) {
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;
}
p_sock = &s_net_socks[sockfd];
if (!p_sock->in_use) {
s_net_errno = NET_ERR_BADF;
return -1;
}
/* 关闭 CH395F Socket */
ch395f_close_socket(sockfd);
/* 清零控制<E68EA7>?*/
memset(p_sock, 0, sizeof(net_sock_t));
return 0;
return net_send_locked(p_sock, buf, len);
}
/*
* 函数功能:注册事件回<EFBFBD>? */
* 函数功能:接收数据(内部版本,绕过消息队列,供 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 == 1net_init() 已调用
*/
int net_set_event_cb(int sockfd, net_event_cb_t cb, void *arg) {
net_sock_t *p_sock;
@@ -832,10 +1132,13 @@ int net_set_event_cb(int sockfd, net_event_cb_t cb, void *arg) {
return 0;
}
/*
* 函数功能:获<EFBFBD>?socket 最后错误码
* 函数功能:获取 Socket 最后一次操作返回的错误码
* 返回值当前错误码值NET_OK=0, NET_ERR_xxx=-N int
* 限定条件:无
* 函数说明:每次 net_*() API 调用失败后,错误码被设置。调用成功时不自动清零
*/
int net_get_errno(void) {
return s_net_errno;
}