Files
STM32F4-Base/Drivers/BSP/NET/net_socket.c
2026-07-19 13:09:06 +08:00

1280 lines
33 KiB
C
Raw Permalink 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 驱动
* 适用平台STM32F4 系列CH395F 以太网芯片)
* 作者:王建锋
* 创建日期2026-07-18
* 修改记录:
*/
#include "net_socket.h"
#include "ch395f.h"
#include "main.h"
#include <string.h>
#include <stdio.h>
/*
* 调试输出配置
*/
#define DBG_TAG "[NET]"
#include "dbg_log.h"
/*
* 私有宏定义区
*/
/*
* 私有变量区
*/
static net_sock_t g_net_socks[NET_MAX_SOCKETS]; /* Socket 控制块数组 */
static int s_net_errno = 0; /* 最后错误码 */
static uint8_t s_net_initialized = 0; /* 初始化标志 */
/*
* 私有宏定义区 - 补充
*/
#define NET_PHY_CHECK_INTERVAL_MS 5000U /* PHY 状态定期检查间隔ms */
/*
* 私有函数声明区
*/
static int alloc_socket(void);
static void handle_connect_event(net_sock_t *sock);
static void handle_disconnect_event(net_sock_t *sock);
static void handle_recv_event(net_sock_t *sock);
static void handle_send_event(net_sock_t *sock);
static void handle_timeout_event(net_sock_t *sock);
static void fire_event(net_sock_t *sock, net_event_t event);
static void parse_ip_string(const char *str, uint8_t *ip_arr);
/*
* 公共函数实现区
*/
/*
* 函数功能:网络子系统初始化
*/
int net_init(const char *ip, const char *mask, const char *gateway)
{
ch395f_status_t ret;
/* 清零 Socket 控制块 */
memset(g_net_socks, 0, sizeof(g_net_socks));
s_net_errno = 0;
s_net_initialized = 0;
/* 检测 CH395F 芯片 */
if (ch395f_check_exist() != CH395F_STATUS_OK)
{
s_net_errno = NET_ERR;
return -1;
}
/* 复位芯片 */
ch395f_reset();
/* 启用 TCP Server 多连接模式bit1=1
* Socket 0 专职监听Socket 1~7 自动分配给新连接 */
ch395f_set_fun_para(0x02);
/* 设置 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);
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;
}
/*
* 函数功能:轮询所有 Socket 状态
*/
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 状态
* 注意:不要在此处读取 per-socket 中断状态ch395f_get_sock_int_status
* 会清除中断标志),避免破坏后续正常处理流程 */
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;
uint16_t cur_int = ch395f_get_glob_int_status_all();
DBG_INFO("GINT=0x%04X", cur_int);
for (int di = 0; di < NET_MAX_SOCKETS; di++)
{
DBG_INFO(" s%d: in_use=%d state=%d rl=%d",
di, g_net_socks[di].in_use, g_net_socks[di].state,
g_net_socks[di].state == NET_SOCK_STATE_ESTABLISHED ? ch395f_get_recv_len((uint8_t)di) : 0);
}
}
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 *sock = &g_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);
/* 连接事件 */
if (sock_int & CH395F_SINT_STAT_CONNECT)
{
handle_connect_event(sock);
event_count++;
}
/* 断开事件 */
if (sock_int & CH395F_SINT_STAT_DISCONNECT)
{
handle_disconnect_event(sock);
event_count++;
}
/* 数据接收事件 */
if (sock_int & CH395F_SINT_STAT_RECV_OK)
{
handle_recv_event(sock);
event_count++;
}
/* 发送完成事件 */
if (sock_int & CH395F_SINT_STAT_SEND_OK)
{
handle_send_event(sock);
event_count++;
}
/* 发送缓冲区空闲 */
if (sock_int & CH395F_SINT_STAT_SENBUF_FREE)
{
sock->send_ready = 1;
}
/* 超时事件 */
if (sock_int & CH395F_SINT_STAT_SOCK_TIMEOUT)
{
handle_timeout_event(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 (g_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;
}
/*
* 函数功能:创建 socket
*/
int net_socket(int domain, int type, int protocol)
{
int sockfd;
net_sock_t *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;
}
sock = &g_net_socks[sockfd];
sock->ch395_sock = (uint8_t)sockfd;
sock->type = (uint8_t)type;
sock->state = NET_SOCK_STATE_CREATED;
sock->in_use = 1;
sock->send_ready = 1;
return sockfd;
}
/*
* 函数功能:绑定本地地址和端口
*/
int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen)
{
net_sock_t *sock;
const struct net_sockaddr_in *addr_in;
/* 参数检查 */
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS)
{
s_net_errno = NET_ERR_BADF;
return -1;
}
sock = &g_net_socks[sockfd];
if (!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;
}
addr_in = (const struct net_sockaddr_in *)addr;
/* 设置本地端口(转换为主机序) */
sock->local_port = net_ntohs(addr_in->sin_port);
/* UDP (SOCK_DGRAM): 直接在此打开 CH395F Socket */
if (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, 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)
{
s_net_errno = NET_ERR_BUSY;
return -1;
}
sock->state = NET_SOCK_STATE_UDP_OPEN;
}
else
{
sock->state = NET_SOCK_STATE_BOUND;
}
return 0;
}
/*
* 函数功能TCP Server 监听
*/
int net_listen(int sockfd, int backlog)
{
net_sock_t *sock;
uint8_t status;
/* 参数检查 */
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS)
{
s_net_errno = NET_ERR_BADF;
return -1;
}
sock = &g_net_socks[sockfd];
if (!sock->in_use || sock->type != NET_SOCK_STREAM)
{
s_net_errno = NET_ERR_INVAL;
return -1;
}
if (sock->state != NET_SOCK_STATE_BOUND &&
sock->state != NET_SOCK_STATE_CREATED)
{
s_net_errno = NET_ERR_INVAL;
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);
/* 按 CH395F 手册 9.2.6 节顺序:先设源端口,再设协议类型 */
ch395f_set_sour_port((uint8_t)ds, sock->local_port);
ch395f_set_proto_type((uint8_t)ds, CH395F_PROTO_TYPE_TCP);
}
/* 最后配置监听 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);
ch395f_set_sour_port(sockfd, sock->local_port);
status = ch395f_open_socket(sockfd);
if (status != CH395F_ERR_SUCCESS)
{
s_net_errno = NET_ERR_BUSY;
return -1;
}
/* 启动 TCP 监听 */
ch395f_tcp_listen(sockfd);
sock->state = NET_SOCK_STATE_LISTENING;
return 0;
}
/*
* 函数功能TCP Server 接受连接
*/
int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen)
{
net_sock_t *listen_sock;
int i;
/* 参数检查 */
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS)
{
s_net_errno = NET_ERR_BADF;
return -1;
}
listen_sock = &g_net_socks[sockfd];
if (!listen_sock->in_use || listen_sock->state != NET_SOCK_STATE_LISTENING)
{
s_net_errno = NET_ERR_INVAL;
return -1;
}
/* 轮询查找已建立连接的数据 Socket */
net_poll();
for (i = 0; i < listen_sock->data_sock_count; i++)
{
int data_sock = listen_sock->data_socks[i];
net_sock_t *data_cb = &g_net_socks[data_sock];
if (data_cb->state == NET_SOCK_STATE_ESTABLISHED)
{
/* 找到已建立连接的 Socket */
if (addr != NULL && addrlen != NULL)
{
struct net_sockaddr_in *addr_in = (struct net_sockaddr_in *)addr;
addr_in->sin_family = NET_AF_INET;
addr_in->sin_port = net_htons(data_cb->remote_port);
addr_in->sin_addr.s_addr = data_cb->remote_ip;
*addrlen = sizeof(struct net_sockaddr_in);
}
return data_sock;
}
}
/* 没有新连接 */
s_net_errno = NET_ERR_WOULDBLOCK;
return -1;
}
/*
* 函数功能TCP Client 发起连接
*/
int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen)
{
net_sock_t *sock;
const struct net_sockaddr_in *addr_in;
uint8_t status;
/* 参数检查 */
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS)
{
s_net_errno = NET_ERR_BADF;
return -1;
}
sock = &g_net_socks[sockfd];
if (!sock->in_use || 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;
}
addr_in = (const struct net_sockaddr_in *)addr;
/* 保存远端地址 */
sock->remote_ip = addr_in->sin_addr.s_addr;
sock->remote_port = net_ntohs(addr_in->sin_port);
/* 转换 IP 为数组格式(低字节在前) */
sock->remote_ip_arr[0] = (uint8_t)(sock->remote_ip);
sock->remote_ip_arr[1] = (uint8_t)(sock->remote_ip >> 8);
sock->remote_ip_arr[2] = (uint8_t)(sock->remote_ip >> 16);
sock->remote_ip_arr[3] = (uint8_t)(sock->remote_ip >> 24);
/* 配置 CH395F Socket */
ch395f_set_proto_type(sockfd, CH395F_PROTO_TYPE_TCP);
ch395f_set_sour_port(sockfd, sock->local_port);
ch395f_set_des_ip(sockfd, sock->remote_ip_arr);
ch395f_set_des_port(sockfd, 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);
sock->state = NET_SOCK_STATE_CONNECTING;
return 0;
}
/*
* 函数功能发送数据TCP
*/
int net_send(int sockfd, const void *buf, int len, int flags)
{
net_sock_t *sock;
int sent = 0;
uint32_t tick_start;
/* 参数检查 */
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS)
{
s_net_errno = NET_ERR_BADF;
return -1;
}
sock = &g_net_socks[sockfd];
if (!sock->in_use || sock->state != NET_SOCK_STATE_ESTABLISHED)
{
s_net_errno = NET_ERR_NOTCONN;
return -1;
}
if (buf == NULL || len <= 0)
{
s_net_errno = NET_ERR_INVAL;
return -1;
}
tick_start = HAL_GetTick();
/* 分块发送 */
while (sent < len)
{
int chunk = len - sent;
if (chunk > NET_SEND_BUF_SIZE)
{
chunk = NET_SEND_BUF_SIZE;
}
/* 检查发送缓冲区是否空闲 */
if (!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);
sock->send_ready = 0;
sent += chunk;
sock->send_bytes += (uint32_t)chunk;
/* 短暂延时等待发送完成 */
tick_start = HAL_GetTick();
while (!sock->send_ready)
{
net_poll();
if (NET_SEND_TIMEOUT_MS > 0 &&
(HAL_GetTick() - tick_start) >= NET_SEND_TIMEOUT_MS)
{
break;
}
}
}
return sent;
}
/*
* 函数功能接收数据TCP
*/
int net_recv(int sockfd, void *buf, int len, int flags)
{
net_sock_t *sock;
uint16_t recv_len;
uint32_t tick_start;
/* 参数检查 */
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS)
{
s_net_errno = NET_ERR_BADF;
return -1;
}
sock = &g_net_socks[sockfd];
if (!sock->in_use)
{
s_net_errno = NET_ERR_BADF;
return -1;
}
/* 检查连接状态 */
if (sock->type == NET_SOCK_STREAM &&
sock->state != NET_SOCK_STATE_ESTABLISHED)
{
s_net_errno = NET_ERR_NOTCONN;
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)
{
/* 有数据可读 */
int read_len = (recv_len > (uint16_t)len) ? len : (int)recv_len;
ch395f_read_recv_buf(sockfd, (uint8_t *)buf, (uint16_t)read_len);
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;
}
/* 连接已断开检查 */
if (sock->state == NET_SOCK_STATE_TCP_ACCEPT)
{
return 0; /* 对端关闭 */
}
}
}
/*
* 函数功能:发送 UDP 数据
*/
int net_sendto(int sockfd, const void *buf, int len, int flags,
const struct net_sockaddr *dest_addr, int addrlen)
{
net_sock_t *sock;
const struct net_sockaddr_in *addr_in;
int sent = 0;
uint32_t tick_start;
/* 参数检查 */
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS)
{
s_net_errno = NET_ERR_BADF;
return -1;
}
sock = &g_net_socks[sockfd];
if (!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))
{
addr_in = (const struct net_sockaddr_in *)dest_addr;
/* 转换 IP 为数组格式 */
uint8_t ip_arr[4];
uint32_t ip = 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(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 (!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);
sock->send_ready = 0;
sent += chunk;
sock->send_bytes += (uint32_t)chunk;
/* 等待发送完成 */
tick_start = HAL_GetTick();
while (!sock->send_ready)
{
net_poll();
if (NET_SEND_TIMEOUT_MS > 0 &&
(HAL_GetTick() - tick_start) >= NET_SEND_TIMEOUT_MS)
{
break;
}
}
}
return sent;
}
/*
* 函数功能:接收 UDP 数据
*/
int net_recvfrom(int sockfd, void *buf, int len, int flags,
struct net_sockaddr *src_addr, int *addrlen)
{
net_sock_t *sock;
uint16_t recv_len;
uint32_t tick_start;
/* 参数检查 */
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS)
{
s_net_errno = NET_ERR_BADF;
return -1;
}
sock = &g_net_socks[sockfd];
if (!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 (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 *addr_in = (struct net_sockaddr_in *)src_addr;
addr_in->sin_family = NET_AF_INET;
/* CH395F UDP 头: [0-1] reserved [2-3] src_port(LE) [4-7] src_ip */
addr_in->sin_port = net_htons((uint16_t)(header[2] | (header[3] << 8)));
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);
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;
}
}
}
/*
* 函数功能:关闭 socket
*/
int net_close(int sockfd)
{
net_sock_t *sock;
/* 参数检查 */
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS)
{
s_net_errno = NET_ERR_BADF;
return -1;
}
sock = &g_net_socks[sockfd];
if (!sock->in_use)
{
s_net_errno = NET_ERR_BADF;
return -1;
}
/* 关闭 CH395F Socket */
ch395f_close_socket(sockfd);
/* 清零控制块 */
memset(sock, 0, sizeof(net_sock_t));
return 0;
}
/*
* 函数功能:注册事件回调
*/
int net_set_event_cb(int sockfd, net_event_cb_t cb, void *arg)
{
net_sock_t *sock;
/* 参数检查 */
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS)
{
s_net_errno = NET_ERR_BADF;
return -1;
}
sock = &g_net_socks[sockfd];
if (!sock->in_use)
{
s_net_errno = NET_ERR_BADF;
return -1;
}
sock->event_cb = cb;
sock->event_arg = arg;
return 0;
}
/*
* 函数功能:获取 socket 最后错误码
*/
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 (!g_net_socks[i].in_use)
{
return i;
}
}
return -1;
}
/*
* 函数功能:处理连接事件
*/
static void handle_connect_event(net_sock_t *sock)
{
if (sock->state == NET_SOCK_STATE_LISTENING)
{
/* 多连接模式:监听 Socket 收到 CONNECT 中断 = 有新连接被分配到数据 Socket
* Socket 0 自身保持 LISTENING不需要改变状态 */
fire_event(sock, NET_EVENT_CONNECTED);
}
else if (!sock->in_use)
{
/* CH395F 自动打开的数据 Socket多连接模式首次收到 CONNECT 中断 */
int sock_idx = (int)(sock - g_net_socks);
sock->ch395_sock = (uint8_t)sock_idx;
DBG_INFO("sock%d AUTO-OPENED, CONNECTED", sock->ch395_sock);
uint8_t remote[6];
ch395f_get_remot_ipp(sock->ch395_sock, remote);
memcpy(sock->remote_ip_arr, remote, 4);
sock->remote_ip = ((uint32_t)remote[0]) |
((uint32_t)remote[1] << 8) |
((uint32_t)remote[2] << 16) |
((uint32_t)remote[3] << 24);
sock->remote_port = (uint16_t)(remote[4] | (remote[5] << 8));
sock->in_use = 1;
sock->state = NET_SOCK_STATE_ESTABLISHED;
sock->send_ready = 1;
ch395f_set_keepalive_enable(sock->ch395_sock, 1);
fire_event(sock, NET_EVENT_CONNECTED);
}
else if (sock->state == NET_SOCK_STATE_CONNECTING)
{
/* TCP Client 连接成功 */
uint8_t remote[6];
ch395f_get_remot_ipp(sock->ch395_sock, remote);
memcpy(sock->remote_ip_arr, remote, 4);
sock->remote_ip = ((uint32_t)remote[0]) |
((uint32_t)remote[1] << 8) |
((uint32_t)remote[2] << 16) |
((uint32_t)remote[3] << 24);
sock->remote_port = (uint16_t)(remote[4] | (remote[5] << 8));
sock->state = NET_SOCK_STATE_ESTABLISHED;
ch395f_set_keepalive_enable(sock->ch395_sock, 1);
fire_event(sock, NET_EVENT_CONNECTED);
}
else if (sock->state == NET_SOCK_STATE_TCP_ACCEPT)
{
/* 数据 Socket 被分配了连接 */
DBG_INFO("data sock%d TCP_ACCEPT -> CONNECTED", sock->ch395_sock);
uint8_t remote[6];
ch395f_get_remot_ipp(sock->ch395_sock, remote);
memcpy(sock->remote_ip_arr, remote, 4);
sock->remote_ip = ((uint32_t)remote[0]) |
((uint32_t)remote[1] << 8) |
((uint32_t)remote[2] << 16) |
((uint32_t)remote[3] << 24);
sock->remote_port = (uint16_t)(remote[4] | (remote[5] << 8));
sock->state = NET_SOCK_STATE_ESTABLISHED;
ch395f_set_keepalive_enable(sock->ch395_sock, 1);
fire_event(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 *sock)
{
if (sock->state == NET_SOCK_STATE_LISTENING)
{
DBG_ERROR("WARNING: listen sock%d got disconnect", sock->ch395_sock);
}
else if (sock->state == NET_SOCK_STATE_ESTABLISHED)
{
/* CH395F 自动关闭了 Socket恢复为未使用状态 */
DBG_INFO("sock%d DISCONNECTED, back to idle", sock->ch395_sock);
memset(sock->remote_ip_arr, 0, 4);
sock->remote_port = 0;
sock->send_ready = 1;
sock->in_use = 0;
sock->state = NET_SOCK_STATE_CREATED;
fire_event(sock, NET_EVENT_DISCONNECTED);
}
else
{
/* 未预期的断开 */
DBG_ERROR("sock%d disconnect in state %d", sock->ch395_sock, sock->state);
fire_event(sock, NET_EVENT_DISCONNECTED);
}
}
/*
* 函数功能:处理数据接收事件
*/
static void handle_recv_event(net_sock_t *sock)
{
uint16_t recv_len = ch395f_get_recv_len(sock->ch395_sock);
if (recv_len > 0)
{
fire_event(sock, NET_EVENT_DATA_RECEIVED);
}
}
/*
* 函数功能:处理发送完成事件
*/
static void handle_send_event(net_sock_t *sock)
{
fire_event(sock, NET_EVENT_SEND_COMPLETE);
}
/*
* 函数功能:处理超时事件
* 函数说明CH395F 在 TIMEOUT 中断后同样自动关闭 Socket
* 需要重新打开并恢复监听
*/
static void handle_timeout_event(net_sock_t *sock)
{
if (sock->state == NET_SOCK_STATE_CONNECTING)
{
/* TCP Client 连接超时 */
DBG_ERROR("sock%d CONNECT TIMEOUT", sock->ch395_sock);
sock->state = NET_SOCK_STATE_CREATED;
}
else if (sock->state == NET_SOCK_STATE_ESTABLISHED)
{
/* 多连接模式:数据 Socket 超时,恢复为 TCP_ACCEPT 等待新连接 */
DBG_INFO("sock%d TIMEOUT, back to ACCEPT", sock->ch395_sock);
memset(sock->remote_ip_arr, 0, 4);
sock->remote_port = 0;
sock->send_ready = 1;
sock->state = NET_SOCK_STATE_TCP_ACCEPT;
}
else if (sock->state == NET_SOCK_STATE_LISTENING)
{
/* 监听超时(异常情况) */
DBG_ERROR("sock%d LISTEN TIMEOUT", sock->ch395_sock);
}
fire_event(sock, NET_EVENT_TIMEOUT);
}
/*
* 函数功能:触发事件回调
*/
static void fire_event(net_sock_t *sock, net_event_t event)
{
if (sock->event_cb != NULL)
{
sock->event_cb(sock->ch395_sock, event, 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 (!g_net_socks[sockfd].in_use)
{
return NULL;
}
return &g_net_socks[sockfd];
}