TCP可以正常使用

This commit is contained in:
2026-07-19 00:59:56 +08:00
parent fe107ea9af
commit f72d08328f
24 changed files with 5505 additions and 352 deletions

View File

@@ -7,12 +7,15 @@
* 创建日期2026-03-14
* 修改记录:
* 2026-03-14 王建锋 创建初始版本,按代码规范重构
* 2026-07-18 王建锋 改造 write_send_buf / read_recv_buf 使用 SPI2 DMA 批量传输
*/
/* 头文件包含区 - 先包含本模块头文件,再包含依赖头文件 */
#include "ch395f.h"
#include "spi.h"
#include "usart.h"
#include <string.h>
#include <stdio.h>
/*
* 私有宏定义区
@@ -21,12 +24,24 @@
#define CH395F_RESET_DELAY_MS 20U /* 复位后等待延时ms */
#define CH395F_INIT_TIMEOUT_MS 500U /* 初始化超时时间ms */
#define CH395F_SPI_BEGIN_DELAY_MS 1U /* SPI 事务开始延时ms */
#define CH395F_DMA_BUF_SIZE 1500U /* DMA 缓冲区最大字节数 */
/*
* 私有变量区 - DMA 传输相关
*/
static volatile uint8_t s_spi2_dma_done = 0U; /* DMA 传输完成标志 */
__attribute__((aligned(4)))
static uint8_t s_spi2_dma_tx_buf[CH395F_DMA_BUF_SIZE]; /* DMA 发送缓冲区 */
__attribute__((aligned(4)))
static uint8_t s_spi2_dma_rx_buf[CH395F_DMA_BUF_SIZE]; /* DMA 接收缓冲区 */
/*
* 私有函数声明区
*/
static void ch395f_spi_begin(void);
static void ch395f_spi_end(void);
static void ch395f_spi_dma_transfer(uint16_t len);
/*
* 私有函数实现区
@@ -34,14 +49,14 @@ static void ch395f_spi_end(void);
/*
* 函数功能:开始 SPI 事务CS 拉高 -> 拉低)
* 函数说明:手册要求 SPI 模式下字节间无需间隔
* 函数说明:手册要求 SPI 模式下字节间无需间隔
* CS 拉高再拉低满足最小片选间隔要求
*/
static void ch395f_spi_begin(void)
{
/* CS 先拉高,确保空闲状态 */
HAL_GPIO_WritePin(CH395_SCS_GPIO_Port, CH395_SCS_Pin, GPIO_PIN_SET);
HAL_Delay(CH395F_SPI_BEGIN_DELAY_MS);
/* CS 拉低,启动事务 */
/* CS 拉低启动事务无需额外延时SPI 时序由 SCK 频率决定) */
HAL_GPIO_WritePin(CH395_SCS_GPIO_Port, CH395_SCS_Pin, GPIO_PIN_RESET);
}
@@ -54,6 +69,81 @@ static void ch395f_spi_end(void)
HAL_GPIO_WritePin(CH395_SCS_GPIO_Port, CH395_SCS_Pin, GPIO_PIN_SET);
}
/*
* 函数功能DMA 全双工传输并等待完成
* 入口参数len - 传输字节数 uint16_t
* 函数说明:发送 s_spi2_dma_tx_buf接收到 s_spi2_dma_rx_buf
* 阻塞等待 DMA 完成回调置位标志
*/
static void ch395f_spi_dma_transfer(uint16_t len)
{
HAL_StatusTypeDef status;
uint32_t tickstart;
volatile uint32_t loop_cnt = 0U;
s_spi2_dma_done = 0U;
status = HAL_SPI_TransmitReceive_DMA(&hspi2, s_spi2_dma_tx_buf, s_spi2_dma_rx_buf, len);
if (status != HAL_OK)
{
printf("[DMA] HAL_SPI_TransmitReceive_DMA FAIL: %d, SPI_State=%d, SPI_Error=0x%lX, DMA_State=%d\r\n",
(int)status,
(int)hspi2.State,
hspi2.ErrorCode,
(int)hspi2.hdmarx->State);
return;
}
tickstart = HAL_GetTick();
while (s_spi2_dma_done == 0U)
{
loop_cnt++;
if ((HAL_GetTick() - tickstart) > 1000U)
{
printf("[DMA] TIMEOUT after 1s, len=%d, loop=%lu, SPI_State=%d, SPI_Error=0x%lX\r\n",
(int)len, loop_cnt,
(int)hspi2.State,
hspi2.ErrorCode);
printf("[DMA] DMA_RX: State=%d, Dir=%lu, CNT=%lu\r\n",
(int)hspi2.hdmarx->State,
hspi2.hdmarx->Init.Direction,
__HAL_DMA_GET_COUNTER(hspi2.hdmarx));
printf("[DMA] DMA_TX: State=%d, Dir=%lu, CNT=%lu\r\n",
(int)hspi2.hdmatx->State,
hspi2.hdmatx->Init.Direction,
__HAL_DMA_GET_COUNTER(hspi2.hdmatx));
printf("[DMA] SPI2_CR1=0x%lX, CR2=0x%lX, SR=0x%lX\r\n",
SPI2->CR1, SPI2->CR2, SPI2->SR);
/* 强制复位 SPI2 DMA 状态,避免死锁 */
HAL_SPI_Abort(&hspi2);
return;
}
}
}
/*
* 函数功能SPI 收发完成回调
* 函数说明:由 HAL SPI 驱动在 DMA TX+RX 完成后调用HAL_SPI_TransmitReceive_DMA 触发此回调)
*/
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
if (hspi->Instance == SPI2)
{
s_spi2_dma_done = 1U;
}
}
/*
* 函数功能SPI 错误回调
* 函数说明:由 HAL SPI 驱动在 DMA 传输出错时调用,释放等待
*/
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
if (hspi->Instance == SPI2)
{
s_spi2_dma_done = 1U;
}
}
/*
* 公共函数实现区
*/
@@ -164,6 +254,299 @@ uint8_t ch395f_get_version(void)
return version;
}
/*
* 函数功能:获取远端 IP 和端口
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* p_buf - 6 字节输出缓冲区4字节IP + 2字节端口
* 限定条件TCP Server 模式下连接建立后调用
* 函数说明IP 低字节在前,端口低字节在前
*/
void ch395f_get_remot_ipp(uint8_t sock, uint8_t *p_buf)
{
uint8_t i;
/* 检查输入参数合法性 */
if (p_buf == NULL)
{
return;
}
/* 开始 SPI 事务 */
ch395f_spi_begin();
/* 发送获取远端 IP 和端口命令 */
ch395f_write_cmd(CH395F_CMD_GET_REMOT_IPP_SN);
/* 发送 Socket 索引 */
ch395f_write_data(sock);
/* 读取 4 字节 IP 地址 */
for (i = 0; i < 4; i++)
{
p_buf[i] = ch395f_read_data();
}
/* 读取 2 字节端口号 */
for (i = 4; i < 6; i++)
{
p_buf[i] = ch395f_read_data();
}
/* 结束 SPI 事务 */
ch395f_spi_end();
}
/*
* 函数功能:设置 CH395 功能参数
* 入口参数para - 4 字节功能参数 uint32_t
* 限定条件:必须在 ch395f_init() 之前调用
*/
void ch395f_set_fun_para(uint32_t para)
{
/* 开始 SPI 事务 */
ch395f_spi_begin();
/* 发送设置功能参数命令 */
ch395f_write_cmd(CH395F_CMD_SET_FUN_PARA);
/* 发送 4 字节参数(低字节在前) */
ch395f_write_data((uint8_t)(para));
ch395f_write_data((uint8_t)(para >> 8));
ch395f_write_data((uint8_t)(para >> 16));
ch395f_write_data((uint8_t)(para >> 24));
/* 结束 SPI 事务 */
ch395f_spi_end();
}
/*
* 函数功能:设置 TCP MSS
* 入口参数mss - MSS 值 uint16_t 60~1460
* 限定条件:必须在 ch395f_init() 之前调用
*/
void ch395f_set_tcp_mss(uint16_t mss)
{
/* 开始 SPI 事务 */
ch395f_spi_begin();
/* 发送设置 TCP MSS 命令 */
ch395f_write_cmd(CH395F_CMD_SET_TCP_MSS);
/* 发送 2 字节 MSS 值(低字节在前) */
ch395f_write_data(mss & 0xFFU);
ch395f_write_data((mss >> 8) & 0xFFU);
/* 结束 SPI 事务 */
ch395f_spi_end();
}
/*
* 函数功能:设置 Socket 接收缓冲区
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* start_block - 起始块地址 uint8_t
* block_count - 块个数 uint8_t
* 限定条件:必须在 OPEN_SOCKET_SN 之前调用
*/
void ch395f_set_recv_buf(uint8_t sock, uint8_t start_block, uint8_t block_count)
{
/* 开始 SPI 事务 */
ch395f_spi_begin();
/* 发送设置接收缓冲区命令 */
ch395f_write_cmd(CH395F_CMD_SET_RECV_BUF);
/* 发送 Socket 索引 */
ch395f_write_data(sock);
/* 发送起始块地址 */
ch395f_write_data(start_block);
/* 发送块个数 */
ch395f_write_data(block_count);
/* 结束 SPI 事务 */
ch395f_spi_end();
}
/*
* 函数功能:设置 Socket 发送缓冲区
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* start_block - 起始块地址 uint8_t
* block_count - 块个数 uint8_t
* 限定条件:必须在 OPEN_SOCKET_SN 之前调用
*/
void ch395f_set_send_buf(uint8_t sock, uint8_t start_block, uint8_t block_count)
{
/* 开始 SPI 事务 */
ch395f_spi_begin();
/* 发送设置发送缓冲区命令 */
ch395f_write_cmd(CH395F_CMD_SET_SEND_BUF);
/* 发送 Socket 索引 */
ch395f_write_data(sock);
/* 发送起始块地址 */
ch395f_write_data(start_block);
/* 发送块个数 */
ch395f_write_data(block_count);
/* 结束 SPI 事务 */
ch395f_spi_end();
}
/*
* 函数功能:清空 Socket 接收缓冲区
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* 限定条件Socket 已打开
*/
void ch395f_clear_recv_buf(uint8_t sock)
{
/* 开始 SPI 事务 */
ch395f_spi_begin();
/* 发送清空接收缓冲区命令 */
ch395f_write_cmd(CH395F_CMD_CLEAR_RECV_BUF_SN);
/* 发送 Socket 索引 */
ch395f_write_data(sock);
/* 结束 SPI 事务 */
ch395f_spi_end();
}
/*
* 函数功能:设置 TCP KeepAlive 空闲时间
* 入口参数time - 空闲时间(秒) uint32_t
* 限定条件:必须在 ch395f_init() 之前调用
*/
void ch395f_set_keepalive_idle(uint32_t time)
{
/* 开始 SPI 事务 */
ch395f_spi_begin();
/* 发送设置 KeepAlive 空闲时间命令 */
ch395f_write_cmd(CH395F_CMD_SET_KEEPALIVE_IDLE);
/* 发送 4 字节时间值(低字节在前) */
ch395f_write_data((uint8_t)(time));
ch395f_write_data((uint8_t)(time >> 8));
ch395f_write_data((uint8_t)(time >> 16));
ch395f_write_data((uint8_t)(time >> 24));
/* 结束 SPI 事务 */
ch395f_spi_end();
}
/*
* 函数功能:设置 TCP KeepAlive 探测间隔
* 入口参数time - 间隔时间(秒) uint32_t
* 限定条件:必须在 ch395f_init() 之前调用
*/
void ch395f_set_keepalive_intvl(uint32_t time)
{
/* 开始 SPI 事务 */
ch395f_spi_begin();
/* 发送设置 KeepAlive 探测间隔命令 */
ch395f_write_cmd(CH395F_CMD_SET_KEEPALIVE_INTVL);
/* 发送 4 字节时间值(低字节在前) */
ch395f_write_data((uint8_t)(time));
ch395f_write_data((uint8_t)(time >> 8));
ch395f_write_data((uint8_t)(time >> 16));
ch395f_write_data((uint8_t)(time >> 24));
/* 结束 SPI 事务 */
ch395f_spi_end();
}
/*
* 函数功能:设置 TCP KeepAlive 探测次数
* 入口参数cnt - 探测次数 uint8_t
* 限定条件:必须在 ch395f_init() 之前调用
*/
void ch395f_set_keepalive_cnt(uint8_t cnt)
{
/* 开始 SPI 事务 */
ch395f_spi_begin();
/* 发送设置 KeepAlive 探测次数命令 */
ch395f_write_cmd(CH395F_CMD_SET_KEEPALIVE_CNT);
/* 发送探测次数 */
ch395f_write_data(cnt);
/* 结束 SPI 事务 */
ch395f_spi_end();
}
/*
* 函数功能:启用/禁用指定 Socket 的 KeepAlive
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* enable - 1 启用0 禁用 uint8_t
* 限定条件Socket 已打开
*/
void ch395f_set_keepalive_enable(uint8_t sock, uint8_t enable)
{
/* 开始 SPI 事务 */
ch395f_spi_begin();
/* 发送设置 KeepAlive 使能命令 */
ch395f_write_cmd(CH395F_CMD_SET_KEEPALIVE_SN);
/* 发送 Socket 索引 */
ch395f_write_data(sock);
/* 发送使能标志 */
ch395f_write_data(enable);
/* 结束 SPI 事务 */
ch395f_spi_end();
}
/*
* 函数功能:设置 TCP 重传次数
* 入口参数cnt - 重传次数 uint8_t0=使用默认值5
* 限定条件:必须在 ch395f_init() 之前调用
*/
void ch395f_set_retrans_count(uint8_t cnt)
{
/* 开始 SPI 事务 */
ch395f_spi_begin();
/* 发送设置重传次数命令 */
ch395f_write_cmd(CH395F_CMD_SET_RETRAN_COUNT);
/* 发送重传次数 */
ch395f_write_data(cnt);
/* 结束 SPI 事务 */
ch395f_spi_end();
}
/*
* 函数功能:设置 TCP 重传周期
* 入口参数period - 重传周期(毫秒) uint16_t
* 限定条件:必须在 ch395f_init() 之前调用
*/
void ch395f_set_retrans_period(uint16_t period)
{
/* 开始 SPI 事务 */
ch395f_spi_begin();
/* 发送设置重传周期命令 */
ch395f_write_cmd(CH395F_CMD_SET_RETRAN_PERIOD);
/* 发送 2 字节周期值(低字节在前) */
ch395f_write_data(period & 0xFFU);
ch395f_write_data((period >> 8) & 0xFFU);
/* 结束 SPI 事务 */
ch395f_spi_end();
}
/*
* 函数功能:软件复位 CH395
* 返回值CH395F_STATUS_OK
@@ -211,55 +594,58 @@ uint8_t ch395f_get_cmd_status(void)
return status;
}
/*
* 函数功能:轮询等待命令执行完成
* 入口参数timeout_ms - 超时时间(毫秒) uint32_t
* 返回值命令执行状态码CH395F_ERR_SUCCESS 或 CH395F_CMD_RET_ABORT
* 限定条件:在发送长执行命令后调用
* 函数说明:每 20ms 查询一次,直到命令完成或超时
*/
uint8_t ch395f_poll_cmd_status(uint32_t timeout_ms)
{
uint8_t status;
uint32_t retry_count = 0U;
uint32_t max_retries = (timeout_ms + 20U - 1U) / 20U;
while (1)
{
HAL_Delay(20U);
status = ch395f_get_cmd_status();
if (status != CH395F_ERR_BUSY)
{
return status;
}
if (++retry_count >= max_retries)
{
return CH395F_ERR_BUSY; /* 超时 */
}
}
}
/*
* 函数功能:初始化 CH395包含 MAC、PHY、TCP/IP 协议栈)
* 返回值CH395F_STATUS_OK - 成功CH395F_STATUS_TIMEOUT - 超时失败
* 限定条件:芯片已通过 ch395f_reset() 复位
* 函数说明:阻塞等待初始化完成或超时(典型 5msTE1
* 函数说明:阻塞等待初始化完成或超时(芯片需要约 200ms这里等最多 4s
*/
ch395f_status_t ch395f_init(void)
{
uint8_t status;
uint32_t retry_count = 0U;
/* 开始 SPI 事务 */
ch395f_spi_begin();
/* 发送初始化命令 */
ch395f_write_cmd(CH395F_CMD_INIT_CH395);
/* 结束 SPI 事务 */
ch395f_spi_end();
/* 轮询等待初始化完成 */
while (1)
{
/* 每次轮询延时 1ms */
HAL_Delay(1U);
status = ch395f_poll_cmd_status(4000U);
/* 查询命令执行状态 */
status = ch395f_get_cmd_status();
/* 状态非 BUSY 表示执行完毕 */
if (status != CH395F_ERR_BUSY)
{
break;
}
/* 超时判断 */
if (++retry_count > CH395F_INIT_TIMEOUT_MS)
{
return CH395F_STATUS_TIMEOUT;
}
}
/* 返回最终执行结果 */
if (status == CH395F_ERR_SUCCESS)
{
return CH395F_STATUS_OK;
}
return CH395F_STATUS_ERROR;
return (status == CH395F_ERR_BUSY) ? CH395F_STATUS_TIMEOUT : CH395F_STATUS_ERROR;
}
/*
@@ -673,114 +1059,95 @@ void ch395f_set_sour_port(uint8_t sock, uint16_t port)
/*
* 函数功能:打开 Socket
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* 返回值命令执行状态码CH395F_ERR_SUCCESS 表示成功) uint8_t
* 限定条件:协议类型、目标 IP、端口已设置
*/
void ch395f_open_socket(uint8_t sock)
uint8_t ch395f_open_socket(uint8_t sock)
{
/* 开始 SPI 事务 */
ch395f_spi_begin();
/* 发送打开 Socket 命令 */
ch395f_write_cmd(CH395F_CMD_OPEN_SOCKET_SN);
/* 发送 Socket 索引 */
ch395f_write_data(sock);
/* 结束 SPI 事务 */
ch395f_spi_end();
return ch395f_poll_cmd_status(4000U);
}
/*
* 函数功能:关闭 Socket
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* 返回值命令执行状态码CH395F_ERR_SUCCESS 表示成功) uint8_t
* 限定条件Socket 已打开
*/
void ch395f_close_socket(uint8_t sock)
uint8_t ch395f_close_socket(uint8_t sock)
{
/* 开始 SPI 事务 */
ch395f_spi_begin();
/* 发送关闭 Socket 命令 */
ch395f_write_cmd(CH395F_CMD_CLOSE_SOCKET_SN);
/* 发送 Socket 索引 */
ch395f_write_data(sock);
/* 结束 SPI 事务 */
ch395f_spi_end();
return ch395f_poll_cmd_status(4000U);
}
/*
* 函数功能:启动 TCP 监听模式
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* 返回值命令执行状态码CH395F_ERR_SUCCESS 表示成功) uint8_t
* 限定条件Socket 已打开且协议类型为 TCP
*/
void ch395f_tcp_listen(uint8_t sock)
uint8_t ch395f_tcp_listen(uint8_t sock)
{
/* 开始 SPI 事务 */
ch395f_spi_begin();
/* 发送 TCP 监听命令 */
ch395f_write_cmd(CH395F_CMD_TCP_LISTEN_SN);
/* 发送 Socket 索引 */
ch395f_write_data(sock);
/* 结束 SPI 事务 */
ch395f_spi_end();
return ch395f_poll_cmd_status(4000U);
}
/*
* 函数功能:启动 TCP 连接
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* 返回值命令执行状态码CH395F_ERR_SUCCESS 表示成功) uint8_t
* 限定条件Socket 已打开且协议类型为 TCP
*/
void ch395f_tcp_connect(uint8_t sock)
uint8_t ch395f_tcp_connect(uint8_t sock)
{
/* 开始 SPI 事务 */
ch395f_spi_begin();
/* 发送 TCP 连接命令 */
ch395f_write_cmd(CH395F_CMD_TCP_CONNECT_SN);
/* 发送 Socket 索引 */
ch395f_write_data(sock);
/* 结束 SPI 事务 */
ch395f_spi_end();
return ch395f_poll_cmd_status(4000U);
}
/*
* 函数功能:断开 TCP 连接
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* 返回值命令执行状态码CH395F_ERR_SUCCESS 表示成功) uint8_t
* 限定条件TCP 已建立连接
*/
void ch395f_tcp_disconnect(uint8_t sock)
uint8_t ch395f_tcp_disconnect(uint8_t sock)
{
/* 开始 SPI 事务 */
ch395f_spi_begin();
/* 发送 TCP 断开命令 */
ch395f_write_cmd(CH395F_CMD_TCP_DISCONNECT_SN);
/* 发送 Socket 索引 */
ch395f_write_data(sock);
/* 结束 SPI 事务 */
ch395f_spi_end();
return ch395f_poll_cmd_status(4000U);
}
/*
* 函数功能:向 Socket 发送缓冲区写入数据
* 函数功能:向 Socket 发送缓冲区写入数据DMA 批量传输)
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* p_data - 数据指针 uint8_t*
* len - 数据长度 uint16_t
* 限定条件:指针非空,长度大于 0TCP 已连接或 UDP 已打开
* 函数说明:将命令头和数据打包到 DMA 缓冲区,一次 SPI DMA 传输完成
*/
void ch395f_write_send_buf(uint8_t sock, uint8_t *p_data, uint16_t len)
{
uint16_t i;
uint16_t total;
/* 检查输入参数合法性 */
if (p_data == NULL)
@@ -788,41 +1155,40 @@ void ch395f_write_send_buf(uint8_t sock, uint8_t *p_data, uint16_t len)
return;
}
/* 开始 SPI 事务 */
ch395f_spi_begin();
/* 发送写入发送缓冲区命令 */
ch395f_write_cmd(CH395F_CMD_WRITE_SEND_BUF_SN);
/* 发送 Socket 索引 */
ch395f_write_data(sock);
/* 发送数据长度低字节 */
ch395f_write_data(len & 0xFFU);
/* 发送数据长度高字节 */
ch395f_write_data((len >> 8) & 0xFFU);
/* 逐字节发送数据 */
for (i = 0; i < len; i++)
/* 计算总长度1(cmd) + 1(sock) + 2(len) + data */
total = 4U + len;
if (total > CH395F_DMA_BUF_SIZE)
{
ch395f_write_data(p_data[i]);
return;
}
/* 结束 SPI 事务 */
/* 打包命令头到 DMA 发送缓冲区 */
s_spi2_dma_tx_buf[0] = CH395F_CMD_WRITE_SEND_BUF_SN;
s_spi2_dma_tx_buf[1] = sock;
s_spi2_dma_tx_buf[2] = len & 0xFFU;
s_spi2_dma_tx_buf[3] = (len >> 8) & 0xFFU;
/* 拷贝用户数据到 DMA 发送缓冲区 */
memcpy(&s_spi2_dma_tx_buf[4], p_data, len);
/* CS 拉低 -> DMA 批量传输 -> CS 拉高 */
ch395f_spi_begin();
ch395f_spi_dma_transfer(total);
ch395f_spi_end();
}
/*
* 函数功能:从 Socket 接收缓冲区读取数据
* 函数功能:从 Socket 接收缓冲区读取数据DMA 批量传输)
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* p_data - 输出缓冲区指针 uint8_t*
* len - 待读取数据长度 uint16_t
* 限定条件:指针非空,长度大于 0接收缓冲区有数据
* 函数说明:命令头打包到发送缓冲区(数据部分填 0xFF 作时钟),
* 一次 SPI DMA 全双工传输,有效数据从接收缓冲区偏移 4 字节处拷出
*/
void ch395f_read_recv_buf(uint8_t sock, uint8_t *p_data, uint16_t len)
{
uint16_t i;
uint16_t total;
/* 检查输入参数合法性 */
if (p_data == NULL)
@@ -830,29 +1196,29 @@ void ch395f_read_recv_buf(uint8_t sock, uint8_t *p_data, uint16_t len)
return;
}
/* 开始 SPI 事务 */
ch395f_spi_begin();
/* 发送读取接收缓冲区命令 */
ch395f_write_cmd(CH395F_CMD_READ_RECV_BUF_SN);
/* 发送 Socket 索引 */
ch395f_write_data(sock);
/* 发送读取长度低字节 */
ch395f_write_data(len & 0xFFU);
/* 发送读取长度高字节 */
ch395f_write_data((len >> 8) & 0xFFU);
/* 逐字节读取数据 */
for (i = 0; i < len; i++)
/* 计算总长度1(cmd) + 1(sock) + 2(len) + data */
total = 4U + len;
if (total > CH395F_DMA_BUF_SIZE)
{
p_data[i] = ch395f_read_data();
return;
}
/* 结束 SPI 事务 */
/* 命令头打包到 DMA 发送缓冲区 */
s_spi2_dma_tx_buf[0] = CH395F_CMD_READ_RECV_BUF_SN;
s_spi2_dma_tx_buf[1] = sock;
s_spi2_dma_tx_buf[2] = len & 0xFFU;
s_spi2_dma_tx_buf[3] = (len >> 8) & 0xFFU;
/* 数据部分填充 0xFFSPI 时钟驱动用) */
memset(&s_spi2_dma_tx_buf[4], 0xFFU, len);
/* CS 拉低 -> DMA 全双工传输(发命令头 + 收数据) -> CS 拉高 */
ch395f_spi_begin();
ch395f_spi_dma_transfer(total);
ch395f_spi_end();
/* 从 DMA 接收缓冲区偏移 4 字节处拷贝有效数据到用户缓冲区 */
memcpy(p_data, &s_spi2_dma_rx_buf[4], len);
}
/*
@@ -910,6 +1276,24 @@ uint8_t ch395f_get_glob_int_status(void)
return status;
}
/*
* 函数功能获取全局中断状态2 字节版,支持 Socket 0~7
* 返回值:中断状态 uint16_t低字节=Socket 0~3 + PHY/DHCP高字节=Socket 4~7 + DHCPv6
* 限定条件:芯片已初始化
*/
uint16_t ch395f_get_glob_int_status_all(void)
{
uint16_t status;
ch395f_spi_begin();
ch395f_write_cmd(CH395F_CMD_GET_GLOB_INT_STATUS_ALL);
status = (uint16_t)ch395f_read_data();
status |= ((uint16_t)ch395f_read_data() << 8U);
ch395f_spi_end();
return status;
}
/*
* 函数功能:获取 Socket 中断状态
* 入口参数sock - Socket 索引 uint8_t 0 - 3
@@ -937,3 +1321,68 @@ uint8_t ch395f_get_sock_int_status(uint8_t sock)
return status;
}
/*
* 函数功能:获取 Socket 状态2 字节输出)
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* status - 2 字节输出缓冲区 [0]=Socket状态, [1]=TCP状态
* 限定条件:芯片已初始化
*/
void ch395f_get_socket_status(uint8_t sock, uint8_t *status)
{
ch395f_spi_begin();
ch395f_write_cmd(CH395F_CMD_GET_SOCKET_STATUS_SN);
ch395f_write_data(sock);
status[0] = ch395f_read_data();
status[1] = ch395f_read_data();
ch395f_spi_end();
}
/*
* 函数功能:设置 ARP 重传参数
* 入口参数period_100ms - ARP 重传周期(单位 100ms0=默认值=10即1秒 uint8_t
* cnt - ARP 重传次数0=默认值=3 uint8_t
* 限定条件:应在 ch395f_init() 之后调用
* 函数说明:周期最大值约 25.5 秒255 表示无限重传
*/
void ch395f_set_arp(uint8_t period_100ms, uint8_t cnt)
{
ch395f_spi_begin();
ch395f_write_cmd(CH395F_CMD_SET_ARP);
ch395f_write_data(period_100ms);
ch395f_write_data(cnt);
ch395f_spi_end();
}
/*
* 函数功能:设置 Socket TTL
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* ttl - TTL 值 uint8_t 最大 128
* 限定条件Socket 已打开TCP Server 模式下不生效
*/
void ch395f_set_ttl(uint8_t sock, uint8_t ttl)
{
ch395f_spi_begin();
ch395f_write_cmd(CH395F_CMD_SET_TTL);
ch395f_write_data(sock);
ch395f_write_data(ttl);
ch395f_spi_end();
}
/*
* 函数功能:获取不可达信息(用于调试连接失败原因)
* 出口参数p_buf - 8 字节输出缓冲区(类型+协议码+端口+IP
* 限定条件:收到 GINT_STAT_UNREACH 中断后调用
*/
void ch395f_get_unreach_info(uint8_t *p_buf)
{
uint8_t i;
ch395f_spi_begin();
ch395f_write_cmd(CH395F_CMD_GET_UNREACH_IPPT);
for (i = 0; i < 8; i++)
{
p_buf[i] = ch395f_read_data();
}
ch395f_spi_end();
}

