TCP可以正常使用
This commit is contained in:
59
AGENTS.md
59
AGENTS.md
@@ -13,6 +13,13 @@ STM32F4-Base/
|
|||||||
├── Drivers/
|
├── Drivers/
|
||||||
│ ├── BSP/
|
│ ├── BSP/
|
||||||
│ │ ├── CH395F/ # CH395F 以太网芯片驱动(手写)
|
│ │ ├── CH395F/ # CH395F 以太网芯片驱动(手写)
|
||||||
|
│ │ ├── NET/ # BSD Socket API 网络抽象层(手写)
|
||||||
|
│ │ │ ├── net_config.h # 网络配置宏定义
|
||||||
|
│ │ │ ├── net_types.h # 类型定义、地址结构、Socket 控制块
|
||||||
|
│ │ │ ├── net_socket.h # BSD Socket API 头文件
|
||||||
|
│ │ │ ├── net_socket.c # API 核心实现 + 状态机
|
||||||
|
│ │ │ ├── net_select.h # select/poll API 头文件
|
||||||
|
│ │ │ └── net_select.c # select/poll 实现
|
||||||
│ │ ├── GD5F2GQ5UE/ # GD5F2GQ5UE NAND Flash 驱动(手写)
|
│ │ ├── GD5F2GQ5UE/ # GD5F2GQ5UE NAND Flash 驱动(手写)
|
||||||
│ │ │ ├── gd5f2gq5ue.h/c # 底层 SPI 驱动
|
│ │ │ ├── gd5f2gq5ue.h/c # 底层 SPI 驱动
|
||||||
│ │ │ ├── fal_flash_gd5f2gq5ue.c # FAL 设备适配层
|
│ │ │ ├── fal_flash_gd5f2gq5ue.c # FAL 设备适配层
|
||||||
@@ -37,6 +44,8 @@ STM32F4-Base/
|
|||||||
|---|---|
|
|---|---|
|
||||||
| `Src/main.c` | 程序入口,初始化序列及主循环 |
|
| `Src/main.c` | 程序入口,初始化序列及主循环 |
|
||||||
| `Drivers/BSP/CH395F/ch395f.c/h` | CH395F 以太网芯片 SPI 驱动 |
|
| `Drivers/BSP/CH395F/ch395f.c/h` | CH395F 以太网芯片 SPI 驱动 |
|
||||||
|
| `Drivers/BSP/NET/net_socket.c/h` | BSD Socket API 网络抽象层 |
|
||||||
|
| `Drivers/BSP/NET/net_select.c/h` | select/poll I/O 多路复用 |
|
||||||
| `Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c/h` | GD5F2GQ5UE NAND Flash SPI 驱动 |
|
| `Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c/h` | GD5F2GQ5UE NAND Flash SPI 驱动 |
|
||||||
| `Drivers/BSP/GD5F2GQ5UE/fal_flash_gd5f2gq5ue.c` | FAL 设备适配层 |
|
| `Drivers/BSP/GD5F2GQ5UE/fal_flash_gd5f2gq5ue.c` | FAL 设备适配层 |
|
||||||
| `Drivers/BSP/TPAFE5160/tpafe5160.c/h` | TPAFE5160 ADC 并行接口驱动 |
|
| `Drivers/BSP/TPAFE5160/tpafe5160.c/h` | TPAFE5160 ADC 并行接口驱动 |
|
||||||
@@ -52,6 +61,29 @@ STM32F4-Base/
|
|||||||
- C 标准:C99
|
- C 标准:C99
|
||||||
- 全局宏定义:`USE_HAL_DRIVER, STM32F407xx`
|
- 全局宏定义:`USE_HAL_DRIVER, STM32F407xx`
|
||||||
|
|
||||||
|
### 命令行编译(Agent 使用)
|
||||||
|
|
||||||
|
修改代码后必须执行命令行编译验证,编译脚本位于 `MDK-ARM/build.bat`:
|
||||||
|
|
||||||
|
```
|
||||||
|
cmd /c "cd /d "工作目录" && build.bat"
|
||||||
|
```
|
||||||
|
|
||||||
|
实际执行示例(从项目根目录):
|
||||||
|
|
||||||
|
```
|
||||||
|
cmd /c "cd /d "D:\Code\DTU 程序\STM32F4-Base\MDK-ARM" && build.bat"
|
||||||
|
```
|
||||||
|
|
||||||
|
**编译结果判读:**
|
||||||
|
- 退出码 0:无错误无警告,编译成功
|
||||||
|
- 退出码 1:有警告无错误,编译失败(警告不可接受,需修复)
|
||||||
|
- 退出码 2+:编译失败,需查看 `MDK-ARM/build_log.txt` 定位错误
|
||||||
|
|
||||||
|
**UV4.exe 路径:** `C:\Keil_v5\UV4\UV4.exe`
|
||||||
|
**工程文件:** `MDK-ARM/STM32F407-Demo.uvprojx`
|
||||||
|
**目标名称:** `STM32F407-Demo`
|
||||||
|
|
||||||
## 硬件配置
|
## 硬件配置
|
||||||
|
|
||||||
- **主频:** HSE 25MHz → PLL 168MHz (4/168/2)
|
- **主频:** HSE 25MHz → PLL 168MHz (4/168/2)
|
||||||
@@ -96,6 +128,11 @@ HAL_Init() → SystemClock_Config() → MX_GPIO_Init() → MX_USART1_UART_Init()
|
|||||||
- **`SET_PHY` 必须在 `INIT_CH395` 之后**,它会复位 MAC/PHY 建立物理链路,不影响已锁定的协议栈参数
|
- **`SET_PHY` 必须在 `INIT_CH395` 之后**,它会复位 MAC/PHY 建立物理链路,不影响已锁定的协议栈参数
|
||||||
- **`CMD_PING_ENABLE` 不需要显式调用**,INIT 后默认可用
|
- **`CMD_PING_ENABLE` 不需要显式调用**,INIT 后默认可用
|
||||||
- 每次 SPI 事务需调用 `ch395f_spi_begin()` / `ch395f_spi_end()` 包裹
|
- 每次 SPI 事务需调用 `ch395f_spi_begin()` / `ch395f_spi_end()` 包裹
|
||||||
|
- **大数据量收发使用 SPI2 DMA**:`ch395f_write_send_buf()` 和 `ch395f_read_recv_buf()` 已改造为 DMA 批量传输(DMA1_Stream3 RX, DMA1_Stream4 TX),命令和配置操作仍使用逐字节轮询
|
||||||
|
- DMA 缓冲区:`s_spi2_dma_tx_buf[1500]` / `s_spi2_dma_rx_buf[1500]`,4 字节对齐
|
||||||
|
- **TCP 重传参数**:`SET_RETRAN_COUNT`(默认12次,最大20)和 `SET_RETRAN_PERIOD`(默认500ms,最大1000ms)必须在 `INIT_CH395` 之前设置,总重传时间 = 次数 × 周期
|
||||||
|
- **KeepAlive 参数必须为 500ms 的倍数**:`SET_KEEPALIVE_IDLE`(默认20000ms)、`SET_KEEPALIVE_INTVL`(默认15000ms)单位为 ms,且 IDLE 必须 > INTVL,均为 500 的倍数;传入非 500 倍数的值会导致未定义行为(CH395F 内部定时器异常,TCP 连接几秒内 TIMEOUT)
|
||||||
|
- **KeepAlive 默认关闭**:需在 `SINT_STAT_CONNECT` 后调用 `ch395f_set_keepalive_enable(sock, 1)` 启用
|
||||||
|
|
||||||
## GD5F2GQ5UE 驱动关键点
|
## GD5F2GQ5UE 驱动关键点
|
||||||
|
|
||||||
@@ -124,6 +161,28 @@ HAL_Init() → SystemClock_Config() → MX_GPIO_Init() → MX_USART1_UART_Init()
|
|||||||
- 读取时序:168MHz 下 GPIO 写操作 + 5个 NOP (~30ns) 覆盖 t10=22ns 和 t14=21ns 要求
|
- 读取时序:168MHz 下 GPIO 写操作 + 5个 NOP (~30ns) 覆盖 t10=22ns 和 t14=21ns 要求
|
||||||
- 硬件 RANGE 接 GND → ±5V 量程,LSB=152.59µV
|
- 硬件 RANGE 接 GND → ±5V 量程,LSB=152.59µV
|
||||||
|
|
||||||
|
## NET 网络层关键点
|
||||||
|
|
||||||
|
- **文件结构**:`Drivers/BSP/NET/` 下包含 net_config.h、net_types.h、net_socket.h/c、net_select.h/c
|
||||||
|
- **使用前必须调用** `net_init(ip, mask, gateway)` 初始化网络子系统
|
||||||
|
- **主循环必须调用** `net_poll()` 轮询所有 Socket 状态,处理中断事件
|
||||||
|
- **TCP Server 多连接模式**:1 个监听 Socket + 最多 7 个数据 Socket
|
||||||
|
- **select/poll 支持**:`net_select()` 和 `net_poll_events()` 用于 I/O 多路复用
|
||||||
|
- **事件回调**:可通过 `net_set_event_cb()` 注册连接/断开/数据到达等事件回调
|
||||||
|
- **非阻塞模式**:`net_recv()` 使用 `NET_MSG_DONTWAIT` 标志,或使用 select/poll
|
||||||
|
- **字节序转换**:使用 `net_htons()/net_ntohs()/net_htonl()/net_ntohl()` 进行主机序/网络序转换
|
||||||
|
- **IP 地址转换**:`net_inet_addr("192.168.1.100")` 字符串转网络序,`net_inet_ntoa()` 反向转换
|
||||||
|
- **注意**:新文件需手动添加到 Keil MDK 工程中才能编译
|
||||||
|
- **RECV 中断是电平触发的**:`net_poll()` 中 `do { ... } while(0)` 只处理一批中断,由主循环读取数据,避免无限循环导致主循环饿死
|
||||||
|
- **TCP Server 多连接模式**:Socket 0 专职监听,Socket 1~7 自动分配
|
||||||
|
- **多连接模式初始化顺序(关键!遗漏将导致 TCP 连接失败)**:
|
||||||
|
1. `ch395f_set_fun_para(0x02)` — 启用多连接(在 `INIT_CH395` 之前)
|
||||||
|
2. `ch395f_init()` — 协议栈初始化
|
||||||
|
3. Socket 0: `SET_PROTO_TCP → SET_SOUR_PORT → OPEN → TCP_LISTEN`
|
||||||
|
4. **Socket 1~7: `SET_PROTO_TCP → SET_SOUR_PORT(相同端口)`(不 OPEN!)**
|
||||||
|
- 如果不配置数据 Socket 的协议类型和源端口,CH395F 不知道哪些 Socket 可用于多连接分配,客户端连接会被静默拒绝(无 CONNECT 中断)
|
||||||
|
- **TCP Server 单连接模式**:Socket 先 `OPEN` → `SET_PROTO_TCP` → `SET_SOUR_PORT` → `OPEN` → `TCP_LISTEN`;收到 `SINT_STAT_CONNECT` 后 Socket 自动切换为数据通道;`DISCONNECT`/`TIMEOUT` 后需重新 `OPEN` → `TCP_LISTEN`
|
||||||
|
|
||||||
## 已知问题
|
## 已知问题
|
||||||
|
|
||||||
### CH395F 与 RTL8305NBI 自动协商不兼容
|
### CH395F 与 RTL8305NBI 自动协商不兼容
|
||||||
|
|||||||
@@ -7,12 +7,15 @@
|
|||||||
* 创建日期:2026-03-14
|
* 创建日期:2026-03-14
|
||||||
* 修改记录:
|
* 修改记录:
|
||||||
* 2026-03-14 王建锋 创建初始版本,按代码规范重构
|
* 2026-03-14 王建锋 创建初始版本,按代码规范重构
|
||||||
|
* 2026-07-18 王建锋 改造 write_send_buf / read_recv_buf 使用 SPI2 DMA 批量传输
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* 头文件包含区 - 先包含本模块头文件,再包含依赖头文件 */
|
/* 头文件包含区 - 先包含本模块头文件,再包含依赖头文件 */
|
||||||
#include "ch395f.h"
|
#include "ch395f.h"
|
||||||
#include "spi.h"
|
#include "spi.h"
|
||||||
|
#include "usart.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 私有宏定义区
|
* 私有宏定义区
|
||||||
@@ -21,12 +24,24 @@
|
|||||||
#define CH395F_RESET_DELAY_MS 20U /* 复位后等待延时(ms) */
|
#define CH395F_RESET_DELAY_MS 20U /* 复位后等待延时(ms) */
|
||||||
#define CH395F_INIT_TIMEOUT_MS 500U /* 初始化超时时间(ms) */
|
#define CH395F_INIT_TIMEOUT_MS 500U /* 初始化超时时间(ms) */
|
||||||
#define CH395F_SPI_BEGIN_DELAY_MS 1U /* SPI 事务开始延时(ms) */
|
#define CH395F_SPI_BEGIN_DELAY_MS 1U /* SPI 事务开始延时(ms) */
|
||||||
|
#define CH395F_DMA_BUF_SIZE 1500U /* DMA 缓冲区最大字节数 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 私有变量区 - DMA 传输相关
|
||||||
|
*/
|
||||||
|
static volatile uint8_t s_spi2_dma_done = 0U; /* DMA 传输完成标志 */
|
||||||
|
|
||||||
|
__attribute__((aligned(4)))
|
||||||
|
static uint8_t s_spi2_dma_tx_buf[CH395F_DMA_BUF_SIZE]; /* DMA 发送缓冲区 */
|
||||||
|
__attribute__((aligned(4)))
|
||||||
|
static uint8_t s_spi2_dma_rx_buf[CH395F_DMA_BUF_SIZE]; /* DMA 接收缓冲区 */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 私有函数声明区
|
* 私有函数声明区
|
||||||
*/
|
*/
|
||||||
static void ch395f_spi_begin(void);
|
static void ch395f_spi_begin(void);
|
||||||
static void ch395f_spi_end(void);
|
static void ch395f_spi_end(void);
|
||||||
|
static void ch395f_spi_dma_transfer(uint16_t len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 私有函数实现区
|
* 私有函数实现区
|
||||||
@@ -34,14 +49,14 @@ static void ch395f_spi_end(void);
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:开始 SPI 事务(CS 拉高 -> 拉低)
|
* 函数功能:开始 SPI 事务(CS 拉高 -> 拉低)
|
||||||
* 函数说明:手册要求 SPI 模式下字节间无需间隔
|
* 函数说明:手册要求 SPI 模式下字节间无需间隔,
|
||||||
|
* CS 拉高再拉低满足最小片选间隔要求
|
||||||
*/
|
*/
|
||||||
static void ch395f_spi_begin(void)
|
static void ch395f_spi_begin(void)
|
||||||
{
|
{
|
||||||
/* CS 先拉高,确保空闲状态 */
|
/* CS 先拉高,确保空闲状态 */
|
||||||
HAL_GPIO_WritePin(CH395_SCS_GPIO_Port, CH395_SCS_Pin, GPIO_PIN_SET);
|
HAL_GPIO_WritePin(CH395_SCS_GPIO_Port, CH395_SCS_Pin, GPIO_PIN_SET);
|
||||||
HAL_Delay(CH395F_SPI_BEGIN_DELAY_MS);
|
/* CS 拉低,启动事务(无需额外延时,SPI 时序由 SCK 频率决定) */
|
||||||
/* CS 拉低,启动事务 */
|
|
||||||
HAL_GPIO_WritePin(CH395_SCS_GPIO_Port, CH395_SCS_Pin, GPIO_PIN_RESET);
|
HAL_GPIO_WritePin(CH395_SCS_GPIO_Port, CH395_SCS_Pin, GPIO_PIN_RESET);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,6 +69,81 @@ static void ch395f_spi_end(void)
|
|||||||
HAL_GPIO_WritePin(CH395_SCS_GPIO_Port, CH395_SCS_Pin, GPIO_PIN_SET);
|
HAL_GPIO_WritePin(CH395_SCS_GPIO_Port, CH395_SCS_Pin, GPIO_PIN_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:DMA 全双工传输并等待完成
|
||||||
|
* 入口参数:len - 传输字节数 uint16_t
|
||||||
|
* 函数说明:发送 s_spi2_dma_tx_buf,接收到 s_spi2_dma_rx_buf,
|
||||||
|
* 阻塞等待 DMA 完成回调置位标志
|
||||||
|
*/
|
||||||
|
static void ch395f_spi_dma_transfer(uint16_t len)
|
||||||
|
{
|
||||||
|
HAL_StatusTypeDef status;
|
||||||
|
uint32_t tickstart;
|
||||||
|
volatile uint32_t loop_cnt = 0U;
|
||||||
|
|
||||||
|
s_spi2_dma_done = 0U;
|
||||||
|
status = HAL_SPI_TransmitReceive_DMA(&hspi2, s_spi2_dma_tx_buf, s_spi2_dma_rx_buf, len);
|
||||||
|
if (status != HAL_OK)
|
||||||
|
{
|
||||||
|
printf("[DMA] HAL_SPI_TransmitReceive_DMA FAIL: %d, SPI_State=%d, SPI_Error=0x%lX, DMA_State=%d\r\n",
|
||||||
|
(int)status,
|
||||||
|
(int)hspi2.State,
|
||||||
|
hspi2.ErrorCode,
|
||||||
|
(int)hspi2.hdmarx->State);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tickstart = HAL_GetTick();
|
||||||
|
while (s_spi2_dma_done == 0U)
|
||||||
|
{
|
||||||
|
loop_cnt++;
|
||||||
|
if ((HAL_GetTick() - tickstart) > 1000U)
|
||||||
|
{
|
||||||
|
printf("[DMA] TIMEOUT after 1s, len=%d, loop=%lu, SPI_State=%d, SPI_Error=0x%lX\r\n",
|
||||||
|
(int)len, loop_cnt,
|
||||||
|
(int)hspi2.State,
|
||||||
|
hspi2.ErrorCode);
|
||||||
|
printf("[DMA] DMA_RX: State=%d, Dir=%lu, CNT=%lu\r\n",
|
||||||
|
(int)hspi2.hdmarx->State,
|
||||||
|
hspi2.hdmarx->Init.Direction,
|
||||||
|
__HAL_DMA_GET_COUNTER(hspi2.hdmarx));
|
||||||
|
printf("[DMA] DMA_TX: State=%d, Dir=%lu, CNT=%lu\r\n",
|
||||||
|
(int)hspi2.hdmatx->State,
|
||||||
|
hspi2.hdmatx->Init.Direction,
|
||||||
|
__HAL_DMA_GET_COUNTER(hspi2.hdmatx));
|
||||||
|
printf("[DMA] SPI2_CR1=0x%lX, CR2=0x%lX, SR=0x%lX\r\n",
|
||||||
|
SPI2->CR1, SPI2->CR2, SPI2->SR);
|
||||||
|
/* 强制复位 SPI2 DMA 状态,避免死锁 */
|
||||||
|
HAL_SPI_Abort(&hspi2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:SPI 收发完成回调
|
||||||
|
* 函数说明:由 HAL SPI 驱动在 DMA TX+RX 完成后调用(HAL_SPI_TransmitReceive_DMA 触发此回调)
|
||||||
|
*/
|
||||||
|
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
|
||||||
|
{
|
||||||
|
if (hspi->Instance == SPI2)
|
||||||
|
{
|
||||||
|
s_spi2_dma_done = 1U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:SPI 错误回调
|
||||||
|
* 函数说明:由 HAL SPI 驱动在 DMA 传输出错时调用,释放等待
|
||||||
|
*/
|
||||||
|
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
|
||||||
|
{
|
||||||
|
if (hspi->Instance == SPI2)
|
||||||
|
{
|
||||||
|
s_spi2_dma_done = 1U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 公共函数实现区
|
* 公共函数实现区
|
||||||
*/
|
*/
|
||||||
@@ -164,6 +254,299 @@ uint8_t ch395f_get_version(void)
|
|||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:获取远端 IP 和端口
|
||||||
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* p_buf - 6 字节输出缓冲区(4字节IP + 2字节端口)
|
||||||
|
* 限定条件:TCP Server 模式下连接建立后调用
|
||||||
|
* 函数说明:IP 低字节在前,端口低字节在前
|
||||||
|
*/
|
||||||
|
void ch395f_get_remot_ipp(uint8_t sock, uint8_t *p_buf)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
/* 检查输入参数合法性 */
|
||||||
|
if (p_buf == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 开始 SPI 事务 */
|
||||||
|
ch395f_spi_begin();
|
||||||
|
|
||||||
|
/* 发送获取远端 IP 和端口命令 */
|
||||||
|
ch395f_write_cmd(CH395F_CMD_GET_REMOT_IPP_SN);
|
||||||
|
|
||||||
|
/* 发送 Socket 索引 */
|
||||||
|
ch395f_write_data(sock);
|
||||||
|
|
||||||
|
/* 读取 4 字节 IP 地址 */
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
p_buf[i] = ch395f_read_data();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 读取 2 字节端口号 */
|
||||||
|
for (i = 4; i < 6; i++)
|
||||||
|
{
|
||||||
|
p_buf[i] = ch395f_read_data();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 结束 SPI 事务 */
|
||||||
|
ch395f_spi_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:设置 CH395 功能参数
|
||||||
|
* 入口参数:para - 4 字节功能参数 uint32_t
|
||||||
|
* 限定条件:必须在 ch395f_init() 之前调用
|
||||||
|
*/
|
||||||
|
void ch395f_set_fun_para(uint32_t para)
|
||||||
|
{
|
||||||
|
/* 开始 SPI 事务 */
|
||||||
|
ch395f_spi_begin();
|
||||||
|
|
||||||
|
/* 发送设置功能参数命令 */
|
||||||
|
ch395f_write_cmd(CH395F_CMD_SET_FUN_PARA);
|
||||||
|
|
||||||
|
/* 发送 4 字节参数(低字节在前) */
|
||||||
|
ch395f_write_data((uint8_t)(para));
|
||||||
|
ch395f_write_data((uint8_t)(para >> 8));
|
||||||
|
ch395f_write_data((uint8_t)(para >> 16));
|
||||||
|
ch395f_write_data((uint8_t)(para >> 24));
|
||||||
|
|
||||||
|
/* 结束 SPI 事务 */
|
||||||
|
ch395f_spi_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:设置 TCP MSS
|
||||||
|
* 入口参数:mss - MSS 值 uint16_t 60~1460
|
||||||
|
* 限定条件:必须在 ch395f_init() 之前调用
|
||||||
|
*/
|
||||||
|
void ch395f_set_tcp_mss(uint16_t mss)
|
||||||
|
{
|
||||||
|
/* 开始 SPI 事务 */
|
||||||
|
ch395f_spi_begin();
|
||||||
|
|
||||||
|
/* 发送设置 TCP MSS 命令 */
|
||||||
|
ch395f_write_cmd(CH395F_CMD_SET_TCP_MSS);
|
||||||
|
|
||||||
|
/* 发送 2 字节 MSS 值(低字节在前) */
|
||||||
|
ch395f_write_data(mss & 0xFFU);
|
||||||
|
ch395f_write_data((mss >> 8) & 0xFFU);
|
||||||
|
|
||||||
|
/* 结束 SPI 事务 */
|
||||||
|
ch395f_spi_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:设置 Socket 接收缓冲区
|
||||||
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* start_block - 起始块地址 uint8_t
|
||||||
|
* block_count - 块个数 uint8_t
|
||||||
|
* 限定条件:必须在 OPEN_SOCKET_SN 之前调用
|
||||||
|
*/
|
||||||
|
void ch395f_set_recv_buf(uint8_t sock, uint8_t start_block, uint8_t block_count)
|
||||||
|
{
|
||||||
|
/* 开始 SPI 事务 */
|
||||||
|
ch395f_spi_begin();
|
||||||
|
|
||||||
|
/* 发送设置接收缓冲区命令 */
|
||||||
|
ch395f_write_cmd(CH395F_CMD_SET_RECV_BUF);
|
||||||
|
|
||||||
|
/* 发送 Socket 索引 */
|
||||||
|
ch395f_write_data(sock);
|
||||||
|
|
||||||
|
/* 发送起始块地址 */
|
||||||
|
ch395f_write_data(start_block);
|
||||||
|
|
||||||
|
/* 发送块个数 */
|
||||||
|
ch395f_write_data(block_count);
|
||||||
|
|
||||||
|
/* 结束 SPI 事务 */
|
||||||
|
ch395f_spi_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:设置 Socket 发送缓冲区
|
||||||
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* start_block - 起始块地址 uint8_t
|
||||||
|
* block_count - 块个数 uint8_t
|
||||||
|
* 限定条件:必须在 OPEN_SOCKET_SN 之前调用
|
||||||
|
*/
|
||||||
|
void ch395f_set_send_buf(uint8_t sock, uint8_t start_block, uint8_t block_count)
|
||||||
|
{
|
||||||
|
/* 开始 SPI 事务 */
|
||||||
|
ch395f_spi_begin();
|
||||||
|
|
||||||
|
/* 发送设置发送缓冲区命令 */
|
||||||
|
ch395f_write_cmd(CH395F_CMD_SET_SEND_BUF);
|
||||||
|
|
||||||
|
/* 发送 Socket 索引 */
|
||||||
|
ch395f_write_data(sock);
|
||||||
|
|
||||||
|
/* 发送起始块地址 */
|
||||||
|
ch395f_write_data(start_block);
|
||||||
|
|
||||||
|
/* 发送块个数 */
|
||||||
|
ch395f_write_data(block_count);
|
||||||
|
|
||||||
|
/* 结束 SPI 事务 */
|
||||||
|
ch395f_spi_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:清空 Socket 接收缓冲区
|
||||||
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* 限定条件:Socket 已打开
|
||||||
|
*/
|
||||||
|
void ch395f_clear_recv_buf(uint8_t sock)
|
||||||
|
{
|
||||||
|
/* 开始 SPI 事务 */
|
||||||
|
ch395f_spi_begin();
|
||||||
|
|
||||||
|
/* 发送清空接收缓冲区命令 */
|
||||||
|
ch395f_write_cmd(CH395F_CMD_CLEAR_RECV_BUF_SN);
|
||||||
|
|
||||||
|
/* 发送 Socket 索引 */
|
||||||
|
ch395f_write_data(sock);
|
||||||
|
|
||||||
|
/* 结束 SPI 事务 */
|
||||||
|
ch395f_spi_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:设置 TCP KeepAlive 空闲时间
|
||||||
|
* 入口参数:time - 空闲时间(秒) uint32_t
|
||||||
|
* 限定条件:必须在 ch395f_init() 之前调用
|
||||||
|
*/
|
||||||
|
void ch395f_set_keepalive_idle(uint32_t time)
|
||||||
|
{
|
||||||
|
/* 开始 SPI 事务 */
|
||||||
|
ch395f_spi_begin();
|
||||||
|
|
||||||
|
/* 发送设置 KeepAlive 空闲时间命令 */
|
||||||
|
ch395f_write_cmd(CH395F_CMD_SET_KEEPALIVE_IDLE);
|
||||||
|
|
||||||
|
/* 发送 4 字节时间值(低字节在前) */
|
||||||
|
ch395f_write_data((uint8_t)(time));
|
||||||
|
ch395f_write_data((uint8_t)(time >> 8));
|
||||||
|
ch395f_write_data((uint8_t)(time >> 16));
|
||||||
|
ch395f_write_data((uint8_t)(time >> 24));
|
||||||
|
|
||||||
|
/* 结束 SPI 事务 */
|
||||||
|
ch395f_spi_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:设置 TCP KeepAlive 探测间隔
|
||||||
|
* 入口参数:time - 间隔时间(秒) uint32_t
|
||||||
|
* 限定条件:必须在 ch395f_init() 之前调用
|
||||||
|
*/
|
||||||
|
void ch395f_set_keepalive_intvl(uint32_t time)
|
||||||
|
{
|
||||||
|
/* 开始 SPI 事务 */
|
||||||
|
ch395f_spi_begin();
|
||||||
|
|
||||||
|
/* 发送设置 KeepAlive 探测间隔命令 */
|
||||||
|
ch395f_write_cmd(CH395F_CMD_SET_KEEPALIVE_INTVL);
|
||||||
|
|
||||||
|
/* 发送 4 字节时间值(低字节在前) */
|
||||||
|
ch395f_write_data((uint8_t)(time));
|
||||||
|
ch395f_write_data((uint8_t)(time >> 8));
|
||||||
|
ch395f_write_data((uint8_t)(time >> 16));
|
||||||
|
ch395f_write_data((uint8_t)(time >> 24));
|
||||||
|
|
||||||
|
/* 结束 SPI 事务 */
|
||||||
|
ch395f_spi_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:设置 TCP KeepAlive 探测次数
|
||||||
|
* 入口参数:cnt - 探测次数 uint8_t
|
||||||
|
* 限定条件:必须在 ch395f_init() 之前调用
|
||||||
|
*/
|
||||||
|
void ch395f_set_keepalive_cnt(uint8_t cnt)
|
||||||
|
{
|
||||||
|
/* 开始 SPI 事务 */
|
||||||
|
ch395f_spi_begin();
|
||||||
|
|
||||||
|
/* 发送设置 KeepAlive 探测次数命令 */
|
||||||
|
ch395f_write_cmd(CH395F_CMD_SET_KEEPALIVE_CNT);
|
||||||
|
|
||||||
|
/* 发送探测次数 */
|
||||||
|
ch395f_write_data(cnt);
|
||||||
|
|
||||||
|
/* 结束 SPI 事务 */
|
||||||
|
ch395f_spi_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:启用/禁用指定 Socket 的 KeepAlive
|
||||||
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* enable - 1 启用,0 禁用 uint8_t
|
||||||
|
* 限定条件:Socket 已打开
|
||||||
|
*/
|
||||||
|
void ch395f_set_keepalive_enable(uint8_t sock, uint8_t enable)
|
||||||
|
{
|
||||||
|
/* 开始 SPI 事务 */
|
||||||
|
ch395f_spi_begin();
|
||||||
|
|
||||||
|
/* 发送设置 KeepAlive 使能命令 */
|
||||||
|
ch395f_write_cmd(CH395F_CMD_SET_KEEPALIVE_SN);
|
||||||
|
|
||||||
|
/* 发送 Socket 索引 */
|
||||||
|
ch395f_write_data(sock);
|
||||||
|
|
||||||
|
/* 发送使能标志 */
|
||||||
|
ch395f_write_data(enable);
|
||||||
|
|
||||||
|
/* 结束 SPI 事务 */
|
||||||
|
ch395f_spi_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:设置 TCP 重传次数
|
||||||
|
* 入口参数:cnt - 重传次数 uint8_t(0=使用默认值5)
|
||||||
|
* 限定条件:必须在 ch395f_init() 之前调用
|
||||||
|
*/
|
||||||
|
void ch395f_set_retrans_count(uint8_t cnt)
|
||||||
|
{
|
||||||
|
/* 开始 SPI 事务 */
|
||||||
|
ch395f_spi_begin();
|
||||||
|
|
||||||
|
/* 发送设置重传次数命令 */
|
||||||
|
ch395f_write_cmd(CH395F_CMD_SET_RETRAN_COUNT);
|
||||||
|
|
||||||
|
/* 发送重传次数 */
|
||||||
|
ch395f_write_data(cnt);
|
||||||
|
|
||||||
|
/* 结束 SPI 事务 */
|
||||||
|
ch395f_spi_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:设置 TCP 重传周期
|
||||||
|
* 入口参数:period - 重传周期(毫秒) uint16_t
|
||||||
|
* 限定条件:必须在 ch395f_init() 之前调用
|
||||||
|
*/
|
||||||
|
void ch395f_set_retrans_period(uint16_t period)
|
||||||
|
{
|
||||||
|
/* 开始 SPI 事务 */
|
||||||
|
ch395f_spi_begin();
|
||||||
|
|
||||||
|
/* 发送设置重传周期命令 */
|
||||||
|
ch395f_write_cmd(CH395F_CMD_SET_RETRAN_PERIOD);
|
||||||
|
|
||||||
|
/* 发送 2 字节周期值(低字节在前) */
|
||||||
|
ch395f_write_data(period & 0xFFU);
|
||||||
|
ch395f_write_data((period >> 8) & 0xFFU);
|
||||||
|
|
||||||
|
/* 结束 SPI 事务 */
|
||||||
|
ch395f_spi_end();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:软件复位 CH395
|
* 函数功能:软件复位 CH395
|
||||||
* 返回值:CH395F_STATUS_OK
|
* 返回值:CH395F_STATUS_OK
|
||||||
@@ -211,55 +594,58 @@ uint8_t ch395f_get_cmd_status(void)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:轮询等待命令执行完成
|
||||||
|
* 入口参数:timeout_ms - 超时时间(毫秒) uint32_t
|
||||||
|
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 或 CH395F_CMD_RET_ABORT)
|
||||||
|
* 限定条件:在发送长执行命令后调用
|
||||||
|
* 函数说明:每 20ms 查询一次,直到命令完成或超时
|
||||||
|
*/
|
||||||
|
uint8_t ch395f_poll_cmd_status(uint32_t timeout_ms)
|
||||||
|
{
|
||||||
|
uint8_t status;
|
||||||
|
uint32_t retry_count = 0U;
|
||||||
|
uint32_t max_retries = (timeout_ms + 20U - 1U) / 20U;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
HAL_Delay(20U);
|
||||||
|
status = ch395f_get_cmd_status();
|
||||||
|
|
||||||
|
if (status != CH395F_ERR_BUSY)
|
||||||
|
{
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++retry_count >= max_retries)
|
||||||
|
{
|
||||||
|
return CH395F_ERR_BUSY; /* 超时 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:初始化 CH395(包含 MAC、PHY、TCP/IP 协议栈)
|
* 函数功能:初始化 CH395(包含 MAC、PHY、TCP/IP 协议栈)
|
||||||
* 返回值:CH395F_STATUS_OK - 成功,CH395F_STATUS_TIMEOUT - 超时失败
|
* 返回值:CH395F_STATUS_OK - 成功,CH395F_STATUS_TIMEOUT - 超时失败
|
||||||
* 限定条件:芯片已通过 ch395f_reset() 复位
|
* 限定条件:芯片已通过 ch395f_reset() 复位
|
||||||
* 函数说明:阻塞等待初始化完成或超时(典型 5ms,TE1)
|
* 函数说明:阻塞等待初始化完成或超时(芯片需要约 200ms,这里等最多 4s)
|
||||||
*/
|
*/
|
||||||
ch395f_status_t ch395f_init(void)
|
ch395f_status_t ch395f_init(void)
|
||||||
{
|
{
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
uint32_t retry_count = 0U;
|
|
||||||
|
|
||||||
/* 开始 SPI 事务 */
|
|
||||||
ch395f_spi_begin();
|
ch395f_spi_begin();
|
||||||
|
|
||||||
/* 发送初始化命令 */
|
|
||||||
ch395f_write_cmd(CH395F_CMD_INIT_CH395);
|
ch395f_write_cmd(CH395F_CMD_INIT_CH395);
|
||||||
|
|
||||||
/* 结束 SPI 事务 */
|
|
||||||
ch395f_spi_end();
|
ch395f_spi_end();
|
||||||
|
|
||||||
/* 轮询等待初始化完成 */
|
status = ch395f_poll_cmd_status(4000U);
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
/* 每次轮询延时 1ms */
|
|
||||||
HAL_Delay(1U);
|
|
||||||
|
|
||||||
/* 查询命令执行状态 */
|
|
||||||
status = ch395f_get_cmd_status();
|
|
||||||
|
|
||||||
/* 状态非 BUSY 表示执行完毕 */
|
|
||||||
if (status != CH395F_ERR_BUSY)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 超时判断 */
|
|
||||||
if (++retry_count > CH395F_INIT_TIMEOUT_MS)
|
|
||||||
{
|
|
||||||
return CH395F_STATUS_TIMEOUT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 返回最终执行结果 */
|
|
||||||
if (status == CH395F_ERR_SUCCESS)
|
if (status == CH395F_ERR_SUCCESS)
|
||||||
{
|
{
|
||||||
return CH395F_STATUS_OK;
|
return CH395F_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CH395F_STATUS_ERROR;
|
return (status == CH395F_ERR_BUSY) ? CH395F_STATUS_TIMEOUT : CH395F_STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -673,114 +1059,95 @@ void ch395f_set_sour_port(uint8_t sock, uint16_t port)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:打开 Socket
|
* 函数功能:打开 Socket
|
||||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t
|
||||||
* 限定条件:协议类型、目标 IP、端口已设置
|
* 限定条件:协议类型、目标 IP、端口已设置
|
||||||
*/
|
*/
|
||||||
void ch395f_open_socket(uint8_t sock)
|
uint8_t ch395f_open_socket(uint8_t sock)
|
||||||
{
|
{
|
||||||
/* 开始 SPI 事务 */
|
|
||||||
ch395f_spi_begin();
|
ch395f_spi_begin();
|
||||||
|
|
||||||
/* 发送打开 Socket 命令 */
|
|
||||||
ch395f_write_cmd(CH395F_CMD_OPEN_SOCKET_SN);
|
ch395f_write_cmd(CH395F_CMD_OPEN_SOCKET_SN);
|
||||||
|
|
||||||
/* 发送 Socket 索引 */
|
|
||||||
ch395f_write_data(sock);
|
ch395f_write_data(sock);
|
||||||
|
|
||||||
/* 结束 SPI 事务 */
|
|
||||||
ch395f_spi_end();
|
ch395f_spi_end();
|
||||||
|
|
||||||
|
return ch395f_poll_cmd_status(4000U);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:关闭 Socket
|
* 函数功能:关闭 Socket
|
||||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t
|
||||||
* 限定条件:Socket 已打开
|
* 限定条件:Socket 已打开
|
||||||
*/
|
*/
|
||||||
void ch395f_close_socket(uint8_t sock)
|
uint8_t ch395f_close_socket(uint8_t sock)
|
||||||
{
|
{
|
||||||
/* 开始 SPI 事务 */
|
|
||||||
ch395f_spi_begin();
|
ch395f_spi_begin();
|
||||||
|
|
||||||
/* 发送关闭 Socket 命令 */
|
|
||||||
ch395f_write_cmd(CH395F_CMD_CLOSE_SOCKET_SN);
|
ch395f_write_cmd(CH395F_CMD_CLOSE_SOCKET_SN);
|
||||||
|
|
||||||
/* 发送 Socket 索引 */
|
|
||||||
ch395f_write_data(sock);
|
ch395f_write_data(sock);
|
||||||
|
|
||||||
/* 结束 SPI 事务 */
|
|
||||||
ch395f_spi_end();
|
ch395f_spi_end();
|
||||||
|
|
||||||
|
return ch395f_poll_cmd_status(4000U);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:启动 TCP 监听模式
|
* 函数功能:启动 TCP 监听模式
|
||||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t
|
||||||
* 限定条件:Socket 已打开且协议类型为 TCP
|
* 限定条件:Socket 已打开且协议类型为 TCP
|
||||||
*/
|
*/
|
||||||
void ch395f_tcp_listen(uint8_t sock)
|
uint8_t ch395f_tcp_listen(uint8_t sock)
|
||||||
{
|
{
|
||||||
/* 开始 SPI 事务 */
|
|
||||||
ch395f_spi_begin();
|
ch395f_spi_begin();
|
||||||
|
|
||||||
/* 发送 TCP 监听命令 */
|
|
||||||
ch395f_write_cmd(CH395F_CMD_TCP_LISTEN_SN);
|
ch395f_write_cmd(CH395F_CMD_TCP_LISTEN_SN);
|
||||||
|
|
||||||
/* 发送 Socket 索引 */
|
|
||||||
ch395f_write_data(sock);
|
ch395f_write_data(sock);
|
||||||
|
|
||||||
/* 结束 SPI 事务 */
|
|
||||||
ch395f_spi_end();
|
ch395f_spi_end();
|
||||||
|
|
||||||
|
return ch395f_poll_cmd_status(4000U);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:启动 TCP 连接
|
* 函数功能:启动 TCP 连接
|
||||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t
|
||||||
* 限定条件:Socket 已打开且协议类型为 TCP
|
* 限定条件:Socket 已打开且协议类型为 TCP
|
||||||
*/
|
*/
|
||||||
void ch395f_tcp_connect(uint8_t sock)
|
uint8_t ch395f_tcp_connect(uint8_t sock)
|
||||||
{
|
{
|
||||||
/* 开始 SPI 事务 */
|
|
||||||
ch395f_spi_begin();
|
ch395f_spi_begin();
|
||||||
|
|
||||||
/* 发送 TCP 连接命令 */
|
|
||||||
ch395f_write_cmd(CH395F_CMD_TCP_CONNECT_SN);
|
ch395f_write_cmd(CH395F_CMD_TCP_CONNECT_SN);
|
||||||
|
|
||||||
/* 发送 Socket 索引 */
|
|
||||||
ch395f_write_data(sock);
|
ch395f_write_data(sock);
|
||||||
|
|
||||||
/* 结束 SPI 事务 */
|
|
||||||
ch395f_spi_end();
|
ch395f_spi_end();
|
||||||
|
|
||||||
|
return ch395f_poll_cmd_status(4000U);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:断开 TCP 连接
|
* 函数功能:断开 TCP 连接
|
||||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t
|
||||||
* 限定条件:TCP 已建立连接
|
* 限定条件:TCP 已建立连接
|
||||||
*/
|
*/
|
||||||
void ch395f_tcp_disconnect(uint8_t sock)
|
uint8_t ch395f_tcp_disconnect(uint8_t sock)
|
||||||
{
|
{
|
||||||
/* 开始 SPI 事务 */
|
|
||||||
ch395f_spi_begin();
|
ch395f_spi_begin();
|
||||||
|
|
||||||
/* 发送 TCP 断开命令 */
|
|
||||||
ch395f_write_cmd(CH395F_CMD_TCP_DISCONNECT_SN);
|
ch395f_write_cmd(CH395F_CMD_TCP_DISCONNECT_SN);
|
||||||
|
|
||||||
/* 发送 Socket 索引 */
|
|
||||||
ch395f_write_data(sock);
|
ch395f_write_data(sock);
|
||||||
|
|
||||||
/* 结束 SPI 事务 */
|
|
||||||
ch395f_spi_end();
|
ch395f_spi_end();
|
||||||
|
|
||||||
|
return ch395f_poll_cmd_status(4000U);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:向 Socket 发送缓冲区写入数据
|
* 函数功能:向 Socket 发送缓冲区写入数据(DMA 批量传输)
|
||||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
||||||
* p_data - 数据指针 uint8_t*
|
* p_data - 数据指针 uint8_t*
|
||||||
* len - 数据长度 uint16_t
|
* len - 数据长度 uint16_t
|
||||||
* 限定条件:指针非空,长度大于 0,TCP 已连接或 UDP 已打开
|
* 限定条件:指针非空,长度大于 0,TCP 已连接或 UDP 已打开
|
||||||
|
* 函数说明:将命令头和数据打包到 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 i;
|
uint16_t total;
|
||||||
|
|
||||||
/* 检查输入参数合法性 */
|
/* 检查输入参数合法性 */
|
||||||
if (p_data == NULL)
|
if (p_data == NULL)
|
||||||
@@ -788,41 +1155,40 @@ void ch395f_write_send_buf(uint8_t sock, uint8_t *p_data, uint16_t len)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 开始 SPI 事务 */
|
/* 计算总长度:1(cmd) + 1(sock) + 2(len) + data */
|
||||||
ch395f_spi_begin();
|
total = 4U + len;
|
||||||
|
if (total > CH395F_DMA_BUF_SIZE)
|
||||||
/* 发送写入发送缓冲区命令 */
|
|
||||||
ch395f_write_cmd(CH395F_CMD_WRITE_SEND_BUF_SN);
|
|
||||||
|
|
||||||
/* 发送 Socket 索引 */
|
|
||||||
ch395f_write_data(sock);
|
|
||||||
|
|
||||||
/* 发送数据长度低字节 */
|
|
||||||
ch395f_write_data(len & 0xFFU);
|
|
||||||
|
|
||||||
/* 发送数据长度高字节 */
|
|
||||||
ch395f_write_data((len >> 8) & 0xFFU);
|
|
||||||
|
|
||||||
/* 逐字节发送数据 */
|
|
||||||
for (i = 0; i < len; i++)
|
|
||||||
{
|
{
|
||||||
ch395f_write_data(p_data[i]);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 结束 SPI 事务 */
|
/* 打包命令头到 DMA 发送缓冲区 */
|
||||||
|
s_spi2_dma_tx_buf[0] = CH395F_CMD_WRITE_SEND_BUF_SN;
|
||||||
|
s_spi2_dma_tx_buf[1] = sock;
|
||||||
|
s_spi2_dma_tx_buf[2] = len & 0xFFU;
|
||||||
|
s_spi2_dma_tx_buf[3] = (len >> 8) & 0xFFU;
|
||||||
|
|
||||||
|
/* 拷贝用户数据到 DMA 发送缓冲区 */
|
||||||
|
memcpy(&s_spi2_dma_tx_buf[4], p_data, len);
|
||||||
|
|
||||||
|
/* CS 拉低 -> DMA 批量传输 -> CS 拉高 */
|
||||||
|
ch395f_spi_begin();
|
||||||
|
ch395f_spi_dma_transfer(total);
|
||||||
ch395f_spi_end();
|
ch395f_spi_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:从 Socket 接收缓冲区读取数据
|
* 函数功能:从 Socket 接收缓冲区读取数据(DMA 批量传输)
|
||||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
||||||
* p_data - 输出缓冲区指针 uint8_t*
|
* p_data - 输出缓冲区指针 uint8_t*
|
||||||
* len - 待读取数据长度 uint16_t
|
* len - 待读取数据长度 uint16_t
|
||||||
* 限定条件:指针非空,长度大于 0,接收缓冲区有数据
|
* 限定条件:指针非空,长度大于 0,接收缓冲区有数据
|
||||||
|
* 函数说明:命令头打包到发送缓冲区(数据部分填 0xFF 作时钟),
|
||||||
|
* 一次 SPI DMA 全双工传输,有效数据从接收缓冲区偏移 4 字节处拷出
|
||||||
*/
|
*/
|
||||||
void ch395f_read_recv_buf(uint8_t sock, uint8_t *p_data, uint16_t len)
|
void ch395f_read_recv_buf(uint8_t sock, uint8_t *p_data, uint16_t len)
|
||||||
{
|
{
|
||||||
uint16_t i;
|
uint16_t total;
|
||||||
|
|
||||||
/* 检查输入参数合法性 */
|
/* 检查输入参数合法性 */
|
||||||
if (p_data == NULL)
|
if (p_data == NULL)
|
||||||
@@ -830,29 +1196,29 @@ void ch395f_read_recv_buf(uint8_t sock, uint8_t *p_data, uint16_t len)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 开始 SPI 事务 */
|
/* 计算总长度:1(cmd) + 1(sock) + 2(len) + data */
|
||||||
ch395f_spi_begin();
|
total = 4U + len;
|
||||||
|
if (total > CH395F_DMA_BUF_SIZE)
|
||||||
/* 发送读取接收缓冲区命令 */
|
|
||||||
ch395f_write_cmd(CH395F_CMD_READ_RECV_BUF_SN);
|
|
||||||
|
|
||||||
/* 发送 Socket 索引 */
|
|
||||||
ch395f_write_data(sock);
|
|
||||||
|
|
||||||
/* 发送读取长度低字节 */
|
|
||||||
ch395f_write_data(len & 0xFFU);
|
|
||||||
|
|
||||||
/* 发送读取长度高字节 */
|
|
||||||
ch395f_write_data((len >> 8) & 0xFFU);
|
|
||||||
|
|
||||||
/* 逐字节读取数据 */
|
|
||||||
for (i = 0; i < len; i++)
|
|
||||||
{
|
{
|
||||||
p_data[i] = ch395f_read_data();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 结束 SPI 事务 */
|
/* 命令头打包到 DMA 发送缓冲区 */
|
||||||
|
s_spi2_dma_tx_buf[0] = CH395F_CMD_READ_RECV_BUF_SN;
|
||||||
|
s_spi2_dma_tx_buf[1] = sock;
|
||||||
|
s_spi2_dma_tx_buf[2] = len & 0xFFU;
|
||||||
|
s_spi2_dma_tx_buf[3] = (len >> 8) & 0xFFU;
|
||||||
|
|
||||||
|
/* 数据部分填充 0xFF(SPI 时钟驱动用) */
|
||||||
|
memset(&s_spi2_dma_tx_buf[4], 0xFFU, len);
|
||||||
|
|
||||||
|
/* CS 拉低 -> DMA 全双工传输(发命令头 + 收数据) -> CS 拉高 */
|
||||||
|
ch395f_spi_begin();
|
||||||
|
ch395f_spi_dma_transfer(total);
|
||||||
ch395f_spi_end();
|
ch395f_spi_end();
|
||||||
|
|
||||||
|
/* 从 DMA 接收缓冲区偏移 4 字节处拷贝有效数据到用户缓冲区 */
|
||||||
|
memcpy(p_data, &s_spi2_dma_rx_buf[4], len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -910,6 +1276,24 @@ uint8_t ch395f_get_glob_int_status(void)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:获取全局中断状态(2 字节版,支持 Socket 0~7)
|
||||||
|
* 返回值:中断状态 uint16_t(低字节=Socket 0~3 + PHY/DHCP,高字节=Socket 4~7 + DHCPv6)
|
||||||
|
* 限定条件:芯片已初始化
|
||||||
|
*/
|
||||||
|
uint16_t ch395f_get_glob_int_status_all(void)
|
||||||
|
{
|
||||||
|
uint16_t status;
|
||||||
|
|
||||||
|
ch395f_spi_begin();
|
||||||
|
ch395f_write_cmd(CH395F_CMD_GET_GLOB_INT_STATUS_ALL);
|
||||||
|
status = (uint16_t)ch395f_read_data();
|
||||||
|
status |= ((uint16_t)ch395f_read_data() << 8U);
|
||||||
|
ch395f_spi_end();
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:获取 Socket 中断状态
|
* 函数功能:获取 Socket 中断状态
|
||||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
||||||
@@ -937,3 +1321,68 @@ uint8_t ch395f_get_sock_int_status(uint8_t sock)
|
|||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:获取 Socket 状态(2 字节输出)
|
||||||
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* status - 2 字节输出缓冲区 [0]=Socket状态, [1]=TCP状态
|
||||||
|
* 限定条件:芯片已初始化
|
||||||
|
*/
|
||||||
|
void ch395f_get_socket_status(uint8_t sock, uint8_t *status)
|
||||||
|
{
|
||||||
|
ch395f_spi_begin();
|
||||||
|
ch395f_write_cmd(CH395F_CMD_GET_SOCKET_STATUS_SN);
|
||||||
|
ch395f_write_data(sock);
|
||||||
|
status[0] = ch395f_read_data();
|
||||||
|
status[1] = ch395f_read_data();
|
||||||
|
ch395f_spi_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:设置 ARP 重传参数
|
||||||
|
* 入口参数:period_100ms - ARP 重传周期(单位 100ms,0=默认值=10即1秒) uint8_t
|
||||||
|
* cnt - ARP 重传次数(0=默认值=3) uint8_t
|
||||||
|
* 限定条件:应在 ch395f_init() 之后调用
|
||||||
|
* 函数说明:周期最大值约 25.5 秒,255 表示无限重传
|
||||||
|
*/
|
||||||
|
void ch395f_set_arp(uint8_t period_100ms, uint8_t cnt)
|
||||||
|
{
|
||||||
|
ch395f_spi_begin();
|
||||||
|
ch395f_write_cmd(CH395F_CMD_SET_ARP);
|
||||||
|
ch395f_write_data(period_100ms);
|
||||||
|
ch395f_write_data(cnt);
|
||||||
|
ch395f_spi_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:设置 Socket TTL
|
||||||
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* ttl - TTL 值 uint8_t 最大 128
|
||||||
|
* 限定条件:Socket 已打开,TCP Server 模式下不生效
|
||||||
|
*/
|
||||||
|
void ch395f_set_ttl(uint8_t sock, uint8_t ttl)
|
||||||
|
{
|
||||||
|
ch395f_spi_begin();
|
||||||
|
ch395f_write_cmd(CH395F_CMD_SET_TTL);
|
||||||
|
ch395f_write_data(sock);
|
||||||
|
ch395f_write_data(ttl);
|
||||||
|
ch395f_spi_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:获取不可达信息(用于调试连接失败原因)
|
||||||
|
* 出口参数:p_buf - 8 字节输出缓冲区(类型+协议码+端口+IP)
|
||||||
|
* 限定条件:收到 GINT_STAT_UNREACH 中断后调用
|
||||||
|
*/
|
||||||
|
void ch395f_get_unreach_info(uint8_t *p_buf)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
ch395f_spi_begin();
|
||||||
|
ch395f_write_cmd(CH395F_CMD_GET_UNREACH_IPPT);
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
p_buf[i] = ch395f_read_data();
|
||||||
|
}
|
||||||
|
ch395f_spi_end();
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ extern "C" {
|
|||||||
#define CH395F_CMD_GET_CMD_STATUS 0x2CU
|
#define CH395F_CMD_GET_CMD_STATUS 0x2CU
|
||||||
#define CH395F_CMD_GET_GLOB_INT_STATUS 0x29U
|
#define CH395F_CMD_GET_GLOB_INT_STATUS 0x29U
|
||||||
#define CH395F_CMD_GET_GLOB_INT_STATUS_ALL 0x19U
|
#define CH395F_CMD_GET_GLOB_INT_STATUS_ALL 0x19U
|
||||||
|
#define CH395F_CMD_GET_UNREACH_IPPT 0x28U
|
||||||
#define CH395F_CMD_GET_PHY_STATUS 0x26U
|
#define CH395F_CMD_GET_PHY_STATUS 0x26U
|
||||||
#define CH395F_CMD_GET_DHCP_STATUS 0x42U
|
#define CH395F_CMD_GET_DHCP_STATUS 0x42U
|
||||||
|
|
||||||
@@ -124,19 +125,26 @@ extern "C" {
|
|||||||
#define CH395F_CMD_WRITE_GPIO_REG 0xEDU
|
#define CH395F_CMD_WRITE_GPIO_REG 0xEDU
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CH395 错误码(来自手册 CH395INC.H 引用)
|
* CH395 命令执行状态码(CMD_GET_CMD_STATUS 返回值,与芯片手册一致)
|
||||||
*/
|
*/
|
||||||
#define CH395F_ERR_SUCCESS 0x00U
|
#define CH395F_ERR_SUCCESS 0x00U /* 成功 */
|
||||||
#define CH395F_ERR_BUSY 0x01U
|
#define CH395F_ERR_BUSY 0x10U /* 忙,命令正在执行 */
|
||||||
#define CH395F_ERR_CMD 0x02U
|
#define CH395F_ERR_MEM 0x11U /* 内存管理错误 */
|
||||||
#define CH395F_ERR_MAC 0x03U
|
#define CH395F_ERR_BUF 0x12U /* 缓冲区错误 */
|
||||||
#define CH395F_ERR_PHY 0x04U
|
#define CH395F_ERR_TIMEOUT 0x13U /* 超时 */
|
||||||
#define CH395F_ERR_IP_CONFLI 0x05U
|
#define CH395F_ERR_RTE 0x14U /* 路由错误 */
|
||||||
#define CH395F_ERR_SOCK 0x06U
|
#define CH395F_ERR_ABRT 0x15U /* 连接中止 */
|
||||||
#define CH395F_ERR_SOCK_BUSY 0x07U
|
#define CH395F_ERR_RST 0x16U /* 连接复位 */
|
||||||
#define CH395F_ERR_SOCK_CLOSED 0x08U
|
#define CH395F_ERR_CLSD 0x17U /* 连接关闭 */
|
||||||
#define CH395F_ERR_SOCK_ERR 0x09U
|
#define CH395F_ERR_CONN 0x18U /* 无连接 */
|
||||||
#define CH395F_ERR_UNKNOW 0xFFU
|
#define CH395F_ERR_VAL 0x19U /* 值错误 */
|
||||||
|
#define CH395F_ERR_ARG 0x1AH /* 参数错误 */
|
||||||
|
#define CH395F_ERR_USE 0x1BH /* 已被使用 */
|
||||||
|
#define CH395F_ERR_IF 0x1CH /* MAC 错误 */
|
||||||
|
#define CH395F_ERR_ISCONN 0x1DH /* 已连接 */
|
||||||
|
#define CH395F_ERR_OPEN 0x20U /* 已打开 */
|
||||||
|
#define CH395F_CMD_RET_ABORT 0x5FU /* 命令中止(来自官方库) */
|
||||||
|
#define CH395F_ERR_UNKNOW 0xFAU /* 未知错误」 */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PHY 状态码
|
* PHY 状态码
|
||||||
@@ -148,6 +156,13 @@ extern "C" {
|
|||||||
#define CH395F_PHY_100M_HALF 0x10U /* 100M 半双工 */
|
#define CH395F_PHY_100M_HALF 0x10U /* 100M 半双工 */
|
||||||
#define CH395F_PHY_AUTO_NEGOTIATE 0x20U /* 自动协商 */
|
#define CH395F_PHY_AUTO_NEGOTIATE 0x20U /* 自动协商 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 功能参数标志位(CMD_SET_FUN_PARA)
|
||||||
|
*/
|
||||||
|
#define CH395F_FUN_PARA_TCP_SERVER (1UL << 1) /* TCP Server 多连接模式 */
|
||||||
|
#define CH395F_FUN_PARA_SOCKET_CLOSE (1UL << 3) /* Socket 关闭控制(0=芯片自动,1=外部控制) */
|
||||||
|
#define CH395F_FUN_PARA_DISABLE_SEND_OK (1UL << 4) /* 禁用 SEND_OK 中断 */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 协议类型
|
* 协议类型
|
||||||
*/
|
*/
|
||||||
@@ -178,7 +193,7 @@ extern "C" {
|
|||||||
#define CH395F_TCP_TIME_WAIT 0x0AU
|
#define CH395F_TCP_TIME_WAIT 0x0AU
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 全局中断状态位
|
* 全局中断状态位(CMD_GET_GLOB_INT_STATUS 1字节版,仅Socket 0~3)
|
||||||
*/
|
*/
|
||||||
#define CH395F_GINT_STAT_UNREACH 0x01U
|
#define CH395F_GINT_STAT_UNREACH 0x01U
|
||||||
#define CH395F_GINT_STAT_IP_CONFLI 0x02U
|
#define CH395F_GINT_STAT_IP_CONFLI 0x02U
|
||||||
@@ -190,15 +205,25 @@ extern "C" {
|
|||||||
#define CH395F_GINT_STAT_SOCK3 0x80U
|
#define CH395F_GINT_STAT_SOCK3 0x80U
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Socket 中断状态位
|
* 全局中断状态位(CMD_GET_GLOB_INT_STATUS_ALL 2字节版,支持Socket 0~7)
|
||||||
|
* 低字节高字节分别定义
|
||||||
*/
|
*/
|
||||||
#define CH395F_SINT_STAT_CONNECT 0x01U
|
#define CH395F_GINT_STAT_SOCK4 0x0100U
|
||||||
#define CH395F_SINT_STAT_DISCONNECT 0x02U
|
#define CH395F_GINT_STAT_SOCK5 0x0200U
|
||||||
#define CH395F_SINT_STAT_SEND_OK 0x04U
|
#define CH395F_GINT_STAT_SOCK6 0x0400U
|
||||||
#define CH395F_SINT_STAT_SENBUF_FREE 0x08U
|
#define CH395F_GINT_STAT_SOCK7 0x0800U
|
||||||
#define CH395F_SINT_STAT_RECV_OK 0x10U
|
#define CH395F_GINT_STAT_DHCPV6 0x8000U
|
||||||
#define CH395F_SINT_STAT_DISCARD 0x20U
|
|
||||||
#define CH395F_SINT_STAT_SOCK_TIMEOUT 0x40U
|
/*
|
||||||
|
* Socket 中断状态位(CMD_GET_INT_STATUS_SN 返回值,来自手册表5-x)
|
||||||
|
*/
|
||||||
|
#define CH395F_SINT_STAT_SENBUF_FREE 0x01U /* bit0: 发送缓冲区空闲 */
|
||||||
|
#define CH395F_SINT_STAT_SEND_OK 0x02U /* bit1: 发送成功 */
|
||||||
|
#define CH395F_SINT_STAT_RECV_OK 0x04U /* bit2: 接收缓冲区非空 */
|
||||||
|
#define CH395F_SINT_STAT_CONNECT 0x08U /* bit3: TCP 连接成功 */
|
||||||
|
#define CH395F_SINT_STAT_DISCONNECT 0x10U /* bit4: TCP 连接断开 */
|
||||||
|
#define CH395F_SINT_STAT_DISCARD 0x20U /* bit5: 保留 */
|
||||||
|
#define CH395F_SINT_STAT_SOCK_TIMEOUT 0x40U /* bit6: 超时 */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 类型定义区 - 驱动返回码
|
* 类型定义区 - 驱动返回码
|
||||||
@@ -277,6 +302,15 @@ ch395f_status_t ch395f_reset(void);
|
|||||||
*/
|
*/
|
||||||
uint8_t ch395f_get_cmd_status(void);
|
uint8_t ch395f_get_cmd_status(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:轮询等待命令执行完成
|
||||||
|
* 入口参数:timeout_ms - 超时时间(毫秒) uint32_t
|
||||||
|
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 或 CH395F_CMD_RET_ABORT)
|
||||||
|
* 限定条件:在发送长执行命令(OPEN/TCP_LISTEN/CONNECT/DISCONNECT/CLOSE/DHCP)后调用
|
||||||
|
* 函数说明:每 20ms 查询一次,直到命令完成或超时
|
||||||
|
*/
|
||||||
|
uint8_t ch395f_poll_cmd_status(uint32_t timeout_ms);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:初始化 CH395(包含 MAC、PHY、TCP/IP 协议栈)
|
* 函数功能:初始化 CH395(包含 MAC、PHY、TCP/IP 协议栈)
|
||||||
* 返回值:CH395F_STATUS_OK - 成功,CH395F_STATUS_TIMEOUT - 超时失败
|
* 返回值:CH395F_STATUS_OK - 成功,CH395F_STATUS_TIMEOUT - 超时失败
|
||||||
@@ -382,7 +416,7 @@ uint8_t ch395f_get_dhcp_status(void);
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:设置 Socket 协议类型
|
* 函数功能:设置 Socket 协议类型
|
||||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
* proto - 协议类型 uint8_t CH395F_PROTO_TYPE_xxx
|
* proto - 协议类型 uint8_t CH395F_PROTO_TYPE_xxx
|
||||||
* 限定条件:Socket 未打开
|
* 限定条件:Socket 未打开
|
||||||
*/
|
*/
|
||||||
@@ -390,7 +424,7 @@ void ch395f_set_proto_type(uint8_t sock, uint8_t proto);
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:设置 Socket 目标 IP 地址
|
* 函数功能:设置 Socket 目标 IP 地址
|
||||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
* p_ip - 4 字节目标 IP 指针 uint8_t*
|
* p_ip - 4 字节目标 IP 指针 uint8_t*
|
||||||
* 限定条件:指针非空
|
* 限定条件:指针非空
|
||||||
*/
|
*/
|
||||||
@@ -398,7 +432,7 @@ void ch395f_set_des_ip(uint8_t sock, uint8_t *p_ip);
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:设置 Socket 目标端口(小端序)
|
* 函数功能:设置 Socket 目标端口(小端序)
|
||||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
* port - 目标端口 uint16_t
|
* port - 目标端口 uint16_t
|
||||||
* 限定条件:无
|
* 限定条件:无
|
||||||
*/
|
*/
|
||||||
@@ -406,7 +440,7 @@ void ch395f_set_des_port(uint8_t sock, uint16_t port);
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:设置 Socket 源端口(小端序)
|
* 函数功能:设置 Socket 源端口(小端序)
|
||||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
* port - 源端口 uint16_t
|
* port - 源端口 uint16_t
|
||||||
* 限定条件:无
|
* 限定条件:无
|
||||||
*/
|
*/
|
||||||
@@ -414,38 +448,43 @@ void ch395f_set_sour_port(uint8_t sock, uint16_t port);
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:打开 Socket
|
* 函数功能:打开 Socket
|
||||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t
|
||||||
* 限定条件:协议类型、目标 IP、端口已设置
|
* 限定条件:协议类型、目标 IP、端口已设置
|
||||||
*/
|
*/
|
||||||
void ch395f_open_socket(uint8_t sock);
|
uint8_t ch395f_open_socket(uint8_t sock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:关闭 Socket
|
* 函数功能:关闭 Socket
|
||||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t
|
||||||
* 限定条件:Socket 已打开
|
* 限定条件:Socket 已打开
|
||||||
*/
|
*/
|
||||||
void ch395f_close_socket(uint8_t sock);
|
uint8_t ch395f_close_socket(uint8_t sock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:启动 TCP 监听模式
|
* 函数功能:启动 TCP 监听模式
|
||||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t
|
||||||
* 限定条件:Socket 已打开且协议类型为 TCP
|
* 限定条件:Socket 已打开且协议类型为 TCP
|
||||||
*/
|
*/
|
||||||
void ch395f_tcp_listen(uint8_t sock);
|
uint8_t ch395f_tcp_listen(uint8_t sock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:启动 TCP 连接
|
* 函数功能:启动 TCP 连接
|
||||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t
|
||||||
* 限定条件:Socket 已打开且协议类型为 TCP
|
* 限定条件:Socket 已打开且协议类型为 TCP
|
||||||
*/
|
*/
|
||||||
void ch395f_tcp_connect(uint8_t sock);
|
uint8_t ch395f_tcp_connect(uint8_t sock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:断开 TCP 连接
|
* 函数功能:断开 TCP 连接
|
||||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t
|
||||||
* 限定条件:TCP 已建立连接
|
* 限定条件:TCP 已建立连接
|
||||||
*/
|
*/
|
||||||
void ch395f_tcp_disconnect(uint8_t sock);
|
uint8_t ch395f_tcp_disconnect(uint8_t sock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数声明区 - Socket 数据传输
|
* 函数声明区 - Socket 数据传输
|
||||||
@@ -453,7 +492,7 @@ void ch395f_tcp_disconnect(uint8_t sock);
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:向 Socket 发送缓冲区写入数据
|
* 函数功能:向 Socket 发送缓冲区写入数据
|
||||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
* p_data - 数据指针 uint8_t*
|
* p_data - 数据指针 uint8_t*
|
||||||
* len - 数据长度 uint16_t
|
* len - 数据长度 uint16_t
|
||||||
* 限定条件:指针非空,长度大于 0,TCP 已连接或 UDP 已打开
|
* 限定条件:指针非空,长度大于 0,TCP 已连接或 UDP 已打开
|
||||||
@@ -462,7 +501,7 @@ void ch395f_write_send_buf(uint8_t sock, uint8_t *p_data, uint16_t len);
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:从 Socket 接收缓冲区读取数据
|
* 函数功能:从 Socket 接收缓冲区读取数据
|
||||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
* p_data - 输出缓冲区指针 uint8_t*
|
* p_data - 输出缓冲区指针 uint8_t*
|
||||||
* len - 待读取数据长度 uint16_t
|
* len - 待读取数据长度 uint16_t
|
||||||
* 限定条件:指针非空,长度大于 0,接收缓冲区有数据
|
* 限定条件:指针非空,长度大于 0,接收缓冲区有数据
|
||||||
@@ -471,7 +510,7 @@ void ch395f_read_recv_buf(uint8_t sock, uint8_t *p_data, uint16_t len);
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:获取 Socket 接收缓冲区数据长度
|
* 函数功能:获取 Socket 接收缓冲区数据长度
|
||||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
* 返回值:接收数据长度 uint16_t
|
* 返回值:接收数据长度 uint16_t
|
||||||
* 限定条件:Socket 已打开
|
* 限定条件:Socket 已打开
|
||||||
*/
|
*/
|
||||||
@@ -488,14 +527,174 @@ uint16_t ch395f_get_recv_len(uint8_t sock);
|
|||||||
*/
|
*/
|
||||||
uint8_t ch395f_get_glob_int_status(void);
|
uint8_t ch395f_get_glob_int_status(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:获取全局中断状态(2 字节版,支持 Socket 0~7)
|
||||||
|
* 返回值:中断状态 uint16_t(低字节=Socket 0~3 + PHY/DHCP,高字节=Socket 4~7 + DHCPv6)
|
||||||
|
* 限定条件:芯片已初始化
|
||||||
|
*/
|
||||||
|
uint16_t ch395f_get_glob_int_status_all(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:获取 Socket 中断状态
|
* 函数功能:获取 Socket 中断状态
|
||||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
* 返回值:Socket 中断状态字节 uint8_t
|
* 返回值:Socket 中断状态字节 uint8_t
|
||||||
* 限定条件:芯片已初始化
|
* 限定条件:芯片已初始化
|
||||||
*/
|
*/
|
||||||
uint8_t ch395f_get_sock_int_status(uint8_t sock);
|
uint8_t ch395f_get_sock_int_status(uint8_t sock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:获取 Socket 状态(2 字节输出)
|
||||||
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* status - 2 字节输出缓冲区 [0]=Socket状态, [1]=TCP状态
|
||||||
|
* 限定条件:芯片已初始化
|
||||||
|
* 函数说明:Socket 状态: 00H=CLOSED, 05H=OPEN
|
||||||
|
* TCP 状态: 00H=CLOSED, 01H=LISTEN, 02H=SYN_SENT, 03H=SYN_RCVD, 04H=ESTABLISHED
|
||||||
|
*/
|
||||||
|
void ch395f_get_socket_status(uint8_t sock, uint8_t *status);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数声明区 - Socket 远端信息
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:获取远端 IP 和端口
|
||||||
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* p_buf - 6 字节输出缓冲区(4字节IP + 2字节端口)
|
||||||
|
* 限定条件:TCP Server 模式下连接建立后调用
|
||||||
|
* 函数说明:IP 低字节在前,端口低字节在前
|
||||||
|
*/
|
||||||
|
void ch395f_get_remot_ipp(uint8_t sock, uint8_t *p_buf);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数声明区 - 功能参数设置
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:设置 CH395 功能参数
|
||||||
|
* 入口参数:para - 4 字节功能参数 uint32_t
|
||||||
|
* bit0: 未使用,必须为 0
|
||||||
|
* bit1: TCP Server 多连接模式使能
|
||||||
|
* bit2: 低功耗模式
|
||||||
|
* bit3: Socket 关闭控制(0=芯片自动关闭,1=外部关闭)
|
||||||
|
* bit4: 禁用 SEND_OK 中断
|
||||||
|
* 限定条件:必须在 ch395f_init() 之前调用
|
||||||
|
*/
|
||||||
|
void ch395f_set_fun_para(uint32_t para);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数声明区 - TCP MSS 设置
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:设置 TCP MSS
|
||||||
|
* 入口参数:mss - MSS 值 uint16_t 60~1460
|
||||||
|
* 限定条件:必须在 ch395f_init() 之前调用
|
||||||
|
*/
|
||||||
|
void ch395f_set_tcp_mss(uint16_t mss);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数声明区 - Socket 缓冲区设置
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:设置 Socket 接收缓冲区
|
||||||
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* start_block - 起始块地址 uint8_t
|
||||||
|
* block_count - 块个数 uint8_t
|
||||||
|
* 限定条件:必须在 OPEN_SOCKET_SN 之前调用
|
||||||
|
*/
|
||||||
|
void ch395f_set_recv_buf(uint8_t sock, uint8_t start_block, uint8_t block_count);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:设置 Socket 发送缓冲区
|
||||||
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* start_block - 起始块地址 uint8_t
|
||||||
|
* block_count - 块个数 uint8_t
|
||||||
|
* 限定条件:必须在 OPEN_SOCKET_SN 之前调用
|
||||||
|
*/
|
||||||
|
void ch395f_set_send_buf(uint8_t sock, uint8_t start_block, uint8_t block_count);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:清空 Socket 接收缓冲区
|
||||||
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* 限定条件:Socket 已打开
|
||||||
|
*/
|
||||||
|
void ch395f_clear_recv_buf(uint8_t sock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:设置 TCP KeepAlive 空闲时间
|
||||||
|
* 入口参数:time - 空闲时间(毫秒,必须为 500 的倍数) uint32_t
|
||||||
|
* 限定条件:必须在 ch395f_init() 之前调用
|
||||||
|
*/
|
||||||
|
void ch395f_set_keepalive_idle(uint32_t time);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:设置 TCP KeepAlive 探测间隔
|
||||||
|
* 入口参数:time - 间隔时间(毫秒,必须为 500 的倍数) uint32_t
|
||||||
|
* 限定条件:必须在 ch395f_init() 之前调用
|
||||||
|
*/
|
||||||
|
void ch395f_set_keepalive_intvl(uint32_t time);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:设置 TCP KeepAlive 探测次数
|
||||||
|
* 入口参数:cnt - 探测次数 uint8_t
|
||||||
|
* 限定条件:必须在 ch395f_init() 之前调用
|
||||||
|
*/
|
||||||
|
void ch395f_set_keepalive_cnt(uint8_t cnt);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:启用/禁用指定 Socket 的 KeepAlive
|
||||||
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* enable - 1 启用,0 禁用 uint8_t
|
||||||
|
* 限定条件:Socket 已打开
|
||||||
|
*/
|
||||||
|
void ch395f_set_keepalive_enable(uint8_t sock, uint8_t enable);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数声明区 - TCP 重传参数设置
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:设置 TCP 重传次数
|
||||||
|
* 入口参数:cnt - 重传次数 uint8_t(0=使用默认值5)
|
||||||
|
* 限定条件:必须在 ch395f_init() 之前调用
|
||||||
|
*/
|
||||||
|
void ch395f_set_retrans_count(uint8_t cnt);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:设置 TCP 重传周期
|
||||||
|
* 入口参数:period - 重传周期(毫秒) uint16_t
|
||||||
|
* 限定条件:必须在 ch395f_init() 之前调用
|
||||||
|
*/
|
||||||
|
void ch395f_set_retrans_period(uint16_t period);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数声明区 - ARP / TTL / 不可达信息
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:设置 ARP 重传参数
|
||||||
|
* 入口参数:period_100ms - ARP 重传周期(单位 100ms,0=默认值=10即1秒) uint8_t
|
||||||
|
* cnt - ARP 重传次数(0=默认值=3,255=无限重传) uint8_t
|
||||||
|
* 限定条件:应在 ch395f_init() 之后调用
|
||||||
|
*/
|
||||||
|
void ch395f_set_arp(uint8_t period_100ms, uint8_t cnt);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:设置 Socket TTL
|
||||||
|
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||||
|
* ttl - TTL 值 uint8_t 最大 128
|
||||||
|
* 限定条件:Socket 已打开,TCP Server 模式下不生效
|
||||||
|
*/
|
||||||
|
void ch395f_set_ttl(uint8_t sock, uint8_t ttl);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:获取不可达信息(用于调试连接失败原因)
|
||||||
|
* 出口参数:p_buf - 8 字节输出缓冲区(类型+协议码+端口+IP)
|
||||||
|
* 限定条件:收到 GINT_STAT_UNREACH 中断后调用
|
||||||
|
*/
|
||||||
|
void ch395f_get_unreach_info(uint8_t *p_buf);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
105
Drivers/BSP/NET/net_config.h
Normal file
105
Drivers/BSP/NET/net_config.h
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:Network Configuration
|
||||||
|
* 模块功能:网络子系统配置宏定义,包括最大Socket数量、缓冲区大小、
|
||||||
|
* 超时时间等参数配置
|
||||||
|
* 适用平台:STM32F4 系列(CH395F 以太网芯片)
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-18
|
||||||
|
* 修改记录:
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __NET_CONFIG_H
|
||||||
|
#define __NET_CONFIG_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 最大支持的 Socket 数量(CH395F 支持 0~7)
|
||||||
|
*/
|
||||||
|
#ifndef NET_MAX_SOCKETS
|
||||||
|
#define NET_MAX_SOCKETS 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TCP Server 多连接模式配置
|
||||||
|
* 监听 Socket 索引和数据 Socket 起始索引
|
||||||
|
*/
|
||||||
|
#ifndef NET_TCP_SERVER_LISTEN_SOCK
|
||||||
|
#define NET_TCP_SERVER_LISTEN_SOCK 0 /* 监听 Socket 索引 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NET_TCP_SERVER_DATA_SOCK_START
|
||||||
|
#define NET_TCP_SERVER_DATA_SOCK_START 1 /* 数据 Socket 起始索引 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NET_TCP_SERVER_MAX_CLIENTS
|
||||||
|
#define NET_TCP_SERVER_MAX_CLIENTS 7 /* 最大客户端数(1~7) */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 缓冲区大小配置
|
||||||
|
*/
|
||||||
|
#ifndef NET_SEND_BUF_SIZE
|
||||||
|
#define NET_SEND_BUF_SIZE 4096 /* 发送缓冲区大小(字节) */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NET_RECV_BUF_SIZE
|
||||||
|
#define NET_RECV_BUF_SIZE 4096 /* 接收缓冲区大小(字节) */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 超时时间配置(毫秒)
|
||||||
|
* 0 = 无限等待(阻塞模式)
|
||||||
|
*/
|
||||||
|
#ifndef NET_CONNECT_TIMEOUT_MS
|
||||||
|
#define NET_CONNECT_TIMEOUT_MS 5000 /* 连接超时 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NET_ACCEPT_TIMEOUT_MS
|
||||||
|
#define NET_ACCEPT_TIMEOUT_MS 0 /* 接受连接超时(0=无限等待) */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NET_SEND_TIMEOUT_MS
|
||||||
|
#define NET_SEND_TIMEOUT_MS 1000 /* 发送超时 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NET_RECV_TIMEOUT_MS
|
||||||
|
#define NET_RECV_TIMEOUT_MS 0 /* 接收超时(0=无限等待) */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TCP KeepAlive 配置
|
||||||
|
*/
|
||||||
|
#ifndef NET_KEEPALIVE_IDLE_MS
|
||||||
|
#define NET_KEEPALIVE_IDLE_MS 7200000 /* KeepAlive 空闲时间(默认2小时) */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NET_KEEPALIVE_INTVL_MS
|
||||||
|
#define NET_KEEPALIVE_INTVL_MS 75000 /* KeepAlive 探测间隔(默认75秒) */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NET_KEEPALIVE_CNT
|
||||||
|
#define NET_KEEPALIVE_CNT 9 /* KeepAlive 探测次数(默认9次) */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* select/poll 最大 fd 数量
|
||||||
|
*/
|
||||||
|
#ifndef NET_SELECT_MAX_FDS
|
||||||
|
#define NET_SELECT_MAX_FDS NET_MAX_SOCKETS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 轮询延时配置(毫秒)
|
||||||
|
*/
|
||||||
|
#ifndef NET_POLL_DELAY_MS
|
||||||
|
#define NET_POLL_DELAY_MS 1 /* 非阻塞轮询延时 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __NET_CONFIG_H */
|
||||||
319
Drivers/BSP/NET/net_select.c
Normal file
319
Drivers/BSP/NET/net_select.c
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:Network Select Implementation
|
||||||
|
* 模块功能:I/O 多路复用实现,包括 select 和 poll 模式,
|
||||||
|
* 用于同时监控多个 Socket 的读写事件
|
||||||
|
* 适用平台:STM32F4 系列(CH395F 以太网芯片)
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-18
|
||||||
|
* 修改记录:
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "net_select.h"
|
||||||
|
#include "net_socket.h"
|
||||||
|
#include "ch395f.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 私有函数声明区
|
||||||
|
*/
|
||||||
|
static int check_socket_readable(int sockfd);
|
||||||
|
static int check_socket_writable(int sockfd);
|
||||||
|
static int check_socket_error(int sockfd);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 公共函数实现区
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:I/O 多路复用(select 模式)
|
||||||
|
*/
|
||||||
|
int net_select(int nfds, net_fd_set *readfds, net_fd_set *writefds,
|
||||||
|
net_fd_set *exceptfds, net_timeval *timeout)
|
||||||
|
{
|
||||||
|
uint32_t start_tick;
|
||||||
|
uint32_t timeout_ms = 0;
|
||||||
|
net_fd_set result_read = {0};
|
||||||
|
net_fd_set result_write = {0};
|
||||||
|
net_fd_set result_except = {0};
|
||||||
|
int ready_count = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* 计算超时时间 */
|
||||||
|
if (timeout != NULL)
|
||||||
|
{
|
||||||
|
timeout_ms = (uint32_t)(timeout->tv_sec * 1000) +
|
||||||
|
(uint32_t)(timeout->tv_usec / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
start_tick = HAL_GetTick();
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* 轮询所有 Socket */
|
||||||
|
net_poll();
|
||||||
|
|
||||||
|
ready_count = 0;
|
||||||
|
|
||||||
|
/* 检查哪些 Socket 有事件 */
|
||||||
|
for (i = 0; i < nfds && i < NET_MAX_SOCKETS; i++)
|
||||||
|
{
|
||||||
|
net_sock_t *sock = net_get_sock(i);
|
||||||
|
|
||||||
|
if (sock == NULL)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 检查可读事件 */
|
||||||
|
if (readfds != NULL && NET_FD_ISSET(i, readfds))
|
||||||
|
{
|
||||||
|
if (check_socket_readable(i))
|
||||||
|
{
|
||||||
|
NET_FD_SET(i, &result_read);
|
||||||
|
ready_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 检查可写事件 */
|
||||||
|
if (writefds != NULL && NET_FD_ISSET(i, writefds))
|
||||||
|
{
|
||||||
|
if (check_socket_writable(i))
|
||||||
|
{
|
||||||
|
NET_FD_SET(i, &result_write);
|
||||||
|
ready_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 检查异常事件 */
|
||||||
|
if (exceptfds != NULL && NET_FD_ISSET(i, exceptfds))
|
||||||
|
{
|
||||||
|
if (check_socket_error(i))
|
||||||
|
{
|
||||||
|
NET_FD_SET(i, &result_except);
|
||||||
|
ready_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 有事件就绪,返回 */
|
||||||
|
if (ready_count > 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 超时检查 */
|
||||||
|
if (timeout != NULL)
|
||||||
|
{
|
||||||
|
if (timeout_ms > 0 &&
|
||||||
|
(HAL_GetTick() - start_tick) >= timeout_ms)
|
||||||
|
{
|
||||||
|
break; /* 超时返回 0 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 短暂延时避免忙等 */
|
||||||
|
HAL_Delay(NET_POLL_DELAY_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 复制结果 */
|
||||||
|
if (readfds != NULL)
|
||||||
|
{
|
||||||
|
readfds->fd_bits = result_read.fd_bits;
|
||||||
|
}
|
||||||
|
if (writefds != NULL)
|
||||||
|
{
|
||||||
|
writefds->fd_bits = result_write.fd_bits;
|
||||||
|
}
|
||||||
|
if (exceptfds != NULL)
|
||||||
|
{
|
||||||
|
exceptfds->fd_bits = result_except.fd_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ready_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:I/O 多路复用(poll 模式)
|
||||||
|
*/
|
||||||
|
int net_poll_events(net_pollfd *fds, int nfds, int timeout)
|
||||||
|
{
|
||||||
|
uint32_t start_tick;
|
||||||
|
int ready = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (fds == NULL || nfds <= 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
start_tick = HAL_GetTick();
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* 轮询 */
|
||||||
|
net_poll();
|
||||||
|
|
||||||
|
ready = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < nfds; i++)
|
||||||
|
{
|
||||||
|
fds[i].revents = 0;
|
||||||
|
|
||||||
|
/* 检查 fd 有效性 */
|
||||||
|
if (fds[i].fd < 0 || fds[i].fd >= NET_MAX_SOCKETS)
|
||||||
|
{
|
||||||
|
fds[i].revents |= NET_POLLNVAL;
|
||||||
|
ready++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
net_sock_t *sock = net_get_sock(fds[i].fd);
|
||||||
|
|
||||||
|
if (sock == NULL)
|
||||||
|
{
|
||||||
|
fds[i].revents |= NET_POLLNVAL;
|
||||||
|
ready++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 检查可读 */
|
||||||
|
if (fds[i].events & NET_POLLIN)
|
||||||
|
{
|
||||||
|
if (check_socket_readable(fds[i].fd))
|
||||||
|
{
|
||||||
|
fds[i].revents |= NET_POLLIN;
|
||||||
|
ready++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 检查可写 */
|
||||||
|
if (fds[i].events & NET_POLLOUT)
|
||||||
|
{
|
||||||
|
if (check_socket_writable(fds[i].fd))
|
||||||
|
{
|
||||||
|
fds[i].revents |= NET_POLLOUT;
|
||||||
|
ready++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 检查错误 */
|
||||||
|
if (check_socket_error(fds[i].fd))
|
||||||
|
{
|
||||||
|
fds[i].revents |= NET_POLLERR;
|
||||||
|
ready++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 检查挂起(连接断开) */
|
||||||
|
if (sock->state == NET_SOCK_STATE_TCP_ACCEPT ||
|
||||||
|
sock->state == NET_SOCK_STATE_CLOSED)
|
||||||
|
{
|
||||||
|
fds[i].revents |= NET_POLLHUP;
|
||||||
|
ready++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ready > 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 超时检查 */
|
||||||
|
if (timeout >= 0)
|
||||||
|
{
|
||||||
|
if ((HAL_GetTick() - start_tick) >= (uint32_t)timeout)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HAL_Delay(NET_POLL_DELAY_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 私有函数实现区
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:检查 Socket 是否可读
|
||||||
|
* 返回值:1 可读,0 不可读
|
||||||
|
*/
|
||||||
|
static int check_socket_readable(int sockfd)
|
||||||
|
{
|
||||||
|
net_sock_t *sock;
|
||||||
|
uint16_t recv_len;
|
||||||
|
|
||||||
|
sock = net_get_sock(sockfd);
|
||||||
|
if (sock == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 监听 Socket 有新连接时可读 */
|
||||||
|
if (sock->state == NET_SOCK_STATE_LISTENING)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 已建立连接的 Socket 有数据可读 */
|
||||||
|
if (sock->state == NET_SOCK_STATE_ESTABLISHED)
|
||||||
|
{
|
||||||
|
recv_len = ch395f_get_recv_len(sockfd);
|
||||||
|
if (recv_len > 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:检查 Socket 是否可写
|
||||||
|
* 返回值:1 可写,0 不可写
|
||||||
|
*/
|
||||||
|
static int check_socket_writable(int sockfd)
|
||||||
|
{
|
||||||
|
net_sock_t *sock;
|
||||||
|
|
||||||
|
sock = net_get_sock(sockfd);
|
||||||
|
if (sock == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 已建立连接的 Socket 发送缓冲区空闲时可写 */
|
||||||
|
if (sock->state == NET_SOCK_STATE_ESTABLISHED)
|
||||||
|
{
|
||||||
|
if (sock->send_ready)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:检查 Socket 是否有错误
|
||||||
|
* 返回值:1 有错误,0 无错误
|
||||||
|
*/
|
||||||
|
static int check_socket_error(int sockfd)
|
||||||
|
{
|
||||||
|
net_sock_t *sock;
|
||||||
|
|
||||||
|
/* 无效 fd 视为错误 */
|
||||||
|
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sock = net_get_sock(sockfd);
|
||||||
|
if (sock == NULL)
|
||||||
|
{
|
||||||
|
return 1; /* 未使用的 Socket 视为错误 */
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
114
Drivers/BSP/NET/net_select.h
Normal file
114
Drivers/BSP/NET/net_select.h
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:Network Select API
|
||||||
|
* 模块功能:I/O 多路复用接口,支持 select 和 poll 模式,
|
||||||
|
* 用于同时监控多个 Socket 的读写事件
|
||||||
|
* 适用平台:STM32F4 系列(CH395F 以太网芯片)
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-18
|
||||||
|
* 修改记录:
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __NET_SELECT_H
|
||||||
|
#define __NET_SELECT_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "net_types.h"
|
||||||
|
#include "net_config.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 文件描述符集合
|
||||||
|
* 每个位对应一个 socket 描述符 (0~7)
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint32_t fd_bits; /* 位掩码 */
|
||||||
|
} net_fd_set;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 时间结构体
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
long tv_sec; /* 秒 */
|
||||||
|
long tv_usec; /* 微秒 */
|
||||||
|
} net_timeval;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* poll 事件结构体
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
int fd; /* socket 描述符 */
|
||||||
|
short events; /* 请求的事件 */
|
||||||
|
short revents; /* 实际发生的事件 */
|
||||||
|
} net_pollfd;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* poll 事件掩码
|
||||||
|
*/
|
||||||
|
#define NET_POLLIN 0x0001 /* 可读 */
|
||||||
|
#define NET_POLLOUT 0x0004 /* 可写 */
|
||||||
|
#define NET_POLLERR 0x0008 /* 错误 */
|
||||||
|
#define NET_POLLHUP 0x0010 /* 挂起 */
|
||||||
|
#define NET_POLLNVAL 0x0020 /* 无效请求 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fd_set 操作宏
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:清空 fd_set
|
||||||
|
*/
|
||||||
|
#define NET_FD_ZERO(fdset) ((fdset)->fd_bits = 0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:将 fd 加入 fd_set
|
||||||
|
*/
|
||||||
|
#define NET_FD_SET(fd, fdset) ((fdset)->fd_bits |= (1U << (fd)))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:将 fd 从 fd_set 移除
|
||||||
|
*/
|
||||||
|
#define NET_FD_CLR(fd, fdset) ((fdset)->fd_bits &= ~(1U << (fd)))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:检查 fd 是否在 fd_set 中
|
||||||
|
*/
|
||||||
|
#define NET_FD_ISSET(fd, fdset) (((fdset)->fd_bits & (1U << (fd))) != 0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* I/O 多路复用 API
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:I/O 多路复用(select 模式)
|
||||||
|
* 入口参数:nfds - 最大 fd + 1(通常为 NET_MAX_SOCKETS)
|
||||||
|
* readfds - 可读事件集合,NULL 表示不关心
|
||||||
|
* writefds - 可写事件集合,NULL 表示不关心
|
||||||
|
* exceptfds - 异常事件集合,NULL 表示不关心
|
||||||
|
* timeout - 超时时间,NULL 表示无限等待
|
||||||
|
* 返回值:就绪的 fd 数量,0=超时,-1=错误
|
||||||
|
* 限定条件:net_init() 已调用
|
||||||
|
* 函数说明:此函数会调用 net_poll() 轮询所有 Socket,
|
||||||
|
* 并检查哪些 Socket 有指定的事件发生。
|
||||||
|
*/
|
||||||
|
int net_select(int nfds, net_fd_set *readfds, net_fd_set *writefds,
|
||||||
|
net_fd_set *exceptfds, net_timeval *timeout);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:I/O 多路复用(poll 模式)
|
||||||
|
* 入口参数:fds - net_pollfd 数组
|
||||||
|
* nfds - 数组元素数量
|
||||||
|
* timeout - 超时时间(毫秒),-1 表示无限等待
|
||||||
|
* 返回值:就绪的 fd 数量,0=超时,-1=错误
|
||||||
|
* 限定条件:net_init() 已调用
|
||||||
|
* 函数说明:与 select 类似,但使用 pollfd 结构体数组,
|
||||||
|
* 更灵活,支持更多事件类型。
|
||||||
|
*/
|
||||||
|
int net_poll_events(net_pollfd *fds, int nfds, int timeout);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __NET_SELECT_H */
|
||||||
1219
Drivers/BSP/NET/net_socket.c
Normal file
1219
Drivers/BSP/NET/net_socket.c
Normal file
File diff suppressed because it is too large
Load Diff
227
Drivers/BSP/NET/net_socket.h
Normal file
227
Drivers/BSP/NET/net_socket.h
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:Network Socket API
|
||||||
|
* 模块功能:BSD Socket API 兼容接口,提供 TCP/UDP 网络通信功能,
|
||||||
|
* 底层基于 CH395F 以太网协议栈芯片
|
||||||
|
* 适用平台:STM32F4 系列(CH395F 以太网芯片)
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-18
|
||||||
|
* 修改记录:
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __NET_SOCKET_H
|
||||||
|
#define __NET_SOCKET_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "net_types.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 网络初始化接口
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:网络子系统初始化(配置 CH395F + 启用多连接模式)
|
||||||
|
* 入口参数:ip - 本地 IP 地址字符串 "192.168.1.100",NULL 使用 DHCP
|
||||||
|
* mask - 子网掩码字符串 "255.255.255.0",NULL 使用默认
|
||||||
|
* gateway - 网关地址字符串 "192.168.1.1",NULL 使用默认
|
||||||
|
* 返回值:0 成功,-1 失败
|
||||||
|
* 限定条件:SPI2 已正确初始化
|
||||||
|
* 函数说明:必须在所有网络操作之前调用
|
||||||
|
*/
|
||||||
|
int net_init(const char *ip, const char *mask, const char *gateway);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:轮询所有 Socket 状态(必须在主循环中调用)
|
||||||
|
* 返回值:有事件发生的 socket 数量
|
||||||
|
* 限定条件:net_init() 已调用
|
||||||
|
* 函数说明:此函数处理所有 Socket 的中断事件,更新状态,
|
||||||
|
* 并触发事件回调。在非阻塞模式下必须定期调用。
|
||||||
|
*/
|
||||||
|
int net_poll(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 核心 Socket API
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:创建 socket
|
||||||
|
* 入口参数:domain - 地址族,仅支持 AF_INET
|
||||||
|
* type - SOCK_STREAM(TCP) 或 SOCK_DGRAM(UDP)
|
||||||
|
* protocol - 通常为 0
|
||||||
|
* 返回值:socket 描述符 (0~7),失败返回 -1
|
||||||
|
* 限定条件:net_init() 已调用
|
||||||
|
*/
|
||||||
|
int net_socket(int domain, int type, int protocol);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:绑定本地地址和端口
|
||||||
|
* 入口参数:sockfd - socket 描述符
|
||||||
|
* addr - 本地地址结构体指针
|
||||||
|
* addrlen - 地址结构体长度
|
||||||
|
* 返回值:0 成功,-1 失败
|
||||||
|
*/
|
||||||
|
int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:TCP Server 监听
|
||||||
|
* 入口参数:sockfd - socket 描述符
|
||||||
|
* backlog - 最大等待连接数(多连接模式下为数据 Socket 数量)
|
||||||
|
* 返回值:0 成功,-1 失败
|
||||||
|
* 限定条件:socket 已绑定
|
||||||
|
*/
|
||||||
|
int net_listen(int sockfd, int backlog);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:TCP Server 接受连接
|
||||||
|
* 入口参数:sockfd - 监听 socket 描述符
|
||||||
|
* addr - 输出:客户端地址
|
||||||
|
* addrlen - 输入输出:地址长度
|
||||||
|
* 返回值:新 socket 描述符,失败返回 -1
|
||||||
|
* 限定条件:socket 正在监听
|
||||||
|
* 函数说明:在非阻塞模式下,如果没有新连接,返回 -1 并设置
|
||||||
|
* net_errno 为 NET_ERR_WOULDBLOCK
|
||||||
|
*/
|
||||||
|
int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:TCP Client 发起连接
|
||||||
|
* 入口参数:sockfd - socket 描述符
|
||||||
|
* addr - 服务器地址
|
||||||
|
* addrlen - 地址长度
|
||||||
|
* 返回值:0 成功,-1 失败
|
||||||
|
* 限定条件:socket 已创建
|
||||||
|
* 函数说明:连接过程是异步的,需要调用 net_poll() 等待连接完成,
|
||||||
|
* 或使用 select() 等待可写事件
|
||||||
|
*/
|
||||||
|
int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:发送数据(TCP)
|
||||||
|
* 入口参数:sockfd - socket 描述符
|
||||||
|
* buf - 数据缓冲区
|
||||||
|
* len - 数据长度
|
||||||
|
* flags - 通常为 0
|
||||||
|
* 返回值:实际发送字节数,失败返回 -1
|
||||||
|
* 限定条件:TCP 连接已建立
|
||||||
|
*/
|
||||||
|
int net_send(int sockfd, const void *buf, int len, int flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:接收数据(TCP)
|
||||||
|
* 入口参数:sockfd - socket 描述符
|
||||||
|
* buf - 接收缓冲区
|
||||||
|
* len - 缓冲区大小
|
||||||
|
* flags - 通常为 0,可设置 NET_MSG_DONTWAIT 非阻塞
|
||||||
|
* 返回值:实际接收字节数,0=对端关闭,-1=错误
|
||||||
|
* 限定条件:TCP 连接已建立
|
||||||
|
* 函数说明:在阻塞模式下,如果没有数据,函数会等待;
|
||||||
|
* 在非阻塞模式下,如果没有数据,返回 -1 并设置
|
||||||
|
* net_errno 为 NET_ERR_WOULDBLOCK
|
||||||
|
*/
|
||||||
|
int net_recv(int sockfd, void *buf, int len, int flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:发送 UDP 数据
|
||||||
|
* 入口参数:sockfd - socket 描述符
|
||||||
|
* buf - 数据缓冲区
|
||||||
|
* len - 数据长度
|
||||||
|
* flags - 通常为 0
|
||||||
|
* dest_addr - 目标地址
|
||||||
|
* addrlen - 地址长度
|
||||||
|
* 返回值:实际发送字节数,失败返回 -1
|
||||||
|
*/
|
||||||
|
int net_sendto(int sockfd, const void *buf, int len, int flags,
|
||||||
|
const struct net_sockaddr *dest_addr, int addrlen);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:接收 UDP 数据
|
||||||
|
* 入口参数:sockfd - socket 描述符
|
||||||
|
* buf - 接收缓冲区
|
||||||
|
* len - 缓冲区大小
|
||||||
|
* flags - 通常为 0
|
||||||
|
* src_addr - 输出:发送方地址
|
||||||
|
* addrlen - 输入输出:地址长度
|
||||||
|
* 返回值:实际接收字节数,失败返回 -1
|
||||||
|
*/
|
||||||
|
int net_recvfrom(int sockfd, void *buf, int len, int flags,
|
||||||
|
struct net_sockaddr *src_addr, int *addrlen);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:关闭 socket
|
||||||
|
* 入口参数:sockfd - socket 描述符
|
||||||
|
* 返回值:0 成功,-1 失败
|
||||||
|
*/
|
||||||
|
int net_close(int sockfd);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 事件回调 API
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:注册事件回调
|
||||||
|
* 入口参数:sockfd - socket 描述符
|
||||||
|
* cb - 回调函数
|
||||||
|
* arg - 用户参数
|
||||||
|
* 返回值:0 成功,-1 失败
|
||||||
|
*/
|
||||||
|
int net_set_event_cb(int sockfd, net_event_cb_t cb, void *arg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 辅助函数
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:获取 socket 最后错误码
|
||||||
|
* 返回值:错误码(NET_ERR_xxx)
|
||||||
|
*/
|
||||||
|
int net_get_errno(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:将 IP 地址字符串转为网络字节序
|
||||||
|
* 入口参数:cp - 点分十进制字符串 "192.168.1.100"
|
||||||
|
* 返回值:网络字节序 IP
|
||||||
|
*/
|
||||||
|
uint32_t net_inet_addr(const char *cp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:将网络字节序 IP 转为字符串
|
||||||
|
* 入口参数:addr - 网络字节序 IP
|
||||||
|
* buf - 输出缓冲区(至少 16 字节)
|
||||||
|
* 返回值:buf 指针
|
||||||
|
*/
|
||||||
|
char *net_inet_ntoa(uint32_t addr, char *buf);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:端口字节序转换(主机序 -> 网络序)
|
||||||
|
*/
|
||||||
|
uint16_t net_htons(uint16_t hostshort);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:端口字节序转换(网络序 -> 主机序)
|
||||||
|
*/
|
||||||
|
uint16_t net_ntohs(uint16_t netshort);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:IP 地址字节序转换(主机序 -> 网络序)
|
||||||
|
*/
|
||||||
|
uint32_t net_htonl(uint32_t hostlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:IP 地址字节序转换(网络序 -> 主机序)
|
||||||
|
*/
|
||||||
|
uint32_t net_ntohl(uint32_t netlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:获取 Socket 控制块指针(内部使用)
|
||||||
|
* 入口参数:sockfd - socket 描述符
|
||||||
|
* 返回值:Socket 控制块指针,失败返回 NULL
|
||||||
|
*/
|
||||||
|
net_sock_t *net_get_sock(int sockfd);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __NET_SOCKET_H */
|
||||||
175
Drivers/BSP/NET/net_types.h
Normal file
175
Drivers/BSP/NET/net_types.h
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:Network Types
|
||||||
|
* 模块功能:网络子系统类型定义,包括地址结构体、Socket状态、
|
||||||
|
* 事件类型、Socket控制块等
|
||||||
|
* 适用平台:STM32F4 系列(CH395F 以太网芯片)
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-18
|
||||||
|
* 修改记录:
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __NET_TYPES_H
|
||||||
|
#define __NET_TYPES_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "net_config.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 地址族定义
|
||||||
|
*/
|
||||||
|
#define NET_AF_INET 2 /* IPv4 */
|
||||||
|
#define NET_AF_INET6 10 /* IPv6(未支持) */
|
||||||
|
#define NET_AF_UNSPEC 0 /* 未指定 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Socket 类型定义
|
||||||
|
*/
|
||||||
|
#define NET_SOCK_STREAM 1 /* TCP */
|
||||||
|
#define NET_SOCK_DGRAM 2 /* UDP */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 协议号定义
|
||||||
|
*/
|
||||||
|
#define NET_IPPROTO_TCP 6
|
||||||
|
#define NET_IPPROTO_UDP 17
|
||||||
|
#define NET_IPPROTO_ICMP 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 特殊地址定义
|
||||||
|
*/
|
||||||
|
#define NET_INADDR_ANY 0 /* 任意地址 */
|
||||||
|
#define NET_INADDR_NONE 0xFFFFFFFF /* 无效地址 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 接收标志定义
|
||||||
|
*/
|
||||||
|
#define NET_MSG_DONTWAIT 0x01 /* 非阻塞模式 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 网络字节序转换宏
|
||||||
|
*/
|
||||||
|
#ifdef __BIG_ENDIAN
|
||||||
|
#define NET_htonl(x) (x)
|
||||||
|
#define NET_htons(x) (x)
|
||||||
|
#define NET_ntohl(x) (x)
|
||||||
|
#define NET_ntohs(x) (x)
|
||||||
|
#else
|
||||||
|
#define NET_htonl(x) (((uint32_t)(x) << 24) | \
|
||||||
|
(((uint32_t)(x) & 0xFF00) << 8) | \
|
||||||
|
(((uint32_t)(x) & 0xFF0000) >> 8) | \
|
||||||
|
((uint32_t)(x) >> 24))
|
||||||
|
#define NET_htons(x) (((uint16_t)(x) << 8) | ((uint16_t)(x) >> 8))
|
||||||
|
#define NET_ntohl(x) NET_htonl(x)
|
||||||
|
#define NET_ntohs(x) NET_htons(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 套接字地址结构体
|
||||||
|
*/
|
||||||
|
struct net_sockaddr {
|
||||||
|
uint16_t sa_family; /* 地址族 */
|
||||||
|
char sa_data[14]; /* 地址数据 */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IPv4 套接字地址结构体
|
||||||
|
*/
|
||||||
|
struct net_sockaddr_in {
|
||||||
|
uint16_t sin_family; /* 地址族,必须为 AF_INET */
|
||||||
|
uint16_t sin_port; /* 端口号(网络字节序) */
|
||||||
|
struct {
|
||||||
|
uint32_t s_addr; /* IP 地址(网络字节序) */
|
||||||
|
} sin_addr;
|
||||||
|
char sin_zero[8]; /* 填充字节 */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Socket 错误码定义
|
||||||
|
*/
|
||||||
|
#define NET_OK 0 /* 成功 */
|
||||||
|
#define NET_ERR -1 /* 通用错误 */
|
||||||
|
#define NET_ERR_BADF -2 /* 无效 socket 描述符 */
|
||||||
|
#define NET_ERR_INVAL -3 /* 无效参数 */
|
||||||
|
#define NET_ERR_NOMEM -4 /* 内存不足 */
|
||||||
|
#define NET_ERR_NOTCONN -5 /* 未连接 */
|
||||||
|
#define NET_ERR_ISCONN -6 /* 已连接 */
|
||||||
|
#define NET_ERR_WOULDBLOCK -7 /* 非阻塞模式下操作未完成 */
|
||||||
|
#define NET_ERR_CONNRESET -8 /* 连接被重置 */
|
||||||
|
#define NET_ERR_TIMEDOUT -9 /* 操作超时 */
|
||||||
|
#define NET_ERR_NOSPACE -10 /* 发送缓冲区无空间 */
|
||||||
|
#define NET_ERR_BUSY -11 /* 操作未完成(CH395F BUSY) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Socket 状态枚举
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
NET_SOCK_STATE_CLOSED = 0, /* 未使用 */
|
||||||
|
NET_SOCK_STATE_CREATED, /* 已创建,未绑定 */
|
||||||
|
NET_SOCK_STATE_BOUND, /* 已绑定 */
|
||||||
|
NET_SOCK_STATE_LISTENING, /* TCP Server 监听中(仅监听 Socket) */
|
||||||
|
NET_SOCK_STATE_CONNECTING, /* TCP Client 连接中 */
|
||||||
|
NET_SOCK_STATE_ESTABLISHED, /* TCP 已连接 */
|
||||||
|
NET_SOCK_STATE_UDP_OPEN, /* UDP 已打开 */
|
||||||
|
NET_SOCK_STATE_TCP_ACCEPT, /* TCP Server 数据 Socket,等待分配连接 */
|
||||||
|
NET_SOCK_STATE_TCP_CLIENT_RECONNECTING, /* TCP Client 重连中 */
|
||||||
|
} net_sock_state_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 网络事件类型枚举
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
NET_EVENT_CONNECTED = 0, /* 连接建立 */
|
||||||
|
NET_EVENT_DISCONNECTED, /* 连接断开 */
|
||||||
|
NET_EVENT_DATA_RECEIVED, /* 收到数据 */
|
||||||
|
NET_EVENT_SEND_COMPLETE, /* 发送完成 */
|
||||||
|
NET_EVENT_TIMEOUT, /* 操作超时 */
|
||||||
|
NET_EVENT_ERROR, /* 错误发生 */
|
||||||
|
} net_event_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 事件回调函数类型定义
|
||||||
|
* 参数:sockfd - socket 描述符
|
||||||
|
* event - 事件类型
|
||||||
|
* arg - 用户参数
|
||||||
|
*/
|
||||||
|
typedef void (*net_event_cb_t)(int sockfd, net_event_t event, void *arg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Socket 控制块结构体
|
||||||
|
* 每个 socket 对应一个控制块,管理其状态和参数
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint8_t ch395_sock; /* CH395F 物理 Socket 索引 (0~7) */
|
||||||
|
net_sock_state_t state; /* Socket 状态 */
|
||||||
|
uint8_t type; /* SOCK_STREAM / SOCK_DGRAM */
|
||||||
|
uint8_t in_use; /* 是否在用标志 */
|
||||||
|
uint16_t local_port; /* 本地端口(主机序) */
|
||||||
|
uint16_t remote_port; /* 远端端口(主机序) */
|
||||||
|
uint32_t remote_ip; /* 远端 IP(网络字节序) */
|
||||||
|
uint8_t remote_ip_arr[4]; /* 远端 IP 数组(低字节在前) */
|
||||||
|
|
||||||
|
/* 事件回调(可选) */
|
||||||
|
net_event_cb_t event_cb;
|
||||||
|
void *event_arg;
|
||||||
|
|
||||||
|
/* TCP Server 多连接模式:监听 Socket 的数据 Socket 列表 */
|
||||||
|
int data_socks[NET_TCP_SERVER_MAX_CLIENTS];
|
||||||
|
int data_sock_count;
|
||||||
|
|
||||||
|
/* 发送就绪标志 */
|
||||||
|
uint8_t send_ready;
|
||||||
|
|
||||||
|
/* 统计信息 */
|
||||||
|
uint32_t recv_bytes; /* 累计接收字节数 */
|
||||||
|
uint32_t send_bytes; /* 累计发送字节数 */
|
||||||
|
} net_sock_t;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __NET_TYPES_H */
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
/* 头文件包含区 */
|
/* 头文件包含区 */
|
||||||
#include "tpafe5160.h"
|
#include "tpafe5160.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
/* ======================== 私有宏定义 ======================== */
|
/* ======================== 私有宏定义 ======================== */
|
||||||
|
|
||||||
@@ -325,13 +326,13 @@ const int16_t* tpafe5160_get_buf(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:BUSY 下降沿 EXTI 回调(由 HAL_GPIO_EXTI_IRQHandler 调用)
|
* 函数功能:BUSY 下降沿 EXTI 处理(由 HAL_GPIO_EXTI_Callback 调用)
|
||||||
* 入口参数:GPIO_Pin - 触发中断的引脚号
|
* 入口参数:GPIO_Pin - 触发中断的引脚号
|
||||||
* 返回值:无
|
* 返回值:无
|
||||||
* 限定条件:BUSY EXTI 已使能
|
* 限定条件:BUSY EXTI 已使能
|
||||||
* 函数说明:转换完成后自动读取 8 通道数据到缓冲区,耗时约 0.5µs (168MHz)
|
* 函数说明:转换完成后自动读取 8 通道数据到缓冲区,耗时约 0.5µs (168MHz)
|
||||||
*/
|
*/
|
||||||
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
|
void tpafe5160_exti_handler(uint16_t GPIO_Pin)
|
||||||
{
|
{
|
||||||
if (GPIO_Pin != TP_BUSY_Pin) {
|
if (GPIO_Pin != TP_BUSY_Pin) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -217,6 +217,15 @@ void tpafe5160_clear_ready(void);
|
|||||||
*/
|
*/
|
||||||
const int16_t* tpafe5160_get_buf(void);
|
const int16_t* tpafe5160_get_buf(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:EXTI 中断处理(由 HAL_GPIO_EXTI_Callback 调用)
|
||||||
|
* 入口参数:GPIO_Pin - 触发的引脚号
|
||||||
|
* 返回值:无
|
||||||
|
* 限定条件:BUSY EXTI 已使能
|
||||||
|
* 函数说明:BUSY 下降沿时自动读取 8 通道数据到缓冲区
|
||||||
|
*/
|
||||||
|
void tpafe5160_exti_handler(uint16_t GPIO_Pin);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ void Error_Handler(void);
|
|||||||
/* USER CODE END EFP */
|
/* USER CODE END EFP */
|
||||||
|
|
||||||
/* Private defines -----------------------------------------------------------*/
|
/* Private defines -----------------------------------------------------------*/
|
||||||
|
#define CH395_INT_Pin GPIO_PIN_5
|
||||||
|
#define CH395_INT_GPIO_Port GPIOE
|
||||||
#define LED1_Pin GPIO_PIN_4
|
#define LED1_Pin GPIO_PIN_4
|
||||||
#define LED1_GPIO_Port GPIOC
|
#define LED1_GPIO_Port GPIOC
|
||||||
#define LED2_Pin GPIO_PIN_5
|
#define LED2_Pin GPIO_PIN_5
|
||||||
|
|||||||
@@ -55,7 +55,10 @@ void SVC_Handler(void);
|
|||||||
void DebugMon_Handler(void);
|
void DebugMon_Handler(void);
|
||||||
void PendSV_Handler(void);
|
void PendSV_Handler(void);
|
||||||
void SysTick_Handler(void);
|
void SysTick_Handler(void);
|
||||||
|
void DMA1_Stream3_IRQHandler(void);
|
||||||
|
void DMA1_Stream4_IRQHandler(void);
|
||||||
void EXTI9_5_IRQHandler(void);
|
void EXTI9_5_IRQHandler(void);
|
||||||
|
void SPI2_IRQHandler(void);
|
||||||
void USART1_IRQHandler(void);
|
void USART1_IRQHandler(void);
|
||||||
void USART2_IRQHandler(void);
|
void USART2_IRQHandler(void);
|
||||||
void USART3_IRQHandler(void);
|
void USART3_IRQHandler(void);
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
|
||||||
<Project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" noNamespaceSchemaLocation="project_projx.xsd">
|
<Project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="project_projx.xsd">
|
||||||
|
|
||||||
<SchemaVersion>2.1</SchemaVersion>
|
<SchemaVersion>2.1</SchemaVersion>
|
||||||
|
|
||||||
<Header>### uVision Project, (C) Keil Software</Header>
|
<Header>### uVision Project, (C) Keil Software</Header>
|
||||||
|
|
||||||
<Targets>
|
<Targets>
|
||||||
<Target>
|
<Target>
|
||||||
<TargetName>STM32F407-Demo</TargetName>
|
<TargetName>STM32F407-Demo</TargetName>
|
||||||
@@ -16,28 +19,28 @@
|
|||||||
<PackID>Keil.STM32F4xx_DFP.3.1.1</PackID>
|
<PackID>Keil.STM32F4xx_DFP.3.1.1</PackID>
|
||||||
<PackURL>https://www.keil.com/pack/</PackURL>
|
<PackURL>https://www.keil.com/pack/</PackURL>
|
||||||
<Cpu>IRAM(0x20000000-0x2001BFFF) IRAM2(0x2001C000-0x2001FFFF) IROM(0x8000000-0x80FFFFF) CLOCK(25000000) FPU2 CPUTYPE("Cortex-M4") TZ</Cpu>
|
<Cpu>IRAM(0x20000000-0x2001BFFF) IRAM2(0x2001C000-0x2001FFFF) IROM(0x8000000-0x80FFFFF) CLOCK(25000000) FPU2 CPUTYPE("Cortex-M4") TZ</Cpu>
|
||||||
<FlashUtilSpec />
|
<FlashUtilSpec></FlashUtilSpec>
|
||||||
<StartupFile />
|
<StartupFile></StartupFile>
|
||||||
<FlashDriverDll />
|
<FlashDriverDll></FlashDriverDll>
|
||||||
<DeviceId>0</DeviceId>
|
<DeviceId>0</DeviceId>
|
||||||
<RegisterFile />
|
<RegisterFile></RegisterFile>
|
||||||
<MemoryEnv />
|
<MemoryEnv></MemoryEnv>
|
||||||
<Cmp />
|
<Cmp></Cmp>
|
||||||
<Asm />
|
<Asm></Asm>
|
||||||
<Linker />
|
<Linker></Linker>
|
||||||
<OHString />
|
<OHString></OHString>
|
||||||
<InfinionOptionDll />
|
<InfinionOptionDll></InfinionOptionDll>
|
||||||
<SLE66CMisc />
|
<SLE66CMisc></SLE66CMisc>
|
||||||
<SLE66AMisc />
|
<SLE66AMisc></SLE66AMisc>
|
||||||
<SLE66LinkerMisc />
|
<SLE66LinkerMisc></SLE66LinkerMisc>
|
||||||
<SFDFile>$$Device:STM32F407ZGTx$CMSIS\SVD\STM32F407.svd</SFDFile>
|
<SFDFile>$$Device:STM32F407ZGTx$CMSIS\SVD\STM32F407.svd</SFDFile>
|
||||||
<bCustSvd>0</bCustSvd>
|
<bCustSvd>0</bCustSvd>
|
||||||
<UseEnv>0</UseEnv>
|
<UseEnv>0</UseEnv>
|
||||||
<BinPath />
|
<BinPath></BinPath>
|
||||||
<IncludePath />
|
<IncludePath></IncludePath>
|
||||||
<LibPath />
|
<LibPath></LibPath>
|
||||||
<RegisterFilePath />
|
<RegisterFilePath></RegisterFilePath>
|
||||||
<DBRegisterFilePath />
|
<DBRegisterFilePath></DBRegisterFilePath>
|
||||||
<TargetStatus>
|
<TargetStatus>
|
||||||
<Error>0</Error>
|
<Error>0</Error>
|
||||||
<ExitCodeStop>0</ExitCodeStop>
|
<ExitCodeStop>0</ExitCodeStop>
|
||||||
@@ -52,15 +55,15 @@
|
|||||||
<CreateHexFile>1</CreateHexFile>
|
<CreateHexFile>1</CreateHexFile>
|
||||||
<DebugInformation>1</DebugInformation>
|
<DebugInformation>1</DebugInformation>
|
||||||
<BrowseInformation>1</BrowseInformation>
|
<BrowseInformation>1</BrowseInformation>
|
||||||
<ListingPath />
|
<ListingPath></ListingPath>
|
||||||
<HexFormatSelection>1</HexFormatSelection>
|
<HexFormatSelection>1</HexFormatSelection>
|
||||||
<Merge32K>0</Merge32K>
|
<Merge32K>0</Merge32K>
|
||||||
<CreateBatchFile>0</CreateBatchFile>
|
<CreateBatchFile>0</CreateBatchFile>
|
||||||
<BeforeCompile>
|
<BeforeCompile>
|
||||||
<RunUserProg1>0</RunUserProg1>
|
<RunUserProg1>0</RunUserProg1>
|
||||||
<RunUserProg2>0</RunUserProg2>
|
<RunUserProg2>0</RunUserProg2>
|
||||||
<UserProg1Name />
|
<UserProg1Name></UserProg1Name>
|
||||||
<UserProg2Name />
|
<UserProg2Name></UserProg2Name>
|
||||||
<UserProg1Dos16Mode>0</UserProg1Dos16Mode>
|
<UserProg1Dos16Mode>0</UserProg1Dos16Mode>
|
||||||
<UserProg2Dos16Mode>0</UserProg2Dos16Mode>
|
<UserProg2Dos16Mode>0</UserProg2Dos16Mode>
|
||||||
<nStopU1X>0</nStopU1X>
|
<nStopU1X>0</nStopU1X>
|
||||||
@@ -69,8 +72,8 @@
|
|||||||
<BeforeMake>
|
<BeforeMake>
|
||||||
<RunUserProg1>0</RunUserProg1>
|
<RunUserProg1>0</RunUserProg1>
|
||||||
<RunUserProg2>0</RunUserProg2>
|
<RunUserProg2>0</RunUserProg2>
|
||||||
<UserProg1Name />
|
<UserProg1Name></UserProg1Name>
|
||||||
<UserProg2Name />
|
<UserProg2Name></UserProg2Name>
|
||||||
<UserProg1Dos16Mode>0</UserProg1Dos16Mode>
|
<UserProg1Dos16Mode>0</UserProg1Dos16Mode>
|
||||||
<UserProg2Dos16Mode>0</UserProg2Dos16Mode>
|
<UserProg2Dos16Mode>0</UserProg2Dos16Mode>
|
||||||
<nStopB1X>0</nStopB1X>
|
<nStopB1X>0</nStopB1X>
|
||||||
@@ -79,15 +82,15 @@
|
|||||||
<AfterMake>
|
<AfterMake>
|
||||||
<RunUserProg1>0</RunUserProg1>
|
<RunUserProg1>0</RunUserProg1>
|
||||||
<RunUserProg2>1</RunUserProg2>
|
<RunUserProg2>1</RunUserProg2>
|
||||||
<UserProg1Name />
|
<UserProg1Name></UserProg1Name>
|
||||||
<UserProg2Name />
|
<UserProg2Name></UserProg2Name>
|
||||||
<UserProg1Dos16Mode>0</UserProg1Dos16Mode>
|
<UserProg1Dos16Mode>0</UserProg1Dos16Mode>
|
||||||
<UserProg2Dos16Mode>0</UserProg2Dos16Mode>
|
<UserProg2Dos16Mode>0</UserProg2Dos16Mode>
|
||||||
<nStopA1X>0</nStopA1X>
|
<nStopA1X>0</nStopA1X>
|
||||||
<nStopA2X>0</nStopA2X>
|
<nStopA2X>0</nStopA2X>
|
||||||
</AfterMake>
|
</AfterMake>
|
||||||
<SelectedForBatchBuild>1</SelectedForBatchBuild>
|
<SelectedForBatchBuild>1</SelectedForBatchBuild>
|
||||||
<SVCSIdString />
|
<SVCSIdString></SVCSIdString>
|
||||||
</TargetCommonOption>
|
</TargetCommonOption>
|
||||||
<CommonProperty>
|
<CommonProperty>
|
||||||
<UseCPPCompiler>0</UseCPPCompiler>
|
<UseCPPCompiler>0</UseCPPCompiler>
|
||||||
@@ -101,8 +104,8 @@
|
|||||||
<AssembleAssemblyFile>0</AssembleAssemblyFile>
|
<AssembleAssemblyFile>0</AssembleAssemblyFile>
|
||||||
<PublicsOnly>0</PublicsOnly>
|
<PublicsOnly>0</PublicsOnly>
|
||||||
<StopOnExitCode>3</StopOnExitCode>
|
<StopOnExitCode>3</StopOnExitCode>
|
||||||
<CustomArgument />
|
<CustomArgument></CustomArgument>
|
||||||
<IncludeLibraryModules />
|
<IncludeLibraryModules></IncludeLibraryModules>
|
||||||
<ComprImg>0</ComprImg>
|
<ComprImg>0</ComprImg>
|
||||||
</CommonProperty>
|
</CommonProperty>
|
||||||
<DllOption>
|
<DllOption>
|
||||||
@@ -136,10 +139,10 @@
|
|||||||
<bUseTDR>1</bUseTDR>
|
<bUseTDR>1</bUseTDR>
|
||||||
<Flash2>BIN\UL2CM3.DLL</Flash2>
|
<Flash2>BIN\UL2CM3.DLL</Flash2>
|
||||||
<Flash3>"" ()</Flash3>
|
<Flash3>"" ()</Flash3>
|
||||||
<Flash4 />
|
<Flash4></Flash4>
|
||||||
<pFcarmOut />
|
<pFcarmOut></pFcarmOut>
|
||||||
<pFcarmGrp />
|
<pFcarmGrp></pFcarmGrp>
|
||||||
<pFcArmRoot />
|
<pFcArmRoot></pFcArmRoot>
|
||||||
<FcArmLst>0</FcArmLst>
|
<FcArmLst>0</FcArmLst>
|
||||||
</Utilities>
|
</Utilities>
|
||||||
<TargetArmAds>
|
<TargetArmAds>
|
||||||
@@ -172,7 +175,7 @@
|
|||||||
<RvctClst>0</RvctClst>
|
<RvctClst>0</RvctClst>
|
||||||
<GenPPlst>0</GenPPlst>
|
<GenPPlst>0</GenPPlst>
|
||||||
<AdsCpuType>"Cortex-M4"</AdsCpuType>
|
<AdsCpuType>"Cortex-M4"</AdsCpuType>
|
||||||
<RvctDeviceName />
|
<RvctDeviceName></RvctDeviceName>
|
||||||
<mOS>0</mOS>
|
<mOS>0</mOS>
|
||||||
<uocRom>0</uocRom>
|
<uocRom>0</uocRom>
|
||||||
<uocRam>0</uocRam>
|
<uocRam>0</uocRam>
|
||||||
@@ -307,7 +310,7 @@
|
|||||||
<Size>0x4000</Size>
|
<Size>0x4000</Size>
|
||||||
</OCR_RVCT10>
|
</OCR_RVCT10>
|
||||||
</OnChipMemories>
|
</OnChipMemories>
|
||||||
<RvctStartVector />
|
<RvctStartVector></RvctStartVector>
|
||||||
</ArmAdsMisc>
|
</ArmAdsMisc>
|
||||||
<Cads>
|
<Cads>
|
||||||
<interw>1</interw>
|
<interw>1</interw>
|
||||||
@@ -334,10 +337,10 @@
|
|||||||
<v6WtE>0</v6WtE>
|
<v6WtE>0</v6WtE>
|
||||||
<v6Rtti>0</v6Rtti>
|
<v6Rtti>0</v6Rtti>
|
||||||
<VariousControls>
|
<VariousControls>
|
||||||
<MiscControls />
|
<MiscControls></MiscControls>
|
||||||
<Define>USE_HAL_DRIVER,STM32F407xx</Define>
|
<Define>USE_HAL_DRIVER,STM32F407xx</Define>
|
||||||
<Undefine />
|
<Undefine></Undefine>
|
||||||
<IncludePath>../Inc;../Drivers/STM32F4xx_HAL_Driver/Inc;../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy;../Drivers/CMSIS/Device/ST/STM32F4xx/Include;../Drivers/CMSIS/Include;../Drivers/BSP/CH395F;../Drivers/BSP/GD5F2GQ5UE;../Lib/FlashDB/port/fal/inc;../Lib/FlashDB/inc;../Drivers/BSP/TPAFE5160;../Drivers/BSP/SD2506;../Drivers/BSP/RS485</IncludePath>
|
<IncludePath>../Inc;../Drivers/STM32F4xx_HAL_Driver/Inc;../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy;../Drivers/CMSIS/Device/ST/STM32F4xx/Include;../Drivers/CMSIS/Include;../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</IncludePath>
|
||||||
</VariousControls>
|
</VariousControls>
|
||||||
</Cads>
|
</Cads>
|
||||||
<Aads>
|
<Aads>
|
||||||
@@ -352,10 +355,10 @@
|
|||||||
<useXO>0</useXO>
|
<useXO>0</useXO>
|
||||||
<ClangAsOpt>1</ClangAsOpt>
|
<ClangAsOpt>1</ClangAsOpt>
|
||||||
<VariousControls>
|
<VariousControls>
|
||||||
<MiscControls />
|
<MiscControls></MiscControls>
|
||||||
<Define />
|
<Define></Define>
|
||||||
<Undefine />
|
<Undefine></Undefine>
|
||||||
<IncludePath />
|
<IncludePath></IncludePath>
|
||||||
</VariousControls>
|
</VariousControls>
|
||||||
</Aads>
|
</Aads>
|
||||||
<LDads>
|
<LDads>
|
||||||
@@ -365,15 +368,15 @@
|
|||||||
<noStLib>0</noStLib>
|
<noStLib>0</noStLib>
|
||||||
<RepFail>1</RepFail>
|
<RepFail>1</RepFail>
|
||||||
<useFile>0</useFile>
|
<useFile>0</useFile>
|
||||||
<TextAddressRange />
|
<TextAddressRange></TextAddressRange>
|
||||||
<DataAddressRange />
|
<DataAddressRange></DataAddressRange>
|
||||||
<pXoBase />
|
<pXoBase></pXoBase>
|
||||||
<ScatterFile />
|
<ScatterFile></ScatterFile>
|
||||||
<IncludeLibs />
|
<IncludeLibs></IncludeLibs>
|
||||||
<IncludeLibsPath />
|
<IncludeLibsPath></IncludeLibsPath>
|
||||||
<Misc />
|
<Misc></Misc>
|
||||||
<LinkerInputFile />
|
<LinkerInputFile></LinkerInputFile>
|
||||||
<DisabledWarnings />
|
<DisabledWarnings></DisabledWarnings>
|
||||||
</LDads>
|
</LDads>
|
||||||
</TargetArmAds>
|
</TargetArmAds>
|
||||||
</TargetOption>
|
</TargetOption>
|
||||||
@@ -418,6 +421,8 @@
|
|||||||
<AssembleAssemblyFile>2</AssembleAssemblyFile>
|
<AssembleAssemblyFile>2</AssembleAssemblyFile>
|
||||||
<PublicsOnly>2</PublicsOnly>
|
<PublicsOnly>2</PublicsOnly>
|
||||||
<StopOnExitCode>11</StopOnExitCode>
|
<StopOnExitCode>11</StopOnExitCode>
|
||||||
|
<CustomArgument></CustomArgument>
|
||||||
|
<IncludeLibraryModules></IncludeLibraryModules>
|
||||||
<ComprImg>1</ComprImg>
|
<ComprImg>1</ComprImg>
|
||||||
</CommonProperty>
|
</CommonProperty>
|
||||||
<FileArmAds>
|
<FileArmAds>
|
||||||
@@ -445,19 +450,13 @@
|
|||||||
<v6Lto>2</v6Lto>
|
<v6Lto>2</v6Lto>
|
||||||
<v6WtE>2</v6WtE>
|
<v6WtE>2</v6WtE>
|
||||||
<v6Rtti>2</v6Rtti>
|
<v6Rtti>2</v6Rtti>
|
||||||
|
<VariousControls>
|
||||||
|
<MiscControls></MiscControls>
|
||||||
|
<Define></Define>
|
||||||
|
<Undefine></Undefine>
|
||||||
|
<IncludePath></IncludePath>
|
||||||
|
</VariousControls>
|
||||||
</Cads>
|
</Cads>
|
||||||
<Aads>
|
|
||||||
<interw>2</interw>
|
|
||||||
<Ropi>2</Ropi>
|
|
||||||
<Rwpi>2</Rwpi>
|
|
||||||
<thumb>2</thumb>
|
|
||||||
<SplitLS>2</SplitLS>
|
|
||||||
<SwStkChk>2</SwStkChk>
|
|
||||||
<NoWarn>2</NoWarn>
|
|
||||||
<uSurpInc>2</uSurpInc>
|
|
||||||
<useXO>2</useXO>
|
|
||||||
<ClangAsOpt>1</ClangAsOpt>
|
|
||||||
</Aads>
|
|
||||||
</FileArmAds>
|
</FileArmAds>
|
||||||
</FileOption>
|
</FileOption>
|
||||||
</File>
|
</File>
|
||||||
@@ -478,6 +477,8 @@
|
|||||||
<AssembleAssemblyFile>2</AssembleAssemblyFile>
|
<AssembleAssemblyFile>2</AssembleAssemblyFile>
|
||||||
<PublicsOnly>2</PublicsOnly>
|
<PublicsOnly>2</PublicsOnly>
|
||||||
<StopOnExitCode>11</StopOnExitCode>
|
<StopOnExitCode>11</StopOnExitCode>
|
||||||
|
<CustomArgument></CustomArgument>
|
||||||
|
<IncludeLibraryModules></IncludeLibraryModules>
|
||||||
<ComprImg>1</ComprImg>
|
<ComprImg>1</ComprImg>
|
||||||
</CommonProperty>
|
</CommonProperty>
|
||||||
<FileArmAds>
|
<FileArmAds>
|
||||||
@@ -505,6 +506,12 @@
|
|||||||
<v6Lto>2</v6Lto>
|
<v6Lto>2</v6Lto>
|
||||||
<v6WtE>2</v6WtE>
|
<v6WtE>2</v6WtE>
|
||||||
<v6Rtti>2</v6Rtti>
|
<v6Rtti>2</v6Rtti>
|
||||||
|
<VariousControls>
|
||||||
|
<MiscControls></MiscControls>
|
||||||
|
<Define></Define>
|
||||||
|
<Undefine></Undefine>
|
||||||
|
<IncludePath></IncludePath>
|
||||||
|
</VariousControls>
|
||||||
</Cads>
|
</Cads>
|
||||||
</FileArmAds>
|
</FileArmAds>
|
||||||
</FileOption>
|
</FileOption>
|
||||||
@@ -526,6 +533,8 @@
|
|||||||
<AssembleAssemblyFile>2</AssembleAssemblyFile>
|
<AssembleAssemblyFile>2</AssembleAssemblyFile>
|
||||||
<PublicsOnly>2</PublicsOnly>
|
<PublicsOnly>2</PublicsOnly>
|
||||||
<StopOnExitCode>11</StopOnExitCode>
|
<StopOnExitCode>11</StopOnExitCode>
|
||||||
|
<CustomArgument></CustomArgument>
|
||||||
|
<IncludeLibraryModules></IncludeLibraryModules>
|
||||||
<ComprImg>1</ComprImg>
|
<ComprImg>1</ComprImg>
|
||||||
</CommonProperty>
|
</CommonProperty>
|
||||||
<FileArmAds>
|
<FileArmAds>
|
||||||
@@ -553,6 +562,12 @@
|
|||||||
<v6Lto>2</v6Lto>
|
<v6Lto>2</v6Lto>
|
||||||
<v6WtE>2</v6WtE>
|
<v6WtE>2</v6WtE>
|
||||||
<v6Rtti>2</v6Rtti>
|
<v6Rtti>2</v6Rtti>
|
||||||
|
<VariousControls>
|
||||||
|
<MiscControls></MiscControls>
|
||||||
|
<Define></Define>
|
||||||
|
<Undefine></Undefine>
|
||||||
|
<IncludePath></IncludePath>
|
||||||
|
</VariousControls>
|
||||||
</Cads>
|
</Cads>
|
||||||
</FileArmAds>
|
</FileArmAds>
|
||||||
</FileOption>
|
</FileOption>
|
||||||
@@ -574,6 +589,8 @@
|
|||||||
<AssembleAssemblyFile>2</AssembleAssemblyFile>
|
<AssembleAssemblyFile>2</AssembleAssemblyFile>
|
||||||
<PublicsOnly>2</PublicsOnly>
|
<PublicsOnly>2</PublicsOnly>
|
||||||
<StopOnExitCode>11</StopOnExitCode>
|
<StopOnExitCode>11</StopOnExitCode>
|
||||||
|
<CustomArgument></CustomArgument>
|
||||||
|
<IncludeLibraryModules></IncludeLibraryModules>
|
||||||
<ComprImg>1</ComprImg>
|
<ComprImg>1</ComprImg>
|
||||||
</CommonProperty>
|
</CommonProperty>
|
||||||
<FileArmAds>
|
<FileArmAds>
|
||||||
@@ -601,6 +618,12 @@
|
|||||||
<v6Lto>2</v6Lto>
|
<v6Lto>2</v6Lto>
|
||||||
<v6WtE>2</v6WtE>
|
<v6WtE>2</v6WtE>
|
||||||
<v6Rtti>2</v6Rtti>
|
<v6Rtti>2</v6Rtti>
|
||||||
|
<VariousControls>
|
||||||
|
<MiscControls></MiscControls>
|
||||||
|
<Define></Define>
|
||||||
|
<Undefine></Undefine>
|
||||||
|
<IncludePath></IncludePath>
|
||||||
|
</VariousControls>
|
||||||
</Cads>
|
</Cads>
|
||||||
</FileArmAds>
|
</FileArmAds>
|
||||||
</FileOption>
|
</FileOption>
|
||||||
@@ -637,6 +660,8 @@
|
|||||||
<AssembleAssemblyFile>2</AssembleAssemblyFile>
|
<AssembleAssemblyFile>2</AssembleAssemblyFile>
|
||||||
<PublicsOnly>2</PublicsOnly>
|
<PublicsOnly>2</PublicsOnly>
|
||||||
<StopOnExitCode>11</StopOnExitCode>
|
<StopOnExitCode>11</StopOnExitCode>
|
||||||
|
<CustomArgument></CustomArgument>
|
||||||
|
<IncludeLibraryModules></IncludeLibraryModules>
|
||||||
<ComprImg>1</ComprImg>
|
<ComprImg>1</ComprImg>
|
||||||
</CommonProperty>
|
</CommonProperty>
|
||||||
<FileArmAds>
|
<FileArmAds>
|
||||||
@@ -664,6 +689,12 @@
|
|||||||
<v6Lto>2</v6Lto>
|
<v6Lto>2</v6Lto>
|
||||||
<v6WtE>2</v6WtE>
|
<v6WtE>2</v6WtE>
|
||||||
<v6Rtti>2</v6Rtti>
|
<v6Rtti>2</v6Rtti>
|
||||||
|
<VariousControls>
|
||||||
|
<MiscControls></MiscControls>
|
||||||
|
<Define></Define>
|
||||||
|
<Undefine></Undefine>
|
||||||
|
<IncludePath></IncludePath>
|
||||||
|
</VariousControls>
|
||||||
</Cads>
|
</Cads>
|
||||||
</FileArmAds>
|
</FileArmAds>
|
||||||
</FileOption>
|
</FileOption>
|
||||||
@@ -685,6 +716,8 @@
|
|||||||
<AssembleAssemblyFile>2</AssembleAssemblyFile>
|
<AssembleAssemblyFile>2</AssembleAssemblyFile>
|
||||||
<PublicsOnly>2</PublicsOnly>
|
<PublicsOnly>2</PublicsOnly>
|
||||||
<StopOnExitCode>11</StopOnExitCode>
|
<StopOnExitCode>11</StopOnExitCode>
|
||||||
|
<CustomArgument></CustomArgument>
|
||||||
|
<IncludeLibraryModules></IncludeLibraryModules>
|
||||||
<ComprImg>1</ComprImg>
|
<ComprImg>1</ComprImg>
|
||||||
</CommonProperty>
|
</CommonProperty>
|
||||||
<FileArmAds>
|
<FileArmAds>
|
||||||
@@ -712,6 +745,12 @@
|
|||||||
<v6Lto>2</v6Lto>
|
<v6Lto>2</v6Lto>
|
||||||
<v6WtE>2</v6WtE>
|
<v6WtE>2</v6WtE>
|
||||||
<v6Rtti>2</v6Rtti>
|
<v6Rtti>2</v6Rtti>
|
||||||
|
<VariousControls>
|
||||||
|
<MiscControls></MiscControls>
|
||||||
|
<Define></Define>
|
||||||
|
<Undefine></Undefine>
|
||||||
|
<IncludePath></IncludePath>
|
||||||
|
</VariousControls>
|
||||||
</Cads>
|
</Cads>
|
||||||
</FileArmAds>
|
</FileArmAds>
|
||||||
</FileOption>
|
</FileOption>
|
||||||
@@ -798,6 +837,8 @@
|
|||||||
<AssembleAssemblyFile>2</AssembleAssemblyFile>
|
<AssembleAssemblyFile>2</AssembleAssemblyFile>
|
||||||
<PublicsOnly>2</PublicsOnly>
|
<PublicsOnly>2</PublicsOnly>
|
||||||
<StopOnExitCode>11</StopOnExitCode>
|
<StopOnExitCode>11</StopOnExitCode>
|
||||||
|
<CustomArgument></CustomArgument>
|
||||||
|
<IncludeLibraryModules></IncludeLibraryModules>
|
||||||
<ComprImg>1</ComprImg>
|
<ComprImg>1</ComprImg>
|
||||||
</CommonProperty>
|
</CommonProperty>
|
||||||
<FileArmAds>
|
<FileArmAds>
|
||||||
@@ -825,6 +866,12 @@
|
|||||||
<v6Lto>2</v6Lto>
|
<v6Lto>2</v6Lto>
|
||||||
<v6WtE>2</v6WtE>
|
<v6WtE>2</v6WtE>
|
||||||
<v6Rtti>2</v6Rtti>
|
<v6Rtti>2</v6Rtti>
|
||||||
|
<VariousControls>
|
||||||
|
<MiscControls></MiscControls>
|
||||||
|
<Define></Define>
|
||||||
|
<Undefine></Undefine>
|
||||||
|
<IncludePath></IncludePath>
|
||||||
|
</VariousControls>
|
||||||
</Cads>
|
</Cads>
|
||||||
</FileArmAds>
|
</FileArmAds>
|
||||||
</FileOption>
|
</FileOption>
|
||||||
@@ -846,6 +893,8 @@
|
|||||||
<AssembleAssemblyFile>2</AssembleAssemblyFile>
|
<AssembleAssemblyFile>2</AssembleAssemblyFile>
|
||||||
<PublicsOnly>2</PublicsOnly>
|
<PublicsOnly>2</PublicsOnly>
|
||||||
<StopOnExitCode>11</StopOnExitCode>
|
<StopOnExitCode>11</StopOnExitCode>
|
||||||
|
<CustomArgument></CustomArgument>
|
||||||
|
<IncludeLibraryModules></IncludeLibraryModules>
|
||||||
<ComprImg>1</ComprImg>
|
<ComprImg>1</ComprImg>
|
||||||
</CommonProperty>
|
</CommonProperty>
|
||||||
<FileArmAds>
|
<FileArmAds>
|
||||||
@@ -873,6 +922,12 @@
|
|||||||
<v6Lto>2</v6Lto>
|
<v6Lto>2</v6Lto>
|
||||||
<v6WtE>2</v6WtE>
|
<v6WtE>2</v6WtE>
|
||||||
<v6Rtti>2</v6Rtti>
|
<v6Rtti>2</v6Rtti>
|
||||||
|
<VariousControls>
|
||||||
|
<MiscControls></MiscControls>
|
||||||
|
<Define></Define>
|
||||||
|
<Undefine></Undefine>
|
||||||
|
<IncludePath></IncludePath>
|
||||||
|
</VariousControls>
|
||||||
</Cads>
|
</Cads>
|
||||||
</FileArmAds>
|
</FileArmAds>
|
||||||
</FileOption>
|
</FileOption>
|
||||||
@@ -922,6 +977,16 @@
|
|||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
<FilePath>..\Drivers\BSP\RS485\rs485.c</FilePath>
|
<FilePath>..\Drivers\BSP\RS485\rs485.c</FilePath>
|
||||||
</File>
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>net_select.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\Drivers\BSP\NET\net_select.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>net_socket.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\Drivers\BSP\NET\net_socket.c</FilePath>
|
||||||
|
</File>
|
||||||
</Files>
|
</Files>
|
||||||
</Group>
|
</Group>
|
||||||
<Group>
|
<Group>
|
||||||
@@ -970,18 +1035,20 @@
|
|||||||
</Groups>
|
</Groups>
|
||||||
</Target>
|
</Target>
|
||||||
</Targets>
|
</Targets>
|
||||||
|
|
||||||
<RTE>
|
<RTE>
|
||||||
<apis />
|
<apis/>
|
||||||
<components>
|
<components>
|
||||||
<component Cclass="CMSIS" Cgroup="CORE" Cvendor="ARM" Cversion="5.5.0" condition="ARMv6_7_8-M Device">
|
<component Cclass="CMSIS" Cgroup="CORE" Cvendor="ARM" Cversion="5.5.0" condition="ARMv6_7_8-M Device">
|
||||||
<package name="CMSIS" schemaVersion="1.3" url="http://www.keil.com/pack/" vendor="ARM" version="5.8.0" />
|
<package name="CMSIS" schemaVersion="1.3" url="http://www.keil.com/pack/" vendor="ARM" version="5.8.0"/>
|
||||||
<targetInfos>
|
<targetInfos>
|
||||||
<targetInfo name="STM32F407-Demo" />
|
<targetInfo name="STM32F407-Demo"/>
|
||||||
</targetInfos>
|
</targetInfos>
|
||||||
</component>
|
</component>
|
||||||
</components>
|
</components>
|
||||||
<files />
|
<files/>
|
||||||
</RTE>
|
</RTE>
|
||||||
|
|
||||||
<LayerInfo>
|
<LayerInfo>
|
||||||
<Layers>
|
<Layers>
|
||||||
<Layer>
|
<Layer>
|
||||||
@@ -990,5 +1057,5 @@
|
|||||||
</Layer>
|
</Layer>
|
||||||
</Layers>
|
</Layers>
|
||||||
</LayerInfo>
|
</LayerInfo>
|
||||||
</Project>
|
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|||||||
19
MDK-ARM/build.bat
Normal file
19
MDK-ARM/build.bat
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal
|
||||||
|
|
||||||
|
set UV4=C:\Keil_v5\UV4\UV4.exe
|
||||||
|
set PROJ=%~dp0STM32F407-Demo.uvprojx
|
||||||
|
set LOG=%~dp0build_log.txt
|
||||||
|
set TARGET=STM32F407-Demo
|
||||||
|
|
||||||
|
"%UV4%" -r "%PROJ%" -t%TARGET% -j0 -o "%LOG%"
|
||||||
|
set RET=%ERRORLEVEL%
|
||||||
|
|
||||||
|
if %RET% equ 0 (
|
||||||
|
echo BUILD_OK: 0 Error(s), 0 Warning(s)
|
||||||
|
) else (
|
||||||
|
echo BUILD_FAIL: exit code %RET%
|
||||||
|
if exist "%LOG%" type "%LOG%"
|
||||||
|
)
|
||||||
|
|
||||||
|
exit /b %RET%
|
||||||
49
MDK-ARM/build_log.txt
Normal file
49
MDK-ARM/build_log.txt
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
*** Using Compiler 'V5.06 update 7 (build 960)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
|
||||||
|
Rebuild target 'STM32F407-Demo'
|
||||||
|
assembling startup_stm32f407xx.s...
|
||||||
|
compiling gpio.c...
|
||||||
|
compiling dma.c...
|
||||||
|
compiling stm32f4xx_hal_i2c_ex.c...
|
||||||
|
compiling stm32f4xx_hal_flash_ramfunc.c...
|
||||||
|
compiling stm32f4xx_it.c...
|
||||||
|
compiling stm32f4xx_hal_pwr_ex.c...
|
||||||
|
compiling stm32f4xx_hal_gpio.c...
|
||||||
|
compiling spi.c...
|
||||||
|
compiling stm32f4xx_hal_flash_ex.c...
|
||||||
|
compiling i2c.c...
|
||||||
|
compiling stm32f4xx_hal.c...
|
||||||
|
compiling stm32f4xx_hal_rcc_ex.c...
|
||||||
|
compiling stm32f4xx_hal_pwr.c...
|
||||||
|
compiling stm32f4xx_hal_cortex.c...
|
||||||
|
compiling stm32f4xx_hal_flash.c...
|
||||||
|
compiling main.c...
|
||||||
|
compiling stm32f4xx_hal_exti.c...
|
||||||
|
compiling usart.c...
|
||||||
|
compiling stm32f4xx_hal_msp.c...
|
||||||
|
compiling stm32f4xx_hal_dma.c...
|
||||||
|
compiling stm32f4xx_hal_rcc.c...
|
||||||
|
compiling stm32f4xx_hal_dma_ex.c...
|
||||||
|
compiling stm32f4xx_hal_i2c.c...
|
||||||
|
compiling fdb.c...
|
||||||
|
compiling fal.c...
|
||||||
|
compiling fal_flash.c...
|
||||||
|
compiling fdb_utils.c...
|
||||||
|
compiling fal_partition.c...
|
||||||
|
compiling fdb_tsdb.c...
|
||||||
|
compiling fdb_kvdb.c...
|
||||||
|
compiling system_stm32f4xx.c...
|
||||||
|
compiling stm32f4xx_hal_spi.c...
|
||||||
|
compiling fal_flash_gd5f2gq5ue.c...
|
||||||
|
compiling ch395f.c...
|
||||||
|
compiling stm32f4xx_hal_uart.c...
|
||||||
|
compiling gd5f2gq5ue.c...
|
||||||
|
compiling rs485.c...
|
||||||
|
compiling sd2506.c...
|
||||||
|
compiling tpafe5160.c...
|
||||||
|
compiling net_select.c...
|
||||||
|
compiling net_socket.c...
|
||||||
|
linking...
|
||||||
|
Program Size: Code=20964 RO-data=624 RW-data=40 ZI-data=7344
|
||||||
|
FromELF: creating hex file...
|
||||||
|
".\STM32F407-Demo\STM32F407-Demo.axf" - 0 Error(s), 0 Warning(s).
|
||||||
|
Build Time Elapsed: 00:00:12
|
||||||
@@ -1,10 +1,32 @@
|
|||||||
#MicroXplorer Configuration settings - do not modify
|
#MicroXplorer Configuration settings - do not modify
|
||||||
CAD.formats=
|
CAD.formats=[]
|
||||||
CAD.pinconfig=
|
CAD.pinconfig=Dual
|
||||||
CAD.provider=
|
CAD.provider=Component Search Engine
|
||||||
Dma.Request0=USART1_TX
|
Dma.Request0=USART1_TX
|
||||||
Dma.Request1=USART1_RX
|
Dma.Request1=USART1_RX
|
||||||
Dma.RequestsNb=2
|
Dma.Request2=SPI2_RX
|
||||||
|
Dma.Request3=SPI2_TX
|
||||||
|
Dma.RequestsNb=4
|
||||||
|
Dma.SPI2_RX.2.Direction=DMA_PERIPH_TO_MEMORY
|
||||||
|
Dma.SPI2_RX.2.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||||
|
Dma.SPI2_RX.2.Instance=DMA1_Stream3
|
||||||
|
Dma.SPI2_RX.2.MemDataAlignment=DMA_MDATAALIGN_BYTE
|
||||||
|
Dma.SPI2_RX.2.MemInc=DMA_MINC_ENABLE
|
||||||
|
Dma.SPI2_RX.2.Mode=DMA_NORMAL
|
||||||
|
Dma.SPI2_RX.2.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
|
||||||
|
Dma.SPI2_RX.2.PeriphInc=DMA_PINC_DISABLE
|
||||||
|
Dma.SPI2_RX.2.Priority=DMA_PRIORITY_VERY_HIGH
|
||||||
|
Dma.SPI2_RX.2.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
|
||||||
|
Dma.SPI2_TX.3.Direction=DMA_MEMORY_TO_PERIPH
|
||||||
|
Dma.SPI2_TX.3.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||||
|
Dma.SPI2_TX.3.Instance=DMA1_Stream4
|
||||||
|
Dma.SPI2_TX.3.MemDataAlignment=DMA_MDATAALIGN_BYTE
|
||||||
|
Dma.SPI2_TX.3.MemInc=DMA_MINC_ENABLE
|
||||||
|
Dma.SPI2_TX.3.Mode=DMA_NORMAL
|
||||||
|
Dma.SPI2_TX.3.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
|
||||||
|
Dma.SPI2_TX.3.PeriphInc=DMA_PINC_DISABLE
|
||||||
|
Dma.SPI2_TX.3.Priority=DMA_PRIORITY_VERY_HIGH
|
||||||
|
Dma.SPI2_TX.3.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
|
||||||
Dma.USART1_RX.1.Direction=DMA_PERIPH_TO_MEMORY
|
Dma.USART1_RX.1.Direction=DMA_PERIPH_TO_MEMORY
|
||||||
Dma.USART1_RX.1.FIFOMode=DMA_FIFOMODE_DISABLE
|
Dma.USART1_RX.1.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||||
Dma.USART1_RX.1.Instance=DMA2_Stream2
|
Dma.USART1_RX.1.Instance=DMA2_Stream2
|
||||||
@@ -45,70 +67,73 @@ Mcu.IP9=USART1
|
|||||||
Mcu.IPNb=12
|
Mcu.IPNb=12
|
||||||
Mcu.Name=STM32F407Z(E-G)Tx
|
Mcu.Name=STM32F407Z(E-G)Tx
|
||||||
Mcu.Package=LQFP144
|
Mcu.Package=LQFP144
|
||||||
Mcu.Pin0=PH0-OSC_IN
|
Mcu.Pin0=PE5
|
||||||
Mcu.Pin1=PH1-OSC_OUT
|
Mcu.Pin1=PH0-OSC_IN
|
||||||
Mcu.Pin10=PF15
|
Mcu.Pin10=PF14
|
||||||
Mcu.Pin11=PG0
|
Mcu.Pin11=PF15
|
||||||
Mcu.Pin12=PG1
|
Mcu.Pin12=PG0
|
||||||
Mcu.Pin13=PB10
|
Mcu.Pin13=PG1
|
||||||
Mcu.Pin14=PB11
|
Mcu.Pin14=PB10
|
||||||
Mcu.Pin15=PB12
|
Mcu.Pin15=PB11
|
||||||
Mcu.Pin16=PB13
|
Mcu.Pin16=PB12
|
||||||
Mcu.Pin17=PB14
|
Mcu.Pin17=PB13
|
||||||
Mcu.Pin18=PB15
|
Mcu.Pin18=PB14
|
||||||
Mcu.Pin19=PG2
|
Mcu.Pin19=PB15
|
||||||
Mcu.Pin2=PC4
|
Mcu.Pin2=PH1-OSC_OUT
|
||||||
Mcu.Pin20=PG3
|
Mcu.Pin20=PG2
|
||||||
Mcu.Pin21=PG4
|
Mcu.Pin21=PG3
|
||||||
Mcu.Pin22=PG5
|
Mcu.Pin22=PG4
|
||||||
Mcu.Pin23=PG6
|
Mcu.Pin23=PG5
|
||||||
Mcu.Pin24=PG7
|
Mcu.Pin24=PG6
|
||||||
Mcu.Pin25=PG8
|
Mcu.Pin25=PG7
|
||||||
Mcu.Pin26=PA9
|
Mcu.Pin26=PG8
|
||||||
Mcu.Pin27=PA10
|
Mcu.Pin27=PA9
|
||||||
Mcu.Pin28=PA13
|
Mcu.Pin28=PA10
|
||||||
Mcu.Pin29=PA14
|
Mcu.Pin29=PA13
|
||||||
Mcu.Pin3=PC5
|
Mcu.Pin3=PC4
|
||||||
Mcu.Pin30=PC10
|
Mcu.Pin30=PA14
|
||||||
Mcu.Pin31=PC11
|
Mcu.Pin31=PC10
|
||||||
Mcu.Pin32=PC12
|
Mcu.Pin32=PC11
|
||||||
Mcu.Pin33=PD0
|
Mcu.Pin33=PC12
|
||||||
Mcu.Pin34=PD1
|
Mcu.Pin34=PD0
|
||||||
Mcu.Pin35=PD2
|
Mcu.Pin35=PD1
|
||||||
Mcu.Pin36=PD3
|
Mcu.Pin36=PD2
|
||||||
Mcu.Pin37=PD4
|
Mcu.Pin37=PD3
|
||||||
Mcu.Pin38=PD5
|
Mcu.Pin38=PD4
|
||||||
Mcu.Pin39=PD6
|
Mcu.Pin39=PD5
|
||||||
Mcu.Pin4=PB1
|
Mcu.Pin4=PC5
|
||||||
Mcu.Pin40=PD7
|
Mcu.Pin40=PD6
|
||||||
Mcu.Pin41=PG9
|
Mcu.Pin41=PD7
|
||||||
Mcu.Pin42=PG10
|
Mcu.Pin42=PG9
|
||||||
Mcu.Pin43=PG11
|
Mcu.Pin43=PG10
|
||||||
Mcu.Pin44=PG12
|
Mcu.Pin44=PG11
|
||||||
Mcu.Pin45=PG13
|
Mcu.Pin45=PG12
|
||||||
Mcu.Pin46=PG14
|
Mcu.Pin46=PG13
|
||||||
Mcu.Pin47=PG15
|
Mcu.Pin47=PG14
|
||||||
Mcu.Pin48=PB3
|
Mcu.Pin48=PG15
|
||||||
Mcu.Pin49=PB4
|
Mcu.Pin49=PB3
|
||||||
Mcu.Pin5=PB2
|
Mcu.Pin5=PB1
|
||||||
Mcu.Pin50=PB5
|
Mcu.Pin50=PB4
|
||||||
Mcu.Pin51=PB6
|
Mcu.Pin51=PB5
|
||||||
Mcu.Pin52=PB7
|
Mcu.Pin52=PB6
|
||||||
Mcu.Pin53=PB8
|
Mcu.Pin53=PB7
|
||||||
Mcu.Pin54=PE0
|
Mcu.Pin54=PB8
|
||||||
Mcu.Pin55=PE1
|
Mcu.Pin55=PE0
|
||||||
Mcu.Pin56=VP_SYS_VS_Systick
|
Mcu.Pin56=PE1
|
||||||
Mcu.Pin6=PF11
|
Mcu.Pin57=VP_SYS_VS_Systick
|
||||||
Mcu.Pin7=PF12
|
Mcu.Pin6=PB2
|
||||||
Mcu.Pin8=PF13
|
Mcu.Pin7=PF11
|
||||||
Mcu.Pin9=PF14
|
Mcu.Pin8=PF12
|
||||||
Mcu.PinsNb=57
|
Mcu.Pin9=PF13
|
||||||
|
Mcu.PinsNb=58
|
||||||
Mcu.ThirdPartyNb=0
|
Mcu.ThirdPartyNb=0
|
||||||
Mcu.UserConstants=
|
Mcu.UserConstants=
|
||||||
Mcu.UserName=STM32F407ZGTx
|
Mcu.UserName=STM32F407ZGTx
|
||||||
MxCube.Version=6.17.0
|
MxCube.Version=6.17.0
|
||||||
MxDb.Version=DB.6.0.170
|
MxDb.Version=DB.6.0.170
|
||||||
NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||||
|
NVIC.DMA1_Stream3_IRQn=true\:1\:0\:true\:false\:true\:false\:true\:true
|
||||||
|
NVIC.DMA1_Stream4_IRQn=true\:1\:0\:true\:false\:true\:false\:true\:true
|
||||||
NVIC.DMA2_Stream2_IRQn=true\:3\:0\:true\:false\:true\:false\:true\:true
|
NVIC.DMA2_Stream2_IRQn=true\:3\:0\:true\:false\:true\:false\:true\:true
|
||||||
NVIC.DMA2_Stream7_IRQn=true\:3\:0\:true\:false\:true\:false\:true\:true
|
NVIC.DMA2_Stream7_IRQn=true\:3\:0\:true\:false\:true\:false\:true\:true
|
||||||
NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||||
@@ -119,6 +144,7 @@ NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
|||||||
NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||||
NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||||
NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
|
NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
|
||||||
|
NVIC.SPI2_IRQn=true\:1\:0\:true\:false\:true\:true\:true\:true
|
||||||
NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||||
NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false
|
NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false
|
||||||
NVIC.UART4_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true
|
NVIC.UART4_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true
|
||||||
@@ -315,6 +341,10 @@ PE1.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
|
|||||||
PE1.Locked=true
|
PE1.Locked=true
|
||||||
PE1.PinState=GPIO_PIN_SET
|
PE1.PinState=GPIO_PIN_SET
|
||||||
PE1.Signal=GPIO_Output
|
PE1.Signal=GPIO_Output
|
||||||
|
PE5.GPIOParameters=GPIO_Label
|
||||||
|
PE5.GPIO_Label=CH395_INT
|
||||||
|
PE5.Locked=true
|
||||||
|
PE5.Signal=GPIO_Input
|
||||||
PF11.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label
|
PF11.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label
|
||||||
PF11.GPIO_Label=LED5
|
PF11.GPIO_Label=LED5
|
||||||
PF11.GPIO_PuPd=GPIO_PULLUP
|
PF11.GPIO_PuPd=GPIO_PULLUP
|
||||||
@@ -481,14 +511,16 @@ RCC.VCOOutputFreq_Value=336000000
|
|||||||
RCC.VcooutputI2S=192000000
|
RCC.VcooutputI2S=192000000
|
||||||
SH.GPXTI7.0=GPIO_EXTI7
|
SH.GPXTI7.0=GPIO_EXTI7
|
||||||
SH.GPXTI7.ConfNb=1
|
SH.GPXTI7.ConfNb=1
|
||||||
SPI1.CalculateBaudRate=42.0 MBits/s
|
SPI1.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_8
|
||||||
|
SPI1.CalculateBaudRate=10.5 MBits/s
|
||||||
SPI1.Direction=SPI_DIRECTION_2LINES
|
SPI1.Direction=SPI_DIRECTION_2LINES
|
||||||
SPI1.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate
|
SPI1.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,BaudRatePrescaler
|
||||||
SPI1.Mode=SPI_MODE_MASTER
|
SPI1.Mode=SPI_MODE_MASTER
|
||||||
SPI1.VirtualType=VM_MASTER
|
SPI1.VirtualType=VM_MASTER
|
||||||
SPI2.CalculateBaudRate=21.0 MBits/s
|
SPI2.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_8
|
||||||
|
SPI2.CalculateBaudRate=5.25 MBits/s
|
||||||
SPI2.Direction=SPI_DIRECTION_2LINES
|
SPI2.Direction=SPI_DIRECTION_2LINES
|
||||||
SPI2.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate
|
SPI2.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,BaudRatePrescaler
|
||||||
SPI2.Mode=SPI_MODE_MASTER
|
SPI2.Mode=SPI_MODE_MASTER
|
||||||
SPI2.VirtualType=VM_MASTER
|
SPI2.VirtualType=VM_MASTER
|
||||||
UART4.IPParameters=VirtualMode
|
UART4.IPParameters=VirtualMode
|
||||||
|
|||||||
@@ -41,8 +41,15 @@ void MX_DMA_Init(void)
|
|||||||
|
|
||||||
/* DMA controller clock enable */
|
/* DMA controller clock enable */
|
||||||
__HAL_RCC_DMA2_CLK_ENABLE();
|
__HAL_RCC_DMA2_CLK_ENABLE();
|
||||||
|
__HAL_RCC_DMA1_CLK_ENABLE();
|
||||||
|
|
||||||
/* DMA interrupt init */
|
/* DMA interrupt init */
|
||||||
|
/* DMA1_Stream3_IRQn interrupt configuration */
|
||||||
|
HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 1, 0);
|
||||||
|
HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
|
||||||
|
/* DMA1_Stream4_IRQn interrupt configuration */
|
||||||
|
HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 1, 0);
|
||||||
|
HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
|
||||||
/* DMA2_Stream2_IRQn interrupt configuration */
|
/* DMA2_Stream2_IRQn interrupt configuration */
|
||||||
HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 3, 0);
|
HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 3, 0);
|
||||||
HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
|
HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ void MX_GPIO_Init(void)
|
|||||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||||
|
|
||||||
/* GPIO Ports Clock Enable */
|
/* GPIO Ports Clock Enable */
|
||||||
|
__HAL_RCC_GPIOE_CLK_ENABLE();
|
||||||
__HAL_RCC_GPIOH_CLK_ENABLE();
|
__HAL_RCC_GPIOH_CLK_ENABLE();
|
||||||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||||
@@ -52,7 +53,6 @@ void MX_GPIO_Init(void)
|
|||||||
__HAL_RCC_GPIOG_CLK_ENABLE();
|
__HAL_RCC_GPIOG_CLK_ENABLE();
|
||||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||||||
__HAL_RCC_GPIOE_CLK_ENABLE();
|
|
||||||
|
|
||||||
/*Configure GPIO pin Output Level */
|
/*Configure GPIO pin Output Level */
|
||||||
HAL_GPIO_WritePin(GPIOC, LED1_Pin|LED2_Pin, GPIO_PIN_SET);
|
HAL_GPIO_WritePin(GPIOC, LED1_Pin|LED2_Pin, GPIO_PIN_SET);
|
||||||
@@ -75,6 +75,12 @@ void MX_GPIO_Init(void)
|
|||||||
/*Configure GPIO pin Output Level */
|
/*Configure GPIO pin Output Level */
|
||||||
HAL_GPIO_WritePin(GPIOE, GD_CS_Pin|GD_HOLD_Pin, GPIO_PIN_SET);
|
HAL_GPIO_WritePin(GPIOE, GD_CS_Pin|GD_HOLD_Pin, GPIO_PIN_SET);
|
||||||
|
|
||||||
|
/*Configure GPIO pin : CH395_INT_Pin */
|
||||||
|
GPIO_InitStruct.Pin = CH395_INT_Pin;
|
||||||
|
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||||
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||||
|
HAL_GPIO_Init(CH395_INT_GPIO_Port, &GPIO_InitStruct);
|
||||||
|
|
||||||
/*Configure GPIO pins : LED1_Pin LED2_Pin */
|
/*Configure GPIO pins : LED1_Pin LED2_Pin */
|
||||||
GPIO_InitStruct.Pin = LED1_Pin|LED2_Pin;
|
GPIO_InitStruct.Pin = LED1_Pin|LED2_Pin;
|
||||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||||||
|
|||||||
115
Src/main.c
115
Src/main.c
@@ -33,6 +33,8 @@
|
|||||||
#include "tpafe5160.h"
|
#include "tpafe5160.h"
|
||||||
#include "sd2506.h"
|
#include "sd2506.h"
|
||||||
#include "rs485.h"
|
#include "rs485.h"
|
||||||
|
#include "net_socket.h"
|
||||||
|
#include "net_select.h"
|
||||||
/* USER CODE END Includes */
|
/* USER CODE END Includes */
|
||||||
|
|
||||||
/* Private typedef -----------------------------------------------------------*/
|
/* Private typedef -----------------------------------------------------------*/
|
||||||
@@ -47,7 +49,10 @@
|
|||||||
|
|
||||||
/* Private macro -------------------------------------------------------------*/
|
/* Private macro -------------------------------------------------------------*/
|
||||||
/* USER CODE BEGIN PM */
|
/* USER CODE BEGIN PM */
|
||||||
|
#define TS() do { \
|
||||||
|
uint32_t _t = HAL_GetTick(); \
|
||||||
|
printf("[%lu.%03lu] ", _t / 1000UL, _t % 1000UL); \
|
||||||
|
} while(0)
|
||||||
/* USER CODE END PM */
|
/* USER CODE END PM */
|
||||||
|
|
||||||
/* Private variables ---------------------------------------------------------*/
|
/* Private variables ---------------------------------------------------------*/
|
||||||
@@ -57,6 +62,9 @@
|
|||||||
rs485_handle_t g_rs485;
|
rs485_handle_t g_rs485;
|
||||||
#define RS485_RX_BUF_SIZE 256
|
#define RS485_RX_BUF_SIZE 256
|
||||||
uint8_t g_rs485_rx_buf[RS485_RX_BUF_SIZE];
|
uint8_t g_rs485_rx_buf[RS485_RX_BUF_SIZE];
|
||||||
|
/* TCP Server Echo 测试 */
|
||||||
|
static int s_listen_sock = -1;
|
||||||
|
static uint8_t s_echo_buf[1500];
|
||||||
/* USER CODE END PV */
|
/* USER CODE END PV */
|
||||||
|
|
||||||
/* Private function prototypes -----------------------------------------------*/
|
/* Private function prototypes -----------------------------------------------*/
|
||||||
@@ -110,36 +118,17 @@ int main(void)
|
|||||||
/* USER CODE BEGIN 2 */
|
/* USER CODE BEGIN 2 */
|
||||||
HAL_Delay(100);
|
HAL_Delay(100);
|
||||||
|
|
||||||
/* CH395F 硬件检测 */
|
/* BSD Socket API 初始化(包含 CH395F 复位/配置/协议栈初始化/多连接模式) */
|
||||||
ch395f_status_t ch395f_ret = ch395f_check_exist();
|
printf("[NET] init: %s\r\n",
|
||||||
printf("[CH395F] SPI: %s\r\n",
|
(net_init("192.168.1.100", "255.255.255.0", "192.168.1.1") == 0) ? "OK" : "FAIL");
|
||||||
(ch395f_ret == CH395F_STATUS_OK) ? "OK" : "FAIL");
|
|
||||||
|
|
||||||
printf("[CH395F] version: 0x%02X\r\n", ch395f_get_version());
|
/* 读取 MAC */
|
||||||
|
|
||||||
if (ch395f_ret == CH395F_STATUS_OK) {
|
|
||||||
/* 1. 复位 */
|
|
||||||
ch395f_reset();
|
|
||||||
|
|
||||||
/* 2. 配置网络参数(必须在 INIT 之前,INIT 会锁定协议栈参数) */
|
|
||||||
uint8_t ip[4] = {192, 168, 1, 100};
|
|
||||||
uint8_t gw[4] = {192, 168, 1, 1};
|
|
||||||
uint8_t mask[4] = {255, 255, 255, 0};
|
|
||||||
ch395f_set_ip_addr(ip);
|
|
||||||
ch395f_set_gwip_addr(gw);
|
|
||||||
ch395f_set_mask_addr(mask);
|
|
||||||
|
|
||||||
/* 3. 初始化协议栈(锁定 IP/GW/MASK 等参数) */
|
|
||||||
printf("[CH395F] init: %s\r\n",
|
|
||||||
(ch395f_init() == CH395F_STATUS_OK) ? "OK" : "FAIL");
|
|
||||||
|
|
||||||
/* 4. 读取 MAC */
|
|
||||||
uint8_t mac[6];
|
uint8_t mac[6];
|
||||||
ch395f_get_mac_addr(mac);
|
ch395f_get_mac_addr(mac);
|
||||||
printf("[CH395F] MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n",
|
printf("[CH395F] MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n",
|
||||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||||
|
|
||||||
/* 5. 强制 100M 全双工,建立 PHY 链路 */
|
/* 强制 100M 全双工,建立 PHY 链路 */
|
||||||
ch395f_set_phy(CH395F_PHY_100M_FULL);
|
ch395f_set_phy(CH395F_PHY_100M_FULL);
|
||||||
HAL_Delay(3000);
|
HAL_Delay(3000);
|
||||||
uint8_t phy = ch395f_get_phy_status();
|
uint8_t phy = ch395f_get_phy_status();
|
||||||
@@ -152,7 +141,6 @@ int main(void)
|
|||||||
case CH395F_PHY_100M_HALF: phy_str = "100M HALF"; break;
|
case CH395F_PHY_100M_HALF: phy_str = "100M HALF"; break;
|
||||||
}
|
}
|
||||||
printf("[CH395F] PHY: %s\r\n", phy_str);
|
printf("[CH395F] PHY: %s\r\n", phy_str);
|
||||||
}
|
|
||||||
|
|
||||||
/* GD5F 初始化测试 */
|
/* GD5F 初始化测试 */
|
||||||
int ret = gd5f2gq5ue_init();
|
int ret = gd5f2gq5ue_init();
|
||||||
@@ -213,6 +201,30 @@ int main(void)
|
|||||||
/* 启动第一次 RS-485 接收 */
|
/* 启动第一次 RS-485 接收 */
|
||||||
rs485_receive_start(&g_rs485, g_rs485_rx_buf, RS485_RX_BUF_SIZE);
|
rs485_receive_start(&g_rs485, g_rs485_rx_buf, RS485_RX_BUF_SIZE);
|
||||||
|
|
||||||
|
/* 创建 TCP Server Echo 测试 */
|
||||||
|
{
|
||||||
|
s_listen_sock = net_socket(NET_AF_INET, NET_SOCK_STREAM, 0);
|
||||||
|
printf("[NET] TCP listen socket: %d\r\n", s_listen_sock);
|
||||||
|
|
||||||
|
struct net_sockaddr_in serv_addr;
|
||||||
|
memset(&serv_addr, 0, sizeof(serv_addr));
|
||||||
|
serv_addr.sin_family = NET_AF_INET;
|
||||||
|
serv_addr.sin_port = net_htons(8080);
|
||||||
|
serv_addr.sin_addr.s_addr = NET_INADDR_ANY;
|
||||||
|
|
||||||
|
if (net_bind(s_listen_sock, (struct net_sockaddr *)&serv_addr, sizeof(serv_addr)) == 0) {
|
||||||
|
printf("[NET] TCP bind: OK (port 8080)\r\n");
|
||||||
|
} else {
|
||||||
|
printf("[NET] TCP bind: FAIL\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (net_listen(s_listen_sock, NET_TCP_SERVER_MAX_CLIENTS) == 0) {
|
||||||
|
printf("[NET] TCP listen: OK (max_clients=%d)\r\n", NET_TCP_SERVER_MAX_CLIENTS);
|
||||||
|
} else {
|
||||||
|
printf("[NET] TCP listen: FAIL\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* 启动第一次转换(CubeMX 已配置 BUSY EXTI 中断) */
|
/* 启动第一次转换(CubeMX 已配置 BUSY EXTI 中断) */
|
||||||
tpafe5160_start_conv_irq();
|
tpafe5160_start_conv_irq();
|
||||||
/* USER CODE END 2 */
|
/* USER CODE END 2 */
|
||||||
@@ -224,22 +236,47 @@ int main(void)
|
|||||||
/* USER CODE END WHILE */
|
/* USER CODE END WHILE */
|
||||||
|
|
||||||
/* USER CODE BEGIN 3 */
|
/* USER CODE BEGIN 3 */
|
||||||
/* TPAFE5160 中断模式读取 */
|
/* 网络轮询(必须在主循环中调用) */
|
||||||
if (tpafe5160_data_ready()) {
|
net_poll();
|
||||||
const int16_t *buf = tpafe5160_get_buf();
|
|
||||||
printf("[TPAFE5160] CH:");
|
/* TCP Server Echo 处理 —— 多连接模式,socket 0 监听,socket 1~7 收发 */
|
||||||
for (int i = 0; i < 8; i++) {
|
{
|
||||||
printf(" %d", buf[i]);
|
int i;
|
||||||
}
|
for (i = NET_TCP_SERVER_DATA_SOCK_START; i < NET_MAX_SOCKETS; i++)
|
||||||
printf("\r\n");
|
{
|
||||||
tpafe5160_clear_ready();
|
net_sock_t *sk = net_get_sock(i);
|
||||||
/* 启动下一次转换 */
|
if (sk == NULL || !sk->in_use || sk->state != NET_SOCK_STATE_ESTABLISHED)
|
||||||
tpafe5160_start_conv_irq();
|
{
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t rlen = ch395f_get_recv_len((uint8_t)i);
|
||||||
|
if (rlen > 0) {
|
||||||
|
uint16_t read_len = (rlen > sizeof(s_echo_buf)) ? sizeof(s_echo_buf) : rlen;
|
||||||
|
ch395f_read_recv_buf((uint8_t)i, s_echo_buf, read_len);
|
||||||
|
TS(); printf("[NET] recv sock%d: %d bytes\r\n", i, read_len);
|
||||||
|
ch395f_write_send_buf((uint8_t)i, s_echo_buf, read_len);
|
||||||
|
TS(); printf("[NET] send sock%d: %d bytes\r\n", i, read_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// /* TPAFE5160 中断模式读取 */
|
||||||
|
// if (tpafe5160_data_ready()) {
|
||||||
|
// const int16_t *buf = tpafe5160_get_buf();
|
||||||
|
// printf("[TPAFE5160] CH:");
|
||||||
|
// for (int i = 0; i < 8; i++) {
|
||||||
|
// printf(" %d", buf[i]);
|
||||||
|
// }
|
||||||
|
// printf("\r\n");
|
||||||
|
// tpafe5160_clear_ready();
|
||||||
|
// /* 启动下一次转换 */
|
||||||
|
// tpafe5160_start_conv_irq();
|
||||||
|
// }
|
||||||
|
|
||||||
/* 其他任务 */
|
/* 其他任务 */
|
||||||
HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
|
// HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
|
||||||
HAL_Delay(500);
|
// HAL_Delay(10);
|
||||||
}
|
}
|
||||||
/* USER CODE END 3 */
|
/* USER CODE END 3 */
|
||||||
}
|
}
|
||||||
|
|||||||
52
Src/spi.c
52
Src/spi.c
@@ -26,6 +26,8 @@
|
|||||||
|
|
||||||
SPI_HandleTypeDef hspi1;
|
SPI_HandleTypeDef hspi1;
|
||||||
SPI_HandleTypeDef hspi2;
|
SPI_HandleTypeDef hspi2;
|
||||||
|
DMA_HandleTypeDef hdma_spi2_rx;
|
||||||
|
DMA_HandleTypeDef hdma_spi2_tx;
|
||||||
|
|
||||||
/* SPI1 init function */
|
/* SPI1 init function */
|
||||||
void MX_SPI1_Init(void)
|
void MX_SPI1_Init(void)
|
||||||
@@ -45,7 +47,7 @@ void MX_SPI1_Init(void)
|
|||||||
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
|
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
|
||||||
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
|
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
|
||||||
hspi1.Init.NSS = SPI_NSS_SOFT;
|
hspi1.Init.NSS = SPI_NSS_SOFT;
|
||||||
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
|
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
|
||||||
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
||||||
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
|
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
|
||||||
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
||||||
@@ -77,7 +79,7 @@ void MX_SPI2_Init(void)
|
|||||||
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
|
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
|
||||||
hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
|
hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
|
||||||
hspi2.Init.NSS = SPI_NSS_SOFT;
|
hspi2.Init.NSS = SPI_NSS_SOFT;
|
||||||
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
|
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
|
||||||
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
||||||
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
|
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
|
||||||
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
||||||
@@ -149,6 +151,46 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
|
|||||||
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
|
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
|
||||||
HAL_GPIO_Init(CH395F_SDO_GPIO_Port, &GPIO_InitStruct);
|
HAL_GPIO_Init(CH395F_SDO_GPIO_Port, &GPIO_InitStruct);
|
||||||
|
|
||||||
|
/* SPI2 DMA Init */
|
||||||
|
/* SPI2_RX Init */
|
||||||
|
hdma_spi2_rx.Instance = DMA1_Stream3;
|
||||||
|
hdma_spi2_rx.Init.Channel = DMA_CHANNEL_0;
|
||||||
|
hdma_spi2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||||||
|
hdma_spi2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||||
|
hdma_spi2_rx.Init.MemInc = DMA_MINC_ENABLE;
|
||||||
|
hdma_spi2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||||
|
hdma_spi2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||||
|
hdma_spi2_rx.Init.Mode = DMA_NORMAL;
|
||||||
|
hdma_spi2_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
|
||||||
|
hdma_spi2_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||||
|
if (HAL_DMA_Init(&hdma_spi2_rx) != HAL_OK)
|
||||||
|
{
|
||||||
|
Error_Handler();
|
||||||
|
}
|
||||||
|
|
||||||
|
__HAL_LINKDMA(spiHandle,hdmarx,hdma_spi2_rx);
|
||||||
|
|
||||||
|
/* SPI2_TX Init */
|
||||||
|
hdma_spi2_tx.Instance = DMA1_Stream4;
|
||||||
|
hdma_spi2_tx.Init.Channel = DMA_CHANNEL_0;
|
||||||
|
hdma_spi2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
|
||||||
|
hdma_spi2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||||
|
hdma_spi2_tx.Init.MemInc = DMA_MINC_ENABLE;
|
||||||
|
hdma_spi2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||||
|
hdma_spi2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||||
|
hdma_spi2_tx.Init.Mode = DMA_NORMAL;
|
||||||
|
hdma_spi2_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
|
||||||
|
hdma_spi2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||||
|
if (HAL_DMA_Init(&hdma_spi2_tx) != HAL_OK)
|
||||||
|
{
|
||||||
|
Error_Handler();
|
||||||
|
}
|
||||||
|
|
||||||
|
__HAL_LINKDMA(spiHandle,hdmatx,hdma_spi2_tx);
|
||||||
|
|
||||||
|
/* SPI2 interrupt Init */
|
||||||
|
HAL_NVIC_SetPriority(SPI2_IRQn, 1, 0);
|
||||||
|
HAL_NVIC_EnableIRQ(SPI2_IRQn);
|
||||||
/* USER CODE BEGIN SPI2_MspInit 1 */
|
/* USER CODE BEGIN SPI2_MspInit 1 */
|
||||||
|
|
||||||
/* USER CODE END SPI2_MspInit 1 */
|
/* USER CODE END SPI2_MspInit 1 */
|
||||||
@@ -192,6 +234,12 @@ void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
|
|||||||
*/
|
*/
|
||||||
HAL_GPIO_DeInit(GPIOB, CH395F_SCK_Pin|CH395F_SDO_Pin|CH395F_SDOB15_Pin);
|
HAL_GPIO_DeInit(GPIOB, CH395F_SCK_Pin|CH395F_SDO_Pin|CH395F_SDOB15_Pin);
|
||||||
|
|
||||||
|
/* SPI2 DMA DeInit */
|
||||||
|
HAL_DMA_DeInit(spiHandle->hdmarx);
|
||||||
|
HAL_DMA_DeInit(spiHandle->hdmatx);
|
||||||
|
|
||||||
|
/* SPI2 interrupt Deinit */
|
||||||
|
HAL_NVIC_DisableIRQ(SPI2_IRQn);
|
||||||
/* USER CODE BEGIN SPI2_MspDeInit 1 */
|
/* USER CODE BEGIN SPI2_MspDeInit 1 */
|
||||||
|
|
||||||
/* USER CODE END SPI2_MspDeInit 1 */
|
/* USER CODE END SPI2_MspDeInit 1 */
|
||||||
|
|||||||
@@ -55,6 +55,9 @@
|
|||||||
/* USER CODE END 0 */
|
/* USER CODE END 0 */
|
||||||
|
|
||||||
/* External variables --------------------------------------------------------*/
|
/* External variables --------------------------------------------------------*/
|
||||||
|
extern DMA_HandleTypeDef hdma_spi2_rx;
|
||||||
|
extern DMA_HandleTypeDef hdma_spi2_tx;
|
||||||
|
extern SPI_HandleTypeDef hspi2;
|
||||||
extern DMA_HandleTypeDef hdma_usart1_tx;
|
extern DMA_HandleTypeDef hdma_usart1_tx;
|
||||||
extern DMA_HandleTypeDef hdma_usart1_rx;
|
extern DMA_HandleTypeDef hdma_usart1_rx;
|
||||||
extern UART_HandleTypeDef huart4;
|
extern UART_HandleTypeDef huart4;
|
||||||
@@ -204,6 +207,34 @@ void SysTick_Handler(void)
|
|||||||
/* please refer to the startup file (startup_stm32f4xx.s). */
|
/* please refer to the startup file (startup_stm32f4xx.s). */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function handles DMA1 stream3 global interrupt.
|
||||||
|
*/
|
||||||
|
void DMA1_Stream3_IRQHandler(void)
|
||||||
|
{
|
||||||
|
/* USER CODE BEGIN DMA1_Stream3_IRQn 0 */
|
||||||
|
|
||||||
|
/* USER CODE END DMA1_Stream3_IRQn 0 */
|
||||||
|
HAL_DMA_IRQHandler(&hdma_spi2_rx);
|
||||||
|
/* USER CODE BEGIN DMA1_Stream3_IRQn 1 */
|
||||||
|
|
||||||
|
/* USER CODE END DMA1_Stream3_IRQn 1 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function handles DMA1 stream4 global interrupt.
|
||||||
|
*/
|
||||||
|
void DMA1_Stream4_IRQHandler(void)
|
||||||
|
{
|
||||||
|
/* USER CODE BEGIN DMA1_Stream4_IRQn 0 */
|
||||||
|
|
||||||
|
/* USER CODE END DMA1_Stream4_IRQn 0 */
|
||||||
|
HAL_DMA_IRQHandler(&hdma_spi2_tx);
|
||||||
|
/* USER CODE BEGIN DMA1_Stream4_IRQn 1 */
|
||||||
|
|
||||||
|
/* USER CODE END DMA1_Stream4_IRQn 1 */
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function handles EXTI line[9:5] interrupts.
|
* @brief This function handles EXTI line[9:5] interrupts.
|
||||||
*/
|
*/
|
||||||
@@ -218,6 +249,20 @@ void EXTI9_5_IRQHandler(void)
|
|||||||
/* USER CODE END EXTI9_5_IRQn 1 */
|
/* USER CODE END EXTI9_5_IRQn 1 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function handles SPI2 global interrupt.
|
||||||
|
*/
|
||||||
|
void SPI2_IRQHandler(void)
|
||||||
|
{
|
||||||
|
/* USER CODE BEGIN SPI2_IRQn 0 */
|
||||||
|
|
||||||
|
/* USER CODE END SPI2_IRQn 0 */
|
||||||
|
HAL_SPI_IRQHandler(&hspi2);
|
||||||
|
/* USER CODE BEGIN SPI2_IRQn 1 */
|
||||||
|
|
||||||
|
/* USER CODE END SPI2_IRQn 1 */
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function handles USART1 global interrupt.
|
* @brief This function handles USART1 global interrupt.
|
||||||
*/
|
*/
|
||||||
|
|||||||
1268
docs/BSD_Socket_API_使用指南.md
Normal file
1268
docs/BSD_Socket_API_使用指南.md
Normal file
File diff suppressed because it is too large
Load Diff
694
test/ch395f_socket_test.py
Normal file
694
test/ch395f_socket_test.py
Normal file
@@ -0,0 +1,694 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
CH395F BSD Socket API 测试程序
|
||||||
|
用于测试 STM32F4 + CH395F 的网络功能
|
||||||
|
|
||||||
|
使用方法:
|
||||||
|
python ch395f_socket_test.py [模式] [选项]
|
||||||
|
|
||||||
|
模式:
|
||||||
|
tcp_server - 作为 TCP 服务器(测试 CH395F TCP Client)
|
||||||
|
tcp_client - 作为 TCP 客户端(测试 CH395F TCP Server)
|
||||||
|
udp_server - 作为 UDP 服务器(测试 CH395F UDP Client)
|
||||||
|
udp_client - 作为 UDP 客户端(测试 CH395F UDP Server)
|
||||||
|
tcp_echo - TCP 回显服务器(测试双向通信)
|
||||||
|
udp_echo - UDP 回显服务器(测试双向通信)
|
||||||
|
stress - 压力测试(多连接并发测试)
|
||||||
|
|
||||||
|
选项:
|
||||||
|
--ip 目标 IP 地址(默认: 192.168.1.100)
|
||||||
|
--port 端口号(默认: 8080)
|
||||||
|
--count 测试次数(默认: 10)
|
||||||
|
--size 数据包大小(默认: 1024)
|
||||||
|
|
||||||
|
示例:
|
||||||
|
# 测试 CH395F TCP Server
|
||||||
|
python ch395f_socket_test.py tcp_client --ip 192.168.1.100 --port 8080
|
||||||
|
|
||||||
|
# 测试 CH395F TCP Client
|
||||||
|
python ch395f_socket_test.py tcp_server --port 8080
|
||||||
|
|
||||||
|
# 测试 CH395F UDP Client
|
||||||
|
python ch395f_socket_test.py udp_server --port 8888
|
||||||
|
|
||||||
|
# 测试 CH395F UDP Server
|
||||||
|
python ch395f_socket_test.py udp_client --ip 192.168.1.100 --port 8888
|
||||||
|
|
||||||
|
# 压力测试(多连接)
|
||||||
|
python ch395f_socket_test.py stress --ip 192.168.1.100 --port 8080 --count 7
|
||||||
|
"""
|
||||||
|
|
||||||
|
import socket
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import argparse
|
||||||
|
import threading
|
||||||
|
import struct
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
|
class Colors:
|
||||||
|
"""终端颜色"""
|
||||||
|
HEADER = '\033[95m'
|
||||||
|
BLUE = '\033[94m'
|
||||||
|
CYAN = '\033[96m'
|
||||||
|
GREEN = '\033[92m'
|
||||||
|
YELLOW = '\033[93m'
|
||||||
|
RED = '\033[91m'
|
||||||
|
END = '\033[0m'
|
||||||
|
BOLD = '\033[1m'
|
||||||
|
|
||||||
|
|
||||||
|
def log_msg(msg, color=Colors.END):
|
||||||
|
"""带时间戳的日志输出"""
|
||||||
|
timestamp = datetime.now().strftime("%H:%M:%S.%f")[:-3]
|
||||||
|
print(f"{Colors.CYAN}[{timestamp}]{Colors.END} {color}{msg}{Colors.END}")
|
||||||
|
|
||||||
|
|
||||||
|
def log_success(msg):
|
||||||
|
log_msg(f"✓ {msg}", Colors.GREEN)
|
||||||
|
|
||||||
|
|
||||||
|
def log_error(msg):
|
||||||
|
log_msg(f"✗ {msg}", Colors.RED)
|
||||||
|
|
||||||
|
|
||||||
|
def log_info(msg):
|
||||||
|
log_msg(f"ℹ {msg}", Colors.BLUE)
|
||||||
|
|
||||||
|
|
||||||
|
def log_warn(msg):
|
||||||
|
log_msg(f"⚠ {msg}", Colors.YELLOW)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_data(size):
|
||||||
|
"""生成测试数据"""
|
||||||
|
return ''.join(random.choices(string.ascii_letters + string.digits, k=size)).encode()
|
||||||
|
|
||||||
|
|
||||||
|
def verify_data(data, expected_len):
|
||||||
|
"""验证数据"""
|
||||||
|
if len(data) != expected_len:
|
||||||
|
return False, f"长度不匹配: 期望 {expected_len}, 实际 {len(data)}"
|
||||||
|
return True, "OK"
|
||||||
|
|
||||||
|
|
||||||
|
# ==================== TCP 测试函数 ====================
|
||||||
|
|
||||||
|
def tcp_server_test(args):
|
||||||
|
"""TCP 服务器测试(测试 CH395F TCP Client)"""
|
||||||
|
log_info("=" * 60)
|
||||||
|
log_info("TCP 服务器测试 - 测试 CH395F TCP Client 功能")
|
||||||
|
log_info("=" * 60)
|
||||||
|
|
||||||
|
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
server_socket.settimeout(30)
|
||||||
|
|
||||||
|
try:
|
||||||
|
server_socket.bind(('0.0.0.0', args.port))
|
||||||
|
server_socket.listen(1)
|
||||||
|
log_success(f"服务器启动,监听端口 {args.port}")
|
||||||
|
log_info("等待 CH395F TCP Client 连接...")
|
||||||
|
|
||||||
|
client_socket, client_addr = server_socket.accept()
|
||||||
|
log_success(f"连接来自: {client_addr[0]}:{client_addr[1]}")
|
||||||
|
client_socket.settimeout(5)
|
||||||
|
|
||||||
|
# 测试接收数据
|
||||||
|
log_info("-" * 40)
|
||||||
|
log_info("测试 1: 接收数据")
|
||||||
|
for i in range(args.count):
|
||||||
|
try:
|
||||||
|
data = client_socket.recv(args.size)
|
||||||
|
if data:
|
||||||
|
log_success(f"收到数据 ({len(data)} bytes): {data[:50]}...")
|
||||||
|
else:
|
||||||
|
log_error("收到空数据")
|
||||||
|
break
|
||||||
|
except socket.timeout:
|
||||||
|
log_error("接收超时")
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"接收错误: {e}")
|
||||||
|
break
|
||||||
|
|
||||||
|
# 测试发送数据
|
||||||
|
log_info("-" * 40)
|
||||||
|
log_info("测试 2: 发送数据")
|
||||||
|
for i in range(args.count):
|
||||||
|
try:
|
||||||
|
test_data = generate_data(min(100, args.size))
|
||||||
|
client_socket.send(test_data)
|
||||||
|
log_success(f"发送数据 ({len(test_data)} bytes)")
|
||||||
|
time.sleep(0.1)
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"发送错误: {e}")
|
||||||
|
break
|
||||||
|
|
||||||
|
# 测试双向通信
|
||||||
|
log_info("-" * 40)
|
||||||
|
log_info("测试 3: 双向通信")
|
||||||
|
for i in range(min(5, args.count)):
|
||||||
|
try:
|
||||||
|
# 发送
|
||||||
|
test_data = f"PING_{i}".encode()
|
||||||
|
client_socket.send(test_data)
|
||||||
|
log_info(f"发送: {test_data.decode()}")
|
||||||
|
|
||||||
|
# 接收回显
|
||||||
|
data = client_socket.recv(args.size)
|
||||||
|
if data:
|
||||||
|
log_info(f"收到: {data.decode()}")
|
||||||
|
if data == test_data:
|
||||||
|
log_success("回显数据匹配!")
|
||||||
|
else:
|
||||||
|
log_error("回显数据不匹配!")
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"通信错误: {e}")
|
||||||
|
break
|
||||||
|
|
||||||
|
client_socket.close()
|
||||||
|
log_success("测试完成,连接已关闭")
|
||||||
|
|
||||||
|
except socket.timeout:
|
||||||
|
log_error("等待连接超时")
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"服务器错误: {e}")
|
||||||
|
finally:
|
||||||
|
server_socket.close()
|
||||||
|
|
||||||
|
|
||||||
|
def tcp_client_test(args):
|
||||||
|
"""TCP 客户端测试(测试 CH395F TCP Server)"""
|
||||||
|
log_info("=" * 60)
|
||||||
|
log_info("TCP 客户端测试 - 测试 CH395F TCP Server 功能")
|
||||||
|
log_info("=" * 60)
|
||||||
|
|
||||||
|
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
client_socket.settimeout(10)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 连接服务器
|
||||||
|
log_info(f"正在连接 CH395F TCP Server: {args.ip}:{args.port}")
|
||||||
|
client_socket.connect((args.ip, args.port))
|
||||||
|
log_success("连接成功!")
|
||||||
|
|
||||||
|
# 测试发送数据
|
||||||
|
log_info("-" * 40)
|
||||||
|
log_info("测试 1: 发送数据")
|
||||||
|
for i in range(args.count):
|
||||||
|
try:
|
||||||
|
test_data = generate_data(min(100, args.size))
|
||||||
|
client_socket.send(test_data)
|
||||||
|
log_success(f"发送数据 ({len(test_data)} bytes)")
|
||||||
|
log_info(f"发送 hex: {' '.join(f'{b:02X}' for b in test_data[:16])}")
|
||||||
|
|
||||||
|
# 等待回显
|
||||||
|
data = client_socket.recv(args.size)
|
||||||
|
if data:
|
||||||
|
log_info(f"接收 hex: {' '.join(f'{b:02X}' for b in data[:16])}")
|
||||||
|
log_info(f"接收长度: {len(data)}, 期望长度: {len(test_data)}")
|
||||||
|
if data == test_data:
|
||||||
|
log_success("回显数据匹配!")
|
||||||
|
else:
|
||||||
|
log_error("回显数据不匹配!")
|
||||||
|
# 找出第一个不同的字节
|
||||||
|
for j in range(min(len(data), len(test_data))):
|
||||||
|
if data[j] != test_data[j]:
|
||||||
|
log_error(f"首个差异: 位置 {j}, 发送={test_data[j]:02X}, 接收={data[j]:02X}")
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
log_error("收到空数据")
|
||||||
|
break
|
||||||
|
|
||||||
|
time.sleep(0.1)
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"发送/接收错误: {e}")
|
||||||
|
break
|
||||||
|
|
||||||
|
# 测试大数据量
|
||||||
|
log_info("-" * 40)
|
||||||
|
log_info("测试 2: 大数据量传输")
|
||||||
|
try:
|
||||||
|
large_data = generate_data(min(1024, args.size))
|
||||||
|
client_socket.send(large_data)
|
||||||
|
log_success(f"发送大数据 ({len(large_data)} bytes)")
|
||||||
|
|
||||||
|
received = b""
|
||||||
|
while len(received) < len(large_data):
|
||||||
|
chunk = client_socket.recv(min(1024, len(large_data) - len(received)))
|
||||||
|
if not chunk:
|
||||||
|
break
|
||||||
|
received += chunk
|
||||||
|
|
||||||
|
if received == large_data:
|
||||||
|
log_success("大数据传输完整!")
|
||||||
|
else:
|
||||||
|
log_error(f"大数据传输不完整: 发送 {len(large_data)}, 接收 {len(received)}")
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"大数据传输错误: {e}")
|
||||||
|
|
||||||
|
# 测试快速收发
|
||||||
|
log_info("-" * 40)
|
||||||
|
log_info("测试 3: 快速收发")
|
||||||
|
success_count = 0
|
||||||
|
fail_count = 0
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
for i in range(args.count):
|
||||||
|
try:
|
||||||
|
test_data = f"FAST_{i:04d}".encode()
|
||||||
|
client_socket.send(test_data)
|
||||||
|
data = client_socket.recv(100)
|
||||||
|
if data and data == test_data:
|
||||||
|
success_count += 1
|
||||||
|
else:
|
||||||
|
fail_count += 1
|
||||||
|
except Exception as e:
|
||||||
|
fail_count += 1
|
||||||
|
|
||||||
|
elapsed = time.time() - start_time
|
||||||
|
log_info(f"快速收发结果: 成功 {success_count}, 失败 {fail_count}, 耗时 {elapsed:.2f}s")
|
||||||
|
|
||||||
|
client_socket.close()
|
||||||
|
log_success("测试完成,连接已关闭")
|
||||||
|
|
||||||
|
except ConnectionRefusedError:
|
||||||
|
log_error("连接被拒绝 - CH395F TCP Server 未运行")
|
||||||
|
except socket.timeout:
|
||||||
|
log_error("连接超时")
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"客户端错误: {e}")
|
||||||
|
finally:
|
||||||
|
client_socket.close()
|
||||||
|
|
||||||
|
|
||||||
|
# ==================== UDP 测试函数 ====================
|
||||||
|
|
||||||
|
def udp_server_test(args):
|
||||||
|
"""UDP 服务器测试(测试 CH395F UDP Client)"""
|
||||||
|
log_info("=" * 60)
|
||||||
|
log_info("UDP 服务器测试 - 测试 CH395F UDP Client 功能")
|
||||||
|
log_info("=" * 60)
|
||||||
|
|
||||||
|
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
server_socket.settimeout(30)
|
||||||
|
|
||||||
|
try:
|
||||||
|
server_socket.bind(('0.0.0.0', args.port))
|
||||||
|
log_success(f"服务器启动,监听端口 {args.port}")
|
||||||
|
log_info("等待 CH395F UDP Client 数据...")
|
||||||
|
|
||||||
|
# 接收数据
|
||||||
|
for i in range(args.count):
|
||||||
|
try:
|
||||||
|
data, client_addr = server_socket.recvfrom(args.size)
|
||||||
|
log_success(f"收到来自 {client_addr[0]}:{client_addr[1]} ({len(data)} bytes)")
|
||||||
|
log_info(f"数据: {data[:50]}...")
|
||||||
|
|
||||||
|
# 回显数据
|
||||||
|
server_socket.sendto(data, client_addr)
|
||||||
|
log_info(f"回显数据到 {client_addr[0]}:{client_addr[1]}")
|
||||||
|
except socket.timeout:
|
||||||
|
log_warn("接收超时")
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"接收错误: {e}")
|
||||||
|
break
|
||||||
|
|
||||||
|
log_success("测试完成")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"服务器错误: {e}")
|
||||||
|
finally:
|
||||||
|
server_socket.close()
|
||||||
|
|
||||||
|
|
||||||
|
def udp_client_test(args):
|
||||||
|
"""UDP 客户端测试(测试 CH395F UDP Server)"""
|
||||||
|
log_info("=" * 60)
|
||||||
|
log_info("UDP 客户端测试 - 测试 CH395F UDP Server 功能")
|
||||||
|
log_info("=" * 60)
|
||||||
|
|
||||||
|
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
client_socket.settimeout(5)
|
||||||
|
|
||||||
|
try:
|
||||||
|
dest_addr = (args.ip, args.port)
|
||||||
|
|
||||||
|
# 发送数据
|
||||||
|
log_info("-" * 40)
|
||||||
|
log_info("测试 1: 发送 UDP 数据")
|
||||||
|
for i in range(args.count):
|
||||||
|
try:
|
||||||
|
test_data = f"UDP_MSG_{i:04d}".encode()
|
||||||
|
client_socket.sendto(test_data, dest_addr)
|
||||||
|
log_success(f"发送数据到 {args.ip}:{args.port} ({len(test_data)} bytes)")
|
||||||
|
|
||||||
|
# 等待回显
|
||||||
|
data, addr = client_socket.recvfrom(args.size)
|
||||||
|
if data:
|
||||||
|
if data == test_data:
|
||||||
|
log_success(f"回显数据匹配! (from {addr[0]}:{addr[1]})")
|
||||||
|
else:
|
||||||
|
log_error("回显数据不匹配!")
|
||||||
|
else:
|
||||||
|
log_error("收到空数据")
|
||||||
|
break
|
||||||
|
|
||||||
|
time.sleep(0.2)
|
||||||
|
except socket.timeout:
|
||||||
|
log_warn("接收超时")
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"发送/接收错误: {e}")
|
||||||
|
break
|
||||||
|
|
||||||
|
# 测试大数据
|
||||||
|
log_info("-" * 40)
|
||||||
|
log_info("测试 2: 大数据 UDP 传输")
|
||||||
|
try:
|
||||||
|
large_data = generate_data(min(512, args.size))
|
||||||
|
client_socket.sendto(large_data, dest_addr)
|
||||||
|
log_success(f"发送大数据 ({len(large_data)} bytes)")
|
||||||
|
|
||||||
|
data, addr = client_socket.recvfrom(args.size)
|
||||||
|
if data and data == large_data:
|
||||||
|
log_success("大数据传输完整!")
|
||||||
|
else:
|
||||||
|
log_error("大数据传输失败")
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"大数据传输错误: {e}")
|
||||||
|
|
||||||
|
log_success("测试完成")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"客户端错误: {e}")
|
||||||
|
finally:
|
||||||
|
client_socket.close()
|
||||||
|
|
||||||
|
|
||||||
|
# ==================== 回显测试 ====================
|
||||||
|
|
||||||
|
def tcp_echo_server_test(args):
|
||||||
|
"""TCP 回显服务器测试"""
|
||||||
|
log_info("=" * 60)
|
||||||
|
log_info("TCP 回显服务器测试 - 测试双向通信功能")
|
||||||
|
log_info("=" * 60)
|
||||||
|
|
||||||
|
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
server_socket.settimeout(60)
|
||||||
|
|
||||||
|
try:
|
||||||
|
server_socket.bind(('0.0.0.0', args.port))
|
||||||
|
server_socket.listen(1)
|
||||||
|
log_success(f"回显服务器启动,端口 {args.port}")
|
||||||
|
log_info("等待连接...")
|
||||||
|
|
||||||
|
client_socket, client_addr = server_socket.accept()
|
||||||
|
log_success(f"连接来自: {client_addr[0]}:{client_addr[1]}")
|
||||||
|
client_socket.settimeout(5)
|
||||||
|
|
||||||
|
# 循环回显
|
||||||
|
echo_count = 0
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
log_info("开始回显测试 (按 Ctrl+C 停止)...")
|
||||||
|
while echo_count < args.count:
|
||||||
|
try:
|
||||||
|
data = client_socket.recv(args.size)
|
||||||
|
if not data:
|
||||||
|
log_warn("客户端断开连接")
|
||||||
|
break
|
||||||
|
|
||||||
|
echo_count += 1
|
||||||
|
client_socket.send(data)
|
||||||
|
|
||||||
|
if echo_count % 10 == 0:
|
||||||
|
elapsed = time.time() - start_time
|
||||||
|
rate = echo_count / elapsed if elapsed > 0 else 0
|
||||||
|
log_info(f"回显 {echo_count} 次, 速率: {rate:.1f} msg/s")
|
||||||
|
|
||||||
|
except socket.timeout:
|
||||||
|
continue
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"回显错误: {e}")
|
||||||
|
break
|
||||||
|
|
||||||
|
elapsed = time.time() - start_time
|
||||||
|
log_success(f"回显测试完成: {echo_count} 次, 耗时 {elapsed:.2f}s")
|
||||||
|
|
||||||
|
client_socket.close()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"服务器错误: {e}")
|
||||||
|
finally:
|
||||||
|
server_socket.close()
|
||||||
|
|
||||||
|
|
||||||
|
def udp_echo_server_test(args):
|
||||||
|
"""UDP 回显服务器测试"""
|
||||||
|
log_info("=" * 60)
|
||||||
|
log_info("UDP 回显服务器测试 - 测试双向通信功能")
|
||||||
|
log_info("=" * 60)
|
||||||
|
|
||||||
|
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
server_socket.settimeout(60)
|
||||||
|
|
||||||
|
try:
|
||||||
|
server_socket.bind(('0.0.0.0', args.port))
|
||||||
|
log_success(f"UDP 回显服务器启动,端口 {args.port}")
|
||||||
|
log_info("等待数据...")
|
||||||
|
|
||||||
|
echo_count = 0
|
||||||
|
start_time = time.time()
|
||||||
|
clients = set()
|
||||||
|
|
||||||
|
while echo_count < args.count:
|
||||||
|
try:
|
||||||
|
data, client_addr = server_socket.recvfrom(args.size)
|
||||||
|
if not data:
|
||||||
|
continue
|
||||||
|
|
||||||
|
clients.add(client_addr)
|
||||||
|
echo_count += 1
|
||||||
|
|
||||||
|
# 回显数据
|
||||||
|
server_socket.sendto(data, client_addr)
|
||||||
|
|
||||||
|
if echo_count % 10 == 0:
|
||||||
|
elapsed = time.time() - start_time
|
||||||
|
rate = echo_count / elapsed if elapsed > 0 else 0
|
||||||
|
log_info(f"回显 {echo_count} 次, 客户端数: {len(clients)}, 速率: {rate:.1f} msg/s")
|
||||||
|
|
||||||
|
except socket.timeout:
|
||||||
|
continue
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"回显错误: {e}")
|
||||||
|
break
|
||||||
|
|
||||||
|
elapsed = time.time() - start_time
|
||||||
|
log_success(f"回显测试完成: {echo_count} 次, 耗时 {elapsed:.2f}s")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"服务器错误: {e}")
|
||||||
|
finally:
|
||||||
|
server_socket.close()
|
||||||
|
|
||||||
|
|
||||||
|
# ==================== 压力测试 ====================
|
||||||
|
|
||||||
|
def stress_test_thread(client_id, args, results):
|
||||||
|
"""压力测试线程"""
|
||||||
|
thread_name = f"Client-{client_id}"
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
sock.settimeout(10)
|
||||||
|
|
||||||
|
try:
|
||||||
|
sock.connect((args.ip, args.port))
|
||||||
|
log_success(f"[{thread_name}] 连接成功")
|
||||||
|
|
||||||
|
success_count = 0
|
||||||
|
fail_count = 0
|
||||||
|
|
||||||
|
for i in range(args.count):
|
||||||
|
try:
|
||||||
|
# 发送
|
||||||
|
test_data = f"T{client_id:02d}_{i:04d}".encode()
|
||||||
|
sock.send(test_data)
|
||||||
|
|
||||||
|
# 接收
|
||||||
|
data = sock.recv(100)
|
||||||
|
if data and data == test_data:
|
||||||
|
success_count += 1
|
||||||
|
else:
|
||||||
|
fail_count += 1
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
fail_count += 1
|
||||||
|
|
||||||
|
results[client_id] = (success_count, fail_count)
|
||||||
|
log_info(f"[{thread_name}] 完成: 成功 {success_count}, 失败 {fail_count}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"[{thread_name}] 错误: {e}")
|
||||||
|
results[client_id] = (0, args.count)
|
||||||
|
finally:
|
||||||
|
sock.close()
|
||||||
|
|
||||||
|
|
||||||
|
def stress_test(args):
|
||||||
|
"""压力测试(多连接并发)"""
|
||||||
|
log_info("=" * 60)
|
||||||
|
log_info("压力测试 - 多连接并发")
|
||||||
|
log_info("=" * 60)
|
||||||
|
|
||||||
|
num_clients = min(args.count, 7) # CH395F 最多支持 7 个并发连接
|
||||||
|
log_info(f"创建 {num_clients} 个并发连接...")
|
||||||
|
|
||||||
|
results = {}
|
||||||
|
threads = []
|
||||||
|
|
||||||
|
# 创建并启动线程
|
||||||
|
for i in range(num_clients):
|
||||||
|
thread = threading.Thread(
|
||||||
|
target=stress_test_thread,
|
||||||
|
args=(i, args, results)
|
||||||
|
)
|
||||||
|
threads.append(thread)
|
||||||
|
thread.start()
|
||||||
|
time.sleep(0.1) # 错开连接时间
|
||||||
|
|
||||||
|
# 等待所有线程完成
|
||||||
|
for thread in threads:
|
||||||
|
thread.join()
|
||||||
|
|
||||||
|
# 汇总结果
|
||||||
|
total_success = sum(r[0] for r in results.values())
|
||||||
|
total_fail = sum(r[1] for r in results.values())
|
||||||
|
|
||||||
|
log_info("-" * 40)
|
||||||
|
log_info("压力测试结果:")
|
||||||
|
log_info(f" 并发连接数: {num_clients}")
|
||||||
|
log_info(f" 每连接测试次数: {args.count}")
|
||||||
|
log_info(f" 总成功: {total_success}")
|
||||||
|
log_info(f" 总失败: {total_fail}")
|
||||||
|
log_info(f" 成功率: {total_success/(total_success+total_fail)*100:.1f}%")
|
||||||
|
|
||||||
|
if total_fail == 0:
|
||||||
|
log_success("压力测试通过!")
|
||||||
|
else:
|
||||||
|
log_error("压力测试有失败!")
|
||||||
|
|
||||||
|
|
||||||
|
# ==================== 数据包大小测试 ====================
|
||||||
|
|
||||||
|
def packet_size_test(args):
|
||||||
|
"""不同数据包大小测试"""
|
||||||
|
log_info("=" * 60)
|
||||||
|
log_info("数据包大小测试")
|
||||||
|
log_info("=" * 60)
|
||||||
|
|
||||||
|
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
client_socket.settimeout(5)
|
||||||
|
|
||||||
|
try:
|
||||||
|
client_socket.connect((args.ip, args.port))
|
||||||
|
log_success("连接成功")
|
||||||
|
|
||||||
|
# 测试不同的数据包大小
|
||||||
|
test_sizes = [1, 10, 100, 512, 1024, 2048, 4096]
|
||||||
|
|
||||||
|
for size in test_sizes:
|
||||||
|
try:
|
||||||
|
test_data = generate_data(size)
|
||||||
|
start_time = time.time()
|
||||||
|
client_socket.send(test_data)
|
||||||
|
|
||||||
|
received = b""
|
||||||
|
while len(received) < size:
|
||||||
|
chunk = client_socket.recv(size - len(received))
|
||||||
|
if not chunk:
|
||||||
|
break
|
||||||
|
received += chunk
|
||||||
|
|
||||||
|
elapsed = time.time() - start_time
|
||||||
|
|
||||||
|
if received == test_data:
|
||||||
|
rate = size / elapsed / 1024 if elapsed > 0 else 0
|
||||||
|
log_success(f"大小 {size:5d} bytes: 成功, 速率 {rate:.1f} KB/s")
|
||||||
|
else:
|
||||||
|
log_error(f"大小 {size:5d} bytes: 数据不匹配")
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"大小 {size:5d} bytes: 错误 - {e}")
|
||||||
|
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"测试错误: {e}")
|
||||||
|
finally:
|
||||||
|
client_socket.close()
|
||||||
|
|
||||||
|
|
||||||
|
# ==================== 主程序 ====================
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description='CH395F BSD Socket API 测试程序',
|
||||||
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
|
epilog="""
|
||||||
|
示例:
|
||||||
|
%(prog)s tcp_client --ip 192.168.1.100 --port 8080
|
||||||
|
%(prog)s tcp_server --port 8080
|
||||||
|
%(prog)s stress --ip 192.168.1.100 --port 8080 --count 5
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument('mode', choices=['tcp_server', 'tcp_client', 'udp_server', 'udp_client',
|
||||||
|
'tcp_echo', 'udp_echo', 'stress', 'packet_size'],
|
||||||
|
help='测试模式')
|
||||||
|
parser.add_argument('--ip', default='192.168.1.100', help='目标 IP 地址')
|
||||||
|
parser.add_argument('--port', type=int, default=8080, help='端口号')
|
||||||
|
parser.add_argument('--count', type=int, default=10, help='测试次数')
|
||||||
|
parser.add_argument('--size', type=int, default=1024, help='数据包大小')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
print()
|
||||||
|
print(Colors.BOLD + "=" * 60 + Colors.END)
|
||||||
|
print(Colors.BOLD + " CH395F BSD Socket API 测试程序" + Colors.END)
|
||||||
|
print(Colors.BOLD + "=" * 60 + Colors.END)
|
||||||
|
print()
|
||||||
|
|
||||||
|
try:
|
||||||
|
if args.mode == 'tcp_server':
|
||||||
|
tcp_server_test(args)
|
||||||
|
elif args.mode == 'tcp_client':
|
||||||
|
tcp_client_test(args)
|
||||||
|
elif args.mode == 'udp_server':
|
||||||
|
udp_server_test(args)
|
||||||
|
elif args.mode == 'udp_client':
|
||||||
|
udp_client_test(args)
|
||||||
|
elif args.mode == 'tcp_echo':
|
||||||
|
tcp_echo_server_test(args)
|
||||||
|
elif args.mode == 'udp_echo':
|
||||||
|
udp_echo_server_test(args)
|
||||||
|
elif args.mode == 'stress':
|
||||||
|
stress_test(args)
|
||||||
|
elif args.mode == 'packet_size':
|
||||||
|
packet_size_test(args)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
log_warn("用户中断")
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"未预期的错误: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user