Files
STM32F4-Base/Drivers/BSP/NET/net_socket.c
2026-07-19 00:59:56 +08:00

1220 lines
30 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 驱动
* 适用平台STM32F4 系列CH395F 以太网芯片)
* 作者:王建锋
* 创建日期2026-07-18
* 修改记录:
*/
#include "net_socket.h"
#include "ch395f.h"
#include "main.h"
#include <string.h>
#include <stdio.h>
/*
* 私有宏定义区
*/
#define TS_FMT() do { \
uint32_t _t = HAL_GetTick(); \
printf("[%lu.%03lu] ", _t / 1000UL, _t % 1000UL); \
} while(0)
/*
* 私有变量区
*/
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;
}
if (int_status & CH395F_GINT_STAT_PHY_CHANGE)
{
uint8_t phy = ch395f_get_phy_status();
printf("[NET] PHY_CHANGE: 0x%02X\r\n", phy);
if (phy == CH395F_PHY_DISCONN)
{
/* PHY 断开:所有活动 Socket 可能需要恢复 */
printf("[NET] PHY disconnected, sockets may need recovery\r\n");
}
}
/* 处理每个 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;
printf("[NET] 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);
printf(" s%d:sw%d/tcp%d rl%d", i, st[0], st[1], rl);
}
}
printf("\r\n");
}
}
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);
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;
}
/* 配置 CH395F Socket */
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);
/* 多连接模式:为数据 Socket 设置协议类型和源端口(不 OPEN
* CH395F 根据这些信息在客户端连接时自动分配空闲 Socket */
for (int ds = NET_TCP_SERVER_DATA_SOCK_START; ds < NET_MAX_SOCKETS; ds++)
{
ch395f_set_proto_type((uint8_t)ds, CH395F_PROTO_TYPE_TCP);
ch395f_set_sour_port((uint8_t)ds, sock->local_port);
}
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;
addr_in->sin_port = net_htons((uint16_t)(header[4] | (header[5] << 8)));
addr_in->sin_addr.s_addr = ((uint32_t)header[0]) |
((uint32_t)header[1] << 8) |
((uint32_t)header[2] << 16) |
((uint32_t)header[3] << 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;
TS_FMT(); printf("[NET] sock%d AUTO-OPENED, CONNECTED\r\n", 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 被分配了连接 */
TS_FMT(); printf("[NET] data sock%d TCP_ACCEPT -> CONNECTED\r\n", 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)
{
/* 监听 Socket 收到断开通知(不应发生) */
printf("[NET] WARNING: listen sock%d got disconnect\r\n", sock->ch395_sock);
}
else if (sock->state == NET_SOCK_STATE_ESTABLISHED)
{
/* CH395F 自动关闭了 Socket恢复为未使用状态 */
TS_FMT(); printf("[NET] sock%d DISCONNECTED, back to idle\r\n", 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
{
/* 未预期的断开 */
printf("[NET] sock%d disconnect in state %d\r\n", 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 连接超时 */
TS_FMT(); printf("[NET] sock%d CONNECT TIMEOUT\r\n", sock->ch395_sock);
sock->state = NET_SOCK_STATE_CREATED;
}
else if (sock->state == NET_SOCK_STATE_ESTABLISHED)
{
/* 多连接模式:数据 Socket 超时,恢复为 TCP_ACCEPT 等待新连接 */
TS_FMT(); printf("[NET] sock%d TIMEOUT, back to ACCEPT\r\n", 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)
{
/* 监听超时(异常情况) */
printf("[NET] sock%d LISTEN TIMEOUT\r\n", 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];
}