View File

@@ -35,6 +35,7 @@ extern "C" {
#define CH395F_CMD_GET_CMD_STATUS 0x2CU
#define CH395F_CMD_GET_GLOB_INT_STATUS 0x29U
#define CH395F_CMD_GET_GLOB_INT_STATUS_ALL 0x19U
#define CH395F_CMD_GET_UNREACH_IPPT 0x28U
#define CH395F_CMD_GET_PHY_STATUS 0x26U
#define CH395F_CMD_GET_DHCP_STATUS 0x42U
@@ -124,19 +125,26 @@ extern "C" {
#define CH395F_CMD_WRITE_GPIO_REG 0xEDU
/*
* CH395 错误码(来自手册 CH395INC.H 引用
* CH395 命令执行状态码CMD_GET_CMD_STATUS 返回值,与芯片手册一致
*/
#define CH395F_ERR_SUCCESS 0x00U
#define CH395F_ERR_BUSY 0x01U
#define CH395F_ERR_CMD 0x02U
#define CH395F_ERR_MAC 0x03U
#define CH395F_ERR_PHY 0x04U
#define CH395F_ERR_IP_CONFLI 0x05U
#define CH395F_ERR_SOCK 0x06U
#define CH395F_ERR_SOCK_BUSY 0x07U
#define CH395F_ERR_SOCK_CLOSED 0x08U
#define CH395F_ERR_SOCK_ERR 0x09U
#define CH395F_ERR_UNKNOW 0xFFU
#define CH395F_ERR_SUCCESS 0x00U /* 成功 */
#define CH395F_ERR_BUSY 0x10U /* 忙,命令正在执行 */
#define CH395F_ERR_MEM 0x11U /* 内存管理错误 */
#define CH395F_ERR_BUF 0x12U /* 缓冲区错误 */
#define CH395F_ERR_TIMEOUT 0x13U /* 超时 */
#define CH395F_ERR_RTE 0x14U /* 路由错误 */
#define CH395F_ERR_ABRT 0x15U /* 连接中止 */
#define CH395F_ERR_RST 0x16U /* 连接复位 */
#define CH395F_ERR_CLSD 0x17U /* 连接关闭 */
#define CH395F_ERR_CONN 0x18U /* 无连接 */
#define CH395F_ERR_VAL 0x19U /* 值错误 */
#define CH395F_ERR_ARG 0x1AH /* 参数错误 */
#define CH395F_ERR_USE 0x1BH /* 已被使用 */
#define CH395F_ERR_IF 0x1CH /* MAC 错误 */
#define CH395F_ERR_ISCONN 0x1DH /* 已连接 */
#define CH395F_ERR_OPEN 0x20U /* 已打开 */
#define CH395F_CMD_RET_ABORT 0x5FU /* 命令中止(来自官方库) */
#define CH395F_ERR_UNKNOW 0xFAU /* 未知错误」 */
/*
* PHY 状态码
@@ -148,6 +156,13 @@ extern "C" {
#define CH395F_PHY_100M_HALF 0x10U /* 100M 半双工 */
#define CH395F_PHY_AUTO_NEGOTIATE 0x20U /* 自动协商 */
/*
* 功能参数标志位CMD_SET_FUN_PARA
*/
#define CH395F_FUN_PARA_TCP_SERVER (1UL << 1) /* TCP Server 多连接模式 */
#define CH395F_FUN_PARA_SOCKET_CLOSE (1UL << 3) /* Socket 关闭控制0=芯片自动1=外部控制) */
#define CH395F_FUN_PARA_DISABLE_SEND_OK (1UL << 4) /* 禁用 SEND_OK 中断 */
/*
* 协议类型
*/
@@ -178,7 +193,7 @@ extern "C" {
#define CH395F_TCP_TIME_WAIT 0x0AU
/*
* 全局中断状态位
* 全局中断状态位CMD_GET_GLOB_INT_STATUS 1字节版仅Socket 0~3
*/
#define CH395F_GINT_STAT_UNREACH 0x01U
#define CH395F_GINT_STAT_IP_CONFLI 0x02U
@@ -190,15 +205,25 @@ extern "C" {
#define CH395F_GINT_STAT_SOCK3 0x80U
/*
* Socket 中断状态位
* 全局中断状态位CMD_GET_GLOB_INT_STATUS_ALL 2字节版支持Socket 0~7
* 低字节高字节分别定义
*/
#define CH395F_SINT_STAT_CONNECT 0x01U
#define CH395F_SINT_STAT_DISCONNECT 0x02U
#define CH395F_SINT_STAT_SEND_OK 0x04U
#define CH395F_SINT_STAT_SENBUF_FREE 0x08U
#define CH395F_SINT_STAT_RECV_OK 0x10U
#define CH395F_SINT_STAT_DISCARD 0x20U
#define CH395F_SINT_STAT_SOCK_TIMEOUT 0x40U
#define CH395F_GINT_STAT_SOCK4 0x0100U
#define CH395F_GINT_STAT_SOCK5 0x0200U
#define CH395F_GINT_STAT_SOCK6 0x0400U
#define CH395F_GINT_STAT_SOCK7 0x0800U
#define CH395F_GINT_STAT_DHCPV6 0x8000U
/*
* Socket 中断状态位CMD_GET_INT_STATUS_SN 返回值来自手册表5-x
*/
#define CH395F_SINT_STAT_SENBUF_FREE 0x01U /* bit0: 发送缓冲区空闲 */
#define CH395F_SINT_STAT_SEND_OK 0x02U /* bit1: 发送成功 */
#define CH395F_SINT_STAT_RECV_OK 0x04U /* bit2: 接收缓冲区非空 */
#define CH395F_SINT_STAT_CONNECT 0x08U /* bit3: TCP 连接成功 */
#define CH395F_SINT_STAT_DISCONNECT 0x10U /* bit4: TCP 连接断开 */
#define CH395F_SINT_STAT_DISCARD 0x20U /* bit5: 保留 */
#define CH395F_SINT_STAT_SOCK_TIMEOUT 0x40U /* bit6: 超时 */
/*
* 类型定义区 - 驱动返回码
@@ -277,6 +302,15 @@ ch395f_status_t ch395f_reset(void);
*/
uint8_t ch395f_get_cmd_status(void);
/*
* 函数功能:轮询等待命令执行完成
* 入口参数timeout_ms - 超时时间(毫秒) uint32_t
* 返回值命令执行状态码CH395F_ERR_SUCCESS 或 CH395F_CMD_RET_ABORT
* 限定条件在发送长执行命令OPEN/TCP_LISTEN/CONNECT/DISCONNECT/CLOSE/DHCP后调用
* 函数说明:每 20ms 查询一次,直到命令完成或超时
*/
uint8_t ch395f_poll_cmd_status(uint32_t timeout_ms);
/*
* 函数功能:初始化 CH395包含 MAC、PHY、TCP/IP 协议栈)
* 返回值CH395F_STATUS_OK - 成功CH395F_STATUS_TIMEOUT - 超时失败
@@ -382,7 +416,7 @@ uint8_t ch395f_get_dhcp_status(void);
/*
* 函数功能:设置 Socket 协议类型
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* proto - 协议类型 uint8_t CH395F_PROTO_TYPE_xxx
* 限定条件Socket 未打开
*/
@@ -390,7 +424,7 @@ void ch395f_set_proto_type(uint8_t sock, uint8_t proto);
/*
* 函数功能:设置 Socket 目标 IP 地址
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* p_ip - 4 字节目标 IP 指针 uint8_t*
* 限定条件:指针非空
*/
@@ -398,7 +432,7 @@ void ch395f_set_des_ip(uint8_t sock, uint8_t *p_ip);
/*
* 函数功能:设置 Socket 目标端口(小端序)
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* port - 目标端口 uint16_t
* 限定条件:无
*/
@@ -406,7 +440,7 @@ void ch395f_set_des_port(uint8_t sock, uint16_t port);
/*
* 函数功能:设置 Socket 源端口(小端序)
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* port - 源端口 uint16_t
* 限定条件:无
*/
@@ -414,38 +448,43 @@ void ch395f_set_sour_port(uint8_t sock, uint16_t port);
/*
* 函数功能:打开 Socket
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* 返回值命令执行状态码CH395F_ERR_SUCCESS 表示成功) uint8_t
* 限定条件:协议类型、目标 IP、端口已设置
*/
void ch395f_open_socket(uint8_t sock);
uint8_t ch395f_open_socket(uint8_t sock);
/*
* 函数功能:关闭 Socket
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* 返回值命令执行状态码CH395F_ERR_SUCCESS 表示成功) uint8_t
* 限定条件Socket 已打开
*/
void ch395f_close_socket(uint8_t sock);
uint8_t ch395f_close_socket(uint8_t sock);
/*
* 函数功能:启动 TCP 监听模式
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* 返回值命令执行状态码CH395F_ERR_SUCCESS 表示成功) uint8_t
* 限定条件Socket 已打开且协议类型为 TCP
*/
void ch395f_tcp_listen(uint8_t sock);
uint8_t ch395f_tcp_listen(uint8_t sock);
/*
* 函数功能:启动 TCP 连接
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* 返回值命令执行状态码CH395F_ERR_SUCCESS 表示成功) uint8_t
* 限定条件Socket 已打开且协议类型为 TCP
*/
void ch395f_tcp_connect(uint8_t sock);
uint8_t ch395f_tcp_connect(uint8_t sock);
/*
* 函数功能:断开 TCP 连接
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* 返回值命令执行状态码CH395F_ERR_SUCCESS 表示成功) uint8_t
* 限定条件TCP 已建立连接
*/
void ch395f_tcp_disconnect(uint8_t sock);
uint8_t ch395f_tcp_disconnect(uint8_t sock);
/*
* 函数声明区 - Socket 数据传输
@@ -453,7 +492,7 @@ void ch395f_tcp_disconnect(uint8_t sock);
/*
* 函数功能:向 Socket 发送缓冲区写入数据
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* p_data - 数据指针 uint8_t*
* len - 数据长度 uint16_t
* 限定条件:指针非空,长度大于 0TCP 已连接或 UDP 已打开
@@ -462,7 +501,7 @@ void ch395f_write_send_buf(uint8_t sock, uint8_t *p_data, uint16_t len);
/*
* 函数功能:从 Socket 接收缓冲区读取数据
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* p_data - 输出缓冲区指针 uint8_t*
* len - 待读取数据长度 uint16_t
* 限定条件:指针非空,长度大于 0接收缓冲区有数据
@@ -471,7 +510,7 @@ void ch395f_read_recv_buf(uint8_t sock, uint8_t *p_data, uint16_t len);
/*
* 函数功能:获取 Socket 接收缓冲区数据长度
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* 返回值:接收数据长度 uint16_t
* 限定条件Socket 已打开
*/
@@ -488,14 +527,174 @@ uint16_t ch395f_get_recv_len(uint8_t sock);
*/
uint8_t ch395f_get_glob_int_status(void);
/*
* 函数功能获取全局中断状态2 字节版,支持 Socket 0~7
* 返回值:中断状态 uint16_t低字节=Socket 0~3 + PHY/DHCP高字节=Socket 4~7 + DHCPv6
* 限定条件:芯片已初始化
*/
uint16_t ch395f_get_glob_int_status_all(void);
/*
* 函数功能:获取 Socket 中断状态
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* 返回值Socket 中断状态字节 uint8_t
* 限定条件:芯片已初始化
*/
uint8_t ch395f_get_sock_int_status(uint8_t sock);
/*
* 函数功能:获取 Socket 状态2 字节输出)
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* status - 2 字节输出缓冲区 [0]=Socket状态, [1]=TCP状态
* 限定条件:芯片已初始化
* 函数说明Socket 状态: 00H=CLOSED, 05H=OPEN
* TCP 状态: 00H=CLOSED, 01H=LISTEN, 02H=SYN_SENT, 03H=SYN_RCVD, 04H=ESTABLISHED
*/
void ch395f_get_socket_status(uint8_t sock, uint8_t *status);
/*
* 函数声明区 - Socket 远端信息
*/
/*
* 函数功能:获取远端 IP 和端口
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* p_buf - 6 字节输出缓冲区4字节IP + 2字节端口
* 限定条件TCP Server 模式下连接建立后调用
* 函数说明IP 低字节在前,端口低字节在前
*/
void ch395f_get_remot_ipp(uint8_t sock, uint8_t *p_buf);
/*
* 函数声明区 - 功能参数设置
*/
/*
* 函数功能:设置 CH395 功能参数
* 入口参数para - 4 字节功能参数 uint32_t
* bit0: 未使用,必须为 0
* bit1: TCP Server 多连接模式使能
* bit2: 低功耗模式
* bit3: Socket 关闭控制0=芯片自动关闭1=外部关闭)
* bit4: 禁用 SEND_OK 中断
* 限定条件:必须在 ch395f_init() 之前调用
*/
void ch395f_set_fun_para(uint32_t para);
/*
* 函数声明区 - TCP MSS 设置
*/
/*
* 函数功能:设置 TCP MSS
* 入口参数mss - MSS 值 uint16_t 60~1460
* 限定条件:必须在 ch395f_init() 之前调用
*/
void ch395f_set_tcp_mss(uint16_t mss);
/*
* 函数声明区 - Socket 缓冲区设置
*/
/*
* 函数功能:设置 Socket 接收缓冲区
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* start_block - 起始块地址 uint8_t
* block_count - 块个数 uint8_t
* 限定条件:必须在 OPEN_SOCKET_SN 之前调用
*/
void ch395f_set_recv_buf(uint8_t sock, uint8_t start_block, uint8_t block_count);
/*
* 函数功能:设置 Socket 发送缓冲区
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* start_block - 起始块地址 uint8_t
* block_count - 块个数 uint8_t
* 限定条件:必须在 OPEN_SOCKET_SN 之前调用
*/
void ch395f_set_send_buf(uint8_t sock, uint8_t start_block, uint8_t block_count);
/*
* 函数功能:清空 Socket 接收缓冲区
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* 限定条件Socket 已打开
*/
void ch395f_clear_recv_buf(uint8_t sock);
/*
* 函数功能:设置 TCP KeepAlive 空闲时间
* 入口参数time - 空闲时间(毫秒,必须为 500 的倍数) uint32_t
* 限定条件:必须在 ch395f_init() 之前调用
*/
void ch395f_set_keepalive_idle(uint32_t time);
/*
* 函数功能:设置 TCP KeepAlive 探测间隔
* 入口参数time - 间隔时间(毫秒,必须为 500 的倍数) uint32_t
* 限定条件:必须在 ch395f_init() 之前调用
*/
void ch395f_set_keepalive_intvl(uint32_t time);
/*
* 函数功能:设置 TCP KeepAlive 探测次数
* 入口参数cnt - 探测次数 uint8_t
* 限定条件:必须在 ch395f_init() 之前调用
*/
void ch395f_set_keepalive_cnt(uint8_t cnt);
/*
* 函数功能:启用/禁用指定 Socket 的 KeepAlive
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* enable - 1 启用0 禁用 uint8_t
* 限定条件Socket 已打开
*/
void ch395f_set_keepalive_enable(uint8_t sock, uint8_t enable);
/*
* 函数声明区 - TCP 重传参数设置
*/
/*
* 函数功能:设置 TCP 重传次数
* 入口参数cnt - 重传次数 uint8_t0=使用默认值5
* 限定条件:必须在 ch395f_init() 之前调用
*/
void ch395f_set_retrans_count(uint8_t cnt);
/*
* 函数功能:设置 TCP 重传周期
* 入口参数period - 重传周期(毫秒) uint16_t
* 限定条件:必须在 ch395f_init() 之前调用
*/
void ch395f_set_retrans_period(uint16_t period);
/*
* 函数声明区 - ARP / TTL / 不可达信息
*/
/*
* 函数功能:设置 ARP 重传参数
* 入口参数period_100ms - ARP 重传周期(单位 100ms0=默认值=10即1秒 uint8_t
* cnt - ARP 重传次数0=默认值=3255=无限重传) uint8_t
* 限定条件:应在 ch395f_init() 之后调用
*/
void ch395f_set_arp(uint8_t period_100ms, uint8_t cnt);
/*
* 函数功能:设置 Socket TTL
* 入口参数sock - Socket 索引 uint8_t 0 - 7
* ttl - TTL 值 uint8_t 最大 128
* 限定条件Socket 已打开TCP Server 模式下不生效
*/
void ch395f_set_ttl(uint8_t sock, uint8_t ttl);
/*
* 函数功能:获取不可达信息(用于调试连接失败原因)
* 出口参数p_buf - 8 字节输出缓冲区(类型+协议码+端口+IP
* 限定条件:收到 GINT_STAT_UNREACH 中断后调用
*/
void ch395f_get_unreach_info(uint8_t *p_buf);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,105 @@
/*
* 模块名称Network Configuration
* 模块功能网络子系统配置宏定义包括最大Socket数量、缓冲区大小、
* 超时时间等参数配置
* 适用平台STM32F4 系列CH395F 以太网芯片)
* 作者:王建锋
* 创建日期2026-07-18
* 修改记录:
*/
#ifndef __NET_CONFIG_H
#define __NET_CONFIG_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* 最大支持的 Socket 数量CH395F 支持 0~7
*/
#ifndef NET_MAX_SOCKETS
#define NET_MAX_SOCKETS 8
#endif
/*
* TCP Server 多连接模式配置
* 监听 Socket 索引和数据 Socket 起始索引
*/
#ifndef NET_TCP_SERVER_LISTEN_SOCK
#define NET_TCP_SERVER_LISTEN_SOCK 0 /* 监听 Socket 索引 */
#endif
#ifndef NET_TCP_SERVER_DATA_SOCK_START
#define NET_TCP_SERVER_DATA_SOCK_START 1 /* 数据 Socket 起始索引 */
#endif
#ifndef NET_TCP_SERVER_MAX_CLIENTS
#define NET_TCP_SERVER_MAX_CLIENTS 7 /* 最大客户端数1~7 */
#endif
/*
* 缓冲区大小配置
*/
#ifndef NET_SEND_BUF_SIZE
#define NET_SEND_BUF_SIZE 4096 /* 发送缓冲区大小(字节) */
#endif
#ifndef NET_RECV_BUF_SIZE
#define NET_RECV_BUF_SIZE 4096 /* 接收缓冲区大小(字节) */
#endif
/*
* 超时时间配置(毫秒)
* 0 = 无限等待(阻塞模式)
*/
#ifndef NET_CONNECT_TIMEOUT_MS
#define NET_CONNECT_TIMEOUT_MS 5000 /* 连接超时 */
#endif
#ifndef NET_ACCEPT_TIMEOUT_MS
#define NET_ACCEPT_TIMEOUT_MS 0 /* 接受连接超时0=无限等待) */
#endif
#ifndef NET_SEND_TIMEOUT_MS
#define NET_SEND_TIMEOUT_MS 1000 /* 发送超时 */
#endif
#ifndef NET_RECV_TIMEOUT_MS
#define NET_RECV_TIMEOUT_MS 0 /* 接收超时0=无限等待) */
#endif
/*
* TCP KeepAlive 配置
*/
#ifndef NET_KEEPALIVE_IDLE_MS
#define NET_KEEPALIVE_IDLE_MS 7200000 /* KeepAlive 空闲时间默认2小时 */
#endif
#ifndef NET_KEEPALIVE_INTVL_MS
#define NET_KEEPALIVE_INTVL_MS 75000 /* KeepAlive 探测间隔默认75秒 */
#endif
#ifndef NET_KEEPALIVE_CNT
#define NET_KEEPALIVE_CNT 9 /* KeepAlive 探测次数默认9次 */
#endif
/*
* select/poll 最大 fd 数量
*/
#ifndef NET_SELECT_MAX_FDS
#define NET_SELECT_MAX_FDS NET_MAX_SOCKETS
#endif
/*
* 轮询延时配置(毫秒)
*/
#ifndef NET_POLL_DELAY_MS
#define NET_POLL_DELAY_MS 1 /* 非阻塞轮询延时 */
#endif
#ifdef __cplusplus
}
#endif
#endif /* __NET_CONFIG_H */

View File

@@ -0,0 +1,319 @@
/*
* 模块名称Network Select Implementation
* 模块功能I/O 多路复用实现,包括 select 和 poll 模式,
* 用于同时监控多个 Socket 的读写事件
* 适用平台STM32F4 系列CH395F 以太网芯片)
* 作者:王建锋
* 创建日期2026-07-18
* 修改记录:
*/
#include "net_select.h"
#include "net_socket.h"
#include "ch395f.h"
/*
* 私有函数声明区
*/
static int check_socket_readable(int sockfd);
static int check_socket_writable(int sockfd);
static int check_socket_error(int sockfd);
/*
* 公共函数实现区
*/
/*
* 函数功能I/O 多路复用select 模式)
*/
int net_select(int nfds, net_fd_set *readfds, net_fd_set *writefds,
net_fd_set *exceptfds, net_timeval *timeout)
{
uint32_t start_tick;
uint32_t timeout_ms = 0;
net_fd_set result_read = {0};
net_fd_set result_write = {0};
net_fd_set result_except = {0};
int ready_count = 0;
int i;
/* 计算超时时间 */
if (timeout != NULL)
{
timeout_ms = (uint32_t)(timeout->tv_sec * 1000) +
(uint32_t)(timeout->tv_usec / 1000);
}
start_tick = HAL_GetTick();
while (1)
{
/* 轮询所有 Socket */
net_poll();
ready_count = 0;
/* 检查哪些 Socket 有事件 */
for (i = 0; i < nfds && i < NET_MAX_SOCKETS; i++)
{
net_sock_t *sock = net_get_sock(i);
if (sock == NULL)
{
continue;
}
/* 检查可读事件 */
if (readfds != NULL && NET_FD_ISSET(i, readfds))
{
if (check_socket_readable(i))
{
NET_FD_SET(i, &result_read);
ready_count++;
}
}
/* 检查可写事件 */
if (writefds != NULL && NET_FD_ISSET(i, writefds))
{
if (check_socket_writable(i))
{
NET_FD_SET(i, &result_write);
ready_count++;
}
}
/* 检查异常事件 */
if (exceptfds != NULL && NET_FD_ISSET(i, exceptfds))
{
if (check_socket_error(i))
{
NET_FD_SET(i, &result_except);
ready_count++;
}
}
}
/* 有事件就绪,返回 */
if (ready_count > 0)
{
break;
}
/* 超时检查 */
if (timeout != NULL)
{
if (timeout_ms > 0 &&
(HAL_GetTick() - start_tick) >= timeout_ms)
{
break; /* 超时返回 0 */
}
}
/* 短暂延时避免忙等 */
HAL_Delay(NET_POLL_DELAY_MS);
}
/* 复制结果 */
if (readfds != NULL)
{
readfds->fd_bits = result_read.fd_bits;
}
if (writefds != NULL)
{
writefds->fd_bits = result_write.fd_bits;
}
if (exceptfds != NULL)
{
exceptfds->fd_bits = result_except.fd_bits;
}
return ready_count;
}
/*
* 函数功能I/O 多路复用poll 模式)
*/
int net_poll_events(net_pollfd *fds, int nfds, int timeout)
{
uint32_t start_tick;
int ready = 0;
int i;
if (fds == NULL || nfds <= 0)
{
return -1;
}
start_tick = HAL_GetTick();
while (1)
{
/* 轮询 */
net_poll();
ready = 0;
for (i = 0; i < nfds; i++)
{
fds[i].revents = 0;
/* 检查 fd 有效性 */
if (fds[i].fd < 0 || fds[i].fd >= NET_MAX_SOCKETS)
{
fds[i].revents |= NET_POLLNVAL;
ready++;
continue;
}
net_sock_t *sock = net_get_sock(fds[i].fd);
if (sock == NULL)
{
fds[i].revents |= NET_POLLNVAL;
ready++;
continue;
}
/* 检查可读 */
if (fds[i].events & NET_POLLIN)
{
if (check_socket_readable(fds[i].fd))
{
fds[i].revents |= NET_POLLIN;
ready++;
}
}
/* 检查可写 */
if (fds[i].events & NET_POLLOUT)
{
if (check_socket_writable(fds[i].fd))
{
fds[i].revents |= NET_POLLOUT;
ready++;
}
}
/* 检查错误 */
if (check_socket_error(fds[i].fd))
{
fds[i].revents |= NET_POLLERR;
ready++;
}
/* 检查挂起(连接断开) */
if (sock->state == NET_SOCK_STATE_TCP_ACCEPT ||
sock->state == NET_SOCK_STATE_CLOSED)
{
fds[i].revents |= NET_POLLHUP;
ready++;
}
}
if (ready > 0)
{
break;
}
/* 超时检查 */
if (timeout >= 0)
{
if ((HAL_GetTick() - start_tick) >= (uint32_t)timeout)
{
break;
}
}
HAL_Delay(NET_POLL_DELAY_MS);
}
return ready;
}
/*
* 私有函数实现区
*/
/*
* 函数功能:检查 Socket 是否可读
* 返回值1 可读0 不可读
*/
static int check_socket_readable(int sockfd)
{
net_sock_t *sock;
uint16_t recv_len;
sock = net_get_sock(sockfd);
if (sock == NULL)
{
return 0;
}
/* 监听 Socket 有新连接时可读 */
if (sock->state == NET_SOCK_STATE_LISTENING)
{
return 1;
}
/* 已建立连接的 Socket 有数据可读 */
if (sock->state == NET_SOCK_STATE_ESTABLISHED)
{
recv_len = ch395f_get_recv_len(sockfd);
if (recv_len > 0)
{
return 1;
}
}
return 0;
}
/*
* 函数功能:检查 Socket 是否可写
* 返回值1 可写0 不可写
*/
static int check_socket_writable(int sockfd)
{
net_sock_t *sock;
sock = net_get_sock(sockfd);
if (sock == NULL)
{
return 0;
}
/* 已建立连接的 Socket 发送缓冲区空闲时可写 */
if (sock->state == NET_SOCK_STATE_ESTABLISHED)
{
if (sock->send_ready)
{
return 1;
}
}
return 0;
}
/*
* 函数功能:检查 Socket 是否有错误
* 返回值1 有错误0 无错误
*/
static int check_socket_error(int sockfd)
{
net_sock_t *sock;
/* 无效 fd 视为错误 */
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS)
{
return 1;
}
sock = net_get_sock(sockfd);
if (sock == NULL)
{
return 1; /* 未使用的 Socket 视为错误 */
}
return 0;
}

View File

@@ -0,0 +1,114 @@
/*
* 模块名称Network Select API
* 模块功能I/O 多路复用接口,支持 select 和 poll 模式,
* 用于同时监控多个 Socket 的读写事件
* 适用平台STM32F4 系列CH395F 以太网芯片)
* 作者:王建锋
* 创建日期2026-07-18
* 修改记录:
*/
#ifndef __NET_SELECT_H
#define __NET_SELECT_H
#ifdef __cplusplus
extern "C" {
#endif
#include "net_types.h"
#include "net_config.h"
/*
* 文件描述符集合
* 每个位对应一个 socket 描述符 (0~7)
*/
typedef struct {
uint32_t fd_bits; /* 位掩码 */
} net_fd_set;
/*
* 时间结构体
*/
typedef struct {
long tv_sec; /* 秒 */
long tv_usec; /* 微秒 */
} net_timeval;
/*
* poll 事件结构体
*/
typedef struct {
int fd; /* socket 描述符 */
short events; /* 请求的事件 */
short revents; /* 实际发生的事件 */
} net_pollfd;
/*
* poll 事件掩码
*/
#define NET_POLLIN 0x0001 /* 可读 */
#define NET_POLLOUT 0x0004 /* 可写 */
#define NET_POLLERR 0x0008 /* 错误 */
#define NET_POLLHUP 0x0010 /* 挂起 */
#define NET_POLLNVAL 0x0020 /* 无效请求 */
/*
* fd_set 操作宏
*/
/*
* 函数功能:清空 fd_set
*/
#define NET_FD_ZERO(fdset) ((fdset)->fd_bits = 0)
/*
* 函数功能:将 fd 加入 fd_set
*/
#define NET_FD_SET(fd, fdset) ((fdset)->fd_bits |= (1U << (fd)))
/*
* 函数功能:将 fd 从 fd_set 移除
*/
#define NET_FD_CLR(fd, fdset) ((fdset)->fd_bits &= ~(1U << (fd)))
/*
* 函数功能:检查 fd 是否在 fd_set 中
*/
#define NET_FD_ISSET(fd, fdset) (((fdset)->fd_bits & (1U << (fd))) != 0)
/*
* I/O 多路复用 API
*/
/*
* 函数功能I/O 多路复用select 模式)
* 入口参数nfds - 最大 fd + 1通常为 NET_MAX_SOCKETS
* readfds - 可读事件集合NULL 表示不关心
* writefds - 可写事件集合NULL 表示不关心
* exceptfds - 异常事件集合NULL 表示不关心
* timeout - 超时时间NULL 表示无限等待
* 返回值:就绪的 fd 数量0=超时,-1=错误
* 限定条件net_init() 已调用
* 函数说明:此函数会调用 net_poll() 轮询所有 Socket
* 并检查哪些 Socket 有指定的事件发生。
*/
int net_select(int nfds, net_fd_set *readfds, net_fd_set *writefds,
net_fd_set *exceptfds, net_timeval *timeout);
/*
* 函数功能I/O 多路复用poll 模式)
* 入口参数fds - net_pollfd 数组
* nfds - 数组元素数量
* timeout - 超时时间(毫秒),-1 表示无限等待
* 返回值:就绪的 fd 数量0=超时,-1=错误
* 限定条件net_init() 已调用
* 函数说明:与 select 类似,但使用 pollfd 结构体数组,
* 更灵活,支持更多事件类型。
*/
int net_poll_events(net_pollfd *fds, int nfds, int timeout);
#ifdef __cplusplus
}
#endif
#endif /* __NET_SELECT_H */

1219
Drivers/BSP/NET/net_socket.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,227 @@
/*
* 模块名称Network Socket API
* 模块功能BSD Socket API 兼容接口,提供 TCP/UDP 网络通信功能,
* 底层基于 CH395F 以太网协议栈芯片
* 适用平台STM32F4 系列CH395F 以太网芯片)
* 作者:王建锋
* 创建日期2026-07-18
* 修改记录:
*/
#ifndef __NET_SOCKET_H
#define __NET_SOCKET_H
#ifdef __cplusplus
extern "C" {
#endif
#include "net_types.h"
/*
* 网络初始化接口
*/
/*
* 函数功能:网络子系统初始化(配置 CH395F + 启用多连接模式)
* 入口参数ip - 本地 IP 地址字符串 "192.168.1.100"NULL 使用 DHCP
* mask - 子网掩码字符串 "255.255.255.0"NULL 使用默认
* gateway - 网关地址字符串 "192.168.1.1"NULL 使用默认
* 返回值0 成功,-1 失败
* 限定条件SPI2 已正确初始化
* 函数说明:必须在所有网络操作之前调用
*/
int net_init(const char *ip, const char *mask, const char *gateway);
/*
* 函数功能:轮询所有 Socket 状态(必须在主循环中调用)
* 返回值:有事件发生的 socket 数量
* 限定条件net_init() 已调用
* 函数说明:此函数处理所有 Socket 的中断事件,更新状态,
* 并触发事件回调。在非阻塞模式下必须定期调用。
*/
int net_poll(void);
/*
* 核心 Socket API
*/
/*
* 函数功能:创建 socket
* 入口参数domain - 地址族,仅支持 AF_INET
* type - SOCK_STREAM(TCP) 或 SOCK_DGRAM(UDP)
* protocol - 通常为 0
* 返回值socket 描述符 (0~7),失败返回 -1
* 限定条件net_init() 已调用
*/
int net_socket(int domain, int type, int protocol);
/*
* 函数功能:绑定本地地址和端口
* 入口参数sockfd - socket 描述符
* addr - 本地地址结构体指针
* addrlen - 地址结构体长度
* 返回值0 成功,-1 失败
*/
int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen);
/*
* 函数功能TCP Server 监听
* 入口参数sockfd - socket 描述符
* backlog - 最大等待连接数(多连接模式下为数据 Socket 数量)
* 返回值0 成功,-1 失败
* 限定条件socket 已绑定
*/
int net_listen(int sockfd, int backlog);
/*
* 函数功能TCP Server 接受连接
* 入口参数sockfd - 监听 socket 描述符
* addr - 输出:客户端地址
* addrlen - 输入输出:地址长度
* 返回值:新 socket 描述符,失败返回 -1
* 限定条件socket 正在监听
* 函数说明:在非阻塞模式下,如果没有新连接,返回 -1 并设置
* net_errno 为 NET_ERR_WOULDBLOCK
*/
int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen);
/*
* 函数功能TCP Client 发起连接
* 入口参数sockfd - socket 描述符
* addr - 服务器地址
* addrlen - 地址长度
* 返回值0 成功,-1 失败
* 限定条件socket 已创建
* 函数说明:连接过程是异步的,需要调用 net_poll() 等待连接完成,
* 或使用 select() 等待可写事件
*/
int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen);
/*
* 函数功能发送数据TCP
* 入口参数sockfd - socket 描述符
* buf - 数据缓冲区
* len - 数据长度
* flags - 通常为 0
* 返回值:实际发送字节数,失败返回 -1
* 限定条件TCP 连接已建立
*/
int net_send(int sockfd, const void *buf, int len, int flags);
/*
* 函数功能接收数据TCP
* 入口参数sockfd - socket 描述符
* buf - 接收缓冲区
* len - 缓冲区大小
* flags - 通常为 0可设置 NET_MSG_DONTWAIT 非阻塞
* 返回值实际接收字节数0=对端关闭,-1=错误
* 限定条件TCP 连接已建立
* 函数说明:在阻塞模式下,如果没有数据,函数会等待;
* 在非阻塞模式下,如果没有数据,返回 -1 并设置
* net_errno 为 NET_ERR_WOULDBLOCK
*/
int net_recv(int sockfd, void *buf, int len, int flags);
/*
* 函数功能:发送 UDP 数据
* 入口参数sockfd - socket 描述符
* buf - 数据缓冲区
* len - 数据长度
* flags - 通常为 0
* dest_addr - 目标地址
* addrlen - 地址长度
* 返回值:实际发送字节数,失败返回 -1
*/
int net_sendto(int sockfd, const void *buf, int len, int flags,
const struct net_sockaddr *dest_addr, int addrlen);
/*
* 函数功能:接收 UDP 数据
* 入口参数sockfd - socket 描述符
* buf - 接收缓冲区
* len - 缓冲区大小
* flags - 通常为 0
* src_addr - 输出:发送方地址
* addrlen - 输入输出:地址长度
* 返回值:实际接收字节数,失败返回 -1
*/
int net_recvfrom(int sockfd, void *buf, int len, int flags,
struct net_sockaddr *src_addr, int *addrlen);
/*
* 函数功能:关闭 socket
* 入口参数sockfd - socket 描述符
* 返回值0 成功,-1 失败
*/
int net_close(int sockfd);
/*
* 事件回调 API
*/
/*
* 函数功能:注册事件回调
* 入口参数sockfd - socket 描述符
* cb - 回调函数
* arg - 用户参数
* 返回值0 成功,-1 失败
*/
int net_set_event_cb(int sockfd, net_event_cb_t cb, void *arg);
/*
* 辅助函数
*/
/*
* 函数功能:获取 socket 最后错误码
* 返回值错误码NET_ERR_xxx
*/
int net_get_errno(void);
/*
* 函数功能:将 IP 地址字符串转为网络字节序
* 入口参数cp - 点分十进制字符串 "192.168.1.100"
* 返回值:网络字节序 IP
*/
uint32_t net_inet_addr(const char *cp);
/*
* 函数功能:将网络字节序 IP 转为字符串
* 入口参数addr - 网络字节序 IP
* buf - 输出缓冲区(至少 16 字节)
* 返回值buf 指针
*/
char *net_inet_ntoa(uint32_t addr, char *buf);
/*
* 函数功能:端口字节序转换(主机序 -> 网络序)
*/
uint16_t net_htons(uint16_t hostshort);
/*
* 函数功能:端口字节序转换(网络序 -> 主机序)
*/
uint16_t net_ntohs(uint16_t netshort);
/*
* 函数功能IP 地址字节序转换(主机序 -> 网络序)
*/
uint32_t net_htonl(uint32_t hostlong);
/*
* 函数功能IP 地址字节序转换(网络序 -> 主机序)
*/
uint32_t net_ntohl(uint32_t netlong);
/*
* 函数功能:获取 Socket 控制块指针(内部使用)
* 入口参数sockfd - socket 描述符
* 返回值Socket 控制块指针,失败返回 NULL
*/
net_sock_t *net_get_sock(int sockfd);
#ifdef __cplusplus
}
#endif
#endif /* __NET_SOCKET_H */

