diff --git a/App/app_cfg.h b/App/app_cfg.h new file mode 100644 index 0000000..49060c4 --- /dev/null +++ b/App/app_cfg.h @@ -0,0 +1,42 @@ +/* + * 模块名称:Application Configuration + * 模块功能:应用层全局配置宏,控制功能模块的编译开关 + * 适用平台:STM32F407ZGTx + * 作者:王建锋 + * 创建日期:2026-07-19 + * 修改记录: + * v1.0 2026-07-19 王建锋 创建初始版本 + */ + +#ifndef __APP_CFG_H +#define __APP_CFG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * 系统时钟源选择 + * 0 - DWT CYCCNT(默认,0 外设开销) + * 1 - TIM2(32-bit 定时器,独立于 DWT) + */ +#define APP_SYS_TIME_SRC 0 + +/* + * 时间戳输出使能 + * 定义后在日志行首自动追加 [T ssssss.uuuuuu] 微秒时间戳 + */ +#define APP_TIMESTAMP_ENABLE + +/* + * 功能模块使能开关 + */ +#define APP_NET_ENABLE +#define APP_ADC_ENABLE +#define APP_RS485_ENABLE + +#ifdef __cplusplus +} +#endif + +#endif /* __APP_CFG_H */ diff --git a/App/app_main.c b/App/app_main.c new file mode 100644 index 0000000..3906956 --- /dev/null +++ b/App/app_main.c @@ -0,0 +1,47 @@ +/* + * 模块名称:Application Main Entry + * 模块功能:应用初始化流程编排、各模块启动、主循环 + * 适用平台:STM32F407ZGTx + * 作者:王建锋 + * 创建日期:2026-07-19 + * 修改记录: + * v1.0 2026-07-19 王建锋 创建初始版本 + */ + +#include "app_main.h" +#include "app_cfg.h" +#include "sys_time.h" + +#define DBG_TAG "[APP]" +#include "dbg_log.h" + +/* + * 函数功能:应用层初始化 + * 入口参数:无 + * 返 回 值:0 - 成功,-1 - 失败 + * 限定条件:CubeMX 外设初始化已完成 + * 函数说明:在 CubeMX 外设初始化之后、FreeRTOS 调度器启动之前调用 + */ +int app_main_init(void) +{ + if (sys_time_init() != 0) { + DBG_ERROR("sys_time_init failed"); + return -1; + } + DBG_INFO("App init OK"); + return 0; +} + +/* + * 函数功能:应用主循环 + * 入口参数:无 + * 返 回 值:无 + * 限定条件:FreeRTOS 调度器启动后不再返回 + * 函数说明:空闲任务可调用的应用层处理入口 + */ +void app_main_run(void) +{ + for (;;) { + /* 应用层空闲处理 */ + } +} diff --git a/App/app_main.h b/App/app_main.h new file mode 100644 index 0000000..2f7b445 --- /dev/null +++ b/App/app_main.h @@ -0,0 +1,27 @@ +/* + * 模块名称:Application Main Entry + * 模块功能:应用层入口,由 main.c 调用完成所有应用初始化与启动 + * 适用平台:STM32F407ZGTx + * 作者:王建锋 + * 创建日期:2026-07-19 + * 修改记录: + * v1.0 2026-07-19 王建锋 创建初始版本 + */ + +#ifndef __APP_MAIN_H +#define __APP_MAIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +int app_main_init(void); +void app_main_run(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __APP_MAIN_H */ diff --git a/App/protocol/.gitkeep b/App/protocol/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/App/sys_time.c b/App/sys_time.c new file mode 100644 index 0000000..510fdfb --- /dev/null +++ b/App/sys_time.c @@ -0,0 +1,107 @@ +/* + * 模块名称:System Timer + * 模块功能:DWT CYCCNT 实现 64-bit 微秒级时间戳 + * 在 SysTick 中断中检测 CYCCNT 溢出以扩展至 64-bit + * 适用平台:STM32F407ZGTx (168MHz) + * 作者:王建锋 + * 创建日期:2026-07-19 + * + * 限定条件: + * - CPU 主频 168MHz(若更改须同步 SYS_TIME_CYCLE_PER_US 宏) + * - 须在 FreeRTOS 启动前调用 sys_time_init() + * - sys_time_systick_hook() 须在 SysTick 中断中调用 + * + * 修改记录: + * v1.0 2026-07-19 王建锋 创建初始版本 + */ + +#include "sys_time.h" +#include "app_cfg.h" +#include "stm32f4xx.h" + +/* + * 每微秒 CPU 周期数(168MHz → 168 cycles/µs) + */ +#define SYS_TIME_CYCLE_PER_US 168UL + +/* + * CYCCNT 每溢出一次代表的微秒数(2^32 / 168 ≈ 25,564,904 µs ≈ 25.56s) + */ +#define SYS_TIME_OVERFLOW_US (uint64_t)(((uint64_t)1 << 32) / SYS_TIME_CYCLE_PER_US) + +static volatile uint32_t s_overflow_cnt; + +/* + * 函数功能:初始化 DWT CYCCNT + * 入口参数:无 + * 返 回 值:0 - 成功 + * 限定条件:须在 FreeRTOS 启动前调用 + * 函数说明:启用 DWT 和 CYCCNT 计数器,计数器从 0 开始 + */ +int sys_time_init(void) +{ + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + DWT->CYCCNT = 0; + DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; + + s_overflow_cnt = 0; + + return 0; +} + +/* + * 函数功能:获取微秒级时间戳 + * 入口参数:无 + * 返 回 值:64 位微秒时间戳 + * 函数说明:由当前 CYCCNT 值与溢出计数合成 64-bit 周期数再转换 + */ +uint64_t sys_time_us(void) +{ + uint32_t cyccnt = 0; + uint64_t ticks = 0; + uint32_t ov = 0; + uint32_t ov2 = 0; + + /* + * 原子读取溢出计数与 CYCCNT,处理潜在的读取竞争 + * 若两次读取溢出计数不一致则重读 CYCCNT + */ + do { + ov = s_overflow_cnt; + cyccnt = DWT->CYCCNT; + ov2 = s_overflow_cnt; + } while (ov != ov2); + + ticks = ((uint64_t)ov << 32) | cyccnt; + return ticks / SYS_TIME_CYCLE_PER_US; +} + +/* + * 函数功能:获取毫秒级时间戳 + * 入口参数:无 + * 返 回 值:64 位毫秒时间戳 + * 限定条件:sys_time_init() 已成功调用 + * 函数说明:通过对 sys_time_us() 取整实现 + */ +uint64_t sys_time_ms(void) +{ + return sys_time_us() / 1000; +} + +/* + * 函数功能:SysTick 中断钩子,检测 CYCCNT 溢出 + * 入口参数:无 + * 返 回 值:无 + * 函数说明:必须在 SysTick_Handler() 中调用 + * 每 1ms 检查一次 CYCCNT 是否已回绕 + */ +void sys_time_systick_hook(void) +{ + static uint32_t s_last_cyccnt = 0; + uint32_t cyccnt = DWT->CYCCNT; + + if (cyccnt < s_last_cyccnt) { + s_overflow_cnt++; + } + s_last_cyccnt = cyccnt; +} diff --git a/App/sys_time.h b/App/sys_time.h new file mode 100644 index 0000000..af1d4cd --- /dev/null +++ b/App/sys_time.h @@ -0,0 +1,29 @@ +/* + * 模块名称:System Timer + * 模块功能:基于 DWT CYCCNT + SysTick 溢出的 64 位微秒级时间戳 + * 适用平台:STM32F407ZGTx (Cortex-M4 FPU) + * 作者:王建锋 + * 创建日期:2026-07-19 + * 修改记录: + * v1.0 2026-07-19 王建锋 创建初始版本 + */ + +#ifndef __SYS_TIME_H +#define __SYS_TIME_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +int sys_time_init(void); +uint64_t sys_time_us(void); +uint64_t sys_time_ms(void); +void sys_time_systick_hook(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __SYS_TIME_H */ diff --git a/App/task/adc_task.c b/App/task/adc_task.c new file mode 100644 index 0000000..ae880dd --- /dev/null +++ b/App/task/adc_task.c @@ -0,0 +1,45 @@ +/* + * 模块名称:ADC Sampling Task + * 模块功能:TPAFE5160 8 通道同步采样,数据缓存与通知 + * 适用平台:STM32F407ZGTx + TPAFE5160 + * 作者:王建锋 + * 创建日期:2026-07-19 + * 修改记录: + * v1.0 2026-07-19 王建锋 创建初始版本 + */ + +#include "adc_task.h" +#include "cmsis_os.h" +#include "tpafe5160.h" + +#define DBG_TAG "[ADC_TASK]" +#include "dbg_log.h" + +/* + * 函数功能:ADC 任务初始化 + * 入口参数:无 + * 返 回 值:0 - 成功,-1 - 失败 + * 限定条件:TPAFE5160 硬件已上电 + * 函数说明:配置采样参数,准备数据缓冲区 + */ +int adc_task_init(void) +{ + DBG_INFO("adc_task_init"); + return 0; +} + +/* + * 函数功能:ADC 任务主函数 + * 入口参数:arg - FreeRTOS 传入参数(未使用) + * 返 回 值:无 + * 限定条件:adc_task_init() 已成功调用 + * 函数说明:定时触发 TPAFE5160 同步采样并处理数据 + */ +void adc_task_func(void const *arg) +{ + (void)arg; + + for (;;) { + osDelay(1000); + } +} diff --git a/App/task/adc_task.h b/App/task/adc_task.h new file mode 100644 index 0000000..674ba3a --- /dev/null +++ b/App/task/adc_task.h @@ -0,0 +1,25 @@ +/* + * 模块名称:ADC Sampling Task + * 模块功能:TPAFE5160 8 通道同步采样,数据缓存与通知 + * 适用平台:STM32F407ZGTx + TPAFE5160 + * 作者:王建锋 + * 创建日期:2026-07-19 + * 修改记录: + * v1.0 2026-07-19 王建锋 创建初始版本 + */ + +#ifndef __ADC_TASK_H +#define __ADC_TASK_H + +#ifdef __cplusplus +extern "C" { +#endif + +int adc_task_init(void); +void adc_task_func(void const *arg); + +#ifdef __cplusplus +} +#endif + +#endif /* __ADC_TASK_H */ diff --git a/App/task/net_task.c b/App/task/net_task.c new file mode 100644 index 0000000..3aeaa63 --- /dev/null +++ b/App/task/net_task.c @@ -0,0 +1,78 @@ +/* + * 模块名称:Network Application Task + * 模块功能:CH395F 协议栈轮询 + TCP/UDP 业务处理 + * 与 net_socket.h 配合,在 FreeRTOS 独立任务中运行 + * 适用平台:STM32F407ZGTx + CH395F + * 作者:王建锋 + * 创建日期:2026-07-19 + * 修改记录: + * v1.0 2026-07-19 王建锋 创建初始版本 + * v1.1 2026-07-19 王建锋 migrate from freertos.c StartNetTask + */ + +#include "net_task.h" +#include "cmsis_os.h" +#include "net_socket.h" +#include "net_select.h" +#include "ch395f_test.h" + +#define DBG_TAG "[NET_TASK]" +#include "dbg_log.h" + +static uint8_t s_net_buf[1500]; + +/* + * 函数功能:网络任务初始化 + * 入口参数:无 + * 返 回 值:0 - 成功,-1 - 失败 + * 限定条件:CH395F 协议栈已初始化 + * 函数说明:创建 TCP Server 监听 Socket,注册回调等 + */ +int net_task_init(void) +{ + DBG_INFO("net_task_init"); + return 0; +} + +/* + * 函数功能:网络任务主函数 + * 入口参数:arg - FreeRTOS 传入参数(未使用) + * 返 回 值:无 + * 函数说明:FreeRTOS 任务函数,启动后先等待 2 秒再进入轮询循环 + * 依次处理 net_poll、TCP echo、UDP/Select 测试 + */ +void net_task_func(void const *arg) +{ + (void)arg; + + osDelay(2000); + DBG_INFO("netTask: started"); + + for (;;) { + net_poll(); + +#ifdef ENABLE_PHASE4_TESTS + for (int i = 1; i < 8; i++) { + net_sock_t *p_sk = net_get_sock(i); + if (p_sk == NULL || p_sk->state != NET_SOCK_STATE_ESTABLISHED) { + continue; + } + + int n = net_recv(i, s_net_buf, sizeof(s_net_buf), NET_MSG_DONTWAIT); + if (n > 0) { + net_send(i, s_net_buf, n, 0); + } + } +#endif + +#ifdef ENABLE_PHASE5_TESTS + ch395f_phase5_tests(); +#endif + +#ifdef ENABLE_PHASE7_TESTS + ch395f_phase7_tests(); +#endif + + osDelay(10); + } +} diff --git a/App/task/net_task.h b/App/task/net_task.h new file mode 100644 index 0000000..34df293 --- /dev/null +++ b/App/task/net_task.h @@ -0,0 +1,25 @@ +/* + * 模块名称:Network Application Task + * 模块功能:网络协议栈轮询、TCP/UDP 业务处理 + * 适用平台:STM32F407ZGTx + CH395F + * 作者:王建锋 + * 创建日期:2026-07-19 + * 修改记录: + * v1.0 2026-07-19 王建锋 创建初始版本 + */ + +#ifndef __NET_TASK_H +#define __NET_TASK_H + +#ifdef __cplusplus +extern "C" { +#endif + +int net_task_init(void); +void net_task_func(void const *arg); + +#ifdef __cplusplus +} +#endif + +#endif /* __NET_TASK_H */ diff --git a/App/task/rs485_task.c b/App/task/rs485_task.c new file mode 100644 index 0000000..f9ac469 --- /dev/null +++ b/App/task/rs485_task.c @@ -0,0 +1,45 @@ +/* + * 模块名称:RS485 Communication Task + * 模块功能:RS-485 轮询收发、协议帧解析与响应 + * 适用平台:STM32F407ZGTx + * 作者:王建锋 + * 创建日期:2026-07-19 + * 修改记录: + * v1.0 2026-07-19 王建锋 创建初始版本 + */ + +#include "rs485_task.h" +#include "cmsis_os.h" +#include "rs485.h" + +#define DBG_TAG "[RS485_TASK]" +#include "dbg_log.h" + +/* + * 函数功能:RS485 任务初始化 + * 入口参数:无 + * 返 回 值:0 - 成功,-1 - 失败 + * 限定条件:UART 和 GPIO 已由 CubeMX 初始化 + * 函数说明:配置 RS-485 通信参数,注册接收回调 + */ +int rs485_task_init(void) +{ + DBG_INFO("rs485_task_init"); + return 0; +} + +/* + * 函数功能:RS485 任务主函数 + * 入口参数:arg - FreeRTOS 传入参数(未使用) + * 返 回 值:无 + * 限定条件:rs485_task_init() 已成功调用 + * 函数说明:轮询接收缓冲区并解析协议帧 + */ +void rs485_task_func(void const *arg) +{ + (void)arg; + + for (;;) { + osDelay(100); + } +} diff --git a/App/task/rs485_task.h b/App/task/rs485_task.h new file mode 100644 index 0000000..f4bde23 --- /dev/null +++ b/App/task/rs485_task.h @@ -0,0 +1,25 @@ +/* + * 模块名称:RS485 Communication Task + * 模块功能:RS-485 数据收发与协议解析 + * 适用平台:STM32F407ZGTx + * 作者:王建锋 + * 创建日期:2026-07-19 + * 修改记录: + * v1.0 2026-07-19 王建锋 创建初始版本 + */ + +#ifndef __RS485_TASK_H +#define __RS485_TASK_H + +#ifdef __cplusplus +extern "C" { +#endif + +int rs485_task_init(void); +void rs485_task_func(void const *arg); + +#ifdef __cplusplus +} +#endif + +#endif /* __RS485_TASK_H */ diff --git a/App/util/crc.c b/App/util/crc.c new file mode 100644 index 0000000..82412da --- /dev/null +++ b/App/util/crc.c @@ -0,0 +1,122 @@ +/* + * 模块名称:CRC Utility + * 模块功能:CRC-16 Modbus (poly=0x8005, init=0xFFFF, refin=true, refout=true, xorout=0x0000) + * CRC-8 (poly=0x07, init=0x00, refin=false, refout=false, xorout=0x00) + * 适用平台:通用嵌入式平台 + * 作者:王建锋 + * 创建日期:2026-07-19 + * 修改记录: + * v1.0 2026-07-19 王建锋 创建初始版本 + */ + +#include "crc.h" + +static const uint16_t s_crc16_table[256] = { + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, + 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, + 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, + 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, + 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, + 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, + 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, + 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, + 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, + 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, + 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, + 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, + 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, + 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, + 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, + 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, + 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, + 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, + 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, + 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, + 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, + 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, + 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, + 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, + 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, + 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, + 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, + 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, + 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, + 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, + 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, + 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040, +}; + +static const uint8_t s_crc8_table[256] = { + 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, + 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, + 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, + 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, + 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, + 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, + 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, + 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, + 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, + 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, + 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, + 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, + 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, + 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, + 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, + 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, + 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, + 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, + 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, + 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, + 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, + 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, + 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, + 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, + 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, + 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, + 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, + 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, + 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, + 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, + 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, + 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3, +}; + +/* + * 函数功能:计算 CRC-16 Modbus + * 入口参数:data - 数据指针 + * len - 数据长度 + * 返 回 值:16 位 CRC 值 + * 限定条件:data 为非空指针 + * 函数说明:多项式 0x8005,初始值 0xFFFF,结果异或 0x0000 + */ +uint16_t crc16_modbus(const uint8_t *data, size_t len) +{ + uint16_t crc = 0xFFFF; + size_t i; + + for (i = 0; i < len; i++) { + crc = (crc >> 8) ^ s_crc16_table[(crc ^ data[i]) & 0xFF]; + } + + return crc; +} + +/* + * 函数功能:计算 CRC-8 + * 入口参数:data - 数据指针 + * len - 数据长度 + * 返 回 值:8 位 CRC 值 + * 限定条件:data 为非空指针 + * 函数说明:多项式 0x07,初始值 0x00 + */ +uint8_t crc8(const uint8_t *data, size_t len) +{ + uint8_t crc = 0; + size_t i; + + for (i = 0; i < len; i++) { + crc = s_crc8_table[crc ^ data[i]]; + } + + return crc; +} diff --git a/App/util/crc.h b/App/util/crc.h new file mode 100644 index 0000000..b0cb46b --- /dev/null +++ b/App/util/crc.h @@ -0,0 +1,28 @@ +/* + * 模块名称:CRC Utility + * 模块功能:CRC-16 Modbus & CRC-8 查表计算 + * 适用平台:通用嵌入式平台 + * 作者:王建锋 + * 创建日期:2026-07-19 + * 修改记录: + * v1.0 2026-07-19 王建锋 创建初始版本 + */ + +#ifndef __CRC_H +#define __CRC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +uint16_t crc16_modbus(const uint8_t *data, size_t len); +uint8_t crc8(const uint8_t *data, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* __CRC_H */ diff --git a/App/util/ringbuf.c b/App/util/ringbuf.c new file mode 100644 index 0000000..7ce6fdb --- /dev/null +++ b/App/util/ringbuf.c @@ -0,0 +1,164 @@ +/* + * 模块名称:Ring Buffer + * 模块功能:字节环形缓冲区实现,head == tail 为空,head + 1 == tail 为满 + * 适用平台:通用嵌入式平台 + * 作者:王建锋 + * 创建日期:2026-07-19 + * 修改记录: + * v1.0 2026-07-19 王建锋 创建初始版本 + */ + +#include "ringbuf.h" + +/* + * 函数功能:初始化环形缓冲区 + * 入口参数:rb - 缓冲区控制块指针 + * pool - 存储池指针 + * size - 存储池大小(字节) + * 返 回 值:无 + * 限定条件:rb 和 pool 均为非空指针 + * 函数说明:size 保留一个空位用于区分空/满状态 + */ +void ringbuf_init(ringbuf_t *rb, uint8_t *pool, size_t size) +{ + rb->buf = pool; + rb->size = size; + rb->head = 0; + rb->tail = 0; +} + +/* + * 函数功能:写入数据到环形缓冲区 + * 入口参数:rb - 缓冲区控制块指针 + * data - 源数据指针 + * len - 待写入长度 + * 返 回 值:实际写入字节数 + * 限定条件:rb 和 data 均为非空指针 + * 函数说明:空间不足时写入能容纳的最大字节数 + */ +size_t ringbuf_put(ringbuf_t *rb, const uint8_t *data, size_t len) +{ + size_t cap = 0; + size_t n = 0; + size_t i = 0; + + cap = rb->size - 1 - ringbuf_avail(rb); + n = (len < cap) ? len : cap; + + for (i = 0; i < n; i++) { + rb->buf[rb->head] = data[i]; + rb->head = (rb->head + 1) % rb->size; + } + + return n; +} + +/* + * 函数功能:从环形缓冲区读取数据 + * 入口参数:rb - 缓冲区控制块指针 + * data - 目标数据指针 + * len - 期望读取长度 + * 返 回 值:实际读取字节数 + * 限定条件:rb 和 data 均为非空指针 + * 函数说明:读取后数据从缓冲区移除 + */ +size_t ringbuf_get(ringbuf_t *rb, uint8_t *data, size_t len) +{ + size_t n = 0; + size_t i = 0; + + n = ringbuf_avail(rb); + n = (n < len) ? n : len; + + for (i = 0; i < n; i++) { + data[i] = rb->buf[rb->tail]; + rb->tail = (rb->tail + 1) % rb->size; + } + + return n; +} + +/* + * 函数功能:预读取数据(不移除) + * 入口参数:rb - 缓冲区控制块指针 + * data - 目标数据指针 + * len - 期望读取长度 + * 返 回 值:实际可读取字节数 + * 限定条件:rb 和 data 均为非空指针 + * 函数说明:与 ringbuf_get 的区别是不移动 tail 指针 + */ +size_t ringbuf_peek(const ringbuf_t *rb, uint8_t *data, size_t len) +{ + size_t n = 0; + size_t i = 0; + size_t idx = 0; + + n = ringbuf_avail(rb); + n = (n < len) ? n : len; + + for (i = 0; i < n; i++) { + idx = (rb->tail + i) % rb->size; + data[i] = rb->buf[idx]; + } + + return n; +} + +/* + * 函数功能:获取缓冲区中有效数据长度 + * 入口参数:rb - 缓冲区控制块指针 + * 返 回 值:有效数据字节数 + * 限定条件:rb 为非空指针 + */ +size_t ringbuf_avail(const ringbuf_t *rb) +{ + if (rb->head >= rb->tail) { + return rb->head - rb->tail; + } + return rb->size - rb->tail + rb->head; +} + +/* + * 函数功能:获取缓冲区剩余空间 + * 入口参数:rb - 缓冲区控制块指针 + * 返 回 值:剩余空间字节数(保留一个空位) + * 限定条件:rb 为非空指针 + */ +size_t ringbuf_space(const ringbuf_t *rb) +{ + return rb->size - 1 - ringbuf_avail(rb); +} + +/* + * 函数功能:判断缓冲区是否为空 + * 入口参数:rb - 缓冲区控制块指针 + * 返 回 值:1 - 空,0 - 非空 + * 限定条件:rb 为非空指针 + */ +int ringbuf_is_empty(const ringbuf_t *rb) +{ + return (rb->head == rb->tail) ? 1 : 0; +} + +/* + * 函数功能:判断缓冲区是否为满 + * 入口参数:rb - 缓冲区控制块指针 + * 返 回 值:1 - 满,0 - 非满 + * 限定条件:rb 为非空指针 + */ +int ringbuf_is_full(const ringbuf_t *rb) +{ + return (ringbuf_avail(rb) == rb->size - 1) ? 1 : 0; +} + +/* + * 函数功能:重置缓冲区 + * 入口参数:rb - 缓冲区控制块指针 + * 返 回 值:无 + * 限定条件:rb 为非空指针 + */ +void ringbuf_reset(ringbuf_t *rb) +{ + rb->head = 0; + rb->tail = 0; +} diff --git a/App/util/ringbuf.h b/App/util/ringbuf.h new file mode 100644 index 0000000..f7c52ec --- /dev/null +++ b/App/util/ringbuf.h @@ -0,0 +1,42 @@ +/* + * 模块名称:Ring Buffer + * 模块功能:线程安全的字节环形缓冲区(单生产者-单消费者模型) + * 适用平台:通用嵌入式平台 + * 作者:王建锋 + * 创建日期:2026-07-19 + * 修改记录: + * v1.0 2026-07-19 王建锋 创建初始版本 + */ + +#ifndef __RINGBUF_H +#define __RINGBUF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef struct { + uint8_t *buf; + size_t size; + size_t head; + size_t tail; +} ringbuf_t; + +void ringbuf_init(ringbuf_t *rb, uint8_t *pool, size_t size); +size_t ringbuf_put(ringbuf_t *rb, const uint8_t *data, size_t len); +size_t ringbuf_get(ringbuf_t *rb, uint8_t *data, size_t len); +size_t ringbuf_peek(const ringbuf_t *rb, uint8_t *data, size_t len); +size_t ringbuf_avail(const ringbuf_t *rb); +size_t ringbuf_space(const ringbuf_t *rb); +int ringbuf_is_empty(const ringbuf_t *rb); +int ringbuf_is_full(const ringbuf_t *rb); +void ringbuf_reset(ringbuf_t *rb); + +#ifdef __cplusplus +} +#endif + +#endif /* __RINGBUF_H */ diff --git a/Drivers/BSP/CH395F/ch395f.c b/Drivers/BSP/CH395F/ch395f.c index 3b06a62..dd45b2f 100644 --- a/Drivers/BSP/CH395F/ch395f.c +++ b/Drivers/BSP/CH395F/ch395f.c @@ -1,21 +1,16 @@ /* * 模块名称:CH395F SPI Ethernet Protocol Stack Driver - * 模块功能:CH395F 以太网协议栈芯片 SPI 驱动实现,提供芯片检测、初始化、 - * 网络参数配置、PHY 管理、DHCP、Socket 管理及数据收发功能 - * 适用平台:STM32F4 系列(SPI2 接口) - * 作者:王建锋 - * 创建日期:2026-03-14 - * 修改记录: - * 2026-03-14 王建锋 创建初始版本,按代码规范重构 - * 2026-07-18 王建锋 改造 write_send_buf / read_recv_buf 使用 SPI2 DMA 批量传输 + * 模块功能:CH395F 以太网协议栈芯片 SPI 驱动实现,提供芯片检测、初始化? * 网络参数配置、PHY 管理、DHCP、Socket 管理及数据收发功? * 适用平台:STM32F4 系列(SPI2 接口? * 作者:王建? * 创建日期?026-03-14 + * 修改记录? * 2026-03-14 王建? 创建初始版本,按代码规范重构 + * 2026-07-18 王建? 改�?write_send_buf / read_recv_buf 使用 SPI2 DMA 批量传输 */ -/* 头文件包含区 - 先包含本模块头文件,再包含依赖头文件 */ +/* 头文件包含区 - 先包含系统头文件,再包含本模块头文件 */ +#include +#include #include "ch395f.h" #include "spi.h" #include "usart.h" -#include -#include /* * 调试输出配置 @@ -26,71 +21,60 @@ /* * 私有宏定义区 */ -#define CH395F_CHECK_EXIST_TEST_DATA 0x57U /* 芯片检测测试字节 */ -#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_CHECK_EXIST_TEST_DATA 0x57U /* 芯片检测测试字?*/ +#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 传输相关 + * 私有变量?- 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 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); /* - * 私有函数实现区 - */ + * 私有函数实现? */ /* - * 函数功能:开始 SPI 事务(CS 拉高 -> 拉低) - * 函数说明:手册要求 SPI 模式下字节间无需间隔, - * CS 拉高再拉低满足最小片选间隔要求 - */ -static void ch395f_spi_begin(void) -{ - /* CS 先拉高,确保空闲状态 */ + * 函数功能:开?SPI 事务(CS 拉高 -> 拉低? * 函数说明:手册要?SPI 模式下字节间无需间隔? * CS 拉高再拉低满足最小片选间隔要? */ +static void ch395f_spi_begin(void) { + /* CS 先拉高,确保空闲状�?*/ HAL_GPIO_WritePin(CH395_SCS_GPIO_Port, CH395_SCS_Pin, GPIO_PIN_SET); - /* CS 拉低,启动事务(无需额外延时,SPI 时序由 SCK 频率决定) */ + /* CS 拉低,启动事务(无需额外延时,SPI 时序?SCK 频率决定?*/ HAL_GPIO_WritePin(CH395_SCS_GPIO_Port, CH395_SCS_Pin, GPIO_PIN_RESET); } /* - * 函数功能:结束 SPI 事务(CS 拉高) - */ -static void ch395f_spi_end(void) -{ - /* CS 拉高,结束事务 */ + * 函数功能:结?SPI 事务(CS 拉高? */ +static void ch395f_spi_end(void) { + /* CS 拉高,结束事?*/ 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 完成回调置位标志 + * 入口参数:len - 传输字节? uint16_t + * 函数说明:发?s_spi2_dma_tx_buf,接收到 s_spi2_dma_rx_buf? * 阻塞等待 DMA 完成回调置位标志 */ -static void ch395f_spi_dma_transfer(uint16_t len) -{ +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) - { + if (status != HAL_OK) { DBG_ERROR("HAL_SPI_TransmitReceive_DMA FAIL: %d, SPI_State=%d, SPI_Error=0x%lX, DMA_State=%d", (int)status, (int)hspi2.State, @@ -100,11 +84,9 @@ static void ch395f_spi_dma_transfer(uint16_t len) } tickstart = HAL_GetTick(); - while (s_spi2_dma_done == 0U) - { + while (s_spi2_dma_done == 0U) { loop_cnt++; - if ((HAL_GetTick() - tickstart) > 1000U) - { + if ((HAL_GetTick() - tickstart) > 1000U) { DBG_ERROR("TIMEOUT after 1s, len=%d, loop=%lu, SPI_State=%d, SPI_Error=0x%lX", (int)len, loop_cnt, (int)hspi2.State, @@ -126,8 +108,7 @@ static void ch395f_spi_dma_transfer(uint16_t len) } /* 检查传输是否成功:SPI 错误码必须为 0 */ - if (hspi2.ErrorCode != 0U) - { + if (hspi2.ErrorCode != 0U) { DBG_INFO("SPI DMA done with errors: ErrorCode=0x%lX, SPI_State=%d", hspi2.ErrorCode, (int)hspi2.State); __HAL_SPI_CLEAR_OVRFLAG(&hspi2); @@ -136,41 +117,35 @@ static void ch395f_spi_dma_transfer(uint16_t len) /* * 函数功能:SPI 收发完成回调 - * 函数说明:由 HAL SPI 驱动在 DMA TX+RX 完成后调用(HAL_SPI_TransmitReceive_DMA 触发此回调) + * 函数说明:由 HAL SPI 驱动?DMA TX+RX 完成后调用(HAL_SPI_TransmitReceive_DMA 触发此回调) */ -void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) -{ - if (hspi->Instance == SPI2) - { +void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) { + if (hspi->Instance == SPI2) { s_spi2_dma_done = 1U; } } /* * 函数功能:SPI 错误回调 - * 函数说明:由 HAL SPI 驱动在 DMA 传输出错时调用,释放等待 + * 函数说明:由 HAL SPI 驱动?DMA 传输出错时调用,释放等待 */ -void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi) -{ - if (hspi->Instance == SPI2) - { +void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi) { + if (hspi->Instance == SPI2) { s_spi2_dma_done = 1U; } } /* - * 公共函数实现区 - */ + * 公共函数实现? */ /* * 函数功能:向 CH395 写入命令字节 - * 入口参数:cmd - 命令码 uint8_t 0x00 - 0xFF - * 返回值:命令码回显值 uint8_t - * 限定条件:需在 ch395f_spi_begin() 和 ch395f_spi_end() 之间调用 + * 入口参数:cmd - 命令? uint8_t 0x00 - 0xFF + * 返回值:命令码回显�? uint8_t + * 限定条件:需?ch395f_spi_begin() ?ch395f_spi_end() 之间调用 * 函数说明:SPI 模式下命令与数据之间无需间隔 */ -uint8_t ch395f_write_cmd(uint8_t cmd) -{ +uint8_t ch395f_write_cmd(uint8_t cmd) { uint8_t rx_data; /* 通过 SPI 发送命令并接收回显 */ @@ -181,11 +156,10 @@ uint8_t ch395f_write_cmd(uint8_t cmd) /* * 函数功能:向 CH395 写入数据字节 * 入口参数:data - 数据字节 uint8_t 0x00 - 0xFF - * 返回值:数据回显值 uint8_t - * 限定条件:需在 ch395f_spi_begin() 和 ch395f_spi_end() 之间调用 + * 返回值:数据回显? uint8_t + * 限定条件:需?ch395f_spi_begin() ?ch395f_spi_end() 之间调用 */ -uint8_t ch395f_write_data(uint8_t data) -{ +uint8_t ch395f_write_data(uint8_t data) { uint8_t rx_data; /* 通过 SPI 发送数据并接收回显 */ @@ -196,37 +170,34 @@ uint8_t ch395f_write_data(uint8_t data) /* * 函数功能:从 CH395 读取数据字节 * 返回值:接收到的数据字节 uint8_t - * 限定条件:需在 ch395f_spi_begin() 和 ch395f_spi_end() 之间调用 + * 限定条件:需?ch395f_spi_begin() ?ch395f_spi_end() 之间调用 */ -uint8_t ch395f_read_data(void) -{ +uint8_t ch395f_read_data(void) { uint8_t tx_dummy = 0xFFU; uint8_t rx_data; - /* 发送 0xFF 作为时钟源,读取芯片返回的数据 */ + /* 发�?0xFF 作为时钟源,读取芯片返回的数?*/ HAL_SPI_TransmitReceive(&hspi2, &tx_dummy, &rx_data, 1, HAL_MAX_DELAY); return rx_data; } /* - * 函数功能:检测 CH395 芯片是否存在且通信正常 + * 函数功能:检?CH395 芯片是否存在且通信正常 * 返回值:CH395F_STATUS_OK - 检测到芯片,CH395F_STATUS_NOT_DETECTED - 未检测到 * 限定条件:SPI2 已正确初始化 - * 函数说明:发送 CMD_CHECK_EXIST (0x06) 及测试字节 0x57, - * 芯片应返回按位取反值 0xA8 + * 函数说明:发?CMD_CHECK_EXIST (0x06) 及测试字?0x57? * 芯片应返回按位取反�?0xA8 */ -ch395f_status_t ch395f_check_exist(void) -{ +ch395f_status_t ch395f_check_exist(void) { uint8_t test_data = CH395F_CHECK_EXIST_TEST_DATA; uint8_t reply_data; - /* 开始 SPI 事务 */ + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送检测命令 */ + /* 发送检测命?*/ ch395f_write_cmd(CH395F_CMD_CHECK_EXIST); - /* 发送测试数据 */ + /* 发送测试数?*/ ch395f_write_data(test_data); /* 读取芯片回复 */ @@ -236,8 +207,7 @@ ch395f_status_t ch395f_check_exist(void) ch395f_spi_end(); /* 验证回复是否为测试数据的按位取反 */ - if (reply_data == (uint8_t)(~test_data)) - { + if (reply_data == (uint8_t)(~test_data)) { return CH395F_STATUS_OK; } @@ -245,21 +215,18 @@ ch395f_status_t ch395f_check_exist(void) } /* - * 函数功能:读取 CH395 芯片版本号 - * 返回值:版本字节(bit5:0 为版本号)uint8_t - * 限定条件:芯片已通过 ch395f_check_exist() 检测 - */ -uint8_t ch395f_get_version(void) -{ + * 函数功能:读?CH395 芯片版本? * 返回值:版本字节(bit5:0 为版本号)uint8_t + * 限定条件:芯片已通过 ch395f_check_exist() 检? */ +uint8_t ch395f_get_version(void) { uint8_t version; - /* 开始 SPI 事务 */ + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送版本读取命令 */ + /* 发送版本读取命?*/ ch395f_write_cmd(CH395F_CMD_GET_IC_VER); - /* 读取版本号 */ + /* 读取版本?*/ version = ch395f_read_data(); /* 结束 SPI 事务 */ @@ -269,40 +236,33 @@ uint8_t ch395f_get_version(void) } /* - * 函数功能:获取远端 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) -{ + * 函数功能:获取远?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) - { + /* 检查输入参数合法�?*/ + if (p_buf == NULL) { return; } - /* 开始 SPI 事务 */ + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送获取远端 IP 和端口命令 */ + /* 发送获取远?IP 和端口命?*/ ch395f_write_cmd(CH395F_CMD_GET_REMOT_IPP_SN); - /* 发送 Socket 索引 */ + /* 发�?Socket 索引 */ ch395f_write_data(sock); /* 读取 4 字节 IP 地址 */ - for (i = 0; i < 4; i++) - { + for (i = 0; i < 4; i++) { p_buf[i] = ch395f_read_data(); } - /* 读取 2 字节端口号 */ - for (i = 4; i < 6; i++) - { + /* 读取 2 字节端口?*/ + for (i = 4; i < 6; i++) { p_buf[i] = ch395f_read_data(); } @@ -311,19 +271,18 @@ void ch395f_get_remot_ipp(uint8_t sock, uint8_t *p_buf) } /* - * 函数功能:设置 CH395 功能参数 + * 函数功能:设?CH395 功能参数 * 入口参数:para - 4 字节功能参数 uint32_t * 限定条件:必须在 ch395f_init() 之前调用 */ -void ch395f_set_fun_para(uint32_t para) -{ - /* 开始 SPI 事务 */ +void ch395f_set_fun_para(uint32_t para) { + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送设置功能参数命令 */ + /* 发送设置功能参数命?*/ ch395f_write_cmd(CH395F_CMD_SET_FUN_PARA); - /* 发送 4 字节参数(低字节在前) */ + /* 发�?4 字节参数(低字节在前?*/ ch395f_write_data((uint8_t)(para)); ch395f_write_data((uint8_t)(para >> 8)); ch395f_write_data((uint8_t)(para >> 16)); @@ -334,19 +293,18 @@ void ch395f_set_fun_para(uint32_t para) } /* - * 函数功能:设置 TCP MSS - * 入口参数:mss - MSS 值 uint16_t 60~1460 + * 函数功能:设?TCP MSS + * 入口参数:mss - MSS ? uint16_t 60~1460 * 限定条件:必须在 ch395f_init() 之前调用 */ -void ch395f_set_tcp_mss(uint16_t mss) -{ - /* 开始 SPI 事务 */ +void ch395f_set_tcp_mss(uint16_t mss) { + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送设置 TCP MSS 命令 */ + /* 发送设?TCP MSS 命令 */ ch395f_write_cmd(CH395F_CMD_SET_TCP_MSS); - /* 发送 2 字节 MSS 值(低字节在前) */ + /* 发�?2 字节 MSS 值(低字节在前) */ ch395f_write_data(mss & 0xFFU); ch395f_write_data((mss >> 8) & 0xFFU); @@ -355,21 +313,19 @@ void ch395f_set_tcp_mss(uint16_t mss) } /* - * 函数功能:设置 Socket 接收缓冲区 - * 入口参数:sock - Socket 索引 uint8_t 0 - 7 + * 函数功能:设?Socket 接收缓冲? * 入口参数:sock - Socket 索引 uint8_t 0 - 7 * start_block - 起始块地址 uint8_t - * block_count - 块个数 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 事务 */ +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 索引 */ + /* 发�?Socket 索引 */ ch395f_write_data(sock); /* 发送起始块地址 */ @@ -383,21 +339,20 @@ void ch395f_set_recv_buf(uint8_t sock, uint8_t start_block, uint8_t block_count) } /* - * 函数功能:设置 Socket 发送缓冲区 + * 函数功能:设?Socket 发送缓冲区 * 入口参数:sock - Socket 索引 uint8_t 0 - 7 * start_block - 起始块地址 uint8_t - * block_count - 块个数 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 事务 */ +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 索引 */ + /* 发�?Socket 索引 */ ch395f_write_data(sock); /* 发送起始块地址 */ @@ -411,19 +366,17 @@ void ch395f_set_send_buf(uint8_t sock, uint8_t start_block, uint8_t block_count) } /* - * 函数功能:清空 Socket 接收缓冲区 - * 入口参数:sock - Socket 索引 uint8_t 0 - 7 + * 函数功能:清?Socket 接收缓冲? * 入口参数:sock - Socket 索引 uint8_t 0 - 7 * 限定条件:Socket 已打开 */ -void ch395f_clear_recv_buf(uint8_t sock) -{ - /* 开始 SPI 事务 */ +void ch395f_clear_recv_buf(uint8_t sock) { + /* 开?SPI 事务 */ ch395f_spi_begin(); /* 发送清空接收缓冲区命令 */ ch395f_write_cmd(CH395F_CMD_CLEAR_RECV_BUF_SN); - /* 发送 Socket 索引 */ + /* 发�?Socket 索引 */ ch395f_write_data(sock); /* 结束 SPI 事务 */ @@ -431,19 +384,18 @@ void ch395f_clear_recv_buf(uint8_t sock) } /* - * 函数功能:设置 TCP KeepAlive 空闲时间 - * 入口参数:time - 空闲时间(秒) uint32_t + * 函数功能:设?TCP KeepAlive 空闲时间 + * 入口参数:time - 空闲时间(秒? uint32_t * 限定条件:必须在 ch395f_init() 之前调用 */ -void ch395f_set_keepalive_idle(uint32_t time) -{ - /* 开始 SPI 事务 */ +void ch395f_set_keepalive_idle(uint32_t time) { + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送设置 KeepAlive 空闲时间命令 */ + /* 发送设?KeepAlive 空闲时间命令 */ ch395f_write_cmd(CH395F_CMD_SET_KEEPALIVE_IDLE); - /* 发送 4 字节时间值(低字节在前) */ + /* 发�?4 字节时间值(低字节在前) */ ch395f_write_data((uint8_t)(time)); ch395f_write_data((uint8_t)(time >> 8)); ch395f_write_data((uint8_t)(time >> 16)); @@ -454,19 +406,18 @@ void ch395f_set_keepalive_idle(uint32_t time) } /* - * 函数功能:设置 TCP KeepAlive 探测间隔 - * 入口参数:time - 间隔时间(秒) uint32_t + * 函数功能:设?TCP KeepAlive 探测间隔 + * 入口参数:time - 间隔时间(秒? uint32_t * 限定条件:必须在 ch395f_init() 之前调用 */ -void ch395f_set_keepalive_intvl(uint32_t time) -{ - /* 开始 SPI 事务 */ +void ch395f_set_keepalive_intvl(uint32_t time) { + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送设置 KeepAlive 探测间隔命令 */ + /* 发送设?KeepAlive 探测间隔命令 */ ch395f_write_cmd(CH395F_CMD_SET_KEEPALIVE_INTVL); - /* 发送 4 字节时间值(低字节在前) */ + /* 发�?4 字节时间值(低字节在前) */ ch395f_write_data((uint8_t)(time)); ch395f_write_data((uint8_t)(time >> 8)); ch395f_write_data((uint8_t)(time >> 16)); @@ -477,19 +428,18 @@ void ch395f_set_keepalive_intvl(uint32_t time) } /* - * 函数功能:设置 TCP KeepAlive 探测次数 + * 函数功能:设?TCP KeepAlive 探测次数 * 入口参数:cnt - 探测次数 uint8_t * 限定条件:必须在 ch395f_init() 之前调用 */ -void ch395f_set_keepalive_cnt(uint8_t cnt) -{ - /* 开始 SPI 事务 */ +void ch395f_set_keepalive_cnt(uint8_t cnt) { + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送设置 KeepAlive 探测次数命令 */ + /* 发送设?KeepAlive 探测次数命令 */ ch395f_write_cmd(CH395F_CMD_SET_KEEPALIVE_CNT); - /* 发送探测次数 */ + /* 发送探测次?*/ ch395f_write_data(cnt); /* 结束 SPI 事务 */ @@ -497,23 +447,22 @@ void ch395f_set_keepalive_cnt(uint8_t cnt) } /* - * 函数功能:启用/禁用指定 Socket 的 KeepAlive + * 函数功能:启?禁用指定 Socket ?KeepAlive * 入口参数:sock - Socket 索引 uint8_t 0 - 7 - * enable - 1 启用,0 禁用 uint8_t + * enable - 1 启用? 禁用 uint8_t * 限定条件:Socket 已打开 */ -void ch395f_set_keepalive_enable(uint8_t sock, uint8_t enable) -{ - /* 开始 SPI 事务 */ +void ch395f_set_keepalive_enable(uint8_t sock, uint8_t enable) { + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送设置 KeepAlive 使能命令 */ + /* 发送设?KeepAlive 使能命令 */ ch395f_write_cmd(CH395F_CMD_SET_KEEPALIVE_SN); - /* 发送 Socket 索引 */ + /* 发�?Socket 索引 */ ch395f_write_data(sock); - /* 发送使能标志 */ + /* 发送使能标?*/ ch395f_write_data(enable); /* 结束 SPI 事务 */ @@ -521,19 +470,17 @@ void ch395f_set_keepalive_enable(uint8_t sock, uint8_t enable) } /* - * 函数功能:设置 TCP 重传次数 - * 入口参数:cnt - 重传次数 uint8_t(0=使用默认值5) - * 限定条件:必须在 ch395f_init() 之前调用 + * 函数功能:设?TCP 重传次数 + * 入口参数:cnt - 重传次数 uint8_t?=使用默认?? * 限定条件:必须在 ch395f_init() 之前调用 */ -void ch395f_set_retrans_count(uint8_t cnt) -{ - /* 开始 SPI 事务 */ +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 事务 */ @@ -541,19 +488,18 @@ void ch395f_set_retrans_count(uint8_t cnt) } /* - * 函数功能:设置 TCP 重传周期 + * 函数功能:设?TCP 重传周期 * 入口参数:period - 重传周期(毫秒) uint16_t * 限定条件:必须在 ch395f_init() 之前调用 */ -void ch395f_set_retrans_period(uint16_t period) -{ - /* 开始 SPI 事务 */ +void ch395f_set_retrans_period(uint16_t period) { + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送设置重传周期命令 */ + /* 发送设置重传周期命?*/ ch395f_write_cmd(CH395F_CMD_SET_RETRAN_PERIOD); - /* 发送 2 字节周期值(低字节在前) */ + /* 发�?2 字节周期值(低字节在前) */ ch395f_write_data(period & 0xFFU); ch395f_write_data((period >> 8) & 0xFFU); @@ -562,44 +508,39 @@ void ch395f_set_retrans_period(uint16_t period) } /* - * 函数功能:软件复位 CH395 + * 函数功能:软件复?CH395 * 返回值:CH395F_STATUS_OK * 限定条件:SPI2 已正确初始化 - * 函数说明:复位耗时约 15ms(TE0),函数内部已包含延时 - */ -ch395f_status_t ch395f_reset(void) -{ - /* 开始 SPI 事务 */ + * 函数说明:复位耗时?15ms(TE0),函数内部已包含延? */ +ch395f_status_t ch395f_reset(void) { + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送复位命令 */ + /* 发送复位命?*/ ch395f_write_cmd(CH395F_CMD_RESET_ALL); /* 结束 SPI 事务 */ ch395f_spi_end(); - /* 等待复位完成(TE0 = 15ms 典型值,等待 20ms) */ + /* 等待复位完成(TE0 = 15ms 典型值,等待 20ms?*/ HAL_Delay(CH395F_RESET_DELAY_MS); return CH395F_STATUS_OK; } /* - * 函数功能:查询命令执行状态 - * 返回值:状态字节(CH395F_ERR_SUCCESS / CH395F_ERR_BUSY / ...)uint8_t - * 限定条件:仅在长执行命令(如初始化)后调用 - */ -uint8_t ch395f_get_cmd_status(void) -{ + * 函数功能:查询命令执行状? * 返回值:状态字节(CH395F_ERR_SUCCESS / CH395F_ERR_BUSY / ...)uint8_t + * 限定条件:仅在长执行命令(如初始化)后调? */ +uint8_t ch395f_get_cmd_status(void) { uint8_t status; - /* 开始 SPI 事务 */ + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送状态查询命令 */ + /* 发送状态查询命?*/ ch395f_write_cmd(CH395F_CMD_GET_CMD_STATUS); - /* 读取状态字节 */ + /* 读取状态字?*/ status = ch395f_read_data(); /* 结束 SPI 事务 */ @@ -609,43 +550,33 @@ uint8_t ch395f_get_cmd_status(void) } /* - * 函数功能:轮询等待命令执行完成 - * 入口参数:timeout_ms - 超时时间(毫秒) uint32_t - * 返回值:命令执行状态码(CH395F_ERR_SUCCESS 或 CH395F_CMD_RET_ABORT) - * 限定条件:在发送长执行命令后调用 - * 函数说明:每 20ms 查询一次,直到命令完成或超时 - */ -uint8_t ch395f_poll_cmd_status(uint32_t timeout_ms) -{ + * 函数功能:轮询等待命令执行完? * 入口参数: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) - { + while (1) { HAL_Delay(20U); status = ch395f_get_cmd_status(); - if (status != CH395F_ERR_BUSY) - { + if (status != CH395F_ERR_BUSY) { return status; } - if (++retry_count >= max_retries) - { + if (++retry_count >= max_retries) { return CH395F_ERR_BUSY; /* 超时 */ } } } /* - * 函数功能:初始化 CH395(包含 MAC、PHY、TCP/IP 协议栈) + * 函数功能:初始化 CH395(包?MAC、PHY、TCP/IP 协议栈) * 返回值:CH395F_STATUS_OK - 成功,CH395F_STATUS_TIMEOUT - 超时失败 * 限定条件:芯片已通过 ch395f_reset() 复位 - * 函数说明:阻塞等待初始化完成或超时(芯片需要约 200ms,这里等最多 4s) - */ -ch395f_status_t ch395f_init(void) -{ + * 函数说明:阻塞等待初始化完成或超时(芯片需要约 200ms,这里等最?4s? */ +ch395f_status_t ch395f_init(void) { uint8_t status; ch395f_spi_begin(); @@ -654,8 +585,7 @@ ch395f_status_t ch395f_init(void) status = ch395f_poll_cmd_status(4000U); - if (status == CH395F_ERR_SUCCESS) - { + if (status == CH395F_ERR_SUCCESS) { return CH395F_STATUS_OK; } @@ -663,29 +593,25 @@ ch395f_status_t ch395f_init(void) } /* - * 函数功能:设置 CH395 IP 地址(低字节在前) - * 入口参数:p_ip - 4 字节 IP 地址指针 uint8_t* + * 函数功能:设?CH395 IP 地址(低字节在前? * 入口参数:p_ip - 4 字节 IP 地址指针 uint8_t* * 限定条件:指针非空,芯片已初始化 */ -void ch395f_set_ip_addr(uint8_t *p_ip) -{ +void ch395f_set_ip_addr(uint8_t *p_ip) { uint8_t i; - /* 检查输入参数合法性 */ - if (p_ip == NULL) - { + /* 检查输入参数合法�?*/ + if (p_ip == NULL) { return; } - /* 开始 SPI 事务 */ + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送设置 IP 命令 */ + /* 发送设?IP 命令 */ ch395f_write_cmd(CH395F_CMD_SET_IP_ADDR); - /* 逐字节发送 IP 地址 */ - for (i = 0; i < 4; i++) - { + /* 逐字节发?IP 地址 */ + for (i = 0; i < 4; i++) { ch395f_write_data(p_ip[i]); } @@ -694,29 +620,25 @@ void ch395f_set_ip_addr(uint8_t *p_ip) } /* - * 函数功能:设置网关 IP 地址(低字节在前) - * 入口参数:p_gwip - 4 字节网关 IP 指针 uint8_t* + * 函数功能:设置网?IP 地址(低字节在前? * 入口参数:p_gwip - 4 字节网关 IP 指针 uint8_t* * 限定条件:指针非空,芯片已初始化 */ -void ch395f_set_gwip_addr(uint8_t *p_gwip) -{ +void ch395f_set_gwip_addr(uint8_t *p_gwip) { uint8_t i; - /* 检查输入参数合法性 */ - if (p_gwip == NULL) - { + /* 检查输入参数合法�?*/ + if (p_gwip == NULL) { return; } - /* 开始 SPI 事务 */ + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送设置网关命令 */ + /* 发送设置网关命?*/ ch395f_write_cmd(CH395F_CMD_SET_GWIP_ADDR); - /* 逐字节发送网关 IP */ - for (i = 0; i < 4; i++) - { + /* 逐字节发送网?IP */ + for (i = 0; i < 4; i++) { ch395f_write_data(p_gwip[i]); } @@ -729,25 +651,22 @@ void ch395f_set_gwip_addr(uint8_t *p_gwip) * 入口参数:p_mask - 4 字节子网掩码指针 uint8_t* * 限定条件:指针非空,芯片已初始化 */ -void ch395f_set_mask_addr(uint8_t *p_mask) -{ +void ch395f_set_mask_addr(uint8_t *p_mask) { uint8_t i; - /* 检查输入参数合法性 */ - if (p_mask == NULL) - { + /* 检查输入参数合法�?*/ + if (p_mask == NULL) { return; } - /* 开始 SPI 事务 */ + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送设置掩码命令 */ + /* 发送设置掩码命?*/ ch395f_write_cmd(CH395F_CMD_SET_MASK_ADDR); - /* 逐字节发送子网掩码 */ - for (i = 0; i < 4; i++) - { + /* 逐字节发送子网掩?*/ + for (i = 0; i < 4; i++) { ch395f_write_data(p_mask[i]); } @@ -756,30 +675,25 @@ void ch395f_set_mask_addr(uint8_t *p_mask) } /* - * 函数功能:设置 MAC 地址(低字节在前,存储于 EEPROM) - * 入口参数:p_mac - 6 字节 MAC 地址指针 uint8_t* + * 函数功能:设?MAC 地址(低字节在前,存储于 EEPROM? * 入口参数:p_mac - 6 字节 MAC 地址指针 uint8_t* * 限定条件:指针非空,芯片已初始化 - * 函数说明:执行耗时约 30us(TE5) - */ -void ch395f_set_mac_addr(uint8_t *p_mac) -{ + * 函数说明:执行耗时?30us(TE5? */ +void ch395f_set_mac_addr(uint8_t *p_mac) { uint8_t i; - /* 检查输入参数合法性 */ - if (p_mac == NULL) - { + /* 检查输入参数合法�?*/ + if (p_mac == NULL) { return; } - /* 开始 SPI 事务 */ + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送设置 MAC 命令 */ + /* 发送设?MAC 命令 */ ch395f_write_cmd(CH395F_CMD_SET_MAC_ADDR); - /* 逐字节发送 MAC 地址 */ - for (i = 0; i < 6; i++) - { + /* 逐字节发?MAC 地址 */ + for (i = 0; i < 6; i++) { ch395f_write_data(p_mac[i]); } @@ -789,28 +703,24 @@ void ch395f_set_mac_addr(uint8_t *p_mac) /* * 函数功能:从 CH395 读取 MAC 地址 - * 出口参数:p_mac - 6 字节 MAC 地址缓冲区指针 uint8_t* - * 限定条件:指针非空 - */ -void ch395f_get_mac_addr(uint8_t *p_mac) -{ + * 出口参数:p_mac - 6 字节 MAC 地址缓冲区指? uint8_t* + * 限定条件:指针非? */ +void ch395f_get_mac_addr(uint8_t *p_mac) { uint8_t i; - /* 检查输入参数合法性 */ - if (p_mac == NULL) - { + /* 检查输入参数合法�?*/ + if (p_mac == NULL) { return; } - /* 开始 SPI 事务 */ + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送读取 MAC 命令 */ + /* 发送读?MAC 命令 */ ch395f_write_cmd(CH395F_CMD_GET_MAC_ADDR); - /* 逐字节读取 MAC 地址 */ - for (i = 0; i < 6; i++) - { + /* 逐字节读?MAC 地址 */ + for (i = 0; i < 6; i++) { p_mac[i] = ch395f_read_data(); } @@ -819,29 +729,24 @@ void ch395f_get_mac_addr(uint8_t *p_mac) } /* - * 函数功能:读取 IP 信息(IP + 掩码 + DNS,共 20 字节) - * 出口参数:p_buf - 20 字节缓冲区指针 uint8_t* - * 限定条件:指针非空 - */ -void ch395f_get_ip_inf(uint8_t *p_buf) -{ + * 函数功能:读?IP 信息(IP + 掩码 + DNS,共 20 字节? * 出口参数:p_buf - 20 字节缓冲区指? uint8_t* + * 限定条件:指针非? */ +void ch395f_get_ip_inf(uint8_t *p_buf) { uint8_t i; - /* 检查输入参数合法性 */ - if (p_buf == NULL) - { + /* 检查输入参数合法�?*/ + if (p_buf == NULL) { return; } - /* 开始 SPI 事务 */ + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送读取 IP 信息命令 */ + /* 发送读?IP 信息命令 */ ch395f_write_cmd(CH395F_CMD_GET_IP_INF); - /* 逐字节读取 IP 信息(共 20 字节) */ - for (i = 0; i < 20; i++) - { + /* 逐字节读?IP 信息(共 20 字节?*/ + for (i = 0; i < 20; i++) { p_buf[i] = ch395f_read_data(); } @@ -850,21 +755,18 @@ void ch395f_get_ip_inf(uint8_t *p_buf) } /* - * 函数功能:获取 PHY 连接状态 - * 返回值:PHY 状态码(CH395F_PHY_DISCONN、CH395F_PHY_10M_FULL 等)uint8_t - * 限定条件:芯片已初始化 - */ -uint8_t ch395f_get_phy_status(void) -{ + * 函数功能:获?PHY 连接状�? * 返回值:PHY 状态码(CH395F_PHY_DISCONN、CH395F_PHY_10M_FULL 等)uint8_t + * 限定条件:芯片已初始? */ +uint8_t ch395f_get_phy_status(void) { uint8_t status; - /* 开始 SPI 事务 */ + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送读取 PHY 状态命令 */ + /* 发送读?PHY 状态命?*/ ch395f_write_cmd(CH395F_CMD_GET_PHY_STATUS); - /* 读取 PHY 状态 */ + /* 读取 PHY 状�?*/ status = ch395f_read_data(); /* 结束 SPI 事务 */ @@ -874,19 +776,17 @@ uint8_t ch395f_get_phy_status(void) } /* - * 函数功能:设置 PHY 连接模式 - * 入口参数:phystat - 连接模式码 uint8_t 0x20 = 自动协商 - * 限定条件:芯片已初始化 - */ -void ch395f_set_phy(uint8_t phystat) -{ - /* 开始 SPI 事务 */ + * 函数功能:设?PHY 连接模式 + * 入口参数:phystat - 连接模式? uint8_t 0x20 = 自动协商 + * 限定条件:芯片已初始? */ +void ch395f_set_phy(uint8_t phystat) { + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送设置 PHY 命令 */ + /* 发送设?PHY 命令 */ ch395f_write_cmd(CH395F_CMD_SET_PHY); - /* 发送连接模式参数 */ + /* 发送连接模式参?*/ ch395f_write_data(phystat); /* 结束 SPI 事务 */ @@ -894,20 +794,17 @@ void ch395f_set_phy(uint8_t phystat) } /* - * 函数功能:使能/关闭 CH395 响应 PING - * 入口参数:enable - 1 使能 PING 响应,0 关闭 - * 限定条件:芯片已初始化 - * 函数说明:手册 5.37 CMD_PING_ENABLE,默认关闭 - */ -void ch395f_ping_enable(uint8_t enable) -{ - /* 开始 SPI 事务 */ + * 函数功能:使?关闭 CH395 响应 PING + * 入口参数:enable - 1 使能 PING 响应? 关闭 + * 限定条件:芯片已初始? * 函数说明:手?5.37 CMD_PING_ENABLE,默认关? */ +void ch395f_ping_enable(uint8_t enable) { + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送 PING 使能命令 */ + /* 发�?PING 使能命令 */ ch395f_write_cmd(CH395F_CMD_PING_ENABLE); - /* 发送使能标志 */ + /* 发送使能标?*/ ch395f_write_data(enable); /* 结束 SPI 事务 */ @@ -915,19 +812,17 @@ void ch395f_ping_enable(uint8_t enable) } /* - * 函数功能:启用/禁用 DHCP - * 入口参数:enable - 1 启用,0 禁用 uint8_t - * 限定条件:芯片已初始化 - */ -void ch395f_set_dhcp(uint8_t enable) -{ - /* 开始 SPI 事务 */ + * 函数功能:启?禁用 DHCP + * 入口参数:enable - 1 启用? 禁用 uint8_t + * 限定条件:芯片已初始? */ +void ch395f_set_dhcp(uint8_t enable) { + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送 DHCP 使能命令 */ + /* 发�?DHCP 使能命令 */ ch395f_write_cmd(CH395F_CMD_DHCP_ENABLE); - /* 发送启用/禁用参数 */ + /* 发送启?禁用参数 */ ch395f_write_data(enable); /* 结束 SPI 事务 */ @@ -935,21 +830,18 @@ void ch395f_set_dhcp(uint8_t enable) } /* - * 函数功能:获取 DHCP 状态 - * 返回值:0 = 成功,非零 = 错误/超时 uint8_t - * 限定条件:芯片已初始化且 DHCP 已启用 - */ -uint8_t ch395f_get_dhcp_status(void) -{ + * 函数功能:获?DHCP 状�? * 返回值:0 = 成功,非?= 错误/超时 uint8_t + * 限定条件:芯片已初始化且 DHCP 已启? */ +uint8_t ch395f_get_dhcp_status(void) { uint8_t status; - /* 开始 SPI 事务 */ + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送读取 DHCP 状态命令 */ + /* 发送读?DHCP 状态命?*/ ch395f_write_cmd(CH395F_CMD_GET_DHCP_STATUS); - /* 读取 DHCP 状态 */ + /* 读取 DHCP 状�?*/ status = ch395f_read_data(); /* 结束 SPI 事务 */ @@ -959,23 +851,22 @@ uint8_t ch395f_get_dhcp_status(void) } /* - * 函数功能:设置 Socket 协议类型 + * 函数功能:设?Socket 协议类型 * 入口参数:sock - Socket 索引 uint8_t 0 - 3 * proto - 协议类型 uint8_t CH395F_PROTO_TYPE_xxx * 限定条件:Socket 未打开 */ -void ch395f_set_proto_type(uint8_t sock, uint8_t proto) -{ - /* 开始 SPI 事务 */ +void ch395f_set_proto_type(uint8_t sock, uint8_t proto) { + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送设置协议类型命令 */ + /* 发送设置协议类型命?*/ ch395f_write_cmd(CH395F_CMD_SET_PROTO_TYPE_SN); - /* 发送 Socket 索引 */ + /* 发�?Socket 索引 */ ch395f_write_data(sock); - /* 发送协议类型 */ + /* 发送协议类?*/ ch395f_write_data(proto); /* 结束 SPI 事务 */ @@ -983,33 +874,29 @@ void ch395f_set_proto_type(uint8_t sock, uint8_t proto) } /* - * 函数功能:设置 Socket 目标 IP 地址 + * 函数功能:设?Socket 目标 IP 地址 * 入口参数:sock - Socket 索引 uint8_t 0 - 3 * p_ip - 4 字节目标 IP 指针 uint8_t* - * 限定条件:指针非空 - */ -void ch395f_set_des_ip(uint8_t sock, uint8_t *p_ip) -{ + * 限定条件:指针非? */ +void ch395f_set_des_ip(uint8_t sock, uint8_t *p_ip) { uint8_t i; - /* 检查输入参数合法性 */ - if (p_ip == NULL) - { + /* 检查输入参数合法�?*/ + if (p_ip == NULL) { return; } - /* 开始 SPI 事务 */ + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送设置目标 IP 命令 */ + /* 发送设置目?IP 命令 */ ch395f_write_cmd(CH395F_CMD_SET_IP_ADDR_SN); - /* 发送 Socket 索引 */ + /* 发�?Socket 索引 */ ch395f_write_data(sock); - /* 逐字节发送目标 IP */ - for (i = 0; i < 4; i++) - { + /* 逐字节发送目?IP */ + for (i = 0; i < 4; i++) { ch395f_write_data(p_ip[i]); } @@ -1018,20 +905,18 @@ void ch395f_set_des_ip(uint8_t sock, uint8_t *p_ip) } /* - * 函数功能:设置 Socket 目标端口(小端序) - * 入口参数:sock - Socket 索引 uint8_t 0 - 3 + * 函数功能:设?Socket 目标端口(小端序? * 入口参数:sock - Socket 索引 uint8_t 0 - 3 * port - 目标端口 uint16_t * 限定条件:无 */ -void ch395f_set_des_port(uint8_t sock, uint16_t port) -{ - /* 开始 SPI 事务 */ +void ch395f_set_des_port(uint8_t sock, uint16_t port) { + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送设置目标端口命令 */ + /* 发送设置目标端口命?*/ ch395f_write_cmd(CH395F_CMD_SET_DES_PORT_SN); - /* 发送 Socket 索引 */ + /* 发�?Socket 索引 */ ch395f_write_data(sock); /* 发送端口低字节 */ @@ -1045,20 +930,19 @@ void ch395f_set_des_port(uint8_t sock, uint16_t port) } /* - * 函数功能:设置 Socket 源端口(小端序) + * 函数功能:设?Socket 源端口(小端序) * 入口参数:sock - Socket 索引 uint8_t 0 - 3 - * port - 源端口 uint16_t + * port - 源端? uint16_t * 限定条件:无 */ -void ch395f_set_sour_port(uint8_t sock, uint16_t port) -{ - /* 开始 SPI 事务 */ +void ch395f_set_sour_port(uint8_t sock, uint16_t port) { + /* 开?SPI 事务 */ ch395f_spi_begin(); /* 发送设置源端口命令 */ ch395f_write_cmd(CH395F_CMD_SET_SOUR_PORT_SN); - /* 发送 Socket 索引 */ + /* 发�?Socket 索引 */ ch395f_write_data(sock); /* 发送端口低字节 */ @@ -1074,11 +958,10 @@ void ch395f_set_sour_port(uint8_t sock, uint16_t port) /* * 函数功能:打开 Socket * 入口参数:sock - Socket 索引 uint8_t 0 - 7 - * 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t - * 限定条件:协议类型、目标 IP、端口已设置 + * 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功? uint8_t + * 限定条件:协议类型、目?IP、端口已设置 */ -uint8_t ch395f_open_socket(uint8_t sock) -{ +uint8_t ch395f_open_socket(uint8_t sock) { ch395f_spi_begin(); ch395f_write_cmd(CH395F_CMD_OPEN_SOCKET_SN); ch395f_write_data(sock); @@ -1088,13 +971,12 @@ uint8_t ch395f_open_socket(uint8_t sock) } /* - * 函数功能:关闭 Socket + * 函数功能:关?Socket * 入口参数:sock - Socket 索引 uint8_t 0 - 7 - * 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t + * 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功? uint8_t * 限定条件:Socket 已打开 */ -uint8_t ch395f_close_socket(uint8_t sock) -{ +uint8_t ch395f_close_socket(uint8_t sock) { ch395f_spi_begin(); ch395f_write_cmd(CH395F_CMD_CLOSE_SOCKET_SN); ch395f_write_data(sock); @@ -1104,13 +986,12 @@ uint8_t ch395f_close_socket(uint8_t sock) } /* - * 函数功能:启动 TCP 监听模式 + * 函数功能:启?TCP 监听模式 * 入口参数:sock - Socket 索引 uint8_t 0 - 7 - * 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t + * 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功? uint8_t * 限定条件:Socket 已打开且协议类型为 TCP */ -uint8_t ch395f_tcp_listen(uint8_t sock) -{ +uint8_t ch395f_tcp_listen(uint8_t sock) { ch395f_spi_begin(); ch395f_write_cmd(CH395F_CMD_TCP_LISTEN_SN); ch395f_write_data(sock); @@ -1120,13 +1001,12 @@ uint8_t ch395f_tcp_listen(uint8_t sock) } /* - * 函数功能:启动 TCP 连接 + * 函数功能:启?TCP 连接 * 入口参数:sock - Socket 索引 uint8_t 0 - 7 - * 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t + * 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功? uint8_t * 限定条件:Socket 已打开且协议类型为 TCP */ -uint8_t ch395f_tcp_connect(uint8_t sock) -{ +uint8_t ch395f_tcp_connect(uint8_t sock) { ch395f_spi_begin(); ch395f_write_cmd(CH395F_CMD_TCP_CONNECT_SN); ch395f_write_data(sock); @@ -1138,11 +1018,9 @@ uint8_t ch395f_tcp_connect(uint8_t sock) /* * 函数功能:断开 TCP 连接 * 入口参数:sock - Socket 索引 uint8_t 0 - 7 - * 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t - * 限定条件:TCP 已建立连接 - */ -uint8_t ch395f_tcp_disconnect(uint8_t sock) -{ + * 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功? uint8_t + * 限定条件:TCP 已建立连? */ +uint8_t ch395f_tcp_disconnect(uint8_t sock) { ch395f_spi_begin(); ch395f_write_cmd(CH395F_CMD_TCP_DISCONNECT_SN); ch395f_write_data(sock); @@ -1152,27 +1030,23 @@ uint8_t ch395f_tcp_disconnect(uint8_t sock) } /* - * 函数功能:向 Socket 发送缓冲区写入数据(DMA 批量传输) - * 入口参数:sock - Socket 索引 uint8_t 0 - 3 + * 函数功能:向 Socket 发送缓冲区写入数据(DMA 批量传输? * 入口参数:sock - Socket 索引 uint8_t 0 - 3 * p_data - 数据指针 uint8_t* * len - 数据长度 uint16_t * 限定条件:指针非空,长度大于 0,TCP 已连接或 UDP 已打开 - * 函数说明:将命令头和数据打包到 DMA 缓冲区,一次 SPI DMA 传输完成 + * 函数说明:将命令头和数据打包?DMA 缓冲区,一?SPI DMA 传输完成 */ -void ch395f_write_send_buf(uint8_t sock, uint8_t *p_data, uint16_t len) -{ +void ch395f_write_send_buf(uint8_t sock, uint8_t *p_data, uint16_t len) { uint16_t total; - /* 检查输入参数合法性 */ - if (p_data == NULL) - { + /* 检查输入参数合法�?*/ + if (p_data == NULL) { return; } /* 计算总长度:1(cmd) + 1(sock) + 2(len) + data */ total = 4U + len; - if (total > CH395F_DMA_BUF_SIZE) - { + if (total > CH395F_DMA_BUF_SIZE) { return; } @@ -1182,10 +1056,10 @@ void ch395f_write_send_buf(uint8_t sock, uint8_t *p_data, uint16_t len) s_spi2_dma_tx_buf[2] = len & 0xFFU; s_spi2_dma_tx_buf[3] = (len >> 8) & 0xFFU; - /* 拷贝用户数据到 DMA 发送缓冲区 */ + /* 拷贝用户数据?DMA 发送缓冲区 */ memcpy(&s_spi2_dma_tx_buf[4], p_data, len); - /* 数据同步屏障:确保 memcpy 写入在 DMA 读取前对总线可见 */ + /* 数据同步屏障:确?memcpy 写入?DMA 读取前对总线可见 */ __DSB(); /* CS 拉低 -> DMA 批量传输 -> CS 拉高 */ @@ -1195,28 +1069,21 @@ void ch395f_write_send_buf(uint8_t sock, uint8_t *p_data, uint16_t len) } /* - * 函数功能:从 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) -{ + * 函数功能:从 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 total; - /* 检查输入参数合法性 */ - if (p_data == NULL) - { + /* 检查输入参数合法�?*/ + if (p_data == NULL) { return; } /* 计算总长度:1(cmd) + 1(sock) + 2(len) + data */ total = 4U + len; - if (total > CH395F_DMA_BUF_SIZE) - { + if (total > CH395F_DMA_BUF_SIZE) { return; } @@ -1234,30 +1101,28 @@ void ch395f_read_recv_buf(uint8_t sock, uint8_t *p_data, uint16_t len) ch395f_spi_dma_transfer(total); ch395f_spi_end(); - /* 从 DMA 接收缓冲区偏移 4 字节处拷贝有效数据到用户缓冲区 */ + /* ?DMA 接收缓冲区偏?4 字节处拷贝有效数据到用户缓冲?*/ memcpy(p_data, &s_spi2_dma_rx_buf[4], len); } /* - * 函数功能:获取 Socket 接收缓冲区数据长度 - * 入口参数:sock - Socket 索引 uint8_t 0 - 3 + * 函数功能:获?Socket 接收缓冲区数据长? * 入口参数:sock - Socket 索引 uint8_t 0 - 3 * 返回值:接收数据长度 uint16_t * 限定条件:Socket 已打开 */ -uint16_t ch395f_get_recv_len(uint8_t sock) -{ +uint16_t ch395f_get_recv_len(uint8_t sock) { uint16_t recv_len; - /* 开始 SPI 事务 */ + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送获取接收长度命令 */ + /* 发送获取接收长度命?*/ ch395f_write_cmd(CH395F_CMD_GET_RECV_LEN_SN); - /* 发送 Socket 索引 */ + /* 发�?Socket 索引 */ ch395f_write_data(sock); - /* 读取长度低字节 */ + /* 读取长度低字?*/ recv_len = ch395f_read_data(); /* 读取长度高字节并组合 */ @@ -1270,21 +1135,18 @@ uint16_t ch395f_get_recv_len(uint8_t sock) } /* - * 函数功能:获取全局中断状态 - * 返回值:中断状态字节 uint8_t - * 限定条件:芯片已初始化 - */ -uint8_t ch395f_get_glob_int_status(void) -{ + * 函数功能:获取全局中断状�? * 返回值:中断状态字? uint8_t + * 限定条件:芯片已初始? */ +uint8_t ch395f_get_glob_int_status(void) { uint8_t status; - /* 开始 SPI 事务 */ + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送读取全局中断状态命令 */ + /* 发送读取全局中断状态命?*/ ch395f_write_cmd(CH395F_CMD_GET_GLOB_INT_STATUS); - /* 读取中断状态 */ + /* 读取中断状�?*/ status = ch395f_read_data(); /* 结束 SPI 事务 */ @@ -1294,12 +1156,8 @@ 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) -{ + * 函数功能:获取全局中断状态(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(); @@ -1312,25 +1170,22 @@ uint16_t ch395f_get_glob_int_status_all(void) } /* - * 函数功能:获取 Socket 中断状态 - * 入口参数:sock - Socket 索引 uint8_t 0 - 7 - * 返回值:Socket 中断状态字节 uint8_t - * 限定条件:芯片已初始化 - */ -uint8_t ch395f_get_sock_int_status(uint8_t sock) -{ + * 函数功能:获?Socket 中断状�? * 入口参数:sock - Socket 索引 uint8_t 0 - 7 + * 返回值:Socket 中断状态字? uint8_t + * 限定条件:芯片已初始? */ +uint8_t ch395f_get_sock_int_status(uint8_t sock) { uint8_t status; - /* 开始 SPI 事务 */ + /* 开?SPI 事务 */ ch395f_spi_begin(); - /* 发送读取 Socket 中断状态命令 */ + /* 发送读?Socket 中断状态命?*/ ch395f_write_cmd(CH395F_CMD_GET_INT_STATUS_SN); - /* 发送 Socket 索引 */ + /* 发�?Socket 索引 */ ch395f_write_data(sock); - /* 读取中断状态 */ + /* 读取中断状�?*/ status = ch395f_read_data(); /* 结束 SPI 事务 */ @@ -1340,30 +1195,25 @@ uint8_t ch395f_get_sock_int_status(uint8_t sock) } /* - * 函数功能:获取 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) -{ + * 函数功能:获?Socket 状态(2 字节输出? * 入口参数:sock - Socket 索引 uint8_t 0 - 7 + * status - 2 字节输出缓冲?[0]=Socket状�? [1]=TCP状�? * 限定条件:芯片已初始? */ +void ch395f_get_socket_status(uint8_t sock, uint8_t *p_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(); + p_status[0] = ch395f_read_data(); + p_status[1] = ch395f_read_data(); ch395f_spi_end(); } /* - * 函数功能:设置 ARP 重传参数 - * 入口参数:period_100ms - ARP 重传周期(单位 100ms,0=默认值=10即1秒) uint8_t - * cnt - ARP 重传次数(0=默认值=3) uint8_t - * 限定条件:应在 ch395f_init() 之后调用 + * 函数功能:设?ARP 重传参数 + * 入口参数:period_100ms - ARP 重传周期(单?100ms?=默认?10?秒) uint8_t + * cnt - ARP 重传次数?=默认?3? uint8_t + * 限定条件:应?ch395f_init() 之后调用 * 函数说明:周期最大值约 25.5 秒,255 表示无限重传 */ -void ch395f_set_arp(uint8_t period_100ms, uint8_t cnt) -{ +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); @@ -1372,13 +1222,12 @@ void ch395f_set_arp(uint8_t period_100ms, uint8_t cnt) } /* - * 函数功能:设置 Socket TTL + * 函数功能:设?Socket TTL * 入口参数:sock - Socket 索引 uint8_t 0 - 7 - * ttl - TTL 值 uint8_t 最大 128 + * ttl - TTL ? uint8_t 最?128 * 限定条件:Socket 已打开,TCP Server 模式下不生效 */ -void ch395f_set_ttl(uint8_t sock, uint8_t ttl) -{ +void ch395f_set_ttl(uint8_t sock, uint8_t ttl) { ch395f_spi_begin(); ch395f_write_cmd(CH395F_CMD_SET_TTL); ch395f_write_data(sock); @@ -1388,18 +1237,16 @@ 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) -{ - uint8_t i; + * 出口参数:p_buf - 8 字节输出缓冲区(类型+协议?端口+IP? * 限定条件:收?GINT_STAT_UNREACH 中断后调? */ +void ch395f_get_unreach_info(uint8_t *p_buf) { + uint8_t i = 0; ch395f_spi_begin(); ch395f_write_cmd(CH395F_CMD_GET_UNREACH_IPPT); - for (i = 0; i < 8; i++) - { + for (i = 0; i < 8; i++) { p_buf[i] = ch395f_read_data(); } ch395f_spi_end(); } + + diff --git a/Drivers/BSP/CH395F/ch395f_test.c b/Drivers/BSP/CH395F/ch395f_test.c index 513b749..32358d8 100644 --- a/Drivers/BSP/CH395F/ch395f_test.c +++ b/Drivers/BSP/CH395F/ch395f_test.c @@ -2,26 +2,23 @@ * 模块名称:CH395F Driver Test Suite * 模块功能:CH395F 驱动各功能模块的测试入口,分阶段组织测试用例 * 适用平台:STM32F4 系列(CH395F 以太网芯片) - * 作者:王建锋 - * 创建日期:2026-07-19 - * 修改记录: - * 2026-07-19 Phase 1/2/3 implemented + * 作者:王建? * 创建日期?026-07-19 + * 修改记录? * 2026-07-19 Phase 1/2/3 implemented */ /* 头文件包含区 */ +#include +#include #include "ch395f_test.h" #include "ch395f.h" #include "net_socket.h" #define DBG_TAG "[CH395T]" #include "dbg_log.h" -#include -#include test_stats_t g_test_stats; /* - * Phase 2 配置默认值 - */ + * Phase 2 配置默认? */ #ifndef PHASE2_REMOTE_IP #define PHASE2_REMOTE_IP "192.168.1.2" #endif @@ -39,8 +36,7 @@ test_stats_t g_test_stats; #endif /* - * Phase 3 配置默认值 - */ + * Phase 3 配置默认? */ #ifndef PHASE3_REMOTE_IP #define PHASE3_REMOTE_IP "192.168.1.2" #endif @@ -58,13 +54,12 @@ test_stats_t g_test_stats; #endif /* - * 恢复 TCP Server 多连接模式的数据 Socket 配置 - */ -static void restore_data_sockets(uint16_t port) -{ - int i; - for (i = NET_TCP_SERVER_DATA_SOCK_START; i < NET_MAX_SOCKETS; i++) - { + * 函数功能:恢?TCP Server 多连接模式的数据 Socket 配置 + * 入口参数:port - TCP 源端口号 + * ??值:? * 限定条件:CH395F 协议栈已初始? * 函数说明:重新设置数?Socket 的协议类型和源端? */ +static void restore_data_sockets(uint16_t port) { + int i = 0; + for (i = NET_TCP_SERVER_DATA_SOCK_START; i < NET_MAX_SOCKETS; i++) { ch395f_set_proto_type((uint8_t)i, CH395F_PROTO_TYPE_TCP); ch395f_set_sour_port((uint8_t)i, port); } @@ -73,12 +68,14 @@ static void restore_data_sockets(uint16_t port) /* * ============================ Phase 1 ============================ - */ + * 函数功能:寄存器读写 + 中断一致性基础测试 + * 入口参数:无 + * ??值:? * 限定条件:CH395F 芯片正常应答 + * 函数说明:包?GET_VERSION / GET_CMD_STATUS / GET_IP_INF ?9 ? */ -void ch395f_phase1_tests(void) -{ - uint8_t i; - int ver; +void ch395f_phase1_tests(void) { + uint8_t i = 0; + int ver = 0; DBG_INFO("=== CH395F Phase 1 Tests ==="); @@ -115,7 +112,7 @@ void ch395f_phase1_tests(void) "GINT_STATUS_ALL: 0x%04X (lo=0x%02X hi=0x%02X)", gint_all, gint_all & 0xFF, (gint_all >> 8) & 0xFF); - /* Test 5: GINT_STATUS (1-byte version) — read-clear check */ + /* Test 5: GINT_STATUS (1-byte version) ?read-clear check */ uint8_t gint_1b = ch395f_get_glob_int_status(); TEST_CHECK(gint_1b == 0x00, "GINT_STATUS_1byte: 0x%02X (expect 0x00 after read-clear)", gint_1b); @@ -139,8 +136,7 @@ void ch395f_phase1_tests(void) /* Test 9: CLEAR_RECV_BUF + SOCK_INT poll */ ch395f_clear_recv_buf(0); TEST_CHECK(1, "CLEAR_RECV_BUF(sock=0): OK"); - for (i = 0; i < 8; i++) - { + for (i = 0; i < 8; i++) { uint8_t si = ch395f_get_sock_int_status(i); TEST_CHECK(si == 0x00, "SOCK_INT(%d): 0x%02X", i, si); } @@ -150,17 +146,17 @@ void ch395f_phase1_tests(void) /* * ============================ Phase 2 ============================ - */ + * 函数功能:TCP Client 收发 + 关闭重连 ×3 ? * 入口参数:无 + * ??值:? * 限定条件:PC 端已启动 TCP Server(默?192.168.1.2:8081? * 函数说明:每轮连接→发送→接收→关闭,连续 3 ? */ -void ch395f_phase2_tests(void) -{ - uint8_t sock; - uint8_t sock_int; - uint8_t rx_buf[300]; - int i; - uint32_t tick; - uint16_t int_st; - int iter_pass; +void ch395f_phase2_tests(void) { + uint8_t sock = 0; + uint8_t sock_int = 0; + uint8_t rx_buf[300] = {0}; + int i = 0; + uint32_t tick = 0; + uint16_t int_st = 0; + int iter_pass = 0; DBG_INFO("=== CH395F Phase 2 Tests (TCP Client - Direct Driver) ==="); @@ -178,15 +174,14 @@ void ch395f_phase2_tests(void) sock = (uint8_t)(NET_MAX_SOCKETS - 1); - /* 一次性配置 */ + /* 一次性配?*/ ch395f_set_proto_type(sock, CH395F_PROTO_TYPE_TCP); ch395f_set_send_buf(sock, 28, 2); ch395f_set_recv_buf(sock, 30, 2); ch395f_set_des_ip(sock, ip_arr); ch395f_set_des_port(sock, PHASE2_REMOTE_PORT); - for (i = 0; i < PHASE2_LOOP_COUNT; i++) - { + for (i = 0; i < PHASE2_LOOP_COUNT; i++) { DBG_INFO("--- Iteration %d/%d ---", i + 1, PHASE2_LOOP_COUNT); iter_pass = 1; @@ -197,11 +192,9 @@ void ch395f_phase2_tests(void) /* 等待 CONNECT */ tick = HAL_GetTick(); - while (HAL_GetTick() - tick < PHASE2_TIMEOUT_MS) - { + while (HAL_GetTick() - tick < PHASE2_TIMEOUT_MS) { int_st = ch395f_get_glob_int_status_all(); - if (int_st & (1U << (sock + 4))) - { + if (int_st & (1U << (sock + 4))) { sock_int = ch395f_get_sock_int_status(sock); if (sock_int & CH395F_SINT_STAT_CONNECT) break; } @@ -211,9 +204,9 @@ void ch395f_phase2_tests(void) HAL_Delay(100); - /* 发送测试数据 */ + /* 发送测试数?*/ { - uint8_t test_buf[64]; + uint8_t test_buf[64] = {0}; const char *msg = "HelloFromCH395F_TCP_Client! This is a 64-byte test message."; int p, mlen = (int)strlen(msg); memcpy(test_buf, msg, mlen); @@ -221,15 +214,13 @@ void ch395f_phase2_tests(void) ch395f_write_send_buf(sock, test_buf, 64); } - /* Echo 循环:收数据 → 回发 */ + /* Echo 循环:收数据 ?回发 */ { int got_echo = 0; tick = HAL_GetTick(); - while (HAL_GetTick() - tick < 10000) - { + while (HAL_GetTick() - tick < 10000) { uint16_t rlen = ch395f_get_recv_len(sock); - if (rlen > 0) - { + if (rlen > 0) { uint16_t read_len = (rlen > sizeof(rx_buf)) ? (uint16_t)sizeof(rx_buf) : rlen; memset(rx_buf, 0, sizeof(rx_buf)); ch395f_read_recv_buf(sock, rx_buf, read_len); @@ -239,8 +230,7 @@ void ch395f_phase2_tests(void) break; } int_st = ch395f_get_glob_int_status_all(); - if (int_st & (1U << (sock + 4))) - { + if (int_st & (1U << (sock + 4))) { sock_int = ch395f_get_sock_int_status(sock); if (sock_int & CH395F_SINT_STAT_DISCONNECT) { DBG_INFO("DISCONNECT"); break; } if (sock_int & CH395F_SINT_STAT_SOCK_TIMEOUT) { DBG_INFO("SOCK_TIMEOUT"); break; } @@ -258,8 +248,7 @@ phase2_iter_done: { uint8_t st[2]; uint32_t wait = HAL_GetTick(); - while (HAL_GetTick() - wait < 5000) - { + while (HAL_GetTick() - wait < 5000) { ch395f_get_socket_status(sock, st); if (st[0] == CH395F_SOCKET_CLOSED) break; HAL_Delay(50); @@ -275,21 +264,22 @@ phase2_iter_done: /* * ============================ Phase 3 ============================ - */ + * 函数功能:UDP Server Echo + PING + 大包测试 + * 入口参数:无 + * ??值:? * 限定条件:PC 端已启动 UDP Client(默?192.168.1.2:8082? * 函数说明:包?20 次回显�? ?PING?0 次大包收? */ -void ch395f_phase3_tests(void) -{ - uint8_t sock; - uint8_t rx_buf[300]; - uint32_t tick; - int i; - int echo_ok; +void ch395f_phase3_tests(void) { + uint8_t sock = 0; + uint8_t rx_buf[300] = {0}; + uint32_t tick = 0; + int i = 0; + int echo_ok = 0; DBG_INFO("=== CH395F Phase 3 Tests (UDP) ==="); sock = (uint8_t)(NET_MAX_SOCKETS - 1); - /* UDP Server 模式:DesIP=0xFFFFFFFF → 接受任意来源 */ + /* UDP Server 模式:DesIP=0xFFFFFFFF ?接受任意来源 */ ch395f_set_proto_type(sock, CH395F_PROTO_TYPE_UDP); ch395f_set_send_buf(sock, 28, 2); ch395f_set_recv_buf(sock, 30, 2); @@ -305,16 +295,13 @@ void ch395f_phase3_tests(void) HAL_Delay(200); - /* Echo 循环:收到 → 解析来源 → 回显 */ - for (i = 0; i < PHASE3_ECHO_COUNT; i++) - { + /* Echo 循环:收??解析来源 ?回显 */ + for (i = 0; i < PHASE3_ECHO_COUNT; i++) { tick = HAL_GetTick(); echo_ok = 0; - while (HAL_GetTick() - tick < PHASE3_TIMEOUT_MS) - { + while (HAL_GetTick() - tick < PHASE3_TIMEOUT_MS) { uint16_t rlen = ch395f_get_recv_len(sock); - if (rlen > 8) - { + if (rlen > 8) { memset(rx_buf, 0, sizeof(rx_buf)); ch395f_read_recv_buf(sock, rx_buf, rlen); @@ -334,11 +321,9 @@ void ch395f_phase3_tests(void) { uint32_t swait = HAL_GetTick(); - while (HAL_GetTick() - swait < 2000) - { + while (HAL_GetTick() - swait < 2000) { uint16_t gs = ch395f_get_glob_int_status_all(); - if (gs & (1U << (sock + 4))) - { + if (gs & (1U << (sock + 4))) { if (ch395f_get_sock_int_status(sock) & CH395F_SINT_STAT_SENBUF_FREE) break; } @@ -363,27 +348,28 @@ void ch395f_phase3_tests(void) /* * ============================ Phase 4 ============================ - * NET 层 TCP Echo:在主循环中调用,用 net_recv + net_send 回显 + * NET ?TCP Echo:在主循环中调用,用 net_recv + net_send 回显 */ #ifdef ENABLE_PHASE4_TESTS static char s_phase4_buf[2048]; #endif -void ch395f_phase4_tests(void) -{ +/* + * 函数功能:NET ?TCP Echo 测试 + * 入口参数:无 + * ??值:? * 限定条件:net_init 已完? * 函数说明:在 netTask 中运行,轮询 Socket 1~7 回显接收数据 + */ +void ch395f_phase4_tests(void) { #ifdef ENABLE_PHASE4_TESTS - for (int i = NET_TCP_SERVER_DATA_SOCK_START; i < NET_MAX_SOCKETS; i++) - { + for (int i = NET_TCP_SERVER_DATA_SOCK_START; i < NET_MAX_SOCKETS; i++) { net_sock_t *sk = net_get_sock(i); - if (sk == NULL || !sk->in_use || sk->state != NET_SOCK_STATE_ESTABLISHED) - { + if (sk == NULL || !sk->in_use || sk->state != NET_SOCK_STATE_ESTABLISHED) { continue; } int n = net_recv(i, s_phase4_buf, sizeof(s_phase4_buf), NET_MSG_DONTWAIT); - if (n > 0) - { + if (n > 0) { net_send(i, s_phase4_buf, n, 0); } } @@ -392,7 +378,7 @@ void ch395f_phase4_tests(void) /* * ============================ Phase 5 ============================ - * NET 层 UDP Echo:netTask 中运行,用 net_recvfrom + net_sendto 回显 + * NET ?UDP Echo:netTask 中运行,?net_recvfrom + net_sendto 回显 */ #ifndef PHASE5_LOCAL_PORT @@ -405,14 +391,15 @@ static char s_phase5_buf[2048]; static uint32_t s_phase5_count = 0; #endif -void ch395f_phase5_init(void) -{ +/* + * 函数功能:NET ?UDP Echo 初始? * 入口参数:无 + * ??值:? * 限定条件:net_init 已完? * 函数说明:创?UDP Socket 并绑定本地端? */ +void ch395f_phase5_init(void) { #ifdef ENABLE_PHASE5_TESTS struct net_sockaddr_in addr; s_phase5_sock = net_socket(NET_AF_INET, NET_SOCK_DGRAM, 0); - if (s_phase5_sock < 0) - { + if (s_phase5_sock < 0) { DBG_ERROR("Phase5: net_socket failed"); return; } @@ -421,8 +408,7 @@ void ch395f_phase5_init(void) addr.sin_family = NET_AF_INET; addr.sin_port = net_htons(PHASE5_LOCAL_PORT); - if (net_bind(s_phase5_sock, (struct net_sockaddr *)&addr, sizeof(addr)) < 0) - { + if (net_bind(s_phase5_sock, (struct net_sockaddr *)&addr, sizeof(addr)) < 0) { DBG_ERROR("Phase5: net_bind failed"); net_close(s_phase5_sock); s_phase5_sock = -1; @@ -434,8 +420,12 @@ void ch395f_phase5_init(void) #endif } -void ch395f_phase5_tests(void) -{ +/* + * 函数功能:NET ?UDP Echo 测试 + * 入口参数:无 + * ??值:? * 限定条件:ch395f_phase5_init 已成功调? * 函数说明:在 netTask 中运行,回显 UDP 接收数据 + */ +void ch395f_phase5_tests(void) { #ifdef ENABLE_PHASE5_TESTS if (s_phase5_sock < 0) return; @@ -445,8 +435,7 @@ void ch395f_phase5_tests(void) int n = net_recvfrom(s_phase5_sock, s_phase5_buf, sizeof(s_phase5_buf), NET_MSG_DONTWAIT, (struct net_sockaddr *)&src, &addrlen); - if (n > 0) - { + if (n > 0) { net_sendto(s_phase5_sock, s_phase5_buf, n, 0, (struct net_sockaddr *)&src, sizeof(src)); s_phase5_count++; @@ -456,8 +445,7 @@ void ch395f_phase5_tests(void) } /* - * Phase 6 配置默认值 - */ + * Phase 6 配置默认? */ #ifndef PHASE6_ANNOUNCE_PORT #define PHASE6_ANNOUNCE_PORT 60001 #endif @@ -467,15 +455,17 @@ void ch395f_phase5_tests(void) /* * ============================ Phase 6 ============================ - * DHCP 自动获取 IP 测试 + * 函数功能:DHCP 自动获取 IP 测试 + * 入口参数:无 + * ??值:? * 限定条件:局域网内存?DHCP Server + * 函数说明:启?DHCP ?轮询等待 IP ?打印结果 ?广播宣告 ?HELLO 回显 */ -void ch395f_phase6_tests(void) -{ +void ch395f_phase6_tests(void) { #ifdef ENABLE_PHASE6_TESTS - uint8_t status; - uint8_t ip_info[20]; - uint32_t tick; + uint8_t status = 0; + uint8_t ip_info[20] = {0}; + uint32_t tick = 0; DBG_INFO("=== CH395F Phase 6 Tests (DHCP) ==="); @@ -486,17 +476,14 @@ void ch395f_phase6_tests(void) /* 2. 轮询等待 DHCP 完成 */ HAL_Delay(500); tick = HAL_GetTick(); - while (HAL_GetTick() - tick < 30000) - { + while (HAL_GetTick() - tick < 30000) { uint16_t gint = ch395f_get_glob_int_status_all(); - if (gint & CH395F_GINT_STAT_DHCP) - { + if (gint & CH395F_GINT_STAT_DHCP) { DBG_INFO("DHCP interrupt"); } status = ch395f_get_dhcp_status(); - if (status == 0x00) - { + if (status == 0x00) { TEST_CHECK(1, "DHCP: SUCCESS"); break; } @@ -507,12 +494,11 @@ void ch395f_phase6_tests(void) TEST_CHECK(HAL_GetTick() - tick < 30000, "DHCP completed within 30s (status=0x%02X)", status); - if (HAL_GetTick() - tick >= 30000) - { + if (HAL_GetTick() - tick >= 30000) { goto phase6_end; } - /* 3. 读取获取的 IP */ + /* 3. 读取获取?IP */ ch395f_get_ip_inf(ip_info); DBG_INFO(" IP: %d.%d.%d.%d", ip_info[0], ip_info[1], ip_info[2], ip_info[3]); DBG_INFO(" GW: %d.%d.%d.%d", ip_info[4], ip_info[5], ip_info[6], ip_info[7]); @@ -527,9 +513,9 @@ void ch395f_phase6_tests(void) #define PHASE6_HELLO_PORT 60000 uint8_t anno_sock = PHASE6_ANNOUNCE_SOCK; uint8_t bcast_ip[4] = {0xFF, 0xFF, 0xFF, 0xFF}; - uint8_t rx_buf[64]; + uint8_t rx_buf[64] = {0}; - /* UDP Server 模式:本地端口 60000(接收 HELLO),DesIP=0xFFFFFFFF */ + /* UDP Server 模式:本地端?60000(接?HELLO),DesIP=0xFFFFFFFF */ ch395f_set_proto_type(anno_sock, CH395F_PROTO_TYPE_UDP); ch395f_set_send_buf(anno_sock, 24, 2); ch395f_set_recv_buf(anno_sock, 26, 2); @@ -537,9 +523,8 @@ void ch395f_phase6_tests(void) ch395f_set_des_ip(anno_sock, bcast_ip); ch395f_set_des_port(anno_sock, 0); - if (ch395f_open_socket(anno_sock) == CH395F_ERR_SUCCESS) - { - /* 发送广播宣告(宣告端口 = 60001,来源端口 = 60000) */ + if (ch395f_open_socket(anno_sock) == CH395F_ERR_SUCCESS) { + /* 发送广播宣告(宣告端口 = 60001,来源端?= 60000?*/ ch395f_set_des_ip(anno_sock, bcast_ip); ch395f_set_des_port(anno_sock, PHASE6_ANNOUNCE_PORT); ch395f_write_send_buf(anno_sock, ip_info, 4); @@ -547,11 +532,9 @@ void ch395f_phase6_tests(void) /* 等待 SENDBUF_FREE(手册要求:每次 write_send_buf 后必须等待) */ { uint32_t swait = HAL_GetTick(); - while (HAL_GetTick() - swait < 2000) - { + while (HAL_GetTick() - swait < 2000) { uint16_t gs = ch395f_get_glob_int_status_all(); - if (gs & (1U << (anno_sock + 4))) - { + if (gs & (1U << (anno_sock + 4))) { if (ch395f_get_sock_int_status(anno_sock) & CH395F_SINT_STAT_SENBUF_FREE) break; } @@ -563,26 +546,23 @@ void ch395f_phase6_tests(void) PHASE6_HELLO_PORT, PHASE6_ANNOUNCE_PORT); TEST_CHECK(1, "DHCP announcement sent"); - /* 重置 Server 模式,等待 PC 发送 HELLO */ + /* 重置 Server 模式,等?PC 发�?HELLO */ ch395f_set_des_ip(anno_sock, bcast_ip); ch395f_set_des_port(anno_sock, 0); uint32_t wait = HAL_GetTick(); uint8_t hello_ok = 0; - while (HAL_GetTick() - wait < 5000) - { - /* 读取全局中断(刷新 socket 中断状态) */ + while (HAL_GetTick() - wait < 5000) { + /* 读取全局中断(刷?socket 中断状态) */ ch395f_get_glob_int_status_all(); uint16_t rlen = ch395f_get_recv_len(anno_sock); - if (rlen > 8) - { + if (rlen > 8) { memset(rx_buf, 0, sizeof(rx_buf)); ch395f_read_recv_buf(anno_sock, rx_buf, rlen); uint16_t payload_len = rlen - 8; uint8_t *payload = &rx_buf[8]; - if (payload_len == 5 && memcmp(payload, "HELLO", 5) == 0) - { + if (payload_len == 5 && memcmp(payload, "HELLO", 5) == 0) { uint8_t *src_ip = &rx_buf[4]; uint16_t src_port = (uint16_t)rx_buf[2] | ((uint16_t)rx_buf[3] << 8); ch395f_set_des_ip(anno_sock, src_ip); @@ -601,9 +581,7 @@ void ch395f_phase6_tests(void) TEST_CHECK(hello_ok, "HELLO echo within 5s"); ch395f_close_socket(anno_sock); - } - else - { + } else { TEST_CHECK(0, "DHCP announcement: open socket failed"); } } @@ -615,7 +593,7 @@ phase6_end: /* * ============================ Phase 7 ============================ - * Select/Poll I/O 多路复用测试 — net_select() + net_recv/send echo + * Select/Poll I/O 多路复用测试 ?net_select() + net_recv/send echo */ #include "net_select.h" @@ -624,20 +602,23 @@ phase6_end: static char s_phase7_buf[2048]; #endif -void ch395f_phase7_tests(void) -{ +/* + * 函数功能:Select/Poll I/O 多路复用测试 + * 入口参数:无 + * ??值:? * 限定条件:net_init 已完成,多连?TCP Server 已启? * 函数说明:在 netTask 中运行,验证 select/poll 正确返回读写事件 + */ +void ch395f_phase7_tests(void) { #ifdef ENABLE_PHASE7_TESTS static uint32_t s_phase7_count = 0; net_fd_set readfds; net_timeval tv; + FD_ZERO NET_FD_ZERO(&readfds); - for (int i = NET_TCP_SERVER_DATA_SOCK_START; i < NET_MAX_SOCKETS; i++) - { + for (int i = NET_TCP_SERVER_DATA_SOCK_START; i < NET_MAX_SOCKETS; i++) { net_sock_t *sk = net_get_sock(i); - if (sk && sk->in_use && sk->state == NET_SOCK_STATE_ESTABLISHED) - { + if (sk && sk->in_use && sk->state == NET_SOCK_STATE_ESTABLISHED) { NET_FD_SET(i, &readfds); } } @@ -648,13 +629,11 @@ void ch395f_phase7_tests(void) int n = net_select(NET_MAX_SOCKETS, &readfds, NULL, NULL, &tv); if (n <= 0) return; - for (int i = 0; i < NET_MAX_SOCKETS; i++) - { + for (int i = 0; i < NET_MAX_SOCKETS; i++) { if (!NET_FD_ISSET(i, &readfds)) continue; int len = net_recv(i, s_phase7_buf, sizeof(s_phase7_buf), NET_MSG_DONTWAIT); - if (len > 0) - { + if (len > 0) { net_send(i, s_phase7_buf, len, 0); s_phase7_count++; TEST_CHECK(1, "Phase7: select echo #%lu (sock=%d, %d bytes)", s_phase7_count, i, len); @@ -662,3 +641,4 @@ void ch395f_phase7_tests(void) } #endif } + diff --git a/Drivers/BSP/CH395F/ch395f_test.h b/Drivers/BSP/CH395F/ch395f_test.h index fd9ed16..a1730d4 100644 --- a/Drivers/BSP/CH395F/ch395f_test.h +++ b/Drivers/BSP/CH395F/ch395f_test.h @@ -60,12 +60,12 @@ extern test_stats_t g_test_stats; g_test_stats.failed++; \ DBG_ERROR("[FAIL] " fmt, ##__VA_ARGS__); \ } \ -} while(0) +} while (0) #define TEST_REPORT(name) do { \ DBG_INFO("=== %s: %d/%d PASSED (failed=%d) ===", \ name, g_test_stats.passed, g_test_stats.total, g_test_stats.failed); \ -} while(0) +} while (0) /* * Phase 1: 底层寄存器测试 diff --git a/Drivers/BSP/GD5F2GQ5UE/fal_cfg.h b/Drivers/BSP/GD5F2GQ5UE/fal_cfg.h index c9769b7..38821f0 100644 --- a/Drivers/BSP/GD5F2GQ5UE/fal_cfg.h +++ b/Drivers/BSP/GD5F2GQ5UE/fal_cfg.h @@ -3,34 +3,31 @@ /* * 模块名称:FAL 配置 - * 模块功能:定义 FAL Flash 设备表和分区表 - * 适用平台:STM32F407ZGT6 - * 作者:王建锋 - * 创建日期:2026-07-16 - * 修改记录: - * 2026-07-16 王建锋 创建初始版本 + * 模块功能:定?FAL Flash 设备表和分区? * 适用平台:STM32F407ZGT6 + * 作者:王建? * 创建日期?026-07-16 + * 修改记录? * 2026-07-16 王建? 创建初始版本 */ #ifdef __cplusplus extern "C" { #endif -/* FAL 调试开关:0-关闭,1-开启 */ +/* FAL 调试开关:0-关闭?-开?*/ #define FAL_DEBUG 0 -/* 启用分区表配置 */ +/* 启用分区表配?*/ #define FAL_PART_HAS_TABLE_CFG -/* ======================== Flash 设备表 ======================== */ +/* ======================== Flash 设备?======================== */ -extern const struct fal_flash_dev gd5f2gq5ue_flash; +extern const struct fal_flash_dev g_gd5f2gq5ue_flash; #define FAL_FLASH_DEV_TABLE \ { \ - &gd5f2gq5ue_flash, \ + &g_gd5f2gq5ue_flash, \ } -/* ======================== 分区表 ======================== */ +/* ======================== 分区?======================== */ /* * 分区名称 设备名称 偏移 大小 * KVDB: 64MB @ 0 @@ -49,3 +46,4 @@ extern const struct fal_flash_dev gd5f2gq5ue_flash; #endif #endif /* __FAL_CFG_H */ + diff --git a/Drivers/BSP/GD5F2GQ5UE/fal_flash_gd5f2gq5ue.c b/Drivers/BSP/GD5F2GQ5UE/fal_flash_gd5f2gq5ue.c index cbb93d1..5a086f5 100644 --- a/Drivers/BSP/GD5F2GQ5UE/fal_flash_gd5f2gq5ue.c +++ b/Drivers/BSP/GD5F2GQ5UE/fal_flash_gd5f2gq5ue.c @@ -1,11 +1,9 @@ /* * 模块名称:FAL Flash 设备适配 - * 模块功能:将 GD5F2GQ5UE 驱动接口适配到 FAL 框架 + * 模块功能:将 GD5F2GQ5UE 驱动接口适配?FAL 框架 * 适用平台:STM32F407ZGT6 - * 作者:王建锋 - * 创建日期:2026-07-16 - * 修改记录: - * 2026-07-16 王建锋 创建初始版本 + * 作者:王建? * 创建日期?026-07-16 + * 修改记录? * 2026-07-16 王建? 创建初始版本 */ /* 头文件包含区 */ @@ -17,60 +15,45 @@ /* * 函数功能:Flash 设备初始化适配 * 入口参数:无 - * 返回值:0 - 成功,其他 - 错误码 - * 限定条件:SPI 和 GPIO 已由 CubeMX 初始化完成 - * 函数说明:调用底层驱动的初始化函数 - */ -static int gd5f_fal_init(void) -{ + * 返回值:0 - 成功,其?- 错误? * 限定条件:SPI ?GPIO 已由 CubeMX 初始化完? * 函数说明:调用底层驱动的初始化函? */ +static int gd5f_fal_init(void) { return gd5f2gq5ue_init(); } /* * 函数功能:Flash 读取适配 * 入口参数:offset - 起始字节偏移 long - * p_buf - 数据缓冲区 uint8_t* - * size - 读取字节数 size_t - * 返回值:0 - 成功,其他 - 错误码 - * 限定条件:gd5f_fal_init() 已成功调用 - * 函数说明:直接转发到底层驱动的读取函数 - */ -static int gd5f_fal_read(long offset, uint8_t *p_buf, size_t size) -{ + * p_buf - 数据缓冲? uint8_t* + * size - 读取字节? size_t + * 返回值:0 - 成功,其?- 错误? * 限定条件:gd5f_fal_init() 已成功调? * 函数说明:直接转发到底层驱动的读取函? */ +static int gd5f_fal_read(long offset, uint8_t *p_buf, size_t size) { return gd5f2gq5ue_read(offset, p_buf, size); } /* * 函数功能:Flash 写入适配 * 入口参数:offset - 起始字节偏移 long - * p_buf - 数据缓冲区 const uint8_t* - * size - 写入字节数 size_t - * 返回值:0 - 成功,其他 - 错误码 - * 限定条件:目标区域已擦除 - * 函数说明:直接转发到底层驱动的写入函数 - */ -static int gd5f_fal_write(long offset, const uint8_t *p_buf, size_t size) -{ + * p_buf - 数据缓冲? const uint8_t* + * size - 写入字节? size_t + * 返回值:0 - 成功,其?- 错误? * 限定条件:目标区域已擦除 + * 函数说明:直接转发到底层驱动的写入函? */ +static int gd5f_fal_write(long offset, const uint8_t *p_buf, size_t size) { return gd5f2gq5ue_write(offset, p_buf, size); } /* * 函数功能:Flash 擦除适配 * 入口参数:offset - 起始字节偏移 long - * size - 擦除字节数 size_t - * 返回值:0 - 成功,其他 - 错误码 - * 限定条件:gd5f_fal_init() 已成功调用 - * 函数说明:直接转发到底层驱动的擦除函数 - */ -static int gd5f_fal_erase(long offset, size_t size) -{ + * size - 擦除字节? size_t + * 返回值:0 - 成功,其?- 错误? * 限定条件:gd5f_fal_init() 已成功调? * 函数说明:直接转发到底层驱动的擦除函? */ +static int gd5f_fal_erase(long offset, size_t size) { return gd5f2gq5ue_erase(offset, size); } /* ======================== FAL Flash 设备定义 ======================== */ -/* GD5F2GQ5UE FAL 设备实例,总容量256MB,块大小128KB */ -const struct fal_flash_dev gd5f2gq5ue_flash = { +/* GD5F2GQ5UE FAL 设备实例,总容?56MB,块大小128KB */ +const struct fal_flash_dev g_gd5f2gq5ue_flash = { .name = "gd5f2gq5ue", .addr = 0, .len = GD5F_TOTAL_SIZE, @@ -83,3 +66,4 @@ const struct fal_flash_dev gd5f2gq5ue_flash = { }, .write_gran = 8, }; + diff --git a/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c b/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c index 37c69be..9cec98b 100644 --- a/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c +++ b/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c @@ -1,17 +1,14 @@ /* * 模块名称:GD5F2GQ5UE SPI NAND Flash 驱动 - * 模块功能:提供 GD5F2GQ5UE SPI NAND Flash 的初始化、读、写、擦除接口 - * 适用平台:STM32F407ZGT6 + SPI1 硬件 SPI - * 作者:王建锋 - * 创建日期:2026-07-16 - * 修改记录: - * 2026-07-16 王建锋 创建初始版本 - * 2026-07-17 王建锋 切换硬件 SPI,修正擦除地址,参考 NuttX 驱动 + * 模块功能:提?GD5F2GQ5UE SPI NAND Flash 的初始化、读、写、擦除接? * 适用平台:STM32F407ZGT6 + SPI1 硬件 SPI + * 作者:王建? * 创建日期?026-07-16 + * 修改记录? * 2026-07-16 王建? 创建初始版本 + * 2026-07-17 王建? 切换硬件 SPI,修正擦除地址,参?NuttX 驱动 */ /* 头文件包含区 */ -#include "gd5f2gq5ue.h" #include +#include "gd5f2gq5ue.h" /* * 调试输出配置 @@ -43,12 +40,11 @@ static int gd5f_block_erase(uint32_t block_addr); /* * 函数功能:等待芯片操作完成(轮询 OIP 位) * 入口参数:timeout_ms - 超时时间 uint32_t > 0 - * 返回值:0 - 操作完成,-2 - 超时 + * 返回值:0 - 操作完成?2 - 超时 * 限定条件:SPI 已初始化 * 函数说明:循环读取状态寄存器直到 OIP 位清零或超时 */ -static int gd5f_wait_busy(uint32_t timeout_ms) -{ +static int gd5f_wait_busy(uint32_t timeout_ms) { uint8_t cmd = GD5F_CMD_GET_FEATURE; uint8_t addr = GD5F_REG_STATUS; uint8_t status = 0; @@ -75,10 +71,8 @@ static int gd5f_wait_busy(uint32_t timeout_ms) * 入口参数:无 * 返回值:0 - 成功 * 限定条件:SPI 已初始化 - * 函数说明:CS# 拉低后发送 06h 命令再拉高 - */ -static int gd5f_write_enable(void) -{ + * 函数说明:CS# 拉低后发?06h 命令再拉? */ +static int gd5f_write_enable(void) { uint8_t cmd = GD5F_CMD_WRITE_ENABLE; GD5F_CS_LOW(); @@ -90,13 +84,11 @@ static int gd5f_write_enable(void) /* * 函数功能:读取状态寄存器 - * 入口参数:p_status - 状态值输出指针 uint8_t* 不为 NULL + * 入口参数:p_status - 状态值输出指? uint8_t* 不为 NULL * 返回值:0 - 成功 * 限定条件:SPI 已初始化 - * 函数说明:发送 0Fh + C0h 地址后读取1字节状态值 - */ -static int gd5f_read_status(uint8_t *p_status) -{ + * 函数说明:发?0Fh + C0h 地址后读?字节状态�? */ +static int gd5f_read_status(uint8_t *p_status) { uint8_t cmd = GD5F_CMD_GET_FEATURE; uint8_t addr = GD5F_REG_STATUS; @@ -110,15 +102,12 @@ static int gd5f_read_status(uint8_t *p_status) } /* - * 函数功能:页读取(将数据从存储阵列加载到内部缓存) - * 入口参数:page_addr - 页地址 uint32_t - * 返回值:0 - 成功,其他 - 错误码 - * 限定条件:SPI 已初始化 - * 函数说明:发送 13h + 3字节行地址,等待 OIP 清零 + * 函数功能:页读取(将数据从存储阵列加载到内部缓存? * 入口参数:page_addr - 页地址 uint32_t + * 返回值:0 - 成功,其?- 错误? * 限定条件:SPI 已初始化 + * 函数说明:发?13h + 3字节行地址,等?OIP 清零 */ -static int gd5f_page_read(uint32_t page_addr) -{ - uint8_t cmd[4]; +static int gd5f_page_read(uint32_t page_addr) { + uint8_t cmd[4] = {0}; cmd[0] = GD5F_CMD_PAGE_READ; cmd[1] = (page_addr >> 16) & 0xFF; @@ -135,16 +124,14 @@ static int gd5f_page_read(uint32_t page_addr) /* * 函数功能:从内部缓存读取数据 * 入口参数:column - 列地址(页内偏移) uint16_t 0 - 2047 - * p_buf - 数据输出缓冲区 uint8_t* 不为 NULL - * size - 读取字节数 size_t > 0 + * p_buf - 数据输出缓冲? uint8_t* 不为 NULL + * size - 读取字节? size_t > 0 * 返回值:0 - 成功 * 限定条件:必须先调用 gd5f_page_read 完成数据加载 - * 函数说明:发送 0Bh + 2字节列地址 +1字节 dummy 后读取数据 - */ + * 函数说明:发?0Bh + 2字节列地址 +1字节 dummy 后读取数? */ static int gd5f_read_from_cache(uint16_t column, uint8_t *p_buf, - size_t size) -{ - uint8_t cmd[4]; + size_t size) { + uint8_t cmd[4] = {0}; cmd[0] = GD5F_CMD_READ_FROM_CACHE; cmd[1] = (column >> 8) & 0xFF; @@ -163,16 +150,13 @@ static int gd5f_read_from_cache(uint16_t column, uint8_t *p_buf, * 函数功能:页编程(将数据写入指定页) * 入口参数:page_addr - 页地址 uint32_t * column - 列地址 uint16_t 0 - 2047 - * p_buf - 数据缓冲区 const uint8_t* - * size - 写入字节数 size_t > 0 - * 返回值:0 - 成功,其他 - 错误码 - * 限定条件:目标区域已擦除 - * 函数说明:1. 写使能 - 02h 加载数据 - 10h 执行编程 - 等待完成 - * 2. 编程完成后检查 P_FAIL 位 - */ + * p_buf - 数据缓冲? const uint8_t* + * size - 写入字节? size_t > 0 + * 返回值:0 - 成功,其?- 错误? * 限定条件:目标区域已擦除 + * 函数说明?. 写使?- 02h 加载数据 - 10h 执行编程 - 等待完成 + * 2. 编程完成后检?P_FAIL ? */ static int gd5f_page_program(uint32_t page_addr, uint16_t column, - const uint8_t *p_buf, size_t size) -{ + const uint8_t *p_buf, size_t size) { int ret = GD5F_OK; uint8_t cmd[4]; uint8_t status = 0; @@ -212,15 +196,12 @@ static int gd5f_page_program(uint32_t page_addr, uint16_t column, } /* - * 函数功能:设置 Feature 寄存器 - * 入口参数:addr - 寄存器地址 uint8_t + * 函数功能:设?Feature 寄存? * 入口参数:addr - 寄存器地址 uint8_t * data - 写入数据 uint8_t * 返回值:0 - 成功 * 限定条件:SPI 已初始化 - * 函数说明:先写使能,发送 1Fh + 地址 + 数据,等待操作完成 - */ -static int gd5f_set_feature(uint8_t addr, uint8_t data) -{ + * 函数说明:先写使能,发�?1Fh + 地址 + 数据,等待操作完? */ +static int gd5f_set_feature(uint8_t addr, uint8_t data) { uint8_t cmd[3]; gd5f_write_enable(); @@ -239,15 +220,11 @@ static int gd5f_set_feature(uint8_t addr, uint8_t data) } /* - * 函数功能:块擦除(擦除128KB块) - * 入口参数:block_addr - 块编号 uint32_t 0 - 2047 - * 返回值:0 - 成功,其他 - 错误码 - * 限定条件:gd5f2gq5ue_init() 已调用 - * 函数说明:1. 写使能 - D8h + 3字节字节地址 - 等待完成 - * 2. 擦除完成后检查 E_FAIL 位 - */ -static int gd5f_block_erase(uint32_t block_addr) -{ + * 函数功能:块擦除(擦?28KB块) + * 入口参数:block_addr - 块编? uint32_t 0 - 2047 + * 返回值:0 - 成功,其?- 错误? * 限定条件:gd5f2gq5ue_init() 已调? * 函数说明?. 写使?- D8h + 3字节字节地址 - 等待完成 + * 2. 擦除完成后检?E_FAIL ? */ +static int gd5f_block_erase(uint32_t block_addr) { int ret = GD5F_OK; uint8_t cmd[4]; uint8_t status = 0; @@ -282,15 +259,11 @@ static int gd5f_block_erase(uint32_t block_addr) /* * 函数功能:初始化 GD5F2GQ5UE * 入口参数:无 - * 返回值:0 - 成功,其他 - 错误码 - * 限定条件:SPI1 和相关 GPIO 已由 CubeMX 初始化完成 - * 函数说明:1. 发送复位命令并等待完成 - * 2. 读取芯片 ID 并校验 - * 3. 使能内部 ECC (B0h bit4) + * 返回值:0 - 成功,其?- 错误? * 限定条件:SPI1 和相?GPIO 已由 CubeMX 初始化完? * 函数说明?. 发送复位命令并等待完成 + * 2. 读取芯片 ID 并校? * 3. 使能内部 ECC (B0h bit4) * 4. 解除所有块保护 (A0h = 0x00) */ -int gd5f2gq5ue_init(void) -{ +int gd5f2gq5ue_init(void) { int ret = GD5F_OK; uint8_t mid = 0; uint8_t did = 0; @@ -338,15 +311,13 @@ int gd5f2gq5ue_init(void) } /* - * 函数功能:读取芯片 ID(MID + DID) - * 入口参数:mid - 制造商 ID 输出指针 uint8_t* 不为 NULL + * 函数功能:读取芯?ID(MID + DID? * 入口参数:mid - 制造商 ID 输出指针 uint8_t* 不为 NULL * did - 设备 ID 输出指针 uint8_t* 不为 NULL * 返回值:0 - 成功 * 限定条件:SPI 已初始化 - * 函数说明:发送 9Fh 命令后接收1个 dummy + MID + DID + * 函数说明:发?9Fh 命令后接??dummy + MID + DID */ -int gd5f2gq5ue_read_id(uint8_t *mid, uint8_t *did) -{ +int gd5f2gq5ue_read_id(uint8_t *p_mid, uint8_t *p_did) { uint8_t cmd = GD5F_CMD_READ_ID; uint8_t id_buf[3] = {0}; @@ -355,23 +326,19 @@ int gd5f2gq5ue_read_id(uint8_t *mid, uint8_t *did) HAL_SPI_Receive(&hspi1, id_buf, 3, GD5F_SPI_TIMEOUT); GD5F_CS_HIGH(); - *mid = id_buf[1]; - *did = id_buf[2]; + *p_mid = id_buf[1]; + *p_did = id_buf[2]; return GD5F_OK; } /* * 函数功能:从 NAND 读取数据(支持跨页) - * 入口参数:offset - 起始字节偏移 long 0 ~ 总容量-1 - * p_buf - 数据缓冲区 uint8_t* 不为 NULL - * size - 读取字节数 size_t > 0 - * 返回值:0 - 成功,其他 - 错误码 - * 限定条件:gd5f2gq5ue_init() 已成功调用 - * 函数说明:自动处理跨页读取 - */ -int gd5f2gq5ue_read(long offset, uint8_t *p_buf, size_t size) -{ + * 入口参数:offset - 起始字节偏移 long 0 ~ 总容?1 + * p_buf - 数据缓冲? uint8_t* 不为 NULL + * size - 读取字节? size_t > 0 + * 返回值:0 - 成功,其?- 错误? * 限定条件:gd5f2gq5ue_init() 已成功调? * 函数说明:自动处理跨页读? */ +int gd5f2gq5ue_read(long offset, uint8_t *p_buf, size_t size) { int ret = GD5F_OK; while (size > 0) { @@ -403,15 +370,11 @@ int gd5f2gq5ue_read(long offset, uint8_t *p_buf, size_t size) /* * 函数功能:向 NAND 写入数据(支持跨页) - * 入口参数:offset - 起始字节偏移 long 0 ~ 总容量-1 - * p_buf - 数据缓冲区 const uint8_t* 不为 NULL - * size - 写入字节数 size_t > 0 - * 返回值:0 - 成功,其他 - 错误码 - * 限定条件:gd5f2gq5ue_init() 已成功调用,目标区域已擦除 - * 函数说明:自动处理跨页写入 - */ -int gd5f2gq5ue_write(long offset, const uint8_t *p_buf, size_t size) -{ + * 入口参数:offset - 起始字节偏移 long 0 ~ 总容?1 + * p_buf - 数据缓冲? const uint8_t* 不为 NULL + * size - 写入字节? size_t > 0 + * 返回值:0 - 成功,其?- 错误? * 限定条件:gd5f2gq5ue_init() 已成功调用,目标区域已擦? * 函数说明:自动处理跨页写? */ +int gd5f2gq5ue_write(long offset, const uint8_t *p_buf, size_t size) { int ret = GD5F_OK; while (size > 0) { @@ -437,15 +400,9 @@ int gd5f2gq5ue_write(long offset, const uint8_t *p_buf, size_t size) } /* - * 函数功能:擦除块(按块擦除,最小单位 128KB) - * 入口参数:offset - 起始字节偏移 long 必须块对齐 - * size - 擦除字节数 size_t 必须块大小整数倍 - * 返回值:0 - 成功,其他 - 错误码 - * 限定条件:gd5f2gq5ue_init() 已成功调用 - * 函数说明:擦除操作以块为单位 + * 函数功能:擦除块(按块擦除,最小单?128KB? * 入口参数:offset - 起始字节偏移 long 必须块对? * size - 擦除字节? size_t 必须块大小整数�? * 返回值:0 - 成功,其?- 错误? * 限定条件:gd5f2gq5ue_init() 已成功调? * 函数说明:擦除操作以块为单位 */ -int gd5f2gq5ue_erase(long offset, size_t size) -{ +int gd5f2gq5ue_erase(long offset, size_t size) { int ret = GD5F_OK; if (offset % GD5F_BLOCK_SIZE != 0) { @@ -471,14 +428,12 @@ int gd5f2gq5ue_erase(long offset, size_t size) } /* - * 函数功能:复位芯片 - * 入口参数:无 + * 函数功能:复位芯? * 入口参数:无 * 返回值:0 - 成功 * 限定条件:SPI 已初始化 - * 函数说明:发送 FFh 复位命令后等待 5ms + * 函数说明:发?FFh 复位命令后等?5ms */ -int gd5f2gq5ue_reset(void) -{ +int gd5f2gq5ue_reset(void) { uint8_t cmd = GD5F_CMD_RESET; GD5F_CS_LOW(); @@ -489,3 +444,4 @@ int gd5f2gq5ue_reset(void) return GD5F_OK; } + diff --git a/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h b/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h index 9fdc309..ff9401d 100644 --- a/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h +++ b/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h @@ -101,7 +101,7 @@ int gd5f2gq5ue_init(void); * 限定条件:SPI 已初始化 * 函数说明:发送 9Fh 命令后接收1个 dummy + MID + DID */ -int gd5f2gq5ue_read_id(uint8_t *mid, uint8_t *did); +int gd5f2gq5ue_read_id(uint8_t *p_mid, uint8_t *p_did); /* * 函数功能:从 NAND 读取数据(支持跨页) diff --git a/Drivers/BSP/NET/net_select.c b/Drivers/BSP/NET/net_select.c index 3de27ee..f0c1643 100644 --- a/Drivers/BSP/NET/net_select.c +++ b/Drivers/BSP/NET/net_select.c @@ -1,34 +1,26 @@ /* * 模块名称:Network Select Implementation - * 模块功能:I/O 多路复用实现,包括 select 和 poll 模式, - * 用于同时监控多个 Socket 的读写事件 - * 适用平台:STM32F4 系列(CH395F 以太网芯片) - * 作者:王建锋 - * 创建日期:2026-07-18 - * 修改记录: - */ + * 模块功能:I/O 多路复用实现,包�?select �?poll 模式�? * 用于同时监控多个 Socket 的读写事�? * 适用平台:STM32F4 系列(CH395F 以太网芯片) + * 作者:王建�? * 创建日期�?026-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 模式) - */ + * 函数功能:I/O 多路复用(select 模式�? */ int net_select(int nfds, net_fd_set *readfds, net_fd_set *writefds, - net_fd_set *exceptfds, net_timeval *timeout) -{ + net_fd_set *exceptfds, net_timeval *timeout) { uint32_t start_tick; uint32_t timeout_ms = 0; net_fd_set result_read = {0}; @@ -38,56 +30,46 @@ int net_select(int nfds, net_fd_set *readfds, net_fd_set *writefds, int i; /* 计算超时时间 */ - if (timeout != NULL) - { + if (timeout != NULL) { timeout_ms = (uint32_t)(timeout->tv_sec * 1000) + (uint32_t)(timeout->tv_usec / 1000); } start_tick = HAL_GetTick(); - while (1) - { - /* 轮询所有 Socket */ + 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); + /* 检查哪�?Socket 有事�?*/ + for (i = 0; i < nfds && i < NET_MAX_SOCKETS; i++) { + net_sock_t *p_sock = net_get_sock(i); - if (sock == NULL) - { + if (p_sock == NULL) { continue; } - /* 检查可读事件 */ - if (readfds != NULL && NET_FD_ISSET(i, readfds)) - { - if (check_socket_readable(i)) - { + /* 检查可读事�?*/ + 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)) - { + /* 检查可写事�?*/ + 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)) - { + /* 检查异常事�?*/ + if (exceptfds != NULL && NET_FD_ISSET(i, exceptfds)) { + if (check_socket_error(i)) { NET_FD_SET(i, &result_except); ready_count++; } @@ -95,17 +77,14 @@ int net_select(int nfds, net_fd_set *readfds, net_fd_set *writefds, } /* 有事件就绪,返回 */ - if (ready_count > 0) - { + if (ready_count > 0) { break; } - /* 超时检查 */ - if (timeout != NULL) - { + /* 超时检�?*/ + if (timeout != NULL) { if (timeout_ms > 0 && - (HAL_GetTick() - start_tick) >= timeout_ms) - { + (HAL_GetTick() - start_tick) >= timeout_ms) { break; /* 超时返回 0 */ } } @@ -115,16 +94,13 @@ int net_select(int nfds, net_fd_set *readfds, net_fd_set *writefds, } /* 复制结果 */ - if (readfds != NULL) - { + if (readfds != NULL) { readfds->fd_bits = result_read.fd_bits; } - if (writefds != NULL) - { + if (writefds != NULL) { writefds->fd_bits = result_write.fd_bits; } - if (exceptfds != NULL) - { + if (exceptfds != NULL) { exceptfds->fd_bits = result_except.fd_bits; } @@ -132,95 +108,79 @@ int net_select(int nfds, net_fd_set *readfds, net_fd_set *writefds, } /* - * 函数功能:I/O 多路复用(poll 模式) - */ -int net_poll_events(net_pollfd *fds, int nfds, int timeout) -{ + * 函数功能: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) - { + if (fds == NULL || nfds <= 0) { return -1; } start_tick = HAL_GetTick(); - while (1) - { + while (1) { /* 轮询 */ net_poll(); ready = 0; - for (i = 0; i < nfds; i++) - { + for (i = 0; i < nfds; i++) { fds[i].revents = 0; - /* 检查 fd 有效性 */ - if (fds[i].fd < 0 || fds[i].fd >= NET_MAX_SOCKETS) - { + /* 检�?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); + net_sock_t *p_sock = net_get_sock(fds[i].fd); - if (sock == NULL) - { + if (p_sock == NULL) { fds[i].revents |= NET_POLLNVAL; ready++; continue; } - /* 检查可读 */ - if (fds[i].events & NET_POLLIN) - { - if (check_socket_readable(fds[i].fd)) - { + /* 检查可�?*/ + 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)) - { + /* 检查可�?*/ + 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)) - { + /* 检查错�?*/ + 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) - { + /* 检查挂起(连接断开�?*/ + if (p_sock->state == NET_SOCK_STATE_TCP_ACCEPT || + p_sock->state == NET_SOCK_STATE_CLOSED) { fds[i].revents |= NET_POLLHUP; ready++; } } - if (ready > 0) - { + if (ready > 0) { break; } - /* 超时检查 */ - if (timeout >= 0) - { - if ((HAL_GetTick() - start_tick) >= (uint32_t)timeout) - { + /* 超时检�?*/ + if (timeout >= 0) { + if ((HAL_GetTick() - start_tick) >= (uint32_t)timeout) { break; } } @@ -232,36 +192,29 @@ int net_poll_events(net_pollfd *fds, int nfds, int timeout) } /* - * 私有函数实现区 - */ + * 私有函数实现�? */ /* - * 函数功能:检查 Socket 是否可读 - * 返回值:1 可读,0 不可读 - */ -static int check_socket_readable(int sockfd) -{ - net_sock_t *sock; + * 函数功能:检�?Socket 是否可读 + * 返回值:1 可读�? 不可�? */ +static int check_socket_readable(int sockfd) { + net_sock_t *p_sock; uint16_t recv_len; - sock = net_get_sock(sockfd); - if (sock == NULL) - { + p_sock = net_get_sock(sockfd); + if (p_sock == NULL) { return 0; } - /* 监听 Socket 有新连接时可读 */ - if (sock->state == NET_SOCK_STATE_LISTENING) - { + /* 监听 Socket 有新连接时可�?*/ + if (p_sock->state == NET_SOCK_STATE_LISTENING) { return 1; } - /* 已建立连接的 Socket 有数据可读 */ - if (sock->state == NET_SOCK_STATE_ESTABLISHED) - { + /* 已建立连接的 Socket 有数据可�?*/ + if (p_sock->state == NET_SOCK_STATE_ESTABLISHED) { recv_len = ch395f_get_recv_len(sockfd); - if (recv_len > 0) - { + if (recv_len > 0) { return 1; } } @@ -270,24 +223,19 @@ static int check_socket_readable(int sockfd) } /* - * 函数功能:检查 Socket 是否可写 - * 返回值:1 可写,0 不可写 - */ -static int check_socket_writable(int sockfd) -{ - net_sock_t *sock; + * 函数功能:检�?Socket 是否可写 + * 返回值:1 可写�? 不可�? */ +static int check_socket_writable(int sockfd) { + net_sock_t *p_sock; - sock = net_get_sock(sockfd); - if (sock == NULL) - { + p_sock = net_get_sock(sockfd); + if (p_sock == NULL) { return 0; } - /* 已建立连接的 Socket 发送缓冲区空闲时可写 */ - if (sock->state == NET_SOCK_STATE_ESTABLISHED) - { - if (sock->send_ready) - { + /* 已建立连接的 Socket 发送缓冲区空闲时可�?*/ + if (p_sock->state == NET_SOCK_STATE_ESTABLISHED) { + if (p_sock->send_ready) { return 1; } } @@ -296,22 +244,17 @@ static int check_socket_writable(int sockfd) } /* - * 函数功能:检查 Socket 是否有错误 - * 返回值:1 有错误,0 无错误 - */ -static int check_socket_error(int sockfd) -{ - net_sock_t *sock; + * 函数功能:检�?Socket 是否有错�? * 返回值:1 有错误,0 无错�? */ +static int check_socket_error(int sockfd) { + net_sock_t *p_sock; /* 无效 fd 视为错误 */ - if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) - { + if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) { return 1; } - sock = net_get_sock(sockfd); - if (sock == NULL) - { + p_sock = net_get_sock(sockfd); + if (p_sock == NULL) { return 1; /* 未使用的 Socket 视为错误 */ } diff --git a/Drivers/BSP/NET/net_socket.c b/Drivers/BSP/NET/net_socket.c index 31c5cc6..53c57f3 100644 --- a/Drivers/BSP/NET/net_socket.c +++ b/Drivers/BSP/NET/net_socket.c @@ -1,18 +1,15 @@ /* * 模块名称:Network Socket Core - * 模块功能:BSD Socket API 核心实现,包括 Socket 管理、状态机、 - * 事件处理、数据收发等功能,底层调用 CH395F 驱动 + * 模块功能:BSD Socket API 核心实现,包�?Socket 管理、状态机�? * 事件处理、数据收发等功能,底层调�?CH395F 驱动 * 适用平台:STM32F4 系列(CH395F 以太网芯片) - * 作者:王建锋 - * 创建日期:2026-07-18 - * 修改记录: - */ + * 作者:王建�? * 创建日期�?026-07-18 + * 修改记录�? */ +#include +#include #include "net_socket.h" #include "ch395f.h" #include "main.h" -#include -#include /* * 调试输出配置 @@ -25,49 +22,43 @@ */ /* - * 私有变量区 - */ -static net_sock_t g_net_socks[NET_MAX_SOCKETS]; /* Socket 控制块数组 */ + * 私有变量�? */ +static net_sock_t s_net_socks[NET_MAX_SOCKETS]; /* Socket 控制块数�?*/ static int s_net_errno = 0; /* 最后错误码 */ -static uint8_t s_net_initialized = 0; /* 初始化标志 */ +static uint8_t s_net_initialized = 0; /* 初始化标�?*/ /* * 私有宏定义区 - 补充 */ -#define NET_PHY_CHECK_INTERVAL_MS 5000U /* PHY 状态定期检查间隔(ms) */ +#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 handle_connect_event(net_sock_t *p_sock); +static void handle_disconnect_event(net_sock_t *p_sock); +static void handle_recv_event(net_sock_t *p_sock); +static void handle_send_event(net_sock_t *p_sock); +static void handle_timeout_event(net_sock_t *p_sock); +static void fire_event(net_sock_t *p_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) -{ + * 函数功能:网络子系统初始�? */ +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)); + /* 清零 Socket 控制�?*/ + memset(s_net_socks, 0, sizeof(s_net_socks)); s_net_errno = 0; s_net_initialized = 0; - /* 检测 CH395F 芯片 */ - if (ch395f_check_exist() != CH395F_STATUS_OK) - { + /* 检�?CH395F 芯片 */ + if (ch395f_check_exist() != CH395F_STATUS_OK) { s_net_errno = NET_ERR; return -1; } @@ -75,25 +66,23 @@ int net_init(const char *ip, const char *mask, const char *gateway) /* 复位芯片 */ ch395f_reset(); - /* 启用 TCP Server 多连接模式(bit1=1) - * Socket 0 专职监听,Socket 1~7 自动分配给新连接 */ + /* 启用 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 次 */ + /* 设置 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 次 */ + /* 设置 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) - { + /* 设置网络参数(必须在 INIT_CH395 之前�?*/ + if (ip != NULL) { uint8_t ip_arr[4]; uint8_t mask_arr[4]; uint8_t gw_arr[4]; @@ -105,17 +94,14 @@ int net_init(const char *ip, const char *mask, const char *gateway) ch395f_set_ip_addr(ip_arr); ch395f_set_gwip_addr(gw_arr); ch395f_set_mask_addr(mask_arr); - } - else - { + } else { /* 启用 DHCP */ ch395f_set_dhcp(1); } - /* 初始化 CH395F 协议栈(先不配置 buffer,测试默认值是否工作) */ + /* 初始�?CH395F 协议栈(先不配置 buffer,测试默认值是否工作) */ ret = ch395f_init(); - if (ret != CH395F_STATUS_OK) - { + if (ret != CH395F_STATUS_OK) { s_net_errno = NET_ERR; return -1; } @@ -129,145 +115,113 @@ int net_init(const char *ip, const char *mask, const char *gateway) } /* - * 函数功能:轮询所有 Socket 状态 - */ -int net_poll(void) -{ + * 函数功能:轮询所�?Socket 状�? */ +int net_poll(void) { int event_count = 0; int i; uint16_t int_status; - if (!s_net_initialized) - { + if (!s_net_initialized) { return 0; } /* - * GPIO 轮询模式:仅在 INT# 有效(低电平)时读取中断状态 - * 读取 GET_GLOB_INT_STATUS_ALL 后 CH395F 拉高 INT#,若仍有中断则再次拉低 - */ + * GPIO 轮询模式:仅�?INT# 有效(低电平)时读取中断状�? * 读取 GET_GLOB_INT_STATUS_ALL �?CH395F 拉高 INT#,若仍有中断则再次拉�? */ do { - if (HAL_GPIO_ReadPin(CH395_INT_GPIO_Port, CH395_INT_Pin) == GPIO_PIN_SET) - { + 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) - { + if (int_status == 0) { break; } - /* 诊断:每 3 秒打印一次全局中断状态位和 Socket 状态 - * 注意:不要在此处读取 per-socket 中断状态(ch395f_get_sock_int_status - * 会清除中断标志),避免破坏后续正常处理流程 */ + /* 诊断:每 3 秒打印一次全局中断状态和 Socket 状�? * 注意:使用已读取的 int_status,不要再读 GINT(读即清除�?*/ static uint32_t s_last_diag = 0; uint32_t now_diag = HAL_GetTick(); - if ((now_diag - s_last_diag >= 3000) || s_last_diag == 0) - { + 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); + DBG_INFO("GINT=0x%04X", int_status); + for (int di = 0; di < NET_MAX_SOCKETS; di++) { + DBG_INFO(" s%d: in_use=%d state=%d", + di, s_net_socks[di].in_use, s_net_socks[di].state); } } - if (int_status & CH395F_GINT_STAT_PHY_CHANGE) - { + 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) - { + 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]; + for (i = 0; i < NET_MAX_SOCKETS; i++) { + net_sock_t *p_sock = &s_net_socks[i]; - /* 检查该 Socket 是否有中断(全局中断状态 bit4~bit11 对应 socket0~7) */ - if (!(int_status & (1U << (i + 4)))) - { + /* 检查该 Socket 是否有中断(全局中断状�?bit4~bit11 对应 socket0~7�?*/ + if (!(int_status & (1U << (i + 4)))) { continue; } - /* 读取 Socket 中断状态 */ + /* 读取 Socket 中断状�?*/ uint8_t sock_int = ch395f_get_sock_int_status(i); /* 连接事件 */ - if (sock_int & CH395F_SINT_STAT_CONNECT) - { - handle_connect_event(sock); + if (sock_int & CH395F_SINT_STAT_CONNECT) { + handle_connect_event(p_sock); event_count++; } /* 断开事件 */ - if (sock_int & CH395F_SINT_STAT_DISCONNECT) - { - handle_disconnect_event(sock); + if (sock_int & CH395F_SINT_STAT_DISCONNECT) { + handle_disconnect_event(p_sock); event_count++; } /* 数据接收事件 */ - if (sock_int & CH395F_SINT_STAT_RECV_OK) - { - handle_recv_event(sock); + if (sock_int & CH395F_SINT_STAT_RECV_OK) { + handle_recv_event(p_sock); event_count++; } - /* 发送完成事件 */ - if (sock_int & CH395F_SINT_STAT_SEND_OK) - { - handle_send_event(sock); + /* 发送完成事�?*/ + if (sock_int & CH395F_SINT_STAT_SEND_OK) { + handle_send_event(p_sock); event_count++; } /* 发送缓冲区空闲 */ - if (sock_int & CH395F_SINT_STAT_SENBUF_FREE) - { - sock->send_ready = 1; + if (sock_int & CH395F_SINT_STAT_SENBUF_FREE) { + p_sock->send_ready = 1; } /* 超时事件 */ - if (sock_int & CH395F_SINT_STAT_SOCK_TIMEOUT) - { - handle_timeout_event(sock); + if (sock_int & CH395F_SINT_STAT_SOCK_TIMEOUT) { + handle_timeout_event(p_sock); event_count++; } } /* - * 处理完毕后检查 INT# 是否仍为低电平 - * 如果是,说明在处理期间有新中断产生,需要再次读取 - * - * 注意:CH395F 的 RECV 中断是电平触发的(只要接收缓冲区有数据就保持低电平), - * 如果不跳出循环,net_poll() 会无限循环处理 RECV 中断, - * 导致主循环中的应用代码(如 echo)永远无法执行。 - * 因此每次 net_poll() 调用只处理一批中断,由主循环负责读取数据。 - */ + * 处理完毕后检�?INT# 是否仍为低电�? * 如果是,说明在处理期间有新中断产生,需要再次读�? * + * 注意:CH395F �?RECV 中断是电平触发的(只要接收缓冲区有数据就保持低电平)�? * 如果不跳出循环,net_poll() 会无限循环处�?RECV 中断�? * 导致主循环中的应用代码(�?echo)永远无法执行�? * 因此每次 net_poll() 调用只处理一批中断,由主循环负责读取数据�? */ } while (0); - /* 每 2 秒打印一次诊断信息(调试用) */ + /* �?2 秒打印一次诊断信息(调试用) */ { static uint32_t s_last_dbg = 0; uint32_t now = HAL_GetTick(); - if (now - s_last_dbg >= 2000) - { + 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) - { + for (i = 0; i < NET_MAX_SOCKETS; i++) { + if (s_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); @@ -281,87 +235,77 @@ int net_poll(void) } /* - * 函数功能:创建 socket + * 函数功能:创�?socket */ -int net_socket(int domain, int type, int protocol) -{ +int net_socket(int domain, int type, int protocol) { int sockfd; - net_sock_t *sock; + net_sock_t *p_sock; - /* 参数检查 */ - if (domain != NET_AF_INET) - { + /* 参数检�?*/ + if (domain != NET_AF_INET) { s_net_errno = NET_ERR_INVAL; return -1; } /* 分配空闲 Socket */ sockfd = alloc_socket(); - if (sockfd < 0) - { + 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; + p_sock = &s_net_socks[sockfd]; + p_sock->ch395_sock = (uint8_t)sockfd; + p_sock->type = (uint8_t)type; + p_sock->state = NET_SOCK_STATE_CREATED; + p_sock->in_use = 1; + p_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; + * 函数功能:绑定本地地址和端�? */ +int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen) { + net_sock_t *p_sock; + const struct net_sockaddr_in *p_addr_in; - /* 参数检查 */ - if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) - { + /* 参数检�?*/ + if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) { s_net_errno = NET_ERR_BADF; return -1; } - sock = &g_net_socks[sockfd]; - if (!sock->in_use) - { + p_sock = &s_net_socks[sockfd]; + if (!p_sock->in_use) { s_net_errno = NET_ERR_BADF; return -1; } - if (addr == NULL || addrlen < (int)sizeof(struct net_sockaddr_in)) - { + 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; + p_addr_in = (const struct net_sockaddr_in *)addr; /* 设置本地端口(转换为主机序) */ - sock->local_port = net_ntohs(addr_in->sin_port); + p_sock->local_port = net_ntohs(p_addr_in->sin_port); /* UDP (SOCK_DGRAM): 直接在此打开 CH395F Socket */ - if (sock->type == NET_SOCK_DGRAM) - { + if (p_sock->type == NET_SOCK_DGRAM) { uint8_t status; /* Socket 4-7 默认无收发缓冲,需显式分配 */ - if (sockfd >= 4) - { + 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); + ch395f_set_sour_port((uint8_t)sockfd, p_sock->local_port); - /* DesIP=0xFFFFFFFF → UDP Server 模式(接受任意来源) */ + /* DesIP=0xFFFFFFFF �?UDP Server 模式(接受任意来源) */ { uint8_t broadcast[4] = {0xFF, 0xFF, 0xFF, 0xFF}; ch395f_set_des_ip((uint8_t)sockfd, broadcast); @@ -369,17 +313,14 @@ 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) - { + 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; + p_sock->state = NET_SOCK_STATE_UDP_OPEN; + } else { + p_sock->state = NET_SOCK_STATE_BOUND; } return 0; @@ -388,55 +329,52 @@ int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen) /* * 函数功能:TCP Server 监听 */ -int net_listen(int sockfd, int backlog) -{ - net_sock_t *sock; +int net_listen(int sockfd, int backlog) { + net_sock_t *p_sock; uint8_t status; - /* 参数检查 */ - if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) - { + /* 参数检�?*/ + 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) - { + 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; } - if (sock->state != NET_SOCK_STATE_BOUND && - sock->state != NET_SOCK_STATE_CREATED) - { + if (p_sock->state != NET_SOCK_STATE_BOUND && + p_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++) - { + /* 多连接模式:先为数据 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 手册 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; } - /* 最后配置监听 Socket 并启动监听 */ + /* 最后配置监�?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); + ch395f_set_sour_port(sockfd, p_sock->local_port); status = ch395f_open_socket(sockfd); - if (status != CH395F_ERR_SUCCESS) - { + if (status != CH395F_ERR_SUCCESS) { s_net_errno = NET_ERR_BUSY; return -1; } @@ -444,7 +382,12 @@ int net_listen(int sockfd, int backlog) /* 启动 TCP 监听 */ ch395f_tcp_listen(sockfd); - sock->state = NET_SOCK_STATE_LISTENING; + p_sock->state = NET_SOCK_STATE_LISTENING; + + for (int j = 0; j < NET_MAX_SOCKETS; j++) { + (void)ch395f_get_sock_int_status((uint8_t)j); + } + (void)ch395f_get_glob_int_status_all(); return 0; } @@ -452,21 +395,18 @@ int net_listen(int sockfd, int backlog) /* * 函数功能:TCP Server 接受连接 */ -int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen) -{ - net_sock_t *listen_sock; +int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen) { + net_sock_t *p_listen_sock; int i; - /* 参数检查 */ - if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) - { + /* 参数检�?*/ + 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) - { + 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; } @@ -474,20 +414,17 @@ int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen) /* 轮询查找已建立连接的数据 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]; + 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 (data_cb->state == NET_SOCK_STATE_ESTABLISHED) - { + if (p_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; + 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_data_cb->remote_port); + p_addr_in->sin_addr.s_addr = p_data_cb->remote_ip; *addrlen = sizeof(struct net_sockaddr_in); } @@ -495,7 +432,7 @@ int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen) } } - /* 没有新连接 */ + /* 没有新连�?*/ s_net_errno = NET_ERR_WOULDBLOCK; return -1; } @@ -503,111 +440,97 @@ int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen) /* * 函数功能: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; +int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen) { + net_sock_t *p_sock; + const struct net_sockaddr_in *p_addr_in; uint8_t status; - /* 参数检查 */ - if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) - { + /* 参数检�?*/ + 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) - { + 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; } - if (addr == NULL || addrlen < (int)sizeof(struct net_sockaddr_in)) - { + 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; + p_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); + p_sock->remote_ip = p_addr_in->sin_addr.s_addr; + p_sock->remote_port = net_ntohs(p_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); + p_sock->remote_ip_arr[0] = (uint8_t)(p_sock->remote_ip); + p_sock->remote_ip_arr[1] = (uint8_t)(p_sock->remote_ip >> 8); + p_sock->remote_ip_arr[2] = (uint8_t)(p_sock->remote_ip >> 16); + p_sock->remote_ip_arr[3] = (uint8_t)(p_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); + ch395f_set_sour_port(sockfd, p_sock->local_port); + ch395f_set_des_ip(sockfd, p_sock->remote_ip_arr); + ch395f_set_des_port(sockfd, p_sock->remote_port); status = ch395f_open_socket(sockfd); - if (status != CH395F_ERR_SUCCESS) - { + if (status != CH395F_ERR_SUCCESS) { s_net_errno = NET_ERR_BUSY; return -1; } /* 发起 TCP 连接 */ ch395f_tcp_connect(sockfd); - sock->state = NET_SOCK_STATE_CONNECTING; + p_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; + * 函数功能:发送数据(TCP�? */ +int net_send(int sockfd, const void *buf, int len, int flags) { + net_sock_t *p_sock; int sent = 0; uint32_t tick_start; - /* 参数检查 */ - if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) - { + /* 参数检�?*/ + 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) - { + p_sock = &s_net_socks[sockfd]; + if (!p_sock->in_use || p_sock->state != NET_SOCK_STATE_ESTABLISHED) { s_net_errno = NET_ERR_NOTCONN; return -1; } - if (buf == NULL || len <= 0) - { + if (buf == NULL || len <= 0) { s_net_errno = NET_ERR_INVAL; return -1; } tick_start = HAL_GetTick(); - /* 分块发送 */ - while (sent < len) - { + /* 分块发�?*/ + while (sent < len) { int chunk = len - sent; - if (chunk > NET_SEND_BUF_SIZE) - { + if (chunk > NET_SEND_BUF_SIZE) { chunk = NET_SEND_BUF_SIZE; } /* 检查发送缓冲区是否空闲 */ - if (!sock->send_ready) - { - /* 超时检查 */ + if (!p_sock->send_ready) { + /* 超时检�?*/ if (NET_SEND_TIMEOUT_MS > 0 && - (HAL_GetTick() - tick_start) >= NET_SEND_TIMEOUT_MS) - { + (HAL_GetTick() - tick_start) >= NET_SEND_TIMEOUT_MS) { s_net_errno = NET_ERR_TIMEDOUT; break; } @@ -617,18 +540,16 @@ int net_send(int sockfd, const void *buf, int len, int flags) } ch395f_write_send_buf(sockfd, (uint8_t *)buf + sent, (uint16_t)chunk); - sock->send_ready = 0; + p_sock->send_ready = 0; sent += chunk; - sock->send_bytes += (uint32_t)chunk; + p_sock->send_bytes += (uint32_t)chunk; - /* 短暂延时等待发送完成 */ + /* 短暂延时等待发送完�?*/ tick_start = HAL_GetTick(); - while (!sock->send_ready) - { + while (!p_sock->send_ready) { net_poll(); if (NET_SEND_TIMEOUT_MS > 0 && - (HAL_GetTick() - tick_start) >= NET_SEND_TIMEOUT_MS) - { + (HAL_GetTick() - tick_start) >= NET_SEND_TIMEOUT_MS) { break; } } @@ -638,146 +559,126 @@ int net_send(int sockfd, const void *buf, int len, int flags) } /* - * 函数功能:接收数据(TCP) - */ -int net_recv(int sockfd, void *buf, int len, int flags) -{ - net_sock_t *sock; + * 函数功能:接收数据(TCP�? */ +int net_recv(int sockfd, void *buf, int len, int flags) { + net_sock_t *p_sock; uint16_t recv_len; uint32_t tick_start; - /* 参数检查 */ - if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) - { + /* 参数检�?*/ + if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) { s_net_errno = NET_ERR_BADF; return -1; } - sock = &g_net_socks[sockfd]; - if (!sock->in_use) - { + p_sock = &s_net_socks[sockfd]; + if (!p_sock->in_use) { s_net_errno = NET_ERR_BADF; return -1; } - /* 检查连接状态 */ - if (sock->type == NET_SOCK_STREAM && - sock->state != NET_SOCK_STATE_ESTABLISHED) - { + /* 检查连接状�?*/ + if (p_sock->type == NET_SOCK_STREAM && + p_sock->state != NET_SOCK_STATE_ESTABLISHED) { s_net_errno = NET_ERR_NOTCONN; return -1; } - if (buf == NULL || len <= 0) - { + if (buf == NULL || len <= 0) { s_net_errno = NET_ERR_INVAL; return -1; } tick_start = HAL_GetTick(); - while (1) - { + while (1) { net_poll(); recv_len = ch395f_get_recv_len(sockfd); - if (recv_len > 0) - { - /* 有数据可读 */ + 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; + p_sock->recv_bytes += (uint32_t)read_len; return read_len; } - /* 非阻塞模式检查 */ - if (flags & NET_MSG_DONTWAIT) - { + /* 非阻塞模式检�?*/ + 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) - { + (HAL_GetTick() - tick_start) >= NET_RECV_TIMEOUT_MS) { s_net_errno = NET_ERR_TIMEDOUT; return -1; } - /* 连接已断开检查 */ - if (sock->state == NET_SOCK_STATE_TCP_ACCEPT) - { + /* 连接已断开检�?*/ + if (p_sock->state == NET_SOCK_STATE_TCP_ACCEPT) { return 0; /* 对端关闭 */ } } } /* - * 函数功能:发送 UDP 数据 + * 函数功能:发�?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; + const struct net_sockaddr *dest_addr, int addrlen) { + net_sock_t *p_sock; + const struct net_sockaddr_in *p_addr_in; int sent = 0; uint32_t tick_start; - /* 参数检查 */ - if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) - { + /* 参数检�?*/ + if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) { s_net_errno = NET_ERR_BADF; return -1; } - sock = &g_net_socks[sockfd]; - if (!sock->in_use) - { + p_sock = &s_net_socks[sockfd]; + if (!p_sock->in_use) { s_net_errno = NET_ERR_BADF; return -1; } - if (buf == NULL || len <= 0) - { + 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; + if (dest_addr != NULL && addrlen >= (int)sizeof(struct net_sockaddr_in)) { + p_addr_in = (const struct net_sockaddr_in *)dest_addr; - /* 转换 IP 为数组格式 */ + /* 转换 IP 为数组格�?*/ uint8_t ip_arr[4]; - uint32_t ip = addr_in->sin_addr.s_addr; + uint32_t ip = p_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)); + ch395f_set_des_port(sockfd, net_ntohs(p_addr_in->sin_port)); } tick_start = HAL_GetTick(); - /* 发送数据 */ - while (sent < len) - { + /* 发送数�?*/ + while (sent < len) { int chunk = len - sent; - if (chunk > NET_SEND_BUF_SIZE) - { + if (chunk > NET_SEND_BUF_SIZE) { chunk = NET_SEND_BUF_SIZE; } /* 检查发送缓冲区 */ - if (!sock->send_ready) - { + if (!p_sock->send_ready) { if (NET_SEND_TIMEOUT_MS > 0 && - (HAL_GetTick() - tick_start) >= NET_SEND_TIMEOUT_MS) - { + (HAL_GetTick() - tick_start) >= NET_SEND_TIMEOUT_MS) { s_net_errno = NET_ERR_TIMEDOUT; break; } @@ -786,18 +687,16 @@ int net_sendto(int sockfd, const void *buf, int len, int flags, } ch395f_write_send_buf(sockfd, (uint8_t *)buf + sent, (uint16_t)chunk); - sock->send_ready = 0; + p_sock->send_ready = 0; sent += chunk; - sock->send_bytes += (uint32_t)chunk; + p_sock->send_bytes += (uint32_t)chunk; - /* 等待发送完成 */ + /* 等待发送完�?*/ tick_start = HAL_GetTick(); - while (!sock->send_ready) - { + while (!p_sock->send_ready) { net_poll(); if (NET_SEND_TIMEOUT_MS > 0 && - (HAL_GetTick() - tick_start) >= NET_SEND_TIMEOUT_MS) - { + (HAL_GetTick() - tick_start) >= NET_SEND_TIMEOUT_MS) { break; } } @@ -807,60 +706,52 @@ int net_sendto(int sockfd, const void *buf, int len, int flags, } /* - * 函数功能:接收 UDP 数据 + * 函数功能:接�?UDP 数据 */ int net_recvfrom(int sockfd, void *buf, int len, int flags, - struct net_sockaddr *src_addr, int *addrlen) -{ - net_sock_t *sock; + struct net_sockaddr *src_addr, int *addrlen) { + net_sock_t *p_sock; uint16_t recv_len; uint32_t tick_start; - /* 参数检查 */ - if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) - { + /* 参数检�?*/ + if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) { s_net_errno = NET_ERR_BADF; return -1; } - sock = &g_net_socks[sockfd]; - if (!sock->in_use) - { + p_sock = &s_net_socks[sockfd]; + if (!p_sock->in_use) { s_net_errno = NET_ERR_BADF; return -1; } - if (buf == NULL || len <= 0) - { + if (buf == NULL || len <= 0) { s_net_errno = NET_ERR_INVAL; return -1; } tick_start = HAL_GetTick(); - while (1) - { + 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) - { + if (recv_len > 0) { + /* UDP Server 模式:前 8 字节为固定格式(IP + 端口 + 长度�?*/ + if (p_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]) | + *addrlen >= (int)sizeof(struct net_sockaddr_in)) { + struct net_sockaddr_in *p_addr_in = (struct net_sockaddr_in *)src_addr; + p_addr_in->sin_family = NET_AF_INET; + /* CH395F UDP �? [0-1] reserved [2-3] src_port(LE) [4-7] src_ip */ + p_addr_in->sin_port = net_htons((uint16_t)(header[2] | (header[3] << 8))); + p_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); @@ -869,26 +760,23 @@ int net_recvfrom(int sockfd, void *buf, int len, int flags, } /* 读取数据 */ - if (recv_len > 0) - { + 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; + p_sock->recv_bytes += (uint32_t)read_len; return read_len; } } - /* 非阻塞模式检查 */ - if (flags & NET_MSG_DONTWAIT) - { + /* 非阻塞模式检�?*/ + 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) - { + (HAL_GetTick() - tick_start) >= NET_RECV_TIMEOUT_MS) { s_net_errno = NET_ERR_TIMEDOUT; return -1; } @@ -896,22 +784,19 @@ int net_recvfrom(int sockfd, void *buf, int len, int flags, } /* - * 函数功能:关闭 socket + * 函数功能:关�?socket */ -int net_close(int sockfd) -{ - net_sock_t *sock; +int net_close(int sockfd) { + net_sock_t *p_sock; - /* 参数检查 */ - if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) - { + /* 参数检�?*/ + if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) { s_net_errno = NET_ERR_BADF; return -1; } - sock = &g_net_socks[sockfd]; - if (!sock->in_use) - { + p_sock = &s_net_socks[sockfd]; + if (!p_sock->in_use) { s_net_errno = NET_ERR_BADF; return -1; } @@ -919,72 +804,62 @@ int net_close(int sockfd) /* 关闭 CH395F Socket */ ch395f_close_socket(sockfd); - /* 清零控制块 */ - memset(sock, 0, sizeof(net_sock_t)); + /* 清零控制�?*/ + memset(p_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; + * 函数功能:注册事件回�? */ +int net_set_event_cb(int sockfd, net_event_cb_t cb, void *arg) { + net_sock_t *p_sock; - /* 参数检查 */ - if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) - { + /* 参数检�?*/ + if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) { s_net_errno = NET_ERR_BADF; return -1; } - sock = &g_net_socks[sockfd]; - if (!sock->in_use) - { + p_sock = &s_net_socks[sockfd]; + if (!p_sock->in_use) { s_net_errno = NET_ERR_BADF; return -1; } - sock->event_cb = cb; - sock->event_arg = arg; + p_sock->event_cb = cb; + p_sock->event_arg = arg; return 0; } /* - * 函数功能:获取 socket 最后错误码 + * 函数功能:获�?socket 最后错误码 */ -int net_get_errno(void) -{ +int net_get_errno(void) { return s_net_errno; } /* * 函数功能:将 IP 地址字符串转为网络字节序 */ -uint32_t net_inet_addr(const char *cp) -{ +uint32_t net_inet_addr(const char *cp) { uint32_t addr = 0; uint32_t val; int i; - if (cp == NULL) - { + if (cp == NULL) { return 0; } - for (i = 0; i < 4; i++) - { + for (i = 0; i < 4; i++) { val = 0; - while (*cp >= '0' && *cp <= '9') - { + while (*cp >= '0' && *cp <= '9') { val = val * 10 + (*cp - '0'); cp++; } addr |= (val << (i * 8)); - if (*cp == '.') - { + if (*cp == '.') { cp++; } } @@ -993,14 +868,11 @@ uint32_t net_inet_addr(const char *cp) } /* - * 函数功能:将网络字节序 IP 转为字符串 - */ -char *net_inet_ntoa(uint32_t addr, char *buf) -{ + * 函数功能:将网络字节�?IP 转为字符�? */ +char *net_inet_ntoa(uint32_t addr, char *buf) { uint32_t naddr = NET_ntohl(addr); - if (buf == NULL) - { + if (buf == NULL) { return NULL; } @@ -1016,51 +888,43 @@ char *net_inet_ntoa(uint32_t addr, char *buf) /* * 函数功能:端口字节序转换(主机序 -> 网络序) */ -uint16_t net_htons(uint16_t hostshort) -{ +uint16_t net_htons(uint16_t hostshort) { return NET_htons(hostshort); } /* * 函数功能:端口字节序转换(网络序 -> 主机序) */ -uint16_t net_ntohs(uint16_t netshort) -{ +uint16_t net_ntohs(uint16_t netshort) { return NET_ntohs(netshort); } /* - * 函数功能:IP 地址字节序转换(主机序 -> 网络序) + * 函数功能:IP 地址字节序转换(主机�?-> 网络序) */ -uint32_t net_htonl(uint32_t hostlong) -{ +uint32_t net_htonl(uint32_t hostlong) { return NET_htonl(hostlong); } /* - * 函数功能:IP 地址字节序转换(网络序 -> 主机序) + * 函数功能:IP 地址字节序转换(网络�?-> 主机序) */ -uint32_t net_ntohl(uint32_t netlong) -{ +uint32_t net_ntohl(uint32_t netlong) { return NET_ntohl(netlong); } /* - * 私有函数实现区 - */ + * 私有函数实现�? */ /* - * 函数功能:分配空闲 Socket - * 返回值:Socket 索引,失败返回 -1 + * 函数功能:分配空�?Socket + * 返回值:Socket 索引,失败返�?-1 */ -static int alloc_socket(void) -{ +static int alloc_socket(void) { int i; - for (i = 0; i < NET_MAX_SOCKETS; i++) - { - if (!g_net_socks[i].in_use) - { + for (i = 0; i < NET_MAX_SOCKETS; i++) { + if (!s_net_socks[i].in_use) { return i; } } @@ -1069,211 +933,179 @@ static int alloc_socket(void) } /* - * 函数功能:处理连接事件 - */ -static void handle_connect_event(net_sock_t *sock) -{ - if (sock->state == NET_SOCK_STATE_LISTENING) - { + * 函数功能:处理连接事�? */ +static void handle_connect_event(net_sock_t *p_sock) { + if (p_sock->state == NET_SOCK_STATE_LISTENING) { /* 多连接模式:监听 Socket 收到 CONNECT 中断 = 有新连接被分配到数据 Socket - * Socket 0 自身保持 LISTENING,不需要改变状态 */ - fire_event(sock, NET_EVENT_CONNECTED); + * Socket 0 自身保持 LISTENING,不需要改变状�?*/ + fire_event(p_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); + else if (!p_sock->in_use) { + /* CH395F 自动打开的数�?Socket(多连接模式),首次收到 CONNECT 中断 */ + int sock_idx = (int)(p_sock - s_net_socks); + p_sock->ch395_sock = (uint8_t)sock_idx; + DBG_INFO("sock%d AUTO-OPENED, CONNECTED", p_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]) | + ch395f_get_remot_ipp(p_sock->ch395_sock, remote); + memcpy(p_sock->remote_ip_arr, remote, 4); + p_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; + p_sock->remote_port = (uint16_t)(remote[4] | (remote[5] << 8)); + p_sock->in_use = 1; + p_sock->state = NET_SOCK_STATE_ESTABLISHED; + p_sock->send_ready = 1; - ch395f_set_keepalive_enable(sock->ch395_sock, 1); + ch395f_set_keepalive_enable(p_sock->ch395_sock, 1); - fire_event(sock, NET_EVENT_CONNECTED); + fire_event(p_sock, NET_EVENT_CONNECTED); } - else if (sock->state == NET_SOCK_STATE_CONNECTING) - { + else if (p_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]) | + ch395f_get_remot_ipp(p_sock->ch395_sock, remote); + memcpy(p_sock->remote_ip_arr, remote, 4); + p_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; + p_sock->remote_port = (uint16_t)(remote[4] | (remote[5] << 8)); + p_sock->state = NET_SOCK_STATE_ESTABLISHED; - ch395f_set_keepalive_enable(sock->ch395_sock, 1); + ch395f_set_keepalive_enable(p_sock->ch395_sock, 1); - fire_event(sock, NET_EVENT_CONNECTED); + fire_event(p_sock, NET_EVENT_CONNECTED); } - else if (sock->state == NET_SOCK_STATE_TCP_ACCEPT) - { + else if (p_sock->state == NET_SOCK_STATE_TCP_ACCEPT) { /* 数据 Socket 被分配了连接 */ - DBG_INFO("data sock%d TCP_ACCEPT -> CONNECTED", sock->ch395_sock); + DBG_INFO("data sock%d TCP_ACCEPT -> CONNECTED", p_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]) | + ch395f_get_remot_ipp(p_sock->ch395_sock, remote); + memcpy(p_sock->remote_ip_arr, remote, 4); + p_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; + p_sock->remote_port = (uint16_t)(remote[4] | (remote[5] << 8)); + p_sock->state = NET_SOCK_STATE_ESTABLISHED; + p_sock->send_ready = 1; - ch395f_set_keepalive_enable(sock->ch395_sock, 1); + ch395f_set_keepalive_enable(p_sock->ch395_sock, 1); - fire_event(sock, NET_EVENT_CONNECTED); + fire_event(p_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); + * 函数说明:CH395F �?DISCONNECT 中断后自动关�?Socket(默�?FUN_PARA_FLAG_SOCKET_CLOSE=0), + * 必须重新 OPEN_SOCKET + TCP_LISTEN 才能接受新连�? */ +static void handle_disconnect_event(net_sock_t *p_sock) { + if (p_sock->state == NET_SOCK_STATE_LISTENING) { + DBG_ERROR("WARNING: listen sock%d got disconnect", p_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 - { + else if (p_sock->state == NET_SOCK_STATE_ESTABLISHED) { + /* CH395F 自动关闭�?Socket,恢复为未使用状�?*/ + DBG_INFO("sock%d DISCONNECTED, back to idle", p_sock->ch395_sock); + memset(p_sock->remote_ip_arr, 0, 4); + p_sock->remote_port = 0; + p_sock->send_ready = 1; + p_sock->state = NET_SOCK_STATE_TCP_ACCEPT; + fire_event(p_sock, NET_EVENT_DISCONNECTED); + } else if (p_sock->state == NET_SOCK_STATE_TCP_ACCEPT) { + memset(p_sock->remote_ip_arr, 0, 4); + p_sock->remote_port = 0; + p_sock->send_ready = 1; + } else { /* 未预期的断开 */ - DBG_ERROR("sock%d disconnect in state %d", sock->ch395_sock, sock->state); - fire_event(sock, NET_EVENT_DISCONNECTED); + DBG_ERROR("sock%d disconnect in state %d", p_sock->ch395_sock, p_sock->state); + fire_event(p_sock, NET_EVENT_DISCONNECTED); } } /* - * 函数功能:处理数据接收事件 - */ -static void handle_recv_event(net_sock_t *sock) -{ - uint16_t recv_len = ch395f_get_recv_len(sock->ch395_sock); + * 函数功能:处理数据接收事�? */ +static void handle_recv_event(net_sock_t *p_sock) { + uint16_t recv_len = ch395f_get_recv_len(p_sock->ch395_sock); - if (recv_len > 0) - { - fire_event(sock, NET_EVENT_DATA_RECEIVED); + if (recv_len > 0) { + fire_event(p_sock, NET_EVENT_DATA_RECEIVED); } } /* - * 函数功能:处理发送完成事件 - */ -static void handle_send_event(net_sock_t *sock) -{ - fire_event(sock, NET_EVENT_SEND_COMPLETE); + * 函数功能:处理发送完成事�? */ +static void handle_send_event(net_sock_t *p_sock) { + fire_event(p_sock, NET_EVENT_SEND_COMPLETE); } /* - * 函数功能:处理超时事件 - * 函数说明:CH395F 在 TIMEOUT 中断后同样自动关闭 Socket, - * 需要重新打开并恢复监听 - */ -static void handle_timeout_event(net_sock_t *sock) -{ - if (sock->state == NET_SOCK_STATE_CONNECTING) - { + * 函数功能:处理超时事�? * 函数说明:CH395F �?TIMEOUT 中断后同样自动关�?Socket�? * 需要重新打开并恢复监�? */ +static void handle_timeout_event(net_sock_t *p_sock) { + if (p_sock->state == NET_SOCK_STATE_CONNECTING) { /* TCP Client 连接超时 */ - DBG_ERROR("sock%d CONNECT TIMEOUT", sock->ch395_sock); - sock->state = NET_SOCK_STATE_CREATED; + DBG_ERROR("sock%d CONNECT TIMEOUT", p_sock->ch395_sock); + p_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 (p_sock->state == NET_SOCK_STATE_ESTABLISHED) { + /* 多连接模式:数据 Socket 超时,恢复为 TCP_ACCEPT 等待新连�?*/ + DBG_INFO("sock%d TIMEOUT, back to ACCEPT", p_sock->ch395_sock); + memset(p_sock->remote_ip_arr, 0, 4); + p_sock->remote_port = 0; + p_sock->send_ready = 1; + p_sock->state = NET_SOCK_STATE_TCP_ACCEPT; } - else if (sock->state == NET_SOCK_STATE_LISTENING) - { + else if (p_sock->state == NET_SOCK_STATE_LISTENING) { /* 监听超时(异常情况) */ - DBG_ERROR("sock%d LISTEN TIMEOUT", sock->ch395_sock); + DBG_ERROR("sock%d LISTEN TIMEOUT", p_sock->ch395_sock); } - fire_event(sock, NET_EVENT_TIMEOUT); + fire_event(p_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); + * 函数功能:触发事件回�? */ +static void fire_event(net_sock_t *p_sock, net_event_t event) { + if (p_sock->event_cb != NULL) { + p_sock->event_cb(p_sock->ch395_sock, event, p_sock->event_arg); } } /* - * 函数功能:解析 IP 地址字符串为数组 + * 函数功能:解�?IP 地址字符串为数组 */ -static void parse_ip_string(const char *str, uint8_t *ip_arr) -{ +static void parse_ip_string(const char *str, uint8_t *ip_arr) { uint32_t val; int i; - if (str == NULL || ip_arr == NULL) - { + if (str == NULL || ip_arr == NULL) { return; } - for (i = 0; i < 4; i++) - { + for (i = 0; i < 4; i++) { val = 0; - while (*str >= '0' && *str <= '9') - { + while (*str >= '0' && *str <= '9') { val = val * 10 + (*str - '0'); str++; } ip_arr[i] = (uint8_t)val; - if (*str == '.') - { + if (*str == '.') { str++; } } } /* - * 函数功能:获取 Socket 控制块指针(内部使用) - */ -net_sock_t *net_get_sock(int sockfd) -{ - if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) - { + * 函数功能:获�?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) - { + if (!s_net_socks[sockfd].in_use) { return NULL; } - return &g_net_socks[sockfd]; + return &s_net_socks[sockfd]; } diff --git a/Drivers/BSP/NET/net_socket.h b/Drivers/BSP/NET/net_socket.h index b63688e..0cf0b37 100644 --- a/Drivers/BSP/NET/net_socket.h +++ b/Drivers/BSP/NET/net_socket.h @@ -52,6 +52,7 @@ int net_poll(void); * protocol - 通常为 0 * 返回值:socket 描述符 (0~7),失败返回 -1 * 限定条件:net_init() 已调用 + * 函数说明:自动分配空闲 Socket 控制块 */ int net_socket(int domain, int type, int protocol); @@ -61,6 +62,8 @@ int net_socket(int domain, int type, int protocol); * addr - 本地地址结构体指针 * addrlen - 地址结构体长度 * 返回值:0 成功,-1 失败 + * 限定条件:socket 已创建且未绑定 + * 函数说明:设置 CH395F 源端口 */ int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen); @@ -70,6 +73,7 @@ int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen); * backlog - 最大等待连接数(多连接模式下为数据 Socket 数量) * 返回值:0 成功,-1 失败 * 限定条件:socket 已绑定 + * 函数说明:内部调用 ch395f_tcp_listen,多连接模式自动配置数据 Socket */ int net_listen(int sockfd, int backlog); @@ -104,7 +108,8 @@ int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen); * len - 数据长度 * flags - 通常为 0 * 返回值:实际发送字节数,失败返回 -1 - * 限定条件:TCP 连接已建立 + * 限定条件:TCP 连接已建立,指针非空 + * 函数说明:阻塞等待发送缓冲区空闲,拷贝数据后触发发送 */ int net_send(int sockfd, const void *buf, int len, int flags); @@ -124,13 +129,15 @@ int net_recv(int sockfd, void *buf, int len, int flags); /* * 函数功能:发送 UDP 数据 - * 入口参数:sockfd - socket 描述符 - * buf - 数据缓冲区 - * len - 数据长度 - * flags - 通常为 0 + * 入口参数:sockfd - socket 描述符 + * buf - 数据缓冲区 + * len - 数据长度 + * flags - 通常为 0 * dest_addr - 目标地址 - * addrlen - 地址长度 + * addrlen - 地址长度 * 返回值:实际发送字节数,失败返回 -1 + * 限定条件:socket 已创建,指针非空 + * 函数说明:设置目标地址后调用 CH395F 发送 */ int net_sendto(int sockfd, const void *buf, int len, int flags, const struct net_sockaddr *dest_addr, int addrlen); @@ -144,6 +151,8 @@ int net_sendto(int sockfd, const void *buf, int len, int flags, * src_addr - 输出:发送方地址 * addrlen - 输入输出:地址长度 * 返回值:实际接收字节数,失败返回 -1 + * 限定条件:socket 已创建,指针非空 + * 函数说明:读取 CH395F 接收缓冲区,获取对端地址 */ int net_recvfrom(int sockfd, void *buf, int len, int flags, struct net_sockaddr *src_addr, int *addrlen); @@ -152,6 +161,8 @@ int net_recvfrom(int sockfd, void *buf, int len, int flags, * 函数功能:关闭 socket * 入口参数:sockfd - socket 描述符 * 返回值:0 成功,-1 失败 + * 限定条件:socket 已打开 + * 函数说明:释放 Socket 控制块,TCP 先断开连接 */ int net_close(int sockfd); @@ -165,6 +176,8 @@ int net_close(int sockfd); * cb - 回调函数 * arg - 用户参数 * 返回值:0 成功,-1 失败 + * 限定条件:socket 已创建 + * 函数说明:回调在 net_poll 上下文中触发 */ int net_set_event_cb(int sockfd, net_event_cb_t cb, void *arg); @@ -181,7 +194,9 @@ int net_get_errno(void); /* * 函数功能:将 IP 地址字符串转为网络字节序 * 入口参数:cp - 点分十进制字符串 "192.168.1.100" - * 返回值:网络字节序 IP + * 返回值:网络字节序 IP,失败返回 0 + * 限定条件:cp 指针非空 + * 函数说明:不支持域名解析 */ uint32_t net_inet_addr(const char *cp); @@ -190,26 +205,43 @@ uint32_t net_inet_addr(const char *cp); * 入口参数:addr - 网络字节序 IP * buf - 输出缓冲区(至少 16 字节) * 返回值:buf 指针 + * 限定条件:buf 指针非空 */ char *net_inet_ntoa(uint32_t addr, char *buf); /* * 函数功能:端口字节序转换(主机序 -> 网络序) + * 入口参数:hostshort - 主机序端口 + * 返回值:网络序端口 + * 限定条件:无 + * 函数说明:小端 → 大端 */ uint16_t net_htons(uint16_t hostshort); /* * 函数功能:端口字节序转换(网络序 -> 主机序) + * 入口参数:netshort - 网络序端口 + * 返回值:主机序端口 + * 限定条件:无 + * 函数说明:大端 → 小端 */ uint16_t net_ntohs(uint16_t netshort); /* * 函数功能:IP 地址字节序转换(主机序 -> 网络序) + * 入口参数:hostlong - 主机序 IP + * 返回值:网络序 IP + * 限定条件:无 + * 函数说明:小端 → 大端 */ uint32_t net_htonl(uint32_t hostlong); /* * 函数功能:IP 地址字节序转换(网络序 -> 主机序) + * 入口参数:netlong - 网络序 IP + * 返回值:主机序 IP + * 限定条件:无 + * 函数说明:大端 → 小端 */ uint32_t net_ntohl(uint32_t netlong); diff --git a/Drivers/BSP/RS485/rs485.c b/Drivers/BSP/RS485/rs485.c index 0ed85cb..9db3dff 100644 --- a/Drivers/BSP/RS485/rs485.c +++ b/Drivers/BSP/RS485/rs485.c @@ -2,21 +2,18 @@ * 模块名称:RS-485 半双工通信驱动 * 模块功能:RS-485 半双工通信驱动实现,核心要点: * 1. 发送前拉高 DE(切换到发送态) - * 2. HAL_UART_Transmit 内部已等待 TC(发送完成)标志 + * 2. HAL_UART_Transmit 内部已等?TC(发送完成)标志 * 3. 发送完毕后拉低 DE(切回接收态) - * 4. 使用 HAL_UARTEx_ReceiveToIdle_IT 实现变长帧接收 - * 参考:ST AN3070 应用笔记、controllerstech.com RS485 教程 + * 4. 使用 HAL_UARTEx_ReceiveToIdle_IT 实现变长帧接? * 参考:ST AN3070 应用笔记、controllerstech.com RS485 教程 * 适用平台:STM32F4 系列 - * 作者:王建锋 - * 创建日期:2026-07-18 - * 修改记录: - * 2026-07-18 王建锋 创建初始版本 + * 作者:王建? * 创建日期?026-07-18 + * 修改记录? * 2026-07-18 王建? 创建初始版本 */ #include "rs485.h" /* - * 内部辅助宏 - 方向控制 + * 内部辅助?- 方向控制 */ #define RS485_DIR_TX(h) HAL_GPIO_WritePin((h)->dir_port, (h)->dir_pin, GPIO_PIN_SET) #define RS485_DIR_RX(h) HAL_GPIO_WritePin((h)->dir_port, (h)->dir_pin, GPIO_PIN_RESET) @@ -31,60 +28,49 @@ * huart - UART 外设句柄 * dir_port - DE 引脚 GPIO 端口 * dir_pin - DE 引脚 GPIO 编号 - * 返回值:无 - * 限定条件:UART 和 GPIO 须先由 CubeMX 完成初始化 - * 函数说明:初始化后立即将 DE 拉低,使 RS-485 收发器处于接收状态 - */ -void rs485_init(rs485_handle_t *handle, - UART_HandleTypeDef *huart, - GPIO_TypeDef *dir_port, - uint16_t dir_pin) -{ - handle->huart = huart; - handle->dir_port = dir_port; - handle->dir_pin = dir_pin; - handle->rx_size = 0; + * 返回值:? * 限定条件:UART ?GPIO 须先?CubeMX 完成初始? * 函数说明:初始化后立即将 DE 拉低,使 RS-485 收发器处于接收状? */ +void rs485_init(rs485_handle_t *p_handle, + UART_HandleTypeDef *p_huart, + GPIO_TypeDef *p_dir_port, + uint16_t dir_pin) { + p_handle->huart = p_huart; + p_handle->dir_port = p_dir_port; + p_handle->dir_pin = dir_pin; + p_handle->rx_size = 0; - /* 默认进入接收状态 */ - RS485_DIR_RX(handle); + /* 默认进入接收状�?*/ + RS485_DIR_RX(p_handle); } /* - * 函数功能:阻塞方式发送数据 - * 入口参数:handle - RS-485 句柄指针 + * 函数功能:阻塞方式发送数? * 入口参数:handle - RS-485 句柄指针 * data - 待发送数据缓冲区 * len - 待发送字节数 - * timeout - 发送超时(ms),传 0 使用默认值 - * 返回值:HAL_OK / HAL_TIMEOUT / HAL_ERROR - * 限定条件:须在主循环或 RTOS 任务中调用,不可在 UART 中断中调用 - * 函数说明: - * 时序:DE=HIGH → UART 发送 N 字节 → 等 TC → DE=LOW - * HAL_UART_Transmit 内部会等待 TXE(发送寄存器空)逐字节搬数据, - * 最后还会等待 TC(发送完成)标志,确保最后一字节的停止位已移出。 - * 因此返回后再拉低 DE 是安全的 + * timeout - 发送超时(ms),?0 使用默认? * 返回值:HAL_OK / HAL_TIMEOUT / HAL_ERROR + * 限定条件:须在主循环?RTOS 任务中调用,不可?UART 中断中调? * 函数说明? * 时序:DE=HIGH ?UART 发�?N 字节 ??TC ?DE=LOW + * HAL_UART_Transmit 内部会等?TXE(发送寄存器空)逐字节搬数据? * 最后还会等?TC(发送完成)标志,确保最后一字节的停止位已移出�? * 因此返回后再拉低 DE 是安全的 */ -HAL_StatusTypeDef rs485_transmit(rs485_handle_t *handle, - const uint8_t *data, +HAL_StatusTypeDef rs485_transmit(rs485_handle_t *p_handle, + const uint8_t *p_data, uint16_t len, - uint32_t timeout) -{ - HAL_StatusTypeDef status; + uint32_t timeout) { + HAL_StatusTypeDef status = HAL_OK; if (timeout == 0U) { timeout = RS485_TIMEOUT_DEFAULT; } - /* 1. 切换到发送状态 */ - RS485_DIR_TX(handle); + /* 1. 切换到发送状?*/ + RS485_DIR_TX(p_handle); - /* 2. 阻塞发送(内部等待 TC) */ - status = HAL_UART_Transmit(handle->huart, - (uint8_t *)data, + /* 2. 阻塞发送(内部等待 TC?*/ + status = HAL_UART_Transmit(p_handle->huart, + (uint8_t *)p_data, len, timeout); - /* 3. 发送完毕或超时,切回接收状态 */ - RS485_DIR_RX(handle); + /* 3. 发送完毕或超时,切回接收状?*/ + RS485_DIR_RX(p_handle); return status; } @@ -92,42 +78,27 @@ HAL_StatusTypeDef rs485_transmit(rs485_handle_t *handle, /* * 函数功能:启动中断方式接收(IDLE 空闲帧检测) * 入口参数:handle - RS-485 句柄指针 - * buf - 接收缓冲区 - * buf_size - 缓冲区最大容量 - * 返回值:HAL_OK / HAL_ERROR - * 限定条件:UART 须已开启全局中断(NVIC 使能) - * 函数说明: - * 使用 HAL_UARTEx_ReceiveToIdle_IT 实现变长帧接收。 - * 当 UART 总线空闲超过 1 个字符时间后,硬件触发 IDLE 中断, - * HAL 自动调用 HAL_UARTEx_RxEventCallback 并返回已接收字节数。 - * 用户须在该回调中重新调用本函数重新开启接收 - */ -HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *handle, - uint8_t *buf, - uint16_t buf_size) -{ - handle->rx_size = 0; - return HAL_UARTEx_ReceiveToIdle_IT(handle->huart, buf, buf_size); + * buf - 接收缓冲? * buf_size - 缓冲区最大容? * 返回值:HAL_OK / HAL_ERROR + * 限定条件:UART 须已开启全局中断(NVIC 使能? * 函数说明? * 使用 HAL_UARTEx_ReceiveToIdle_IT 实现变长帧接收�? * ?UART 总线空闲超过 1 个字符时间后,硬件触?IDLE 中断? * HAL 自动调用 HAL_UARTEx_RxEventCallback 并返回已接收字节数�? * 用户须在该回调中重新调用本函数重新开启接? */ +HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *p_handle, + uint8_t *p_buf, + uint16_t buf_size) { + p_handle->rx_size = 0; + return HAL_UARTEx_ReceiveToIdle_IT(p_handle->huart, p_buf, buf_size); } /* - * 函数功能:缓存最近一次接收的字节数 - * 入口参数:handle - RS-485 句柄指针 - * size - 本次接收到的字节数 - * 返回值:无 - * 限定条件:须在 HAL_UARTEx_RxEventCallback 中调用 - */ -void rs485_rx_set_size(rs485_handle_t *handle, uint16_t size) -{ - handle->rx_size = size; + * 函数功能:缓存最近一次接收的字节? * 入口参数:handle - RS-485 句柄指针 + * size - 本次接收到的字节? * 返回值:? * 限定条件:须?HAL_UARTEx_RxEventCallback 中调? */ +void rs485_rx_set_size(rs485_handle_t *p_handle, uint16_t size) { + p_handle->rx_size = size; } /* - * 函数功能:获取最近一次接收的字节数 - * 入口参数:handle - RS-485 句柄指针 - * 返回值:字节数 - */ -uint16_t rs485_rx_get_size(const rs485_handle_t *handle) -{ - return handle->rx_size; + * 函数功能:获取最近一次接收的字节? * 入口参数:handle - RS-485 句柄指针 + * 返回值:字节? */ +uint16_t rs485_rx_get_size(const rs485_handle_t *p_handle) { + return p_handle->rx_size; } + + diff --git a/Drivers/BSP/RS485/rs485.h b/Drivers/BSP/RS485/rs485.h index b27fd76..4a1f099 100644 --- a/Drivers/BSP/RS485/rs485.h +++ b/Drivers/BSP/RS485/rs485.h @@ -50,9 +50,9 @@ typedef struct { * 限定条件:UART 和 GPIO 须先由 CubeMX 完成初始化 * 函数说明:初始化后默认处于接收状态(DE 引脚拉低) */ -void rs485_init(rs485_handle_t *handle, - UART_HandleTypeDef *huart, - GPIO_TypeDef *dir_port, +void rs485_init(rs485_handle_t *p_handle, + UART_HandleTypeDef *p_huart, + GPIO_TypeDef *p_dir_port, uint16_t dir_pin); /* @@ -66,8 +66,8 @@ void rs485_init(rs485_handle_t *handle, * 函数说明:发送前自动拉高 DE,发送完成后等待 TC 标志再拉低 DE, * 确保最后一字节完全移出后再切换到接收状态 */ -HAL_StatusTypeDef rs485_transmit(rs485_handle_t *handle, - const uint8_t *data, +HAL_StatusTypeDef rs485_transmit(rs485_handle_t *p_handle, + const uint8_t *p_data, uint16_t len, uint32_t timeout); @@ -82,8 +82,8 @@ HAL_StatusTypeDef rs485_transmit(rs485_handle_t *handle, * 收到完整帧后在 RxEventCallback 中通知用户。 * 用户须在回调中重新调用本函数重新开启接收 */ -HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *handle, - uint8_t *buf, +HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *p_handle, + uint8_t *p_buf, uint16_t buf_size); /* @@ -93,7 +93,7 @@ HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *handle, * 限定条件:须在 HAL_UART_RxCpltCallback / HAL_UARTEx_RxEventCallback 中调用 * 函数说明:将 HAL 回调中接收到的数据大小回写到句柄的 rx_size 字段 */ -void rs485_rx_set_size(rs485_handle_t *handle, uint16_t size); +void rs485_rx_set_size(rs485_handle_t *p_handle, uint16_t size); /* * 函数功能:获取最近一次接收的字节数 @@ -101,7 +101,7 @@ void rs485_rx_set_size(rs485_handle_t *handle, uint16_t size); * 返回值:最近一次接收的字节数 * 限定条件:须在 HAL_UARTEx_RxEventCallback 触发后调用 */ -uint16_t rs485_rx_get_size(const rs485_handle_t *handle); +uint16_t rs485_rx_get_size(const rs485_handle_t *p_handle); #ifdef __cplusplus } diff --git a/Drivers/BSP/SD2506/sd2506.c b/Drivers/BSP/SD2506/sd2506.c index 990fec5..04dad06 100644 --- a/Drivers/BSP/SD2506/sd2506.c +++ b/Drivers/BSP/SD2506/sd2506.c @@ -1,39 +1,43 @@ /* * 模块名称:SD2506API-G RTC 实时时钟驱动 - * 模块功能:SD2506API-G 高精度温补实时时钟模块 I2C 驱动 + * 模块功能:SD2506API-G 高精度温补实时时钟模�?I2C 驱动 * 适用平台:STM32F407ZGT6,I2C1 接口 (PB6-SCL, PB7-SDA) - * 作者:王建锋 - * 创建日期:2026-07-17 - * 修改记录: - * 2026-07-17 王建锋 创建初始版本,参考 SD2506API-G Ver2.0 手册 + * 作者:王建�? * 创建日期�?026-07-17 + * 修改记录�? * 2026-07-17 王建�? 创建初始版本,参�?SD2506API-G Ver2.0 手册 */ +#include #include "sd2506.h" #include "i2c.h" -#include extern I2C_HandleTypeDef hi2c1; /* ======================== 内部辅助函数 ======================== */ -uint8_t sd2506_bcd_to_dec(uint8_t bcd) -{ +/* + * 函数功能:BCD 码转十进�? * 入口参数:bcd - BCD 编码�? uint8_t 0x00 - 0x99 + * �?�?值:十进制数�? * 限定条件:输入为合法 BCD �? * 函数说明:高 4 位为十位,低 4 位为个位 + */ +uint8_t sd2506_bcd_to_dec(uint8_t bcd) { return ((bcd >> 4) * 10) + (bcd & 0x0FU); } -uint8_t sd2506_dec_to_bcd(uint8_t dec) -{ +/* + * 函数功能:十进制�?BCD �? * 入口参数:dec - 十进制数�? uint8_t 0 - 99 + * �?�?值:BCD 编码�? * 限定条件:输入值在 0 - 99 范围�? * 函数说明:十位存入高 4 位,个位存入�?4 �? */ +uint8_t sd2506_dec_to_bcd(uint8_t dec) { return ((dec / 10) << 4) | (dec % 10); } /* - * 写单字节寄存器 - * reg: 寄存器地址 (00H~79H) - * val: 写入值 - * 返回: 0=成功, -2=I2C错误 + * 函数功能:写单字节寄存器 + * 入口参数:reg - 寄存器地址 uint8_t 00H - 79H + * val - 写入�? uint8_t 0x00 - 0xFF + * �?�?值:0 - 成功�?2 - I2C 错误 + * 限定条件:I2C 外设已初始化 + * 函数说明:通过 I2C 向指定地址写入 1 字节 */ -static int sd2506_write_reg(uint8_t reg, uint8_t val) -{ +static int sd2506_write_reg(uint8_t reg, uint8_t val) { if (HAL_I2C_Mem_Write(&hi2c1, SD2506_I2C_ADDR_WRITE, reg, I2C_MEMADD_SIZE_8BIT, &val, 1, SD2506_I2C_TIMEOUT_MS) != HAL_OK) { @@ -43,15 +47,15 @@ static int sd2506_write_reg(uint8_t reg, uint8_t val) } /* - * 读单字节寄存器 - * reg: 寄存器地址 (00H~79H) - * val: 读取值指针 - * 返回: 0=成功, -2=I2C错误 + * 函数功能:读单字节寄存器 + * 入口参数:reg - 寄存器地址 uint8_t 00H - 79H + * val - 读取值指�? uint8_t* + * �?�?值:0 - 成功�?2 - I2C 错误 + * 限定条件:I2C 外设已初始化,val 为非空指�? * 函数说明:通过 I2C 从指定地址读取 1 字节 */ -static int sd2506_read_reg(uint8_t reg, uint8_t *val) -{ +static int sd2506_read_reg(uint8_t reg, uint8_t *p_val) { if (HAL_I2C_Mem_Read(&hi2c1, SD2506_I2C_ADDR_READ, reg, - I2C_MEMADD_SIZE_8BIT, val, 1, + I2C_MEMADD_SIZE_8BIT, p_val, 1, SD2506_I2C_TIMEOUT_MS) != HAL_OK) { return SD2506_I2C_ERROR; } @@ -59,16 +63,16 @@ static int sd2506_read_reg(uint8_t reg, uint8_t *val) } /* - * 写多字节寄存器 (从 reg 开始连续写入 len 字节) - * reg: 起始寄存器地址 - * data: 数据缓冲区 - * len: 数据长度 - * 返回: 0=成功, -2=I2C错误 + * 函数功能:写多字节寄存器 + * 入口参数:reg - 起始寄存器地址 uint8_t 00H - 79H + * data - 数据缓冲区指�? uint8_t* + * len - 数据长度 uint8_t 1 - N + * �?�?值:0 - 成功�?2 - I2C 错误 + * 限定条件:I2C 外设已初始化,data 为非空指�? * 函数说明:从 reg 开始连续写�?len 字节 */ -static int sd2506_write_regs(uint8_t reg, const uint8_t *data, uint8_t len) -{ +static int sd2506_write_regs(uint8_t reg, const uint8_t *p_data, uint8_t len) { if (HAL_I2C_Mem_Write(&hi2c1, SD2506_I2C_ADDR_WRITE, reg, - I2C_MEMADD_SIZE_8BIT, (uint8_t *)data, len, + I2C_MEMADD_SIZE_8BIT, (uint8_t *)p_data, len, SD2506_I2C_TIMEOUT_MS) != HAL_OK) { return SD2506_I2C_ERROR; } @@ -76,16 +80,16 @@ static int sd2506_write_regs(uint8_t reg, const uint8_t *data, uint8_t len) } /* - * 读多字节寄存器 (从 reg 开始连续读取 len 字节) - * reg: 起始寄存器地址 - * data: 数据缓冲区 - * len: 数据长度 - * 返回: 0=成功, -2=I2C错误 + * 函数功能:读多字节寄存器 + * 入口参数:reg - 起始寄存器地址 uint8_t 00H - 79H + * data - 数据缓冲区指�? uint8_t* + * len - 数据长度 uint8_t 1 - N + * �?�?值:0 - 成功�?2 - I2C 错误 + * 限定条件:I2C 外设已初始化,data 为非空指�? * 函数说明:从 reg 开始连续读�?len 字节 */ -static int sd2506_read_regs(uint8_t reg, uint8_t *data, uint8_t len) -{ +static int sd2506_read_regs(uint8_t reg, uint8_t *p_data, uint8_t len) { if (HAL_I2C_Mem_Read(&hi2c1, SD2506_I2C_ADDR_READ, reg, - I2C_MEMADD_SIZE_8BIT, data, len, + I2C_MEMADD_SIZE_8BIT, p_data, len, SD2506_I2C_TIMEOUT_MS) != HAL_OK) { return SD2506_I2C_ERROR; } @@ -93,14 +97,16 @@ static int sd2506_read_regs(uint8_t reg, uint8_t *data, uint8_t len) } /* - * 开启写保护 (允许写入 00H~71H 寄存器) - * 顺序: 先写 WRTC1=1, 再写 WRTC2=1 + WRTC3=1 + * 函数功能:开启写保护(允许写�?00H~71H 寄存器) + * 入口参数:无 + * 返回值:0 - 成功�?2 - I2C 错误 + * 限定条件:I2C 外设已初始化 + * 函数说明:顺序:先写 WRTC1=1, 再写 WRTC2=1 + WRTC3=1 */ -static int sd2506_write_enable(void) -{ - int ret; +static int sd2506_write_enable(void) { + int ret = 0; - /* 先置 WRTC1=1 (bit6=1), 其它位参考手册: 0x84 */ + /* 先置 WRTC1=1 (bit6=1), 其它位参考手�? 0x84 */ ret = sd2506_write_reg(SD2506_REG_CTR1, 0x84U); if (ret != SD2506_OK) return ret; @@ -112,12 +118,14 @@ static int sd2506_write_enable(void) } /* - * 关闭写保护 (禁止写入 00H~71H 寄存器) - * 顺序: 先写 WRTC2=0 + WRTC3=0, 再写 WRTC1=0 + * 函数功能:关闭写保护(禁止写�?00H~71H 寄存器) + * 入口参数:无 + * 返回值:0 - 成功�?2 - I2C 错误 + * 限定条件:I2C 外设已初始化 + * 函数说明:顺序:先写 WRTC2=0 + WRTC3=0, 再写 WRTC1=0 */ -static int sd2506_write_disable(void) -{ - int ret; +static int sd2506_write_disable(void) { + int ret = 0; /* 先清 WRTC2=0, WRTC3=0: 0x00 */ ret = sd2506_write_reg(SD2506_REG_CTR2, 0x00U); @@ -132,28 +140,36 @@ static int sd2506_write_disable(void) /* ======================== 公共 API 实现 ======================== */ -int sd2506_init(void) -{ - int ret; - uint8_t id[8]; +/* + * 函数功能:初始化 SD2506API-G RTC + * 入口参数:无 + * 返回值:0 - 成功�?2 - I2C 错误 + * 限定条件:CubeMX 已完�?I2C1 初始�? + * 函数说明�?. 读取芯片 ID 验证通信 + * 2. 上电重置充电寄存�?18H=82H + * 3. 配置 24 小时制、开自动复位 + */ +int sd2506_init(void) { + int ret = 0; + uint8_t a_id[8] = {0}; /* 验证 I2C 通信: 尝试读取 8 字节 ID */ - ret = sd2506_read_regs(SD2506_REG_ID_START, id, SD2506_ID_SIZE); + ret = sd2506_read_regs(SD2506_REG_ID_START, a_id, SD2506_ID_SIZE); if (ret != SD2506_OK) { return ret; } - /* 上电重置充电寄存器 18H = 82H (开启充电, 5K电阻) - * 手册强烈建议每次上电时重置此值 */ + /* 上电重置充电寄存�?18H = 82H (开启充�? 5K电阻) + * 手册强烈建议每次上电时重置此�?*/ ret = sd2506_write_reg(SD2506_REG_CHARGE, 0x82U); if (ret != SD2506_OK) { return ret; } - /* 配置: 24小时制, 自动复位使能 - * 0FH = 0x20 (bit5=ARST=1, 其它标志位清零) - * 写入时需注意: 写允许状态下 0FH 的 WRTC 位必须为1 - * 此处直接写入 0x20 即可 (ARST=1, 无 WRTC 位) */ + /* 配置: 24小时�? 自动复位使能 + * 0FH = 0x20 (bit5=ARST=1, 其它标志位清�? + * 写入时需注意: 写允许状态下 0FH �?WRTC 位必须为1 + * 此处直接写入 0x20 即可 (ARST=1, �?WRTC �? */ ret = sd2506_write_reg(SD2506_REG_CTR1, SD2506_CTR1_WRITE_OFF); if (ret != SD2506_OK) { return ret; @@ -162,73 +178,91 @@ int sd2506_init(void) return SD2506_OK; } -int sd2506_set_time(const sd2506_time_t *time) -{ - int ret; - uint8_t buf[7]; +/* + * 函数功能:设�?RTC 时间日期 + * 入口参数:p_time - 时间结构体指针,包含要设置的时间 + * 返回值:0 - 成功�?2 - I2C 错误 + * 限定条件:sd2506_init() 已调�? + * 函数说明�?. 先开写保�? + * 2. 一次性写�?7 字节时间数据 (00H~06H) + * 3. 关闭写保�? + */ +int sd2506_set_time(const sd2506_time_t *p_time) { + int ret = 0; + uint8_t buf[7] = {0}; - if (time == NULL) { + if (p_time == NULL) { return SD2506_ERROR; } - /* 组装 7 字节时间数据 (BCD 码) */ - buf[0] = sd2506_dec_to_bcd(time->second); /* 00H: 秒 */ - buf[1] = sd2506_dec_to_bcd(time->minute); /* 01H: 分 */ - buf[2] = sd2506_dec_to_bcd(time->hour) | 0x80U; /* 02H: 时 (bit7=1, 24小时制) */ - buf[3] = sd2506_dec_to_bcd(time->week); /* 03H: 星期 */ - buf[4] = sd2506_dec_to_bcd(time->day); /* 04H: 日 */ - buf[5] = sd2506_dec_to_bcd(time->month); /* 05H: 月 */ - buf[6] = sd2506_dec_to_bcd(time->year - 2000U); /* 06H: 年 */ + /* 组装 7 字节时间数据 (BCD �? */ + buf[0] = sd2506_dec_to_bcd(p_time->second); /* 00H: �?*/ + buf[1] = sd2506_dec_to_bcd(p_time->minute); /* 01H: �?*/ + buf[2] = sd2506_dec_to_bcd(p_time->hour) | 0x80U; /* 02H: �?(bit7=1, 24小时�? */ + buf[3] = sd2506_dec_to_bcd(p_time->week); /* 03H: 星期 */ + buf[4] = sd2506_dec_to_bcd(p_time->day); /* 04H: �?*/ + buf[5] = sd2506_dec_to_bcd(p_time->month); /* 05H: �?*/ + buf[6] = sd2506_dec_to_bcd(p_time->year - 2000U); /* 06H: �?*/ /* 开启写保护 */ ret = sd2506_write_enable(); if (ret != SD2506_OK) return ret; - /* 一次性写入 7 字节时间数据 (00H~06H) - * 手册要求: 不可单独写某一个时间寄存器,否则可能引起错误进位 */ + /* 一次性写�?7 字节时间数据 (00H~06H) + * 手册要求: 不可单独写某一个时间寄存器,否则可能引起错误进�?*/ ret = sd2506_write_regs(SD2506_REG_SEC, buf, 7); if (ret != SD2506_OK) return ret; - /* 关闭写保护 */ + /* 关闭写保�?*/ ret = sd2506_write_disable(); if (ret != SD2506_OK) return ret; return SD2506_OK; } -int sd2506_get_time(sd2506_time_t *time) -{ - int ret; - uint8_t buf[7]; +/* + * function: read RTC time + * param: p_time - output time struct + * return: 0=OK, -2=I2C error + * note: sd2506_init() must be called first + */ +int sd2506_get_time(sd2506_time_t *p_time) { + int ret = 0; + uint8_t buf[7] = {0}; - if (time == NULL) { + if (p_time == NULL) { return SD2506_ERROR; } - /* 一次读取 7 字节时间数据 (00H~06H) - * 手册说明: 读取时所有实时数据被锁存,避免错读 */ + /* 一次读�?7 字节时间数据 (00H~06H) + * 手册说明: 读取时所有实时数据被锁存,避免错�?*/ ret = sd2506_read_regs(SD2506_REG_SEC, buf, 7); if (ret != SD2506_OK) { return ret; } - time->second = sd2506_bcd_to_dec(buf[0] & 0x7FU); /* 00H: 秒 */ - time->minute = sd2506_bcd_to_dec(buf[1] & 0x7FU); /* 01H: 分 */ - time->hour = sd2506_bcd_to_dec(buf[2] & 0x7FU); /* 02H: 屏蔽 bit7 (12/24标志) */ - time->week = sd2506_bcd_to_dec(buf[3] & 0x07U); /* 03H: 星期 */ - time->day = sd2506_bcd_to_dec(buf[4] & 0x3FU); /* 04H: 日 */ - time->month = sd2506_bcd_to_dec(buf[5] & 0x1FU); /* 05H: 月 */ - time->year = sd2506_bcd_to_dec(buf[6]) + 2000U; /* 06H: 年 */ + p_time->second = sd2506_bcd_to_dec(buf[0] & 0x7FU); /* 00H: �?*/ + p_time->minute = sd2506_bcd_to_dec(buf[1] & 0x7FU); /* 01H: �?*/ + p_time->hour = sd2506_bcd_to_dec(buf[2] & 0x7FU); /* 02H: 屏蔽 bit7 (12/24标志) */ + p_time->week = sd2506_bcd_to_dec(buf[3] & 0x07U); /* 03H: 星期 */ + p_time->day = sd2506_bcd_to_dec(buf[4] & 0x3FU); /* 04H: �?*/ + p_time->month = sd2506_bcd_to_dec(buf[5] & 0x1FU); /* 05H: �?*/ + p_time->year = sd2506_bcd_to_dec(buf[6]) + 2000U; /* 06H: �?*/ return SD2506_OK; } -int sd2506_get_temperature(int8_t *temp) -{ - int ret; - uint8_t val; +/* + * function: read internal temperature + * param: p_temp - output temperature + * return: 0=OK, -2=I2C error + * note: reads register 0x16 + */ +int sd2506_get_temperature(int8_t *p_temp) { + int ret = 0; + uint8_t val = 0; - if (temp == NULL) { + if (p_temp == NULL) { return SD2506_ERROR; } @@ -237,54 +271,72 @@ int sd2506_get_temperature(int8_t *temp) return ret; } - /* bit7 为符号位, 其余为温度值 */ + /* bit7 为符号位, 其余为温度�?*/ if (val & 0x80U) { - /* 负温度: 取补码 */ - *temp = (int8_t)(val | 0xF0U); + /* 负温�? 取补�?*/ + *p_temp = (int8_t)(val | 0xF0U); } else { - /* 正温度 */ - *temp = (int8_t)(val & 0x7FU); + /* 正温�?*/ + *p_temp = (int8_t)(val & 0x7FU); } return SD2506_OK; } -int sd2506_get_battery_voltage(uint16_t *voltage) -{ - int ret; - uint8_t val_high, val_low; +/* + * function: read battery voltage (mV) + * param: p_voltage - output voltage + * return: 0=OK, -2=I2C error + * note: combines 9-bit value + */ +int sd2506_get_battery_voltage(uint16_t *p_voltage) { + int ret = 0; + uint8_t val_high = 0; + uint8_t val_low = 0; - if (voltage == NULL) { + if (p_voltage == NULL) { return SD2506_ERROR; } - /* 读取 1AH bit7 (BAT8_VAL) 和 1BH (BAT_VL) */ + /* 读取 1AH bit7 (BAT8_VAL) �?1BH (BAT_VL) */ ret = sd2506_read_reg(SD2506_REG_CTR5, &val_high); if (ret != SD2506_OK) return ret; ret = sd2506_read_reg(SD2506_REG_BAT_VAL, &val_low); if (ret != SD2506_OK) return ret; - /* 组合 9 位: bit8=BAT8_VAL(1AH bit7), bit7~0=BAT_VL(1BH) - * 如 1AH=80H, 1BH=30H => 电压 = 0x130 = 304 => 3.04V => 3040mV */ + /* 组合 9 �? bit8=BAT8_VAL(1AH bit7), bit7~0=BAT_VL(1BH) + * �?1AH=80H, 1BH=30H => 电压 = 0x130 = 304 => 3.04V => 3040mV */ uint16_t raw = ((val_high & 0x80U) << 1) | val_low; - *voltage = raw * 10; /* 转换为毫伏 (raw 单位 0.01V) */ + *p_voltage = raw * 10; /* 转换为毫�?(raw 单位 0.01V) */ return SD2506_OK; } -int sd2506_get_id(uint8_t id[8]) -{ - if (id == NULL) { +/* + * function: read 8-byte chip ID + * param: p_id - 8-byte output buffer + * return: 0=OK, -2=I2C error + * note: reads registers 0x72-0x79 + */ +int sd2506_get_id(uint8_t p_id[8]) { + if (p_id == NULL) { return SD2506_ERROR; } - return sd2506_read_regs(SD2506_REG_ID_START, id, SD2506_ID_SIZE); + return sd2506_read_regs(SD2506_REG_ID_START, p_id, SD2506_ID_SIZE); } -int sd2506_read_sram(uint8_t addr, uint8_t *buf, uint8_t len) -{ - if (buf == NULL || len == 0 || addr >= SD2506_SRAM_SIZE) { +/* + * function: read SRAM data + * param: addr - start address (0-69) + * p_buf - output buffer + * len - read length + * return: 0=OK, -1=param err, -2=I2C err + * note: SRAM range 0x2C-0x71 + */ +int sd2506_read_sram(uint8_t addr, uint8_t *p_buf, uint8_t len) { + if (p_buf == NULL || len == 0 || addr >= SD2506_SRAM_SIZE) { return SD2506_ERROR; } @@ -292,12 +344,18 @@ int sd2506_read_sram(uint8_t addr, uint8_t *buf, uint8_t len) return SD2506_ERROR; } - return sd2506_read_regs(SD2506_REG_SRAM_START + addr, buf, len); + return sd2506_read_regs(SD2506_REG_SRAM_START + addr, p_buf, len); } -int sd2506_write_sram(uint8_t addr, const uint8_t *buf, uint8_t len) -{ - if (buf == NULL || len == 0 || addr >= SD2506_SRAM_SIZE) { +/* + * function: write SRAM data + * param: addr - start address (0-69) + * p_buf - input data + * len - write length + * return: 0=OK, -1=param err, -2=I2C err + */ +int sd2506_write_sram(uint8_t addr, const uint8_t *p_buf, uint8_t len) { + if (p_buf == NULL || len == 0 || addr >= SD2506_SRAM_SIZE) { return SD2506_ERROR; } @@ -305,64 +363,74 @@ int sd2506_write_sram(uint8_t addr, const uint8_t *buf, uint8_t len) return SD2506_ERROR; } - /* SRAM 无需开写保护即可写入 (写保护仅对 00H~71H 有效, SRAM 是 2CH~71H) - * 但为安全起见, SRAM 写入也走写保护流程 */ - int ret; + /* SRAM 无需开写保护即可写�?(写保护仅�?00H~71H 有效, SRAM �?2CH~71H) + * 但为安全起见, SRAM 写入也走写保护流�?*/ + int ret = 0; ret = sd2506_write_enable(); if (ret != SD2506_OK) return ret; - ret = sd2506_write_regs(SD2506_REG_SRAM_START + addr, buf, len); + ret = sd2506_write_regs(SD2506_REG_SRAM_START + addr, p_buf, len); if (ret != SD2506_OK) return ret; ret = sd2506_write_disable(); return ret; } -int sd2506_set_alarm(const sd2506_time_t *time, uint8_t mask) -{ - int ret; - uint8_t buf[8]; +/* + * function: set alarm interrupt + * param: p_time - alarm time struct + * mask - alarm match mask + * return: 0=OK, -2=I2C error + */ +int sd2506_set_alarm(const sd2506_time_t *p_time, uint8_t mask) { + int ret = 0; + uint8_t buf[8] = {0}; - if (time == NULL) { + if (p_time == NULL) { return SD2506_ERROR; } /* 组装 8 字节报警数据 (07H~0EH) */ - buf[0] = sd2506_dec_to_bcd(time->second) & 0x7FU; /* 07H: 秒报警 */ - buf[1] = sd2506_dec_to_bcd(time->minute) & 0x7FU; /* 08H: 分报警 */ - buf[2] = sd2506_dec_to_bcd(time->hour) & 0x3FU; /* 09H: 时报警 (最高位始终为0) */ + buf[0] = sd2506_dec_to_bcd(p_time->second) & 0x7FU; /* 07H: 秒报�?*/ + buf[1] = sd2506_dec_to_bcd(p_time->minute) & 0x7FU; /* 08H: 分报�?*/ + buf[2] = sd2506_dec_to_bcd(p_time->hour) & 0x3FU; /* 09H: 时报�?(最高位始终�?) */ buf[3] = 0x00U; /* 0AH: 星期报警 */ - buf[4] = sd2506_dec_to_bcd(time->day) & 0x3FU; /* 0BH: 日报警 */ - buf[5] = sd2506_dec_to_bcd(time->month) & 0x1FU; /* 0CH: 月报警 */ - buf[6] = sd2506_dec_to_bcd(time->year - 2000U); /* 0DH: 年报警 */ + buf[4] = sd2506_dec_to_bcd(p_time->day) & 0x3FU; /* 0BH: 日报�?*/ + buf[5] = sd2506_dec_to_bcd(p_time->month) & 0x1FU; /* 0CH: 月报�?*/ + buf[6] = sd2506_dec_to_bcd(p_time->year - 2000U); /* 0DH: 年报�?*/ buf[7] = mask; /* 0EH: 报警允许 */ /* 开启写保护 */ ret = sd2506_write_enable(); if (ret != SD2506_OK) return ret; - /* 写入报警寄存器 (07H~0EH) */ + /* 写入报警寄存�?(07H~0EH) */ ret = sd2506_write_regs(SD2506_REG_AL_SEC, buf, 8); if (ret != SD2506_OK) return ret; - /* 使能报警中断: CTR2 的 INTAE=1, INTS1=0, INTS0=1, IM=1 (周期性) */ + /* 使能报警中断: CTR2 �?INTAE=1, INTS1=0, INTS0=1, IM=1 (周期�? */ ret = sd2506_write_reg(SD2506_REG_CTR2, SD2506_CTR2_INTAE | SD2506_CTR2_INTS0 | SD2506_CTR2_IM); if (ret != SD2506_OK) return ret; - /* 关闭写保护 */ + /* 关闭写保�?*/ ret = sd2506_write_disable(); if (ret != SD2506_OK) return ret; return SD2506_OK; } -int sd2506_clear_alarm(void) -{ - int ret; - uint8_t val; +/* + * function: clear alarm interrupt flag + * param: none + * return: 0=OK, -2=I2C error + * note: reading CTR1 clears INTAF + */ +int sd2506_clear_alarm(void) { + int ret = 0; + uint8_t val = 0; - /* 读取 CTR1, ARST=1 时自动清除 INTAF */ + /* 读取 CTR1, ARST=1 时自动清�?INTAF */ ret = sd2506_read_reg(SD2506_REG_CTR1, &val); if (ret != SD2506_OK) { return ret; @@ -371,11 +439,16 @@ int sd2506_clear_alarm(void) return SD2506_OK; } -int sd2506_read_ctr1(uint8_t *val) -{ - if (val == NULL) { +/* + * function: read control register 1 + * param: p_val - output value + * return: 0=OK, -2=I2C error + */ +int sd2506_read_ctr1(uint8_t *p_val) { + if (p_val == NULL) { return SD2506_ERROR; } - return sd2506_read_reg(SD2506_REG_CTR1, val); + return sd2506_read_reg(SD2506_REG_CTR1, p_val); } + diff --git a/Drivers/BSP/SD2506/sd2506.h b/Drivers/BSP/SD2506/sd2506.h index 827d5d7..d937002 100644 --- a/Drivers/BSP/SD2506/sd2506.h +++ b/Drivers/BSP/SD2506/sd2506.h @@ -180,7 +180,7 @@ int sd2506_init(void); * 3. 关闭写保护 * 注意:不可单独写某一个时间寄存器 */ -int sd2506_set_time(const sd2506_time_t *time); +int sd2506_set_time(const sd2506_time_t *p_time); /* * 函数功能:读取 RTC 时间日期 @@ -191,7 +191,7 @@ int sd2506_set_time(const sd2506_time_t *time); * 2. BCD 转十进制 * 3. 屏蔽小时 bit7 (12/24标志位) */ -int sd2506_get_time(sd2506_time_t *time); +int sd2506_get_time(sd2506_time_t *p_time); /* * 函数功能:读取芯片内部温度 @@ -200,7 +200,7 @@ int sd2506_get_time(sd2506_time_t *time); * 限定条件:sd2506_init() 已调用 * 函数说明:读取 16H 寄存器,bit7 为符号位,范围 -40~+85 */ -int sd2506_get_temperature(int8_t *temp); +int sd2506_get_temperature(int8_t *p_temp); /* * 函数功能:读取电池电压 (毫伏) @@ -210,7 +210,7 @@ int sd2506_get_temperature(int8_t *temp); * 函数说明:1. 读取 1AH bit7 (BAT8_VAL) 和 1BH (BAT_VL) * 2. 组合 9 位数据得到电压值 (如 0x135 = 309 = 3.09V) */ -int sd2506_get_battery_voltage(uint16_t *voltage); +int sd2506_get_battery_voltage(uint16_t *p_voltage); /* * 函数功能:读取芯片 8 字节 ID @@ -219,7 +219,7 @@ int sd2506_get_battery_voltage(uint16_t *voltage); * 限定条件:sd2506_init() 已调用 * 函数说明:读取 72H~79H 共 8 字节唯一 ID */ -int sd2506_get_id(uint8_t id[8]); +int sd2506_get_id(uint8_t p_id[8]); /* * 函数功能:读取用户 SRAM 数据 @@ -230,7 +230,7 @@ int sd2506_get_id(uint8_t id[8]); * 限定条件:sd2506_init() 已调用 * 函数说明:SRAM 地址范围 0~69,对应寄存器 2CH~71H */ -int sd2506_read_sram(uint8_t addr, uint8_t *buf, uint8_t len); +int sd2506_read_sram(uint8_t addr, uint8_t *p_buf, uint8_t len); /* * 函数功能:写入用户 SRAM 数据 @@ -242,7 +242,7 @@ int sd2506_read_sram(uint8_t addr, uint8_t *buf, uint8_t len); * 函数说明:SRAM 地址范围 0~69,对应寄存器 2CH~71H * SRAM 无需开写保护即可写入 */ -int sd2506_write_sram(uint8_t addr, const uint8_t *buf, uint8_t len); +int sd2506_write_sram(uint8_t addr, const uint8_t *p_buf, uint8_t len); /* * 函数功能:设置报警中断 @@ -255,7 +255,7 @@ int sd2506_write_sram(uint8_t addr, const uint8_t *buf, uint8_t len); * 3. 使能报警中断 INTAE * 4. 关写保护 */ -int sd2506_set_alarm(const sd2506_time_t *time, uint8_t mask); +int sd2506_set_alarm(const sd2506_time_t *p_time, uint8_t mask); /* * 函数功能:清除报警中断标志 @@ -271,7 +271,7 @@ int sd2506_clear_alarm(void); * 入口参数:val - 输出值指针 * 返回值:0 - 成功,-2 - I2C 通信错误 */ -int sd2506_read_ctr1(uint8_t *val); +int sd2506_read_ctr1(uint8_t *p_val); /* * 函数功能:BCD 码转十进制 diff --git a/Drivers/BSP/TPAFE5160/tpafe5160.c b/Drivers/BSP/TPAFE5160/tpafe5160.c index 0a0a35d..6b52bea 100644 --- a/Drivers/BSP/TPAFE5160/tpafe5160.c +++ b/Drivers/BSP/TPAFE5160/tpafe5160.c @@ -1,12 +1,9 @@ /* - * 模块名称:TPAFE5160 16位8通道同步采样ADC驱动 - * 模块功能:提供 TPAFE5160 并行接口模式下的初始化、过采样设置、转换启动、数据读取接口 - * 适用平台:STM32F407ZGT6,并行16位数据总线接 GPIOG[15:0] - * 作者:王建锋 - * 创建日期:2026-07-17 - * 修改记录: - * 2026-07-17 王建锋 创建初始版本,参考 AD7606 并行驱动及 TPAFE5160 手册 - * 2026-07-17 王建锋 增加 EXTI 中断读取模式 + * 模块名称:TPAFE5160 16�?通道同步采样ADC驱动 + * 模块功能:提�?TPAFE5160 并行接口模式下的初始化、过采样设置、转换启动、数据读取接�? * 适用平台:STM32F407ZGT6,并�?6位数据总线�?GPIOG[15:0] + * 作者:王建�? * 创建日期�?026-07-17 + * 修改记录�? * 2026-07-17 王建�? 创建初始版本,参�?AD7606 并行驱动�?TPAFE5160 手册 + * 2026-07-17 王建�? 增加 EXTI 中断读取模式 */ /* 头文件包含区 */ @@ -19,35 +16,31 @@ #define DBG_TAG "[ADC]" #include "dbg_log.h" -/* ======================== 私有宏定义 ======================== */ +/* ======================== 私有宏定�?======================== */ /* - * 并行读取时序延时 (168MHz 主频,1 NOP ≈ 5.95ns) + * 并行读取时序延时 (168MHz 主频�? NOP �?5.95ns) * - * TPAFE5160 并行时序要求 (VDRIVE > 2.7V): - * t10 (RD 低脉宽) ≥ 22ns - * t11 (RD 高脉宽) ≥ 10ns - * t14 (数据访问时间) ≤ 21ns (从 RD 下降沿算起) - * t15 (数据保持时间) ≥ 6ns (从 RD 下降沿算起) + * TPAFE5160 并行时序要求 (VDRIVE > 2.7V)�? * t10 (RD 低脉�? �?22ns + * t11 (RD 高脉�? �?10ns + * t14 (数据访问时间) �?21ns (�?RD 下降沿算�? + * t15 (数据保持时间) �?6ns (�?RD 下降沿算�? * - * GPIO 写操作本身约 1 个 AHB 周期 (~6ns), - * 加上端口延迟 (~12-18ns),实际 RD 引脚翻转滞后约 18-24ns。 - * 因此 NOP 延时只需覆盖数据建立时间即可。 - */ -#define TP_NOP_5() __NOP(); __NOP(); __NOP(); __NOP(); __NOP() + * GPIO 写操作本身约 1 �?AHB 周期 (~6ns)�? * 加上端口延迟 (~12-18ns),实�?RD 引脚翻转滞后�?18-24ns�? * 因此 NOP 延时只需覆盖数据建立时间即可�? */ +#define TPAFE5160_NOP_5() __NOP(); __NOP(); __NOP(); __NOP(); __NOP() -/* RD 低脉宽延时:GPIO写(~6ns) + 5NOP(~30ns) > 22ns */ -#define TP_RD_LOW_DLY() do { TPAFE5160_RD_LOW(); TP_NOP_5(); } while (0) +/* RD 低脉宽延时:GPIO�?~6ns) + 5NOP(~30ns) > 22ns */ +#define TPAFE5160_RD_LOW_DLY() do { TPAFE5160_RD_LOW(); TPAFE5160_NOP_5(); } while (0) -/* RD 高脉宽延时:GPIO写(~6ns) + 3NOP(~18ns) > 10ns */ -#define TP_RD_HIGH_DLY() do { TPAFE5160_RD_HIGH(); __NOP(); __NOP(); __NOP(); } while (0) +/* RD 高脉宽延时:GPIO�?~6ns) + 3NOP(~18ns) > 10ns */ +#define TPAFE5160_RD_HIGH_DLY() do { TPAFE5160_RD_HIGH(); __NOP(); __NOP(); __NOP(); } while (0) -/* CONVST 脉冲延时:上升沿前需保证低电平,5NOP 覆盖 t5 ≥ 20ns */ -#define TP_CONVST_PULSE() do { \ +/* CONVST 脉冲延时:上升沿前需保证低电平,5NOP 覆盖 t5 �?20ns */ +#define TPAFE5160_CONVST_PULSE() do { \ TPAFE5160_CONVST_LOW(); \ - TP_NOP_5(); \ + TPAFE5160_NOP_5(); \ TPAFE5160_CONVST_HIGH(); \ - TP_NOP_5(); \ + TPAFE5160_NOP_5(); \ } while (0) /* ======================== 私有函数声明 ======================== */ @@ -59,22 +52,20 @@ static void tpafe5160_read_channels(uint8_t count, int16_t *buf); /* * 函数功能:初始化 TPAFE5160(设置过采样、等待就绪) * 入口参数:无 - * 返回值:0 - 成功,-2 - BUSY 超时 - * 限定条件:CubeMX 已完成 GPIO 初始化 - * 函数说明:1. 设置过采样为无过采样 (000) + * 返回值:0 - 成功�?2 - BUSY 超时 + * 限定条件:CubeMX 已完�?GPIO 初始�? * 函数说明�?. 设置过采样为无过采样 (000) * 2. 确保 RD 为高、CONVST 为低 * 3. 等待 BUSY 释放(转换空闲) */ -int tpafe5160_init(void) -{ +int tpafe5160_init(void) { /* 设置默认过采样:无过采样 (OS[2:0] = 000) */ - tpafe5160_set_os(TP_OS_NONE); + tpafe5160_set_os(TPAFE5160_OS_NONE); - /* 确保控制引脚处于空闲状态 */ + /* 确保控制引脚处于空闲状�?*/ TPAFE5160_RD_HIGH(); TPAFE5160_CONVST_LOW(); - /* 等待 BUSY 释放,确保上电后无残留转换 */ + /* 等待 BUSY 释放,确保上电后无残留转�?*/ int ret = tpafe5160_wait_busy(TPAFE5160_CONV_TIMEOUT_MS); if (ret != TPAFE5160_OK) { DBG_ERROR("Init wait BUSY timeout"); @@ -85,14 +76,10 @@ int tpafe5160_init(void) } /* - * 函数功能:设置过采样率 - * 入口参数:os - 过采样率枚举值 tpafe5160_os_t - * 返回值:无 - * 限定条件:GPIO 已初始化 - * 函数说明:通过 OS[2:0] 引脚设置过采样率,在下一次 BUSY 下降沿锁存生效 - */ -void tpafe5160_set_os(tpafe5160_os_t os) -{ + * 函数功能:设置过采样�? * 入口参数:os - 过采样率枚举�? tpafe5160_os_t + * 返回值:�? * 限定条件:GPIO 已初始化 + * 函数说明:通过 OS[2:0] 引脚设置过采样率,在下一�?BUSY 下降沿锁存生�? */ +void tpafe5160_set_os(tpafe5160_os_t os) { TPAFE5160_OS0(os & 0x01); /* OS0 = bit0 */ TPAFE5160_OS1((os >> 1) & 0x01); /* OS1 = bit1 */ TPAFE5160_OS2((os >> 2) & 0x01); /* OS2 = bit2 */ @@ -101,27 +88,22 @@ void tpafe5160_set_os(tpafe5160_os_t os) /* * 函数功能:启动一次转换(CONVST 上升沿触发) * 入口参数:无 - * 返回值:无 - * 限定条件:GPIO 已初始化 - * 函数说明:产生 CONVST 脉冲上升沿,启动全部8通道同步采样与转换 - */ -void tpafe5160_start_conv(void) -{ - TP_CONVST_PULSE(); + * 返回值:�? * 限定条件:GPIO 已初始化 + * 函数说明:产�?CONVST 脉冲上升沿,启动全部8通道同步采样与转�? */ +void tpafe5160_start_conv(void) { + TPAFE5160_CONVST_PULSE(); } /* - * 函数功能:等待转换完成 - * 入口参数:timeout_ms - 超时时间 uint32_t > 0 - * 返回值:0 - 转换完成,-2 - 超时 + + * 函数功能:等待转换完�? * 入口参数:timeout_ms - 超时时间 uint32_t > 0 + * 返回值:0 - 转换完成�?2 - 超时 * 限定条件:已调用 tpafe5160_start_conv() - * 函数说明:轮询 BUSY 引脚等待下降沿 - */ -int tpafe5160_wait_busy(uint32_t timeout_ms) -{ + * 函数说明:轮�?BUSY 引脚等待下降�? */ +int tpafe5160_wait_busy(uint32_t timeout_ms) { uint32_t tick_start = HAL_GetTick(); - /* 等待 BUSY 释放(低电平表示空闲) */ + /* 等待 BUSY 释放(低电平表示空闲�?*/ while (TPAFE5160_BUSY_READ() == GPIO_PIN_SET) { if ((HAL_GetTick() - tick_start) >= timeout_ms) { return TPAFE5160_BUSY_TIMEOUT; @@ -132,29 +114,26 @@ int tpafe5160_wait_busy(uint32_t timeout_ms) } /* - * 函数功能:查询当前是否正在转换 - * 入口参数:无 - * 返回值:1 - 正在转换,0 - 空闲 + * 函数功能:查询当前是否正在转�? * 入口参数:无 + * 返回值:1 - 正在转换�? - 空闲 * 限定条件:GPIO 已初始化 - * 函数说明:读取 BUSY 引脚电平 + * 函数说明:读�?BUSY 引脚电平 */ -uint8_t tpafe5160_is_busy(void) -{ +uint8_t tpafe5160_is_busy(void) { return (TPAFE5160_BUSY_READ() == GPIO_PIN_SET) ? 1 : 0; } /* - * 函数功能:读取全部8通道转换结果 + * 函数功能:读取全�?通道转换结果 * 入口参数:buf - 8个int16_t的输出缓冲区 int16_t* 不为 NULL - * 返回值:0 - 成功,-2 - BUSY 超时 + * 返回值:0 - 成功�?2 - BUSY 超时 * 限定条件:GPIO 已初始化 - * 函数说明:1. 启动转换并等待 BUSY 释放 + * 函数说明�?. 启动转换并等�?BUSY 释放 * 2. 连续8次拉低RD读取各通道数据 * 3. 通过 FRSTDATA 验证第一通道 */ -int tpafe5160_read_all(int16_t *buf) -{ - int ret; +int tpafe5160_read_all(int16_t *buf) { + int ret = 0; /* 启动转换 */ tpafe5160_start_conv(); @@ -173,17 +152,15 @@ int tpafe5160_read_all(int16_t *buf) } /* - * 函数功能:读取指定通道的转换结果 - * 入口参数:channel - 通道号 uint8_t 0 - 7 + * 函数功能:读取指定通道的转换结�? * 入口参数:channel - 通道�? uint8_t 0 - 7 * value - 输出指针 int16_t* 不为 NULL - * 返回值:0 - 成功,-1 - 通道号无效,-2 - BUSY 超时 + * 返回值:0 - 成功�?1 - 通道号无效,-2 - BUSY 超时 * 限定条件:GPIO 已初始化 * 函数说明:启动转换并等待完成后,连续读取至指定通道 */ -int tpafe5160_read_channel(uint8_t channel, int16_t *value) -{ - int ret; - int16_t buf[TPAFE5160_CH_NUM]; +int tpafe5160_read_channel(uint8_t channel, int16_t *value) { + int ret = 0; + int16_t buf[TPAFE5160_CH_NUM] = {0}; if (channel >= TPAFE5160_CH_NUM || value == NULL) { return TPAFE5160_ERROR; @@ -199,29 +176,23 @@ int tpafe5160_read_channel(uint8_t channel, int16_t *value) } /* - * 函数功能:原始ADC值转电压值 - * 入口参数:raw - ADC原始值 int16_t 有符号补码 - * 返回值:电压值 float 单位 V + * 函数功能:原始ADC值转电压�? * 入口参数:raw - ADC原始�? int16_t 有符号补�? * 返回值:电压�? float 单位 V * 限定条件:无 - * 函数说明:±5V量程时 LSB = 10V / 65536 ≈ 152.59μV - * ±10V量程时 LSB = 20V / 65536 ≈ 305.18μV - * 硬件 RANGE 引脚接 GND,默认 ±5V 量程 + * 函数说明:�?V量程�?LSB = 10V / 65536 �?152.59μV + * ±10V量程�?LSB = 20V / 65536 �?305.18μV + * 硬件 RANGE 引脚�?GND,默�?±5V 量程 */ -float tpafe5160_to_voltage(int16_t raw) -{ - /* RANGE 接 GND → ±5V 量程,满量程 10V */ +float tpafe5160_to_voltage(int16_t raw) { + /* RANGE �?GND �?±5V 量程,满量程 10V */ return (float)raw * (10.0f / 65536.0f); } /* - * 函数功能:直接读取并行数据总线(不启动转换) - * 入口参数:无 - * 返回值:16位原始数据 uint16_t - * 限定条件:RD 为低或 CS 与 RD 已拉低 - * 函数说明:读取 GPIOG->IDR 低16位,对应 DB[15:0] + * 函数功能:直接读取并行数据总线(不启动转换�? * 入口参数:无 + * 返回值:16位原始数�? uint16_t + * 限定条件:RD 为低�?CS �?RD 已拉�? * 函数说明:读�?GPIOG->IDR �?6位,对应 DB[15:0] */ -uint16_t tpafe5160_read_bus(void) -{ +uint16_t tpafe5160_read_bus(void) { return TPAFE5160_READ_BUS(); } @@ -229,100 +200,82 @@ uint16_t tpafe5160_read_bus(void) /* * 函数功能:通过 RD 脉冲连续读取多个通道数据 - * 入口参数:count - 要读取的通道数 uint8_t 1 - 8 - * buf - 输出缓冲区 int16_t* 不为 NULL - * 返回值:无 - * 限定条件:转换已完成(BUSY 为低),RD 初始为高 - * 函数说明:每次 RD 下降沿输出一个通道数据,按通道1~8顺序输出 - * DB[15:0] 直接接 GPIOG[15:0],通过 IDR 寄存器一次读取 - * - * 时序关键点 (VDRIVE > 2.7V, 168MHz 主频): - * GPIO 写操作 ~6ns + 端口延迟 ~18ns → RD 引脚实际翻转约 24ns 后 - * t14 数据建立 ≤ 21ns → 数据在 RD 下降沿后 21ns 内有效 - * 5 个 NOP (~30ns) 覆盖建立时间 + * 入口参数:count - 要读取的通道�? uint8_t 1 - 8 + * buf - 输出缓冲�? int16_t* 不为 NULL + * 返回值:�? * 限定条件:转换已完成(BUSY 为低),RD 初始为高 + * 函数说明:每�?RD 下降沿输出一个通道数据,按通道1~8顺序输出 + * DB[15:0] 直接�?GPIOG[15:0],通过 IDR 寄存器一次读�? * + * 时序关键�?(VDRIVE > 2.7V, 168MHz 主频)�? * GPIO 写操�?~6ns + 端口延迟 ~18ns �?RD 引脚实际翻转�?24ns �? * t14 数据建立 �?21ns �?数据�?RD 下降沿后 21ns 内有�? * 5 �?NOP (~30ns) 覆盖建立时间 */ -static void tpafe5160_read_channels(uint8_t count, int16_t *buf) -{ +static void tpafe5160_read_channels(uint8_t count, int16_t *buf) { uint8_t i; for (i = 0; i < count; i++) { - /* RD 下降沿:ADC 输出当前通道数据到 DB[15:0] */ - TP_RD_LOW_DLY(); + /* RD 下降沿:ADC 输出当前通道数据�?DB[15:0] */ + TPAFE5160_RD_LOW_DLY(); - /* 读取16位并行数据 */ + /* 读取16位并行数�?*/ buf[i] = (int16_t)TPAFE5160_READ_BUS(); /* RD 上升沿:准备下一通道 */ - TP_RD_HIGH_DLY(); + TPAFE5160_RD_HIGH_DLY(); } } /* ======================== 中断模式实现 ======================== */ -/* 双缓冲区:ISR 写 s_buf_b,主循环读 s_buf_a */ +/* 双缓冲区:ISR �?s_buf_b,主循环�?s_buf_a */ static int16_t s_buf_a[TPAFE5160_CH_NUM]; static int16_t s_buf_b[TPAFE5160_CH_NUM]; static volatile uint8_t s_ready = 0; -static volatile uint8_t s_buf_sel = 0; /* 0 = 写 B / 读 A, 1 = 写 A / 读 B */ +static volatile uint8_t s_buf_sel = 0; /* 0 = �?B / �?A, 1 = �?A / �?B */ /* - * 函数功能:使能 BUSY EXTI 中断(运行时重使能用) - * 入口参数:无 - * 返回值:无 - * 限定条件:CubeMX 已完成 GPIO 和 NVIC 配置 - * 函数说明:正常启动流程无需调用,仅在 irq_disable() 后需要重新使能时使用 + * 函数功能:使�?BUSY EXTI 中断(运行时重使能用�? * 入口参数:无 + * 返回值:�? * 限定条件:CubeMX 已完�?GPIO �?NVIC 配置 + * 函数说明:正常启动流程无需调用,仅�?irq_disable() 后需要重新使能时使用 */ -void tpafe5160_irq_enable(void) -{ +void tpafe5160_irq_enable(void) { HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); } /* - * 函数功能:关闭 BUSY EXTI 中断 + * 函数功能:关�?BUSY EXTI 中断 * 入口参数:无 - * 返回值:无 - * 限定条件:已调用 tpafe5160_irq_enable() + * 返回值:�? * 限定条件:已调用 tpafe5160_irq_enable() * 函数说明:仅禁用 NVIC 中断,GPIO 配置保持 CubeMX 设定 */ -void tpafe5160_irq_disable(void) -{ +void tpafe5160_irq_disable(void) { HAL_NVIC_DisableIRQ(EXTI9_5_IRQn); } /* - * 函数功能:启动转换(中断模式) - * 入口参数:无 - * 返回值:无 - * 限定条件:已调用 tpafe5160_irq_enable() - * 函数说明:产生 CONVST 脉冲,转换完成后由 EXTI 中断自动读取 8 通道数据 + * 函数功能:启动转换(中断模式�? * 入口参数:无 + * 返回值:�? * 限定条件:已调用 tpafe5160_irq_enable() + * 函数说明:产�?CONVST 脉冲,转换完成后�?EXTI 中断自动读取 8 通道数据 */ -void tpafe5160_start_conv_irq(void) -{ +void tpafe5160_start_conv_irq(void) { s_ready = 0; - TP_CONVST_PULSE(); + TPAFE5160_CONVST_PULSE(); } /* * 函数功能:检查是否有新的转换数据 * 入口参数:无 - * 返回值:1 - 数据就绪,0 - 无新数据 + * 返回值:1 - 数据就绪�? - 无新数据 * 限定条件:中断模式已启用 * 函数说明:在 EXTI 回调中置位,主循环读取后需调用 tpafe5160_clear_ready() 清除 */ -uint8_t tpafe5160_data_ready(void) -{ +uint8_t tpafe5160_data_ready(void) { return s_ready; } /* - * 函数功能:清除数据就绪标志 - * 入口参数:无 - * 返回值:无 - * 限定条件:中断模式已启用 + * 函数功能:清除数据就绪标�? * 入口参数:无 + * 返回值:�? * 限定条件:中断模式已启用 * 函数说明:主循环处理完数据后调用 */ -void tpafe5160_clear_ready(void) -{ +void tpafe5160_clear_ready(void) { s_ready = 0; } @@ -330,23 +283,16 @@ void tpafe5160_clear_ready(void) * 函数功能:获取数据缓冲区指针 * 入口参数:无 * 返回值:int16_t[8] 数据缓冲区的 const 指针 - * 限定条件:tpafe5160_data_ready() 返回 1 时调用 - * 函数说明:双缓冲切换,ISR 写另一个缓冲区,主循环安全读取当前缓冲区 - */ -const int16_t* tpafe5160_get_buf(void) -{ + * 限定条件:tpafe5160_data_ready() 返回 1 时调�? * 函数说明:双缓冲切换,ISR 写另一个缓冲区,主循环安全读取当前缓冲�? */ +const int16_t* tpafe5160_get_buf(void) { return (s_buf_sel == 0) ? s_buf_a : s_buf_b; } /* - * 函数功能:BUSY 下降沿 EXTI 处理(由 HAL_GPIO_EXTI_Callback 调用) - * 入口参数:GPIO_Pin - 触发中断的引脚号 - * 返回值:无 - * 限定条件:BUSY EXTI 已使能 - * 函数说明:转换完成后自动读取 8 通道数据到缓冲区,耗时约 0.5µs (168MHz) + * 函数功能:BUSY 下降�?EXTI 处理(由 HAL_GPIO_EXTI_Callback 调用�? * 入口参数:GPIO_Pin - 触发中断的引脚号 + * 返回值:�? * 限定条件:BUSY EXTI 已使�? * 函数说明:转换完成后自动读取 8 通道数据到缓冲区,耗时�?0.5µs (168MHz) */ -void tpafe5160_exti_handler(uint16_t GPIO_Pin) -{ +void tpafe5160_exti_handler(uint16_t GPIO_Pin) { if (GPIO_Pin != TP_BUSY_Pin) { return; } @@ -357,9 +303,9 @@ void tpafe5160_exti_handler(uint16_t GPIO_Pin) /* 连续读取8个通道,约 0.5µs @ 168MHz */ uint8_t i; for (i = 0; i < TPAFE5160_CH_NUM; i++) { - TP_RD_LOW_DLY(); + TPAFE5160_RD_LOW_DLY(); p_wr[i] = (int16_t)TPAFE5160_READ_BUS(); - TP_RD_HIGH_DLY(); + TPAFE5160_RD_HIGH_DLY(); } /* 切换缓冲区并标记就绪 */ diff --git a/Drivers/BSP/TPAFE5160/tpafe5160.h b/Drivers/BSP/TPAFE5160/tpafe5160.h index 90d1569..6ec4309 100644 --- a/Drivers/BSP/TPAFE5160/tpafe5160.h +++ b/Drivers/BSP/TPAFE5160/tpafe5160.h @@ -48,20 +48,20 @@ extern "C" { /* 过采样率枚举 (OS[2:0] 编码,OS2为MSB, OS0为LSB) */ typedef enum { - TP_OS_NONE = 0, /* 000 — 无过采样,350 kSPS */ - TP_OS_X2 = 1, /* 001 — 2倍过采样,175 kSPS */ - TP_OS_X4 = 2, /* 010 — 4倍过采样,87.5 kSPS */ - TP_OS_X8 = 3, /* 011 — 8倍过采样,43.75 kSPS */ - TP_OS_X16 = 4, /* 100 — 16倍过采样,21.875 kSPS */ - TP_OS_X32 = 5, /* 101 — 32倍过采样,10.94 kSPS */ - TP_OS_X64 = 6, /* 110 — 64倍过采样,5.47 kSPS */ - TP_OS_HBW = 7 /* 111 — 高带宽模式 (~30kHz),350 kSPS */ + TPAFE5160_OS_NONE = 0, /* 000 — 无过采样,350 kSPS */ + TPAFE5160_OS_X2 = 1, /* 001 — 2倍过采样,175 kSPS */ + TPAFE5160_OS_X4 = 2, /* 010 — 4倍过采样,87.5 kSPS */ + TPAFE5160_OS_X8 = 3, /* 011 — 8倍过采样,43.75 kSPS */ + TPAFE5160_OS_X16 = 4, /* 100 — 16倍过采样,21.875 kSPS */ + TPAFE5160_OS_X32 = 5, /* 101 — 32倍过采样,10.94 kSPS */ + TPAFE5160_OS_X64 = 6, /* 110 — 64倍过采样,5.47 kSPS */ + TPAFE5160_OS_HBW = 7 /* 111 — 高带宽模式 (~30kHz),350 kSPS */ } tpafe5160_os_t; /* 输入量程枚举 */ typedef enum { - TP_RANGE_5V = 0, /* ±5V (RANGE = LOW) */ - TP_RANGE_10V = 1 /* ±10V (RANGE = HIGH) */ + TPAFE5160_RANGE_5V = 0, /* ±5V (RANGE = LOW) */ + TPAFE5160_RANGE_10V = 1 /* ±10V (RANGE = HIGH) */ } tpafe5160_range_t; /* 返回值定义 */ diff --git a/Drivers/BSP/dbg_cfg.h b/Drivers/BSP/dbg_cfg.h index 8a1b664..b3647b1 100644 --- a/Drivers/BSP/dbg_cfg.h +++ b/Drivers/BSP/dbg_cfg.h @@ -8,6 +8,11 @@ * - 两者都不定义:所有 DBG_* 宏为空操作(release 版本) * * 用户可在本文件中直接控制,也可在编译器预定义中覆盖 + * 适用平台:所有 BSP 驱动 + * 作者:王建锋 + * 创建日期:2026-07-18 + * 修改记录: + * 2026-07-18 王建锋 创建初始版本 */ #ifndef __DBG_CFG_H diff --git a/Drivers/BSP/dbg_log.h b/Drivers/BSP/dbg_log.h index 10b0fbf..ff3e71d 100644 --- a/Drivers/BSP/dbg_log.h +++ b/Drivers/BSP/dbg_log.h @@ -8,6 +8,10 @@ * #define DBG_TAG "[CH395]" * #include "dbg_log.h" * 适用平台:所有 BSP 驱动 + * 作者:王建锋 + * 创建日期:2026-07-18 + * 修改记录: + * 2026-07-18 王建锋 创建初始版本 */ #ifndef __DBG_LOG_H @@ -49,14 +53,14 @@ extern "C" { */ #define DBG_ERROR(fmt, ...) do { \ DBG_PRINT("[ERR]" DBG_TAG " " fmt "\r\n", ##__VA_ARGS__); \ -} while(0) +} while (0) /* * DBG_INFO - 信息输出,受 DBG_ENABLE 控制 */ #define DBG_INFO(fmt, ...) do { \ DBG_PRINT(DBG_TAG " " fmt "\r\n", ##__VA_ARGS__); \ -} while(0) +} while (0) /* * DBG_DEBUG - 调试输出,需 DBG_ENABLE + DBG_DEBUG_ENABLE 同时定义 @@ -64,7 +68,7 @@ extern "C" { #ifdef DBG_DEBUG_ENABLE #define DBG_DEBUG(fmt, ...) do { \ DBG_PRINT(DBG_TAG "(%s:%d) " fmt "\r\n", __func__, __LINE__, ##__VA_ARGS__); \ -} while(0) +} while (0) #else #define DBG_DEBUG(fmt, ...) #endif diff --git a/MDK-ARM/STM32F407-Demo.uvprojx b/MDK-ARM/STM32F407-Demo.uvprojx index f93d106..0749d72 100644 --- a/MDK-ARM/STM32F407-Demo.uvprojx +++ b/MDK-ARM/STM32F407-Demo.uvprojx @@ -340,7 +340,7 @@ USE_HAL_DRIVER,STM32F407xx - ../Inc;../Drivers/STM32F4xx_HAL_Driver/Inc;../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy;../Drivers/CMSIS/Device/ST/STM32F4xx/Include;../Drivers/CMSIS/Include;../Drivers/BSP;../Drivers/BSP/CH395F;../Drivers/BSP/GD5F2GQ5UE;../Lib/FlashDB/port/fal/inc;../Lib/FlashDB/inc;../Drivers/BSP/TPAFE5160;../Drivers/BSP/SD2506;../Drivers/BSP/RS485;../Drivers/BSP/NET;../Middlewares/Third_Party/FreeRTOS/Source/include;../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2;../Middlewares/Third_Party/FreeRTOS/Source/portable/RVDS/ARM_CM4F + ../Inc;../Drivers/STM32F4xx_HAL_Driver/Inc;../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy;../Drivers/CMSIS/Device/ST/STM32F4xx/Include;../Drivers/CMSIS/Include;../Drivers/BSP;../Drivers/BSP/CH395F;../Drivers/BSP/GD5F2GQ5UE;../Lib/FlashDB/port/fal/inc;../Lib/FlashDB/inc;../Drivers/BSP/TPAFE5160;../Drivers/BSP/SD2506;../Drivers/BSP/RS485;../Drivers/BSP/NET;../App;../App/task;../App/util;../Middlewares/Third_Party/FreeRTOS/Source/include;../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2;../Middlewares/Third_Party/FreeRTOS/Source/portable/RVDS/ARM_CM4F @@ -752,6 +752,46 @@ + + App + + + app_main.c + 1 + ..\App\app_main.c + + + sys_time.c + 1 + ..\App\sys_time.c + + + net_task.c + 1 + ..\App\task\net_task.c + + + adc_task.c + 1 + ..\App\task\adc_task.c + + + rs485_task.c + 1 + ..\App\task\rs485_task.c + + + ringbuf.c + 1 + ..\App\util\ringbuf.c + + + crc.c + 1 + ..\App\util\crc.c + + + Drivers/STM32F4xx_HAL_Driver diff --git a/MDK-ARM/build_log.txt b/MDK-ARM/build_log.txt index f069827..bda1137 100644 --- a/MDK-ARM/build_log.txt +++ b/MDK-ARM/build_log.txt @@ -1,4 +1,71 @@ *** Using Compiler 'V5.06 update 7 (build 960)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin' -Build target 'STM32F407-Demo' +Rebuild target 'STM32F407-Demo' +assembling startup_stm32f407xx.s... +compiling net_task.c... +compiling app_main.c... +compiling crc.c... +compiling ringbuf.c... +compiling dma.c... +compiling stm32f4xx_hal_flash_ex.c... +compiling sys_time.c... +compiling stm32f4xx_hal_msp.c... +compiling stm32f4xx_hal_timebase_tim.c... +compiling stm32f4xx_hal_flash_ramfunc.c... +compiling i2c.c... +compiling spi.c... +compiling gpio.c... +compiling stm32f4xx_it.c... +compiling stm32f4xx_hal_rcc_ex.c... +compiling usart.c... +compiling stm32f4xx_hal_dma.c... +compiling stm32f4xx_hal_gpio.c... +compiling freertos.c... +compiling stm32f4xx_hal_flash.c... +compiling rs485_task.c... +compiling stm32f4xx_hal_rcc.c... +compiling adc_task.c... +compiling main.c... +compiling stm32f4xx_hal_dma_ex.c... +compiling stm32f4xx_hal_tim_ex.c... +compiling stm32f4xx_hal_tim.c... +compiling fdb.c... +compiling fdb_utils.c... +compiling fdb_tsdb.c... +compiling fal.c... +compiling fdb_kvdb.c... +compiling fal_flash.c... +compiling croutine.c... +compiling fal_partition.c... +compiling list.c... +compiling event_groups.c... +compiling stream_buffer.c... +compiling queue.c... +compiling timers.c... +compiling tasks.c... +compiling port.c... +compiling heap_4.c... +compiling stm32f4xx_hal_pwr.c... +compiling stm32f4xx_hal_i2c_ex.c... +compiling stm32f4xx_hal_pwr_ex.c... +compiling system_stm32f4xx.c... +compiling stm32f4xx_hal_exti.c... +compiling fal_flash_gd5f2gq5ue.c... +compiling stm32f4xx_hal.c... +compiling stm32f4xx_hal_cortex.c... +compiling rs485.c... +compiling sd2506.c... +compiling tpafe5160.c... +compiling net_select.c... +compiling ch395f_test.c... +compiling ch395f.c... +compiling gd5f2gq5ue.c... +compiling stm32f4xx_hal_spi.c... +compiling net_socket.c... +compiling stm32f4xx_hal_uart.c... +compiling stm32f4xx_hal_i2c.c... +compiling cmsis_os2.c... +linking... +Program Size: Code=29372 RO-data=888 RW-data=180 ZI-data=41420 +FromELF: creating hex file... ".\STM32F407-Demo\STM32F407-Demo.axf" - 0 Error(s), 0 Warning(s). -Build Time Elapsed: 00:00:00 +Build Time Elapsed: 00:00:16 diff --git a/Src/freertos.c b/Src/freertos.c index 4c8cdeb..a4a4f98 100644 --- a/Src/freertos.c +++ b/Src/freertos.c @@ -25,10 +25,8 @@ /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ -#include "net_socket.h" -#include "net_select.h" +#include "net_task.h" #include "ch395f.h" -#include "ch395f_test.h" #include "dbg_log.h" /* USER CODE END Includes */ @@ -49,9 +47,7 @@ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN Variables */ -#ifdef ENABLE_PHASE4_TESTS -static uint8_t s_net_buf[1500]; -#endif + /* USER CODE END Variables */ /* Definitions for defaultTask */ osThreadId_t defaultTaskHandle; @@ -64,7 +60,7 @@ const osThreadAttr_t defaultTask_attributes = { osThreadId_t netTaskHandle; const osThreadAttr_t netTask_attributes = { .name = "netTask", - .stack_size = 1024 * 4, + .stack_size = 1024 * 8, .priority = (osPriority_t) osPriorityNormal, }; @@ -149,40 +145,7 @@ void StartDefaultTask(void *argument) void StartNetTask(void *argument) { /* USER CODE BEGIN StartNetTask */ - osDelay(2000); - - DBG_INFO("netTask: started"); - - for(;;) - { - net_poll(); - -#ifdef ENABLE_PHASE4_TESTS - for (int i = 1; i < 8; i++) - { - net_sock_t *sk = net_get_sock(i); - if (sk == NULL || !sk->in_use || sk->state != NET_SOCK_STATE_ESTABLISHED) - { - continue; - } - - int n = net_recv(i, s_net_buf, sizeof(s_net_buf), NET_MSG_DONTWAIT); - if (n > 0) - { - net_send(i, s_net_buf, n, 0); - } - } -#endif - -#ifdef ENABLE_PHASE5_TESTS - ch395f_phase5_tests(); -#endif -#ifdef ENABLE_PHASE7_TESTS - ch395f_phase7_tests(); -#endif - - osDelay(10); - } + net_task_func(argument); /* USER CODE END StartNetTask */ } diff --git a/test/ch395f_socket_test.py b/test/ch395f_socket_test.py index 7ef5858..f384b3b 100644 --- a/test/ch395f_socket_test.py +++ b/test/ch395f_socket_test.py @@ -525,40 +525,69 @@ def udp_echo_server_test(args): # ==================== 压力测试 ==================== -def stress_test_thread(client_id, args, results): +def stress_test_thread(client_id, args, results, barrier): """压力测试线程""" thread_name = f"Client-{client_id}" sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.settimeout(10) + sock.settimeout(5) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: + t0 = time.time() sock.connect((args.ip, args.port)) - log_success(f"[{thread_name}] 连接成功") + local = sock.getsockname() + remote = sock.getpeername() + t_conn = (time.time() - t0) * 1000 + log_success(f"[{thread_name}] 连接成功 " + f"(local={local[0]}:{local[1]}, " + f"remote={remote[0]}:{remote[1]}, " + f"{t_conn:.0f}ms)") + + barrier.wait() success_count = 0 fail_count = 0 for i in range(args.count): try: - # 发送 test_data = f"T{client_id:02d}_{i:04d}".encode() + t_send = time.time() sock.send(test_data) - - # 接收 data = sock.recv(100) - if data and data == test_data: - success_count += 1 + t_rtt = (time.time() - t_send) * 1000 + if data: + if data == test_data: + success_count += 1 + log_info(f"[{thread_name}] #{i}: OK ({t_rtt:.0f}ms)") + else: + fail_count += 1 + log_warn(f"[{thread_name}] #{i}: MISMATCH " + f"want={len(test_data)}B/{test_data[:20].decode(errors='replace')!r} " + f"got={len(data)}B/{data[:20].decode(errors='replace')!r}" + f" ({t_rtt:.0f}ms)") else: fail_count += 1 + log_warn(f"[{thread_name}] #{i}: recv returned empty ({t_rtt:.0f}ms)") + except socket.timeout: + fail_count += 1 + t_elapsed = (time.time() - t_send) * 1000 + log_error(f"[{thread_name}] #{i}: TIMEOUT ({t_elapsed:.0f}ms)") + except ConnectionResetError: + fail_count += 1 + t_elapsed = (time.time() - t_send) * 1000 + log_error(f"[{thread_name}] #{i}: RESET by peer ({t_elapsed:.0f}ms)") except Exception as e: fail_count += 1 + t_elapsed = (time.time() - t_send) * 1000 + log_error(f"[{thread_name}] #{i}: {type(e).__name__}: {e} ({t_elapsed:.0f}ms)") results[client_id] = (success_count, fail_count) - log_info(f"[{thread_name}] 完成: 成功 {success_count}, 失败 {fail_count}") + t_total = (time.time() - t0) * 1000 + log_info(f"[{thread_name}] 完成: 成功 {success_count}, 失败 {fail_count} ({t_total:.0f}ms)") except Exception as e: - log_error(f"[{thread_name}] 错误: {e}") + log_error(f"[{thread_name}] 连接失败: {type(e).__name__}: {e}") results[client_id] = (0, args.count) finally: sock.close() @@ -575,12 +604,13 @@ def stress_test(args): results = {} threads = [] + barrier = threading.Barrier(num_clients) # 创建并启动线程 for i in range(num_clients): thread = threading.Thread( target=stress_test_thread, - args=(i, args, results) + args=(i, args, results, barrier) ) threads.append(thread) thread.start()