修改网络的初始化,异步支持问题

This commit is contained in:
2026-07-21 01:22:09 +08:00
parent fbe0726991
commit f50b9c9e66
7 changed files with 337 additions and 138 deletions

View File

@@ -1,6 +1,6 @@
/*
* 模块名称Network Application Task
* 模块功能CH395F 协议栈轮询 + TCP/UDP 业务处理
* 模块功能CH395F 协议栈初始化 + 轮询 + TCP/UDP 业务处理
* 与 net_socket.h 配合,在 FreeRTOS 独立任务中运行
* 适用平台STM32F407ZGTx + CH395F
* 作者:王建锋
@@ -8,12 +8,15 @@
* 修改记录:
* v1.0 2026-07-19 王建锋 创建初始版本
* v1.1 2026-07-19 王建锋 migrate from freertos.c StartNetTask
* v1.2 2026-07-21 王建锋 网络初始化移入本任务net_init + TCP 监听)
*/
#include <string.h>
#include "net_task.h"
#include "cmsis_os.h"
#include "net_socket.h"
#include "net_select.h"
#include "ch395f.h"
#include "ch395f_test.h"
#define DBG_TAG "[NET_TASK]"
@@ -38,16 +41,66 @@ int net_task_init(void)
* 函数功能:网络任务主函数
* 入口参数arg - FreeRTOS 传入参数(未使用)
* 返 回 值:无
* 函数说明:FreeRTOS 任务函数,启动后先等待 2 秒再进入轮询循环
* 依次处理 net_poll、TCP echo、UDP/Select 测试
* 函数说明:启动后先调用 net_init 初始化 CH395F 协议栈,创建 TCP 监听,
* 再进入轮询循环处理网络事件
*/
void net_task_func(void const *arg)
{
(void)arg;
osDelay(2000);
/* ==================== CH395F 协议栈初始化 ==================== */
DBG_INFO("=== Network Init ===");
if (net_init("192.168.1.100", "255.255.255.0", "192.168.1.1") == 0) {
DBG_INFO("net init: OK");
uint8_t mac[6];
ch395f_get_mac_addr(mac);
DBG_INFO("MAC: %02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
ch395f_set_phy(CH395F_PHY_100M_FULL);
HAL_Delay(3000);
uint8_t phy = ch395f_get_phy_status();
DBG_INFO("PHY: %s",
(phy == CH395F_PHY_100M_FULL) ? "100M FULL" :
(phy == CH395F_PHY_100M_HALF) ? "100M HALF" :
(phy == CH395F_PHY_10M_FULL) ? "10M FULL" :
(phy == CH395F_PHY_10M_HALF) ? "10M HALF" :
(phy == CH395F_PHY_DISCONN) ? "DISCONNECT" : "UNKNOWN");
} else {
DBG_ERROR("net init: FAIL");
}
/* ==================== TCP Server Echo 测试 ==================== */
{
int listen_sock = net_socket(NET_AF_INET, NET_SOCK_STREAM, 0);
DBG_INFO("TCP listen socket: %d", listen_sock);
struct net_sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = NET_AF_INET;
serv_addr.sin_port = net_htons(8080);
serv_addr.sin_addr.s_addr = NET_INADDR_ANY;
if (net_bind(listen_sock, (struct net_sockaddr *)&serv_addr, sizeof(serv_addr)) == 0) {
DBG_INFO("TCP bind: OK (port 8080)");
} else {
DBG_ERROR("TCP bind: FAIL");
}
if (net_listen_locked(listen_sock, NET_TCP_SERVER_MAX_CLIENTS) == 0) {
DBG_INFO("TCP listen: OK (max_clients=%d)", NET_TCP_SERVER_MAX_CLIENTS);
} else {
DBG_ERROR("TCP listen: FAIL");
}
}
DBG_INFO("netTask: started, processing messages");
/* ==================== 主轮询循环 ==================== */
for (;;) {
net_poll();
net_process_messages();

View File

@@ -66,6 +66,7 @@ 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 + 启用多连接模式)
@@ -333,6 +334,17 @@ void net_process_messages(void) {
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;
@@ -438,6 +450,7 @@ int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen) {
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;
}
@@ -451,27 +464,16 @@ int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen) {
}
/*
* 函数功能:启动 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
* 函数功能:启动 TCP Server 监听(内部版本,必须在 netTask 上下文调用
* 入口参数sockfd - Socket 描述符 (0~7) int
* backlog - 数据 Socket 数量0=单连接模式) int
* 返回值0 - 成功,-1 - 失败 int
* 限定条件sockfd 已绑定且为 TCPnetTask 上下文
*/
int net_listen(int sockfd, int backlog) {
net_sock_t *p_sock;
int net_listen_locked(int sockfd, int backlog) {
net_sock_t *p_sock = &s_net_socks[sockfd];
uint8_t status;
/* 参数检<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->type != NET_SOCK_STREAM) {
s_net_errno = NET_ERR_INVAL;
return -1;
@@ -483,15 +485,16 @@ int net_listen(int sockfd, int backlog) {
return -1;
}
/* 多连接模式:先为数据 Socket 设置协议类型、源端口和独立缓冲区。
* 必须在监听 Socket OPEN+LISTEN 之前配置,确保 CH395F
* 自动分配机制能扫描到所有可用 Socket。
* CH395F 根据源端口匹配、协议类型为 TCP、状态为 CLOSED 查找可用 Socket。 */
for (int ds = NET_TCP_SERVER_DATA_SOCK_START; ds < NET_MAX_SOCKETS; ds++) {
/* 多连接模式:按 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);
/* <20>?CH395F 手册 9.2.6 节顺序:先设源端口,再设协议类型 */
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;
@@ -499,9 +502,12 @@ int net_listen(int sockfd, int backlog) {
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;
}
}
/* 最后配置监<EFBFBD>?Socket 并启动监<EFBFBD>?*/
/* 配置监Socket */
ch395f_set_send_buf((uint8_t)sockfd, 0, 2);
ch395f_set_recv_buf((uint8_t)sockfd, 2, 2);
ch395f_set_proto_type(sockfd, CH395F_PROTO_TYPE_TCP);
@@ -513,10 +519,12 @@ int net_listen(int sockfd, int backlog) {
return -1;
}
/* 启动 TCP 监听 */
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);
@@ -527,39 +535,72 @@ int net_listen(int sockfd, int backlog) {
}
/*
* 函数功能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
* 函数功能:启动 TCP Server 监听(线程安全版本,通过消息队列委托给 netTask
* 入口参数sockfd - Socket 描述符 int
* backlog - 数据 Socket 数量 int
* 返回值0 - 成功,-1 - 失败 int
* 限定条件net_init() + MX_FREERTOS_Init() 已执行;必须在任务上下文中调用
* 函数说明:通过消息队列委托给 netTask确保 SPI 串行化
*/
int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen) {
net_sock_t *p_listen_sock;
int i;
int net_listen(int sockfd, int backlog) {
net_msg_t msg;
/* 参数检<E695B0>?*/
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;
}
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
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 || p_listen_sock->state != NET_SOCK_STATE_LISTENING) {
s_net_errno = NET_ERR_INVAL;
return -1;
}
/* 轮询查找已建立连接的数据 Socket */
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) {
/* 找到已建立连接的 Socket */
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;
@@ -567,16 +608,73 @@ int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen) {
p_addr_in->sin_addr.s_addr = p_data_cb->remote_ip;
*addrlen = sizeof(struct net_sockaddr_in);
}
return data_sock;
}
}
/* 没有新连<EFBFBD>?*/
/* 单连接模式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;
}
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
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

View File

@@ -27,6 +27,8 @@ typedef enum {
NET_MSG_RECV,
NET_MSG_CLOSE,
NET_MSG_CONNECT,
NET_MSG_LISTEN,
NET_MSG_ACCEPT,
} net_msg_type_t;
typedef struct {
@@ -318,6 +320,15 @@ int net_recv_sock(net_sock_t *p_sock, void *buf, int len, int flags);
*/
int net_close_sock(net_sock_t *p_sock);
/*
* 函数功能:启动 TCP Server 监听(内部版本,直接操作,不经过消息队列)
* 入口参数sockfd - Socket 描述符
* backlog - 数据 Socket 数量0=单连接模式)
* 返回值0 成功,-1 失败
* 限定条件:必须在 netTask 上下文中调用
*/
int net_listen_locked(int sockfd, int backlog);
#ifdef __cplusplus
}
#endif