175
Drivers/BSP/NET/net_types.h Normal file
View File

@@ -0,0 +1,175 @@
/*
* 模块名称Network Types
* 模块功能网络子系统类型定义包括地址结构体、Socket状态、
* 事件类型、Socket控制块等
* 适用平台STM32F4 系列CH395F 以太网芯片)
* 作者:王建锋
* 创建日期2026-07-18
* 修改记录:
*/
#ifndef __NET_TYPES_H
#define __NET_TYPES_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "net_config.h"
/*
* 地址族定义
*/
#define NET_AF_INET 2 /* IPv4 */
#define NET_AF_INET6 10 /* IPv6未支持 */
#define NET_AF_UNSPEC 0 /* 未指定 */
/*
* Socket 类型定义
*/
#define NET_SOCK_STREAM 1 /* TCP */
#define NET_SOCK_DGRAM 2 /* UDP */
/*
* 协议号定义
*/
#define NET_IPPROTO_TCP 6
#define NET_IPPROTO_UDP 17
#define NET_IPPROTO_ICMP 1
/*
* 特殊地址定义
*/
#define NET_INADDR_ANY 0 /* 任意地址 */
#define NET_INADDR_NONE 0xFFFFFFFF /* 无效地址 */
/*
* 接收标志定义
*/
#define NET_MSG_DONTWAIT 0x01 /* 非阻塞模式 */
/*
* 网络字节序转换宏
*/
#ifdef __BIG_ENDIAN
#define NET_htonl(x) (x)
#define NET_htons(x) (x)
#define NET_ntohl(x) (x)
#define NET_ntohs(x) (x)
#else
#define NET_htonl(x) (((uint32_t)(x) << 24) | \
(((uint32_t)(x) & 0xFF00) << 8) | \
(((uint32_t)(x) & 0xFF0000) >> 8) | \
((uint32_t)(x) >> 24))
#define NET_htons(x) (((uint16_t)(x) << 8) | ((uint16_t)(x) >> 8))
#define NET_ntohl(x) NET_htonl(x)
#define NET_ntohs(x) NET_htons(x)
#endif
/*
* 套接字地址结构体
*/
struct net_sockaddr {
uint16_t sa_family; /* 地址族 */
char sa_data[14]; /* 地址数据 */
};
/*
* IPv4 套接字地址结构体
*/
struct net_sockaddr_in {
uint16_t sin_family; /* 地址族,必须为 AF_INET */
uint16_t sin_port; /* 端口号(网络字节序) */
struct {
uint32_t s_addr; /* IP 地址(网络字节序) */
} sin_addr;
char sin_zero[8]; /* 填充字节 */
};
/*
* Socket 错误码定义
*/
#define NET_OK 0 /* 成功 */
#define NET_ERR -1 /* 通用错误 */
#define NET_ERR_BADF -2 /* 无效 socket 描述符 */
#define NET_ERR_INVAL -3 /* 无效参数 */
#define NET_ERR_NOMEM -4 /* 内存不足 */
#define NET_ERR_NOTCONN -5 /* 未连接 */
#define NET_ERR_ISCONN -6 /* 已连接 */
#define NET_ERR_WOULDBLOCK -7 /* 非阻塞模式下操作未完成 */
#define NET_ERR_CONNRESET -8 /* 连接被重置 */
#define NET_ERR_TIMEDOUT -9 /* 操作超时 */
#define NET_ERR_NOSPACE -10 /* 发送缓冲区无空间 */
#define NET_ERR_BUSY -11 /* 操作未完成CH395F BUSY */
/*
* Socket 状态枚举
*/
typedef enum {
NET_SOCK_STATE_CLOSED = 0, /* 未使用 */
NET_SOCK_STATE_CREATED, /* 已创建,未绑定 */
NET_SOCK_STATE_BOUND, /* 已绑定 */
NET_SOCK_STATE_LISTENING, /* TCP Server 监听中(仅监听 Socket */
NET_SOCK_STATE_CONNECTING, /* TCP Client 连接中 */
NET_SOCK_STATE_ESTABLISHED, /* TCP 已连接 */
NET_SOCK_STATE_UDP_OPEN, /* UDP 已打开 */
NET_SOCK_STATE_TCP_ACCEPT, /* TCP Server 数据 Socket等待分配连接 */
NET_SOCK_STATE_TCP_CLIENT_RECONNECTING, /* TCP Client 重连中 */
} net_sock_state_t;
/*
* 网络事件类型枚举
*/
typedef enum {
NET_EVENT_CONNECTED = 0, /* 连接建立 */
NET_EVENT_DISCONNECTED, /* 连接断开 */
NET_EVENT_DATA_RECEIVED, /* 收到数据 */
NET_EVENT_SEND_COMPLETE, /* 发送完成 */
NET_EVENT_TIMEOUT, /* 操作超时 */
NET_EVENT_ERROR, /* 错误发生 */
} net_event_t;
/*
* 事件回调函数类型定义
* 参数sockfd - socket 描述符
* event - 事件类型
* arg - 用户参数
*/
typedef void (*net_event_cb_t)(int sockfd, net_event_t event, void *arg);
/*
* Socket 控制块结构体
* 每个 socket 对应一个控制块,管理其状态和参数
*/
typedef struct {
uint8_t ch395_sock; /* CH395F 物理 Socket 索引 (0~7) */
net_sock_state_t state; /* Socket 状态 */
uint8_t type; /* SOCK_STREAM / SOCK_DGRAM */
uint8_t in_use; /* 是否在用标志 */
uint16_t local_port; /* 本地端口(主机序) */
uint16_t remote_port; /* 远端端口(主机序) */
uint32_t remote_ip; /* 远端 IP网络字节序 */
uint8_t remote_ip_arr[4]; /* 远端 IP 数组(低字节在前) */
/* 事件回调(可选) */
net_event_cb_t event_cb;
void *event_arg;
/* TCP Server 多连接模式:监听 Socket 的数据 Socket 列表 */
int data_socks[NET_TCP_SERVER_MAX_CLIENTS];
int data_sock_count;
/* 发送就绪标志 */
uint8_t send_ready;
/* 统计信息 */
uint32_t recv_bytes; /* 累计接收字节数 */
uint32_t send_bytes; /* 累计发送字节数 */
} net_sock_t;
#ifdef __cplusplus
}
#endif
#endif /* __NET_TYPES_H */

