修改网络的初始化,异步支持问题
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
@@ -437,10 +449,11 @@ int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen) {
|
||||
ch395f_set_des_port((uint8_t)sockfd, 0);
|
||||
|
||||
status = ch395f_open_socket((uint8_t)sockfd);
|
||||
if (status != CH395F_ERR_SUCCESS) {
|
||||
s_net_errno = NET_ERR_BUSY;
|
||||
return -1;
|
||||
}
|
||||
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 {
|
||||
@@ -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. 多连接模式下,先为数据 Socket(NET_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 已绑定且为 TCP;netTask 上下文
|
||||
*/
|
||||
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,25 +485,29 @@ 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++) {
|
||||
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;
|
||||
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;
|
||||
/* 多连接模式:按 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 最后配置监<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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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; /* 累计发送字节数 */
|
||||
|
||||
@@ -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
|
||||
|
||||
46
Src/main.c
46
Src/main.c
@@ -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();
|
||||
|
||||
|
||||
80
docs/NET_Socket_FTP_Support_Plan.md
Normal file
80
docs/NET_Socket_FTP_Support_Plan.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# NET Socket FTP 支持改造方案
|
||||
|
||||
## 背景
|
||||
|
||||
在 net_socket API 上移植 FTP Server(lftpd),需要支持 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)
|
||||
- 设 1:PASV 监听者 `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 部分不碰 SPI,UDP 暂无需跨任务调用)。
|
||||
|
||||
## 向后兼容
|
||||
|
||||
- 控制通道 `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()`
|
||||
Reference in New Issue
Block a user