View File

@@ -163,6 +163,9 @@ typedef struct {
/* 发送就绪标志 */
uint8_t send_ready;
/* 独立监听标志PASV 用):该 Socket 为独立监听者,收到 CONNECT 后转为 ESTABLISHED断开后释放 */
uint8_t standalone_accept;
/* 统计信息 */
uint32_t recv_bytes; /* 累计接收字节数 */
uint32_t send_bytes; /* 累计发送字节数 */

View File

@@ -1,30 +1,30 @@
*** Using Compiler 'V5.06 update 7 (build 960)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
Rebuild target 'STM32F407-Demo'
assembling startup_stm32f407xx.s...
compiling ringbuf.c...
compiling crc.c...
compiling stm32f4xx_hal_msp.c...
compiling stm32f4xx_it.c...
compiling i2c.c...
compiling ringbuf.c...
compiling dma.c...
compiling gpio.c...
compiling spi.c...
compiling stm32f4xx_hal_timebase_tim.c...
compiling app_main.c...
compiling sys_clock.c...
compiling dma.c...
compiling stm32f4xx_hal_msp.c...
compiling i2c.c...
compiling stm32f4xx_hal_flash_ramfunc.c...
compiling stm32f4xx_hal_gpio.c...
compiling usart.c...
compiling stm32f4xx_hal_flash.c...
compiling stm32f4xx_hal_flash_ex.c...
compiling stm32f4xx_it.c...
compiling sys_clock.c...
compiling stm32f4xx_hal_timebase_tim.c...
compiling stm32f4xx_hal_rcc_ex.c...
compiling usart.c...
compiling app_main.c...
compiling stm32f4xx_hal_flash_ex.c...
compiling stm32f4xx_hal_gpio.c...
compiling stm32f4xx_hal_flash.c...
compiling rs485_task.c...
compiling net_task.c...
compiling adc_task.c...
compiling stm32f4xx_hal_rcc.c...
compiling stm32f4xx_hal_tim_ex.c...
compiling net_task.c...
compiling freertos.c...
compiling stm32f4xx_hal_rcc.c...
compiling main.c...
compiling stm32f4xx_hal_tim_ex.c...
compiling stm32f4xx_hal_tim.c...
compiling fdb.c...
compiling fdb_kvdb.c...
@@ -34,42 +34,42 @@ compiling fal.c...
compiling fal_flash.c...
compiling fal_partition.c...
compiling croutine.c...
compiling stm32f4xx_hal_dma_ex.c...
compiling event_groups.c...
compiling list.c...
compiling stm32f4xx_hal_dma.c...
compiling system_stm32f4xx.c...
compiling stm32f4xx_hal_i2c_ex.c...
compiling stm32f4xx_hal_exti.c...
compiling stm32f4xx_hal_pwr.c...
compiling stm32f4xx_hal_dma.c...
compiling stm32f4xx_hal_pwr_ex.c...
compiling system_stm32f4xx.c...
compiling stm32f4xx_hal_cortex.c...
compiling stm32f4xx_hal.c...
compiling sd2506.c...
compiling stm32f4xx_hal_exti.c...
compiling rs485.c...
compiling stm32f4xx_hal_dma_ex.c...
compiling fal_flash_gd5f2gq5ue.c...
compiling tpafe5160.c...
compiling ch395f.c...
compiling nand_ftl.c...
compiling gd5f2gq5ue.c...
compiling stm32f4xx_hal_spi.c...
compiling ch395f_test.c...
compiling stm32f4xx_hal_uart.c...
compiling queue.c...
compiling net_select.c...
compiling fal_flash_gd5f2gq5ue.c...
compiling stream_buffer.c...
compiling ch395f.c...
compiling tpafe5160.c...
compiling sd2506.c...
compiling gd5f2gq5ue.c...
compiling timers.c...
compiling stm32f4xx_hal_spi.c...
compiling nand_ftl.c...
compiling net_select.c...
compiling heap_4.c...
compiling net_socket.c...
compiling map.c...
compiling stm32f4xx_hal_uart.c...
compiling ch395f_test.c...
compiling tasks.c...
compiling journal.c...
compiling map.c...
compiling port.c...
compiling journal.c...
compiling net_socket.c...
compiling stm32f4xx_hal_i2c.c...
compiling ff.c...
compiling cmsis_os2.c...
linking...
Program Size: Code=58468 RO-data=3488 RW-data=248 ZI-data=54792
Program Size: Code=58876 RO-data=3560 RW-data=244 ZI-data=54796
FromELF: creating hex file...
".\STM32F407-Demo\STM32F407-Demo.axf" - 0 Error(s), 0 Warning(s).
Build Time Elapsed: 00:00:19
Build Time Elapsed: 00:00:17

View File

@@ -64,8 +64,6 @@
rs485_handle_t g_rs485;
#define RS485_RX_BUF_SIZE 256
uint8_t g_rs485_rx_buf[RS485_RX_BUF_SIZE];
/* TCP Server Echo 测试 */
static int s_listen_sock = -1;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
@@ -135,26 +133,6 @@ int main(void)
/* 启动第一次 RS-485 接收 */
rs485_receive_start(&g_rs485, g_rs485_rx_buf, RS485_RX_BUF_SIZE);
/* BSD Socket API 初始化(包含 CH395F 复位/配置/协议栈初始化/多连接模式) */
DBG_INFO("net init: %s",
(net_init("192.168.1.100", "255.255.255.0", "192.168.1.1") == 0) ? "OK" : "FAIL");
/* 读取 MAC */
uint8_t mac[6];
ch395f_get_mac_addr(mac);
DBG_INFO("MAC: %02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
/* 强制 100M 全双工,建立 PHY 链路 */
ch395f_set_phy(CH395F_PHY_100M_FULL);
HAL_Delay(3000);
uint8_t phy = ch395f_get_phy_status();
DBG_INFO("PHY: %s",
(phy == CH395F_PHY_100M_FULL) ? "100M FULL" :
(phy == CH395F_PHY_100M_HALF) ? "100M HALF" :
(phy == CH395F_PHY_10M_FULL) ? "10M FULL" :
(phy == CH395F_PHY_10M_HALF) ? "10M HALF" :
(phy == CH395F_PHY_DISCONN) ? "DISCONNECT" : "UNKNOWN");
/* GD5F 初始化测试 */
int ret = gd5f2gq5ue_init();
@@ -201,30 +179,6 @@ int main(void)
sd_vbat / 1000, (sd_vbat % 1000) / 10);
}
/* 创建 TCP Server Echo 测试 */
{
s_listen_sock = net_socket(NET_AF_INET, NET_SOCK_STREAM, 0);
DBG_INFO("TCP listen socket: %d", s_listen_sock);
struct net_sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = NET_AF_INET;
serv_addr.sin_port = net_htons(8080);
serv_addr.sin_addr.s_addr = NET_INADDR_ANY;
if (net_bind(s_listen_sock, (struct net_sockaddr *)&serv_addr, sizeof(serv_addr)) == 0) {
DBG_INFO("TCP bind: OK (port 8080)");
} else {
DBG_ERROR("TCP bind: FAIL");
}
if (net_listen(s_listen_sock, NET_TCP_SERVER_MAX_CLIENTS) == 0) {
DBG_INFO("TCP listen: OK (max_clients=%d)", NET_TCP_SERVER_MAX_CLIENTS);
} else {
DBG_ERROR("TCP listen: FAIL");
}
}
/* 启动第一次转换CubeMX 已配置 BUSY EXTI 中断) */
tpafe5160_start_conv_irq();