View File

@@ -11,6 +11,7 @@
/* 头文件包含区 */
#include "tpafe5160.h"
#include "main.h"
/* ======================== 私有宏定义 ======================== */
@@ -325,13 +326,13 @@ const int16_t* tpafe5160_get_buf(void)
}
/*
* 函数功能BUSY 下降沿 EXTI 回调(由 HAL_GPIO_EXTI_IRQHandler 调用)
* 函数功能BUSY 下降沿 EXTI 处理(由 HAL_GPIO_EXTI_Callback 调用)
* 入口参数GPIO_Pin - 触发中断的引脚号
* 返回值:无
* 限定条件BUSY EXTI 已使能
* 函数说明:转换完成后自动读取 8 通道数据到缓冲区,耗时约 0.5µs (168MHz)
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
void tpafe5160_exti_handler(uint16_t GPIO_Pin)
{
if (GPIO_Pin != TP_BUSY_Pin) {
return;

View File

@@ -217,6 +217,15 @@ void tpafe5160_clear_ready(void);
*/
const int16_t* tpafe5160_get_buf(void);
/*
* 函数功能EXTI 中断处理(由 HAL_GPIO_EXTI_Callback 调用)
* 入口参数GPIO_Pin - 触发的引脚号
* 返回值:无
* 限定条件BUSY EXTI 已使能
* 函数说明BUSY 下降沿时自动读取 8 通道数据到缓冲区
*/
void tpafe5160_exti_handler(uint16_t GPIO_Pin);
#ifdef __cplusplus
}
#endif