View File

@@ -0,0 +1,80 @@
# NET Socket FTP 支持改造方案
## 背景
在 net_socket API 上移植 FTP Serverlftpd需要支持 PASV 模式数据通道。现有 API 仅支持"一个监听 Socket 独占全部数据 Socket"的单 TCP Server 模型,改造后需支持**多监听者 + 动态 Socket 分配**。
## Socket 需求量
| 用途 | Socket | 说明 |
|------|--------|------|
| 控制通道监听(端口 21 | Socket 0 | 多连接 TCP Server |
| 控制通道数据 | Socket 1 | backlog=1只接受 1 个 FTP 客户端 |
| PASV 数据监听 + 传输 | Socket 2 | 动态分配,用后释放 |
| 空闲 | Socket 3~7 | 备胎 |
## 改造项7 项)
### A. `net_sock_t` 新增 `standalone_accept` 标志
- 位置:`net_types.h:net_sock_t`
- 用途:区分多连接数据 Socket 和独立监听者(如 PASV
- 设 1PASV 监听者 `handle_connect_event` → 原地转为 `ESTABLISHED`
- 设 1`handle_disconnect_event` → 释放(`CLOSED`),不恢复 `TCP_ACCEPT`
### B. `net_listen()` 按 backlog 分配 + 登记 data_socks[]
- 循环从 `NET_TCP_SERVER_DATA_SOCK_START``backlog`
- 分配的数据 Socket 登记到 `p_sock->data_socks[]`,设 `data_sock_count`
- `backlog == 0` 时:不分配数据 Socket`standalone_accept=1`
### C. `net_bind()` 支持 port=0 自动分配
- `sin_port == 0` 时从 49152~65535 分配
- 静态变量 `s_dynamic_port` 递增
### D. `handle_connect_event()` 支持独立监听
- `LISTENING + standalone_accept`:拷贝远程 IP/Port状态转 `ESTABLISHED`
- `LISTENING + !standalone_accept`:保持 LISTENING现有行为
### E. `handle_disconnect_event()` 支持独立释放
- `ESTABLISHED + standalone_accept`:设 `state = CLOSED, in_use = 0`(释放)
- `ESTABLISHED + !standalone_accept`:恢复 `TCP_ACCEPT`(现有行为)
- 释放时不清零整个控制块(正在 `net_recv` 中的任务仍需读取 state
### F. `net_accept()` 支持单连接 + 修复多连接
- 先查 `data_socks[]`(修复现行 bug
- 再查 `standalone_accept` 监听者是否 `ESTABLISHED` → 返回自身
### G. 新增 `net_getsockname()`
- 返回 `local_port` + 本机 IP
- 本机 IP 在 `net_init()` 时缓存(`s_local_ip`),避免 SPI 竞态
## 消息队列序列化
### 问题
`net_listen()``net_accept()` 直接调用 CH395F SPI从非 netTask如 FTP 任务)调用会与 `net_poll()` 冲突。
### 方案
新增消息类型通过现有消息队列串行化:
| 消息类型 | 用途 | 状态 |
|---------|------|------|
| `NET_MSG_LISTEN` | `net_listen()` 委托 netTask 执行 | 本次实现 |
| `NET_MSG_ACCEPT` | `net_accept()` 委托 netTask 执行 | 本次实现 |
`net_bind()` 暂不消息化TCP 部分不碰 SPIUDP 暂无需跨任务调用)。
## 向后兼容
- 控制通道 `net_listen(sockfd=0, backlog=7)` 行为不变(仍配满 Socket 1~7
- `backlog < 7` 时才释放多余 Socket
- `NET_MSG_LISTEN`/`NET_MSG_ACCEPT` 仅新增,不影响现有 `NET_MSG_SEND/RECV/CLOSE/CONNECT`
- `net_sock_t` 新增字段 `standalone_accept` 默认 0不影响现有使用
## 实施顺序
1. 消息队列加 `NET_MSG_LISTEN``NET_MSG_ACCEPT`
2. `net_listen()` 消息化 + 按 backlog 分配 + data_socks 登记
3. `net_accept()` 消息化 + 单连接支持
4. `net_bind()` port=0 支持
5. `net_types.h` standalone_accept 字段
6. `handle_connect_event()` / `handle_disconnect_event()` 独立监听逻辑
7. `net_getsockname()`