Compare commits
4 Commits
fe107ea9af
...
9ed4c22022
| Author | SHA1 | Date | |
|---|---|---|---|
| 9ed4c22022 | |||
| 4eb728583b | |||
| 1669cd216d | |||
| f72d08328f |
10
.mxproject
10
.mxproject
File diff suppressed because one or more lines are too long
117
AGENTS.md
117
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,9 +44,13 @@ 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 并行接口驱动 |
|
||||||
|
| `Src/freertos.c` | FreeRTOS task 创建和任务函数(CubeMX 生成 + 手写) |
|
||||||
|
| `Inc/FreeRTOSConfig.h` | FreeRTOS 内核配置 |
|
||||||
| `MDK-ARM/STM32F407-Demo.uvprojx` | Keil MDK 项目文件 |
|
| `MDK-ARM/STM32F407-Demo.uvprojx` | Keil MDK 项目文件 |
|
||||||
| `STM32F407-Demo.ioc` | STM32CubeMX 项目源文件 |
|
| `STM32F407-Demo.ioc` | STM32CubeMX 项目源文件 |
|
||||||
|
|
||||||
@@ -52,6 +63,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)
|
||||||
@@ -64,7 +98,10 @@ STM32F4-Base/
|
|||||||
## 启动顺序
|
## 启动顺序
|
||||||
|
|
||||||
```
|
```
|
||||||
HAL_Init() → SystemClock_Config() → MX_GPIO_Init() → MX_USART1_UART_Init() → MX_SPI2_Init() → MX_SPI1_Init() → gd5f2gq5ue_init() → fdb_kvdb_init()
|
HAL_Init() → SystemClock_Config() → MX_GPIO_Init() → MX_USART1_UART_Init() → MX_SPI2_Init() → MX_SPI1_Init()
|
||||||
|
→ gd5f2gq5ue_init() → fdb_kvdb_init() → [USER CODE: net_init + TCP listen + 其他外设初始化]
|
||||||
|
→ osKernelInitialize() → MX_FREERTOS_Init() → osKernelStart() ← FreeRTOS 调度器启动
|
||||||
|
→ [FreeRTOS tasks: defaultTask, netTask 运行]
|
||||||
```
|
```
|
||||||
|
|
||||||
## 代码规范
|
## 代码规范
|
||||||
@@ -88,14 +125,30 @@ HAL_Init() → SystemClock_Config() → MX_GPIO_Init() → MX_USART1_UART_Init()
|
|||||||
- FlashDB 使用 FAL 模式,`fdb_cfg.h` 中定义 `FDB_USING_FAL_MODE`,`fal_cfg.h` 中定义分区表
|
- FlashDB 使用 FAL 模式,`fdb_cfg.h` 中定义 `FDB_USING_FAL_MODE`,`fal_cfg.h` 中定义分区表
|
||||||
- FlashDB 详细使用说明见 `FlashDB使用说明.md`
|
- FlashDB 详细使用说明见 `FlashDB使用说明.md`
|
||||||
- `sd2506.c/h` 为纯手工代码,不受 CubeMX 保护
|
- `sd2506.c/h` 为纯手工代码,不受 CubeMX 保护
|
||||||
|
- FreeRTOS Kernel V10.3.1 via CMSIS-RTOS V2 接口,HAL 时基使用 TIM7(非 SysTick,避免与 FreeRTOS 冲突)
|
||||||
|
- NVIC 优先级分组 4 位,外设中断优先级全部 ≥ `configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY`(5),确保 ISR 可调 FreeRTOS API
|
||||||
|
- 网络处理在 `netTask` 中运行,`net_poll()` 每 10ms 调用一次,TCP echo 在 netTask 中完成
|
||||||
|
- `freeertos.c` 中 `USER CODE` 区域可添加自定义 task、mutex、semaphore、queue
|
||||||
|
|
||||||
## CH395F 驱动关键点
|
## CH395F 驱动关键点
|
||||||
|
|
||||||
- 初始化必须按手册9.2.1节顺序:`SET_MAC` → `SET_IP/GWIP/MASK` → `INIT_CH395` → `SET_PHY`
|
驱动初始化顺序、SPI/DMA 通信、TCP/UDP 参数配置、Socket 缓冲区分配等完整关键点见 `docs/CH395F_Trap_Records.md` → 附:CH395F 驱动关键点。
|
||||||
- **IP/网关/掩码必须在 `INIT_CH395` 之前设置**,INIT 会读取并锁定当前寄存器值到协议栈,之后再设 IP 无效
|
|
||||||
- **`SET_PHY` 必须在 `INIT_CH395` 之后**,它会复位 MAC/PHY 建立物理链路,不影响已锁定的协议栈参数
|
## 测试说明
|
||||||
- **`CMD_PING_ENABLE` 不需要显式调用**,INIT 后默认可用
|
|
||||||
- 每次 SPI 事务需调用 `ch395f_spi_begin()` / `ch395f_spi_end()` 包裹
|
- **测试代码文件**:`Drivers/BSP/CH395F/ch395f_test.h` / `ch395f_test.c`
|
||||||
|
- **PC 端测试脚本**:`test/ch395f_socket_test.py`,支持 Python 3.7+
|
||||||
|
- **调用入口**:`Src/main.c` 的 `USER CODE BEGIN 2` 区域
|
||||||
|
- **Phase 1**(9 项寄存器测试):✅ 通过
|
||||||
|
- **Phase 2**(TCP Client 收发 + 关闭重连 ×3 轮):✅ 通过
|
||||||
|
- **Phase 3**(UDP Server Echo + PING + 大包):✅ 通过
|
||||||
|
- **Phase 4**(NET 层 TCP Echo):✅ 通过(netTask 中永久运行)
|
||||||
|
- **Phase 5**(NET 层 UDP Echo):✅ 通过
|
||||||
|
- **Phase 6**(DHCP 自动获取 IP):✅ 通过(MCU 广播宣告 + PC 监听发现)
|
||||||
|
- **Phase 7**(Select/Poll I/O 多路复用):✅ 通过
|
||||||
|
- **Phase 8**(多客户端 7 并发):✅ 通过,成功率 100%
|
||||||
|
- **测试拓扑**:PC (192.168.1.2) ↔ 交换机 ↔ CH395F (192.168.1.100)
|
||||||
|
- **详细使用说明**:见 `docs/CH395F_Test_Guide.md`
|
||||||
|
|
||||||
## GD5F2GQ5UE 驱动关键点
|
## GD5F2GQ5UE 驱动关键点
|
||||||
|
|
||||||
@@ -124,10 +177,54 @@ 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 网络层关键点
|
||||||
|
|
||||||
### CH395F 与 RTL8305NBI 自动协商不兼容
|
- **文件结构**:`Drivers/BSP/NET/` 下包含 net_config.h、net_types.h、net_socket.h/c、net_select.h/c
|
||||||
|
- **使用前必须调用** `net_init(ip, mask, gateway)` 初始化网络子系统
|
||||||
|
- **`net_poll()` 在 FreeRTOS netTask 中定期调用**(10ms 周期),轮询所有 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 1~7**(必须!必须在监听 Socket 之前配置,CH395F 在 `TCP_LISTEN` 时刻扫描可用 Socket):
|
||||||
|
- `SET_SEND_BUF` → `SET_RECV_BUF` → `SET_SOUR_PORT(与监听端口相同)` → `SET_PROTO_TCP`
|
||||||
|
- 数据 Socket 不调用 `OPEN_SOCKET`,由 CH395F 在连接到达时自动打开
|
||||||
|
4. **再配置监听 Socket 0**:
|
||||||
|
- `SET_PROTO_TCP → SET_SOUR_PORT → OPEN → TCP_LISTEN`
|
||||||
|
- 如果不按此顺序,Socket 4~7 不可用,最多只接受 3 个并发连接
|
||||||
|
- **TCP Server 单连接模式**:Socket 先 `OPEN` → `SET_PROTO_TCP` → `SET_SOUR_PORT` → `OPEN` → `TCP_LISTEN`;收到 `SINT_STAT_CONNECT` 后 Socket 自动切换为数据通道;`DISCONNECT`/`TIMEOUT` 后需重新 `OPEN` → `TCP_LISTEN`
|
||||||
|
|
||||||
CH395F 与 RTL8305NBI-CG 直连(经网络变压器)时,自动协商始终失败(返回 `PHY_DISCONN`),但强制 100M 全双工工作正常。强制 10M 全双工同样失败。
|
## 测试状态
|
||||||
|
|
||||||
**解决方案:** 初始化协议栈后调用 `ch395f_set_phy(CH395F_PHY_100M_FULL)` 跳过自动协商。
|
| Phase | 描述 | 状态 | 备注 |
|
||||||
|
|-------|------|------|------|
|
||||||
|
| 1 | 寄存器测试 | ✅ 19/19 | |
|
||||||
|
| 2 | TCP Client | ✅ 3/3 | |
|
||||||
|
| 3 | UDP Server | ✅ 通过 | |
|
||||||
|
| 4 | NET TCP Echo | ✅ 通过 | netTask 中永久运行 |
|
||||||
|
| 5 | NET UDP Echo | ✅ 通过 | |
|
||||||
|
| 6 | DHCP | ✅ 通过 | 支持广播宣告 + DHCP Server 两种模式 |
|
||||||
|
| 7 | Select/Poll | ✅ 通过 | |
|
||||||
|
| 8 | 多客户端 7 并发 | ✅ 70/70 100% | 修复顺序后通过 |
|
||||||
|
|
||||||
|
## 陷阱记录
|
||||||
|
|
||||||
|
详细陷阱记录(含根因分析、解决方案、发现时间)见 `docs/CH395F_Trap_Records.md`。
|
||||||
|
|
||||||
|
当前已记录陷阱:
|
||||||
|
- **Trap 01** Socket 4~7 自动分配不到(初始化顺序)
|
||||||
|
- **Trap 02** 数据 Socket 缓冲区重叠
|
||||||
|
- **Trap 03** DHCP 包 xid 偏移错误
|
||||||
|
- **Trap 04** UDP 发送未等待 SENDBUF_FREE
|
||||||
|
- **Trap 05** CH395F 与 RTL8305NBI 自动协商不兼容
|
||||||
|
- **Trap 06** TCP KeepAlive 参数非 500ms 倍数
|
||||||
|
- **Trap 07** TCP 关闭误用 disconnect 导致 FIN_WAIT_2
|
||||||
|
- **Trap 08** RECV 中断电平触发无限循环
|
||||||
|
|||||||
@@ -7,12 +7,21 @@
|
|||||||
* 创建日期: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>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 调试输出配置
|
||||||
|
*/
|
||||||
|
#define DBG_TAG "[CH395]"
|
||||||
|
#include "dbg_log.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 私有宏定义区
|
* 私有宏定义区
|
||||||
@@ -21,12 +30,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 +55,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 +75,89 @@ 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)
|
||||||
|
{
|
||||||
|
DBG_ERROR("HAL_SPI_TransmitReceive_DMA FAIL: %d, SPI_State=%d, SPI_Error=0x%lX, DMA_State=%d",
|
||||||
|
(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)
|
||||||
|
{
|
||||||
|
DBG_ERROR("TIMEOUT after 1s, len=%d, loop=%lu, SPI_State=%d, SPI_Error=0x%lX",
|
||||||
|
(int)len, loop_cnt,
|
||||||
|
(int)hspi2.State,
|
||||||
|
hspi2.ErrorCode);
|
||||||
|
DBG_ERROR(" DMA_RX: State=%d, Dir=%lu, CNT=%lu",
|
||||||
|
(int)hspi2.hdmarx->State,
|
||||||
|
hspi2.hdmarx->Init.Direction,
|
||||||
|
__HAL_DMA_GET_COUNTER(hspi2.hdmarx));
|
||||||
|
DBG_ERROR(" DMA_TX: State=%d, Dir=%lu, CNT=%lu",
|
||||||
|
(int)hspi2.hdmatx->State,
|
||||||
|
hspi2.hdmatx->Init.Direction,
|
||||||
|
__HAL_DMA_GET_COUNTER(hspi2.hdmatx));
|
||||||
|
DBG_ERROR(" SPI2_CR1=0x%lX, CR2=0x%lX, SR=0x%lX",
|
||||||
|
SPI2->CR1, SPI2->CR2, SPI2->SR);
|
||||||
|
/* 强制复位 SPI2 DMA 状态,避免死锁 */
|
||||||
|
HAL_SPI_Abort(&hspi2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 检查传输是否成功:SPI 错误码必须为 0 */
|
||||||
|
if (hspi2.ErrorCode != 0U)
|
||||||
|
{
|
||||||
|
DBG_INFO("SPI DMA done with errors: ErrorCode=0x%lX, SPI_State=%d",
|
||||||
|
hspi2.ErrorCode, (int)hspi2.State);
|
||||||
|
__HAL_SPI_CLEAR_OVRFLAG(&hspi2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能: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 +268,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 +608,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 +1073,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 +1169,43 @@ 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);
|
||||||
|
|
||||||
|
/* 数据同步屏障:确保 memcpy 写入在 DMA 读取前对总线可见 */
|
||||||
|
__DSB();
|
||||||
|
|
||||||
|
/* 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 +1213,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,9 +1293,27 @@ 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 - 7
|
||||||
* 返回值:Socket 中断状态字节 uint8_t
|
* 返回值:Socket 中断状态字节 uint8_t
|
||||||
* 限定条件:芯片已初始化
|
* 限定条件:芯片已初始化
|
||||||
*/
|
*/
|
||||||
@@ -937,3 +1338,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
|
||||||
|
|||||||
664
Drivers/BSP/CH395F/ch395f_test.c
Normal file
664
Drivers/BSP/CH395F/ch395f_test.c
Normal file
@@ -0,0 +1,664 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:CH395F Driver Test Suite
|
||||||
|
* 模块功能:CH395F 驱动各功能模块的测试入口,分阶段组织测试用例
|
||||||
|
* 适用平台:STM32F4 系列(CH395F 以太网芯片)
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-19
|
||||||
|
* 修改记录:
|
||||||
|
* 2026-07-19 Phase 1/2/3 implemented
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 头文件包含区 */
|
||||||
|
#include "ch395f_test.h"
|
||||||
|
#include "ch395f.h"
|
||||||
|
#include "net_socket.h"
|
||||||
|
#define DBG_TAG "[CH395T]"
|
||||||
|
#include "dbg_log.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
test_stats_t g_test_stats;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Phase 2 配置默认值
|
||||||
|
*/
|
||||||
|
#ifndef PHASE2_REMOTE_IP
|
||||||
|
#define PHASE2_REMOTE_IP "192.168.1.2"
|
||||||
|
#endif
|
||||||
|
#ifndef PHASE2_REMOTE_PORT
|
||||||
|
#define PHASE2_REMOTE_PORT 8081
|
||||||
|
#endif
|
||||||
|
#ifndef PHASE2_LOCAL_PORT
|
||||||
|
#define PHASE2_LOCAL_PORT 50000
|
||||||
|
#endif
|
||||||
|
#ifndef PHASE2_LOOP_COUNT
|
||||||
|
#define PHASE2_LOOP_COUNT 3
|
||||||
|
#endif
|
||||||
|
#ifndef PHASE2_TIMEOUT_MS
|
||||||
|
#define PHASE2_TIMEOUT_MS 10000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Phase 3 配置默认值
|
||||||
|
*/
|
||||||
|
#ifndef PHASE3_REMOTE_IP
|
||||||
|
#define PHASE3_REMOTE_IP "192.168.1.2"
|
||||||
|
#endif
|
||||||
|
#ifndef PHASE3_REMOTE_PORT
|
||||||
|
#define PHASE3_REMOTE_PORT 8082
|
||||||
|
#endif
|
||||||
|
#ifndef PHASE3_LOCAL_PORT
|
||||||
|
#define PHASE3_LOCAL_PORT 60000
|
||||||
|
#endif
|
||||||
|
#ifndef PHASE3_ECHO_COUNT
|
||||||
|
#define PHASE3_ECHO_COUNT 30
|
||||||
|
#endif
|
||||||
|
#ifndef PHASE3_TIMEOUT_MS
|
||||||
|
#define PHASE3_TIMEOUT_MS 30000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 恢复 TCP Server 多连接模式的数据 Socket 配置
|
||||||
|
*/
|
||||||
|
static void restore_data_sockets(uint16_t port)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = NET_TCP_SERVER_DATA_SOCK_START; i < NET_MAX_SOCKETS; i++)
|
||||||
|
{
|
||||||
|
ch395f_set_proto_type((uint8_t)i, CH395F_PROTO_TYPE_TCP);
|
||||||
|
ch395f_set_sour_port((uint8_t)i, port);
|
||||||
|
}
|
||||||
|
DBG_INFO("data socks restored (port %d)", port);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================ Phase 1 ============================
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ch395f_phase1_tests(void)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
int ver;
|
||||||
|
|
||||||
|
DBG_INFO("=== CH395F Phase 1 Tests ===");
|
||||||
|
|
||||||
|
/* Test 1: GET_VERSION */
|
||||||
|
ver = ch395f_get_version();
|
||||||
|
TEST_CHECK(ver > 0, "GET_VERSION: 0x%02X (ver=%d)", ver, ver & 0x3F);
|
||||||
|
|
||||||
|
/* Test 2: GET_CMD_STATUS */
|
||||||
|
uint8_t cmd_st = ch395f_get_cmd_status();
|
||||||
|
TEST_CHECK(cmd_st == CH395F_ERR_SUCCESS,
|
||||||
|
"GET_CMD_STATUS: 0x%02X (%s)", cmd_st,
|
||||||
|
cmd_st == CH395F_ERR_SUCCESS ? "SUCCESS" :
|
||||||
|
cmd_st == CH395F_ERR_BUSY ? "BUSY" : "OTHER");
|
||||||
|
|
||||||
|
/* Test 3: GET_IP_INF */
|
||||||
|
uint8_t ip_info[20];
|
||||||
|
ch395f_get_ip_inf(ip_info);
|
||||||
|
DBG_INFO("GET_IP_INF:");
|
||||||
|
DBG_INFO(" IP: %d.%d.%d.%d", ip_info[0], ip_info[1], ip_info[2], ip_info[3]);
|
||||||
|
DBG_INFO(" GW: %d.%d.%d.%d", ip_info[4], ip_info[5], ip_info[6], ip_info[7]);
|
||||||
|
DBG_INFO(" MASK: %d.%d.%d.%d", ip_info[8], ip_info[9], ip_info[10], ip_info[11]);
|
||||||
|
DBG_INFO(" DNS1: %d.%d.%d.%d", ip_info[12], ip_info[13], ip_info[14], ip_info[15]);
|
||||||
|
DBG_INFO(" DNS2: %d.%d.%d.%d", ip_info[16], ip_info[17], ip_info[18], ip_info[19]);
|
||||||
|
TEST_CHECK(ip_info[0]==192 && ip_info[1]==168 && ip_info[2]==1 && ip_info[3]==100,
|
||||||
|
"IP match");
|
||||||
|
TEST_CHECK(ip_info[4]==192 && ip_info[5]==168 && ip_info[6]==1 && ip_info[7]==1,
|
||||||
|
"GW match");
|
||||||
|
TEST_CHECK(ip_info[8]==255 && ip_info[9]==255 && ip_info[10]==255 && ip_info[11]==0,
|
||||||
|
"MASK match");
|
||||||
|
|
||||||
|
/* Test 4: GINT_STATUS_ALL (2-byte version) */
|
||||||
|
uint16_t gint_all = ch395f_get_glob_int_status_all();
|
||||||
|
TEST_CHECK((gint_all & 0xFF) == 0x04 || (gint_all & 0xFF) == 0x00,
|
||||||
|
"GINT_STATUS_ALL: 0x%04X (lo=0x%02X hi=0x%02X)",
|
||||||
|
gint_all, gint_all & 0xFF, (gint_all >> 8) & 0xFF);
|
||||||
|
|
||||||
|
/* Test 5: GINT_STATUS (1-byte version) — read-clear check */
|
||||||
|
uint8_t gint_1b = ch395f_get_glob_int_status();
|
||||||
|
TEST_CHECK(gint_1b == 0x00,
|
||||||
|
"GINT_STATUS_1byte: 0x%02X (expect 0x00 after read-clear)", gint_1b);
|
||||||
|
|
||||||
|
/* Test 6: SOCK_STATUS(0) */
|
||||||
|
{
|
||||||
|
uint8_t st[2];
|
||||||
|
ch395f_get_socket_status(0, st);
|
||||||
|
TEST_CHECK(st[0] == 0x05 && st[1] == 0x01,
|
||||||
|
"SOCK_STATUS(0): sock=0x%02X(LISTEN), tcp=0x%02X(LISTEN)", st[0], st[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test 7: SET_ARP */
|
||||||
|
ch395f_set_arp(10, 5);
|
||||||
|
TEST_CHECK(1, "SET_ARP(period=10*100ms, cnt=5): OK");
|
||||||
|
|
||||||
|
/* Test 8: SET_TTL */
|
||||||
|
ch395f_set_ttl(0, 64);
|
||||||
|
TEST_CHECK(1, "SET_TTL(sock=0, ttl=64): OK");
|
||||||
|
|
||||||
|
/* Test 9: CLEAR_RECV_BUF + SOCK_INT poll */
|
||||||
|
ch395f_clear_recv_buf(0);
|
||||||
|
TEST_CHECK(1, "CLEAR_RECV_BUF(sock=0): OK");
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
uint8_t si = ch395f_get_sock_int_status(i);
|
||||||
|
TEST_CHECK(si == 0x00, "SOCK_INT(%d): 0x%02X", i, si);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_REPORT("Phase 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================ Phase 2 ============================
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ch395f_phase2_tests(void)
|
||||||
|
{
|
||||||
|
uint8_t sock;
|
||||||
|
uint8_t sock_int;
|
||||||
|
uint8_t rx_buf[300];
|
||||||
|
int i;
|
||||||
|
uint32_t tick;
|
||||||
|
uint16_t int_st;
|
||||||
|
int iter_pass;
|
||||||
|
|
||||||
|
DBG_INFO("=== CH395F Phase 2 Tests (TCP Client - Direct Driver) ===");
|
||||||
|
|
||||||
|
/* 解析目标 IP */
|
||||||
|
uint8_t ip_arr[4];
|
||||||
|
{
|
||||||
|
uint32_t a[4];
|
||||||
|
sscanf(PHASE2_REMOTE_IP, "%lu.%lu.%lu.%lu", &a[0], &a[1], &a[2], &a[3]);
|
||||||
|
ip_arr[0] = (uint8_t)a[0];
|
||||||
|
ip_arr[1] = (uint8_t)a[1];
|
||||||
|
ip_arr[2] = (uint8_t)a[2];
|
||||||
|
ip_arr[3] = (uint8_t)a[3];
|
||||||
|
}
|
||||||
|
DBG_INFO("Target: %s:%d", PHASE2_REMOTE_IP, PHASE2_REMOTE_PORT);
|
||||||
|
|
||||||
|
sock = (uint8_t)(NET_MAX_SOCKETS - 1);
|
||||||
|
|
||||||
|
/* 一次性配置 */
|
||||||
|
ch395f_set_proto_type(sock, CH395F_PROTO_TYPE_TCP);
|
||||||
|
ch395f_set_send_buf(sock, 28, 2);
|
||||||
|
ch395f_set_recv_buf(sock, 30, 2);
|
||||||
|
ch395f_set_des_ip(sock, ip_arr);
|
||||||
|
ch395f_set_des_port(sock, PHASE2_REMOTE_PORT);
|
||||||
|
|
||||||
|
for (i = 0; i < PHASE2_LOOP_COUNT; i++)
|
||||||
|
{
|
||||||
|
DBG_INFO("--- Iteration %d/%d ---", i + 1, PHASE2_LOOP_COUNT);
|
||||||
|
iter_pass = 1;
|
||||||
|
|
||||||
|
ch395f_set_sour_port(sock, PHASE2_LOCAL_PORT + i);
|
||||||
|
|
||||||
|
if (ch395f_open_socket(sock) != CH395F_ERR_SUCCESS) { TEST_CHECK(0, "open socket"); iter_pass = 0; goto phase2_iter_done; }
|
||||||
|
if (ch395f_tcp_connect(sock) != CH395F_ERR_SUCCESS) { TEST_CHECK(0, "tcp connect"); iter_pass = 0; ch395f_close_socket(sock); goto phase2_iter_done; }
|
||||||
|
|
||||||
|
/* 等待 CONNECT */
|
||||||
|
tick = HAL_GetTick();
|
||||||
|
while (HAL_GetTick() - tick < PHASE2_TIMEOUT_MS)
|
||||||
|
{
|
||||||
|
int_st = ch395f_get_glob_int_status_all();
|
||||||
|
if (int_st & (1U << (sock + 4)))
|
||||||
|
{
|
||||||
|
sock_int = ch395f_get_sock_int_status(sock);
|
||||||
|
if (sock_int & CH395F_SINT_STAT_CONNECT) break;
|
||||||
|
}
|
||||||
|
HAL_Delay(10);
|
||||||
|
}
|
||||||
|
if (HAL_GetTick() - tick >= PHASE2_TIMEOUT_MS) { TEST_CHECK(0, "connect timeout"); iter_pass = 0; ch395f_close_socket(sock); goto phase2_iter_done; }
|
||||||
|
|
||||||
|
HAL_Delay(100);
|
||||||
|
|
||||||
|
/* 发送测试数据 */
|
||||||
|
{
|
||||||
|
uint8_t test_buf[64];
|
||||||
|
const char *msg = "HelloFromCH395F_TCP_Client! This is a 64-byte test message.";
|
||||||
|
int p, mlen = (int)strlen(msg);
|
||||||
|
memcpy(test_buf, msg, mlen);
|
||||||
|
for (p = mlen; p < 64; p++) test_buf[p] = (uint8_t)('0' + (p - mlen) % 10);
|
||||||
|
ch395f_write_send_buf(sock, test_buf, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Echo 循环:收数据 → 回发 */
|
||||||
|
{
|
||||||
|
int got_echo = 0;
|
||||||
|
tick = HAL_GetTick();
|
||||||
|
while (HAL_GetTick() - tick < 10000)
|
||||||
|
{
|
||||||
|
uint16_t rlen = ch395f_get_recv_len(sock);
|
||||||
|
if (rlen > 0)
|
||||||
|
{
|
||||||
|
uint16_t read_len = (rlen > sizeof(rx_buf)) ? (uint16_t)sizeof(rx_buf) : rlen;
|
||||||
|
memset(rx_buf, 0, sizeof(rx_buf));
|
||||||
|
ch395f_read_recv_buf(sock, rx_buf, read_len);
|
||||||
|
DBG_INFO("recv: %d bytes [%.30s]", read_len, (char *)rx_buf);
|
||||||
|
ch395f_write_send_buf(sock, rx_buf, read_len);
|
||||||
|
got_echo = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int_st = ch395f_get_glob_int_status_all();
|
||||||
|
if (int_st & (1U << (sock + 4)))
|
||||||
|
{
|
||||||
|
sock_int = ch395f_get_sock_int_status(sock);
|
||||||
|
if (sock_int & CH395F_SINT_STAT_DISCONNECT) { DBG_INFO("DISCONNECT"); break; }
|
||||||
|
if (sock_int & CH395F_SINT_STAT_SOCK_TIMEOUT) { DBG_INFO("SOCK_TIMEOUT"); break; }
|
||||||
|
}
|
||||||
|
HAL_Delay(50);
|
||||||
|
}
|
||||||
|
if (!got_echo) { TEST_CHECK(0, "echo recv (iter %d)", i + 1); iter_pass = 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
phase2_iter_done:
|
||||||
|
if (iter_pass) TEST_CHECK(1, "Iteration %d PASS", i + 1);
|
||||||
|
|
||||||
|
/* 关闭 socket */
|
||||||
|
ch395f_close_socket(sock);
|
||||||
|
{
|
||||||
|
uint8_t st[2];
|
||||||
|
uint32_t wait = HAL_GetTick();
|
||||||
|
while (HAL_GetTick() - wait < 5000)
|
||||||
|
{
|
||||||
|
ch395f_get_socket_status(sock, st);
|
||||||
|
if (st[0] == CH395F_SOCKET_CLOSED) break;
|
||||||
|
HAL_Delay(50);
|
||||||
|
}
|
||||||
|
DBG_INFO("closed: sock=0x%02X tcp=0x%02X", st[0], st[1]);
|
||||||
|
}
|
||||||
|
HAL_Delay(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
restore_data_sockets(8080);
|
||||||
|
TEST_REPORT("Phase 2");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================ Phase 3 ============================
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ch395f_phase3_tests(void)
|
||||||
|
{
|
||||||
|
uint8_t sock;
|
||||||
|
uint8_t rx_buf[300];
|
||||||
|
uint32_t tick;
|
||||||
|
int i;
|
||||||
|
int echo_ok;
|
||||||
|
|
||||||
|
DBG_INFO("=== CH395F Phase 3 Tests (UDP) ===");
|
||||||
|
|
||||||
|
sock = (uint8_t)(NET_MAX_SOCKETS - 1);
|
||||||
|
|
||||||
|
/* UDP Server 模式:DesIP=0xFFFFFFFF → 接受任意来源 */
|
||||||
|
ch395f_set_proto_type(sock, CH395F_PROTO_TYPE_UDP);
|
||||||
|
ch395f_set_send_buf(sock, 28, 2);
|
||||||
|
ch395f_set_recv_buf(sock, 30, 2);
|
||||||
|
ch395f_set_sour_port(sock, PHASE3_LOCAL_PORT);
|
||||||
|
{
|
||||||
|
uint8_t zero_ip[4] = {0xFF, 0xFF, 0xFF, 0xFF};
|
||||||
|
ch395f_set_des_ip(sock, zero_ip);
|
||||||
|
}
|
||||||
|
ch395f_set_des_port(sock, 0);
|
||||||
|
|
||||||
|
TEST_CHECK(ch395f_open_socket(sock) == CH395F_ERR_SUCCESS,
|
||||||
|
"UDP socket %d opened (port=%d)", sock, PHASE3_LOCAL_PORT);
|
||||||
|
|
||||||
|
HAL_Delay(200);
|
||||||
|
|
||||||
|
/* Echo 循环:收到 → 解析来源 → 回显 */
|
||||||
|
for (i = 0; i < PHASE3_ECHO_COUNT; i++)
|
||||||
|
{
|
||||||
|
tick = HAL_GetTick();
|
||||||
|
echo_ok = 0;
|
||||||
|
while (HAL_GetTick() - tick < PHASE3_TIMEOUT_MS)
|
||||||
|
{
|
||||||
|
uint16_t rlen = ch395f_get_recv_len(sock);
|
||||||
|
if (rlen > 8)
|
||||||
|
{
|
||||||
|
memset(rx_buf, 0, sizeof(rx_buf));
|
||||||
|
ch395f_read_recv_buf(sock, rx_buf, rlen);
|
||||||
|
|
||||||
|
uint16_t payload_len = rlen - 8;
|
||||||
|
uint16_t src_port = (uint16_t)rx_buf[2] | ((uint16_t)rx_buf[3] << 8);
|
||||||
|
uint8_t *src_ip = &rx_buf[4];
|
||||||
|
uint8_t *payload = &rx_buf[8];
|
||||||
|
|
||||||
|
DBG_INFO("UDP #%d: %dB from %d.%d.%d.%d:%d [%.32s]",
|
||||||
|
i + 1, payload_len,
|
||||||
|
src_ip[0], src_ip[1], src_ip[2], src_ip[3], src_port,
|
||||||
|
payload_len > 0 ? (char *)payload : "");
|
||||||
|
|
||||||
|
ch395f_set_des_ip(sock, src_ip);
|
||||||
|
ch395f_set_des_port(sock, src_port);
|
||||||
|
ch395f_write_send_buf(sock, payload, payload_len);
|
||||||
|
|
||||||
|
{
|
||||||
|
uint32_t swait = HAL_GetTick();
|
||||||
|
while (HAL_GetTick() - swait < 2000)
|
||||||
|
{
|
||||||
|
uint16_t gs = ch395f_get_glob_int_status_all();
|
||||||
|
if (gs & (1U << (sock + 4)))
|
||||||
|
{
|
||||||
|
if (ch395f_get_sock_int_status(sock) & CH395F_SINT_STAT_SENBUF_FREE)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
HAL_Delay(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
echo_ok = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
HAL_Delay(50);
|
||||||
|
}
|
||||||
|
TEST_CHECK(echo_ok, "UDP echo #%d/%d", i + 1, PHASE3_ECHO_COUNT);
|
||||||
|
if (!echo_ok) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ch395f_close_socket(sock);
|
||||||
|
TEST_CHECK(1, "UDP socket closed");
|
||||||
|
|
||||||
|
restore_data_sockets(8080);
|
||||||
|
TEST_REPORT("Phase 3");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================ Phase 4 ============================
|
||||||
|
* NET 层 TCP Echo:在主循环中调用,用 net_recv + net_send 回显
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef ENABLE_PHASE4_TESTS
|
||||||
|
static char s_phase4_buf[2048];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void ch395f_phase4_tests(void)
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_PHASE4_TESTS
|
||||||
|
for (int i = NET_TCP_SERVER_DATA_SOCK_START; i < NET_MAX_SOCKETS; i++)
|
||||||
|
{
|
||||||
|
net_sock_t *sk = net_get_sock(i);
|
||||||
|
if (sk == NULL || !sk->in_use || sk->state != NET_SOCK_STATE_ESTABLISHED)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int n = net_recv(i, s_phase4_buf, sizeof(s_phase4_buf), NET_MSG_DONTWAIT);
|
||||||
|
if (n > 0)
|
||||||
|
{
|
||||||
|
net_send(i, s_phase4_buf, n, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================ Phase 5 ============================
|
||||||
|
* NET 层 UDP Echo:netTask 中运行,用 net_recvfrom + net_sendto 回显
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PHASE5_LOCAL_PORT
|
||||||
|
#define PHASE5_LOCAL_PORT 60000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_PHASE5_TESTS
|
||||||
|
static int s_phase5_sock = -1;
|
||||||
|
static char s_phase5_buf[2048];
|
||||||
|
static uint32_t s_phase5_count = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void ch395f_phase5_init(void)
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_PHASE5_TESTS
|
||||||
|
struct net_sockaddr_in addr;
|
||||||
|
|
||||||
|
s_phase5_sock = net_socket(NET_AF_INET, NET_SOCK_DGRAM, 0);
|
||||||
|
if (s_phase5_sock < 0)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Phase5: net_socket failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sin_family = NET_AF_INET;
|
||||||
|
addr.sin_port = net_htons(PHASE5_LOCAL_PORT);
|
||||||
|
|
||||||
|
if (net_bind(s_phase5_sock, (struct net_sockaddr *)&addr, sizeof(addr)) < 0)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Phase5: net_bind failed");
|
||||||
|
net_close(s_phase5_sock);
|
||||||
|
s_phase5_sock = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_phase5_count = 0;
|
||||||
|
DBG_INFO("Phase5: UDP socket %d bound to port %d", s_phase5_sock, PHASE5_LOCAL_PORT);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ch395f_phase5_tests(void)
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_PHASE5_TESTS
|
||||||
|
if (s_phase5_sock < 0) return;
|
||||||
|
|
||||||
|
struct net_sockaddr_in src;
|
||||||
|
int addrlen = sizeof(src);
|
||||||
|
|
||||||
|
int n = net_recvfrom(s_phase5_sock, s_phase5_buf, sizeof(s_phase5_buf),
|
||||||
|
NET_MSG_DONTWAIT,
|
||||||
|
(struct net_sockaddr *)&src, &addrlen);
|
||||||
|
if (n > 0)
|
||||||
|
{
|
||||||
|
net_sendto(s_phase5_sock, s_phase5_buf, n, 0,
|
||||||
|
(struct net_sockaddr *)&src, sizeof(src));
|
||||||
|
s_phase5_count++;
|
||||||
|
TEST_CHECK(1, "Phase5: UDP echo #%lu (%d bytes)", s_phase5_count, n);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Phase 6 配置默认值
|
||||||
|
*/
|
||||||
|
#ifndef PHASE6_ANNOUNCE_PORT
|
||||||
|
#define PHASE6_ANNOUNCE_PORT 60001
|
||||||
|
#endif
|
||||||
|
#ifndef PHASE6_ANNOUNCE_SOCK
|
||||||
|
#define PHASE6_ANNOUNCE_SOCK 6
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================ Phase 6 ============================
|
||||||
|
* DHCP 自动获取 IP 测试
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ch395f_phase6_tests(void)
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_PHASE6_TESTS
|
||||||
|
uint8_t status;
|
||||||
|
uint8_t ip_info[20];
|
||||||
|
uint32_t tick;
|
||||||
|
|
||||||
|
DBG_INFO("=== CH395F Phase 6 Tests (DHCP) ===");
|
||||||
|
|
||||||
|
/* 1. 启用 DHCP */
|
||||||
|
ch395f_set_dhcp(1);
|
||||||
|
TEST_CHECK(1, "DHCP enabled, waiting for IP...");
|
||||||
|
|
||||||
|
/* 2. 轮询等待 DHCP 完成 */
|
||||||
|
HAL_Delay(500);
|
||||||
|
tick = HAL_GetTick();
|
||||||
|
while (HAL_GetTick() - tick < 30000)
|
||||||
|
{
|
||||||
|
uint16_t gint = ch395f_get_glob_int_status_all();
|
||||||
|
if (gint & CH395F_GINT_STAT_DHCP)
|
||||||
|
{
|
||||||
|
DBG_INFO("DHCP interrupt");
|
||||||
|
}
|
||||||
|
|
||||||
|
status = ch395f_get_dhcp_status();
|
||||||
|
if (status == 0x00)
|
||||||
|
{
|
||||||
|
TEST_CHECK(1, "DHCP: SUCCESS");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
HAL_Delay(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CHECK(HAL_GetTick() - tick < 30000,
|
||||||
|
"DHCP completed within 30s (status=0x%02X)", status);
|
||||||
|
|
||||||
|
if (HAL_GetTick() - tick >= 30000)
|
||||||
|
{
|
||||||
|
goto phase6_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. 读取获取的 IP */
|
||||||
|
ch395f_get_ip_inf(ip_info);
|
||||||
|
DBG_INFO(" IP: %d.%d.%d.%d", ip_info[0], ip_info[1], ip_info[2], ip_info[3]);
|
||||||
|
DBG_INFO(" GW: %d.%d.%d.%d", ip_info[4], ip_info[5], ip_info[6], ip_info[7]);
|
||||||
|
DBG_INFO(" MASK: %d.%d.%d.%d", ip_info[8], ip_info[9], ip_info[10], ip_info[11]);
|
||||||
|
DBG_INFO(" DNS1: %d.%d.%d.%d", ip_info[12], ip_info[13], ip_info[14], ip_info[15]);
|
||||||
|
|
||||||
|
TEST_CHECK(ip_info[0] != 0 || ip_info[1] != 0 || ip_info[2] != 0 || ip_info[3] != 0,
|
||||||
|
"IP = %d.%d.%d.%d (non-zero)", ip_info[0], ip_info[1], ip_info[2], ip_info[3]);
|
||||||
|
|
||||||
|
/* 4. 广播宣告 + 等待 PC HELLO 确认 */
|
||||||
|
{
|
||||||
|
#define PHASE6_HELLO_PORT 60000
|
||||||
|
uint8_t anno_sock = PHASE6_ANNOUNCE_SOCK;
|
||||||
|
uint8_t bcast_ip[4] = {0xFF, 0xFF, 0xFF, 0xFF};
|
||||||
|
uint8_t rx_buf[64];
|
||||||
|
|
||||||
|
/* UDP Server 模式:本地端口 60000(接收 HELLO),DesIP=0xFFFFFFFF */
|
||||||
|
ch395f_set_proto_type(anno_sock, CH395F_PROTO_TYPE_UDP);
|
||||||
|
ch395f_set_send_buf(anno_sock, 24, 2);
|
||||||
|
ch395f_set_recv_buf(anno_sock, 26, 2);
|
||||||
|
ch395f_set_sour_port(anno_sock, PHASE6_HELLO_PORT);
|
||||||
|
ch395f_set_des_ip(anno_sock, bcast_ip);
|
||||||
|
ch395f_set_des_port(anno_sock, 0);
|
||||||
|
|
||||||
|
if (ch395f_open_socket(anno_sock) == CH395F_ERR_SUCCESS)
|
||||||
|
{
|
||||||
|
/* 发送广播宣告(宣告端口 = 60001,来源端口 = 60000) */
|
||||||
|
ch395f_set_des_ip(anno_sock, bcast_ip);
|
||||||
|
ch395f_set_des_port(anno_sock, PHASE6_ANNOUNCE_PORT);
|
||||||
|
ch395f_write_send_buf(anno_sock, ip_info, 4);
|
||||||
|
|
||||||
|
/* 等待 SENDBUF_FREE(手册要求:每次 write_send_buf 后必须等待) */
|
||||||
|
{
|
||||||
|
uint32_t swait = HAL_GetTick();
|
||||||
|
while (HAL_GetTick() - swait < 2000)
|
||||||
|
{
|
||||||
|
uint16_t gs = ch395f_get_glob_int_status_all();
|
||||||
|
if (gs & (1U << (anno_sock + 4)))
|
||||||
|
{
|
||||||
|
if (ch395f_get_sock_int_status(anno_sock) & CH395F_SINT_STAT_SENBUF_FREE)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
HAL_Delay(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DBG_INFO("DHCP announcement: IP=%d.%d.%d.%d (port %d->%d)",
|
||||||
|
ip_info[0], ip_info[1], ip_info[2], ip_info[3],
|
||||||
|
PHASE6_HELLO_PORT, PHASE6_ANNOUNCE_PORT);
|
||||||
|
TEST_CHECK(1, "DHCP announcement sent");
|
||||||
|
|
||||||
|
/* 重置 Server 模式,等待 PC 发送 HELLO */
|
||||||
|
ch395f_set_des_ip(anno_sock, bcast_ip);
|
||||||
|
ch395f_set_des_port(anno_sock, 0);
|
||||||
|
|
||||||
|
uint32_t wait = HAL_GetTick();
|
||||||
|
uint8_t hello_ok = 0;
|
||||||
|
while (HAL_GetTick() - wait < 5000)
|
||||||
|
{
|
||||||
|
/* 读取全局中断(刷新 socket 中断状态) */
|
||||||
|
ch395f_get_glob_int_status_all();
|
||||||
|
uint16_t rlen = ch395f_get_recv_len(anno_sock);
|
||||||
|
if (rlen > 8)
|
||||||
|
{
|
||||||
|
memset(rx_buf, 0, sizeof(rx_buf));
|
||||||
|
ch395f_read_recv_buf(anno_sock, rx_buf, rlen);
|
||||||
|
uint16_t payload_len = rlen - 8;
|
||||||
|
uint8_t *payload = &rx_buf[8];
|
||||||
|
|
||||||
|
if (payload_len == 5 && memcmp(payload, "HELLO", 5) == 0)
|
||||||
|
{
|
||||||
|
uint8_t *src_ip = &rx_buf[4];
|
||||||
|
uint16_t src_port = (uint16_t)rx_buf[2] | ((uint16_t)rx_buf[3] << 8);
|
||||||
|
ch395f_set_des_ip(anno_sock, src_ip);
|
||||||
|
ch395f_set_des_port(anno_sock, src_port);
|
||||||
|
ch395f_write_send_buf(anno_sock, payload, payload_len);
|
||||||
|
HAL_Delay(100);
|
||||||
|
DBG_INFO("HELLO response sent to %d.%d.%d.%d:%d",
|
||||||
|
src_ip[0], src_ip[1], src_ip[2], src_ip[3], src_port);
|
||||||
|
TEST_CHECK(1, "HELLO echo OK");
|
||||||
|
hello_ok = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HAL_Delay(50);
|
||||||
|
}
|
||||||
|
TEST_CHECK(hello_ok, "HELLO echo within 5s");
|
||||||
|
|
||||||
|
ch395f_close_socket(anno_sock);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TEST_CHECK(0, "DHCP announcement: open socket failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
phase6_end:
|
||||||
|
TEST_REPORT("Phase 6");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================ Phase 7 ============================
|
||||||
|
* Select/Poll I/O 多路复用测试 — net_select() + net_recv/send echo
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "net_select.h"
|
||||||
|
|
||||||
|
#ifdef ENABLE_PHASE7_TESTS
|
||||||
|
static char s_phase7_buf[2048];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void ch395f_phase7_tests(void)
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_PHASE7_TESTS
|
||||||
|
static uint32_t s_phase7_count = 0;
|
||||||
|
net_fd_set readfds;
|
||||||
|
net_timeval tv;
|
||||||
|
|
||||||
|
NET_FD_ZERO(&readfds);
|
||||||
|
|
||||||
|
for (int i = NET_TCP_SERVER_DATA_SOCK_START; i < NET_MAX_SOCKETS; i++)
|
||||||
|
{
|
||||||
|
net_sock_t *sk = net_get_sock(i);
|
||||||
|
if (sk && sk->in_use && sk->state == NET_SOCK_STATE_ESTABLISHED)
|
||||||
|
{
|
||||||
|
NET_FD_SET(i, &readfds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 50000;
|
||||||
|
|
||||||
|
int n = net_select(NET_MAX_SOCKETS, &readfds, NULL, NULL, &tv);
|
||||||
|
if (n <= 0) return;
|
||||||
|
|
||||||
|
for (int i = 0; i < NET_MAX_SOCKETS; i++)
|
||||||
|
{
|
||||||
|
if (!NET_FD_ISSET(i, &readfds)) continue;
|
||||||
|
|
||||||
|
int len = net_recv(i, s_phase7_buf, sizeof(s_phase7_buf), NET_MSG_DONTWAIT);
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
net_send(i, s_phase7_buf, len, 0);
|
||||||
|
s_phase7_count++;
|
||||||
|
TEST_CHECK(1, "Phase7: select echo #%lu (sock=%d, %d bytes)", s_phase7_count, i, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
139
Drivers/BSP/CH395F/ch395f_test.h
Normal file
139
Drivers/BSP/CH395F/ch395f_test.h
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:CH395F Driver Test Suite
|
||||||
|
* 模块功能:CH395F 驱动各功能模块的测试入口,分阶段组织测试用例,
|
||||||
|
* 覆盖 SPI 命令路径、协议栈配置、Socket 状态机等
|
||||||
|
* 适用平台:STM32F4 系列(CH395F 以太网芯片)
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-19
|
||||||
|
* 修改记录:
|
||||||
|
*
|
||||||
|
* === 通过标准速查 ===
|
||||||
|
*
|
||||||
|
* Phase | 通过条件 | 失败特征
|
||||||
|
* ---------|-----------------------------------|--------------------------------
|
||||||
|
* Phase 1 | 9 项全部打印 OK/SUCCESS/YES/0x00 | 任何一项显示 FAIL、ERROR、MISMATCH
|
||||||
|
* Phase 2 | 3 轮 "PASS" 打印 | 任何一轮打印 "FAIL" 或超时
|
||||||
|
* Phase 3 | 20/20 回显 + PING 5/5 + 大包 10/10 | 任何回显超时或丢包
|
||||||
|
* Phase 4 | PC 脚本显示 10/10 sent/received | 断连、数据错乱
|
||||||
|
* Phase 5 | PC 脚本显示 10/10 sent/received | 断连、数据错乱
|
||||||
|
* Phase 6 | 日志打印 IP/GW/MASK 非零 IP | DHCP timeout 或 0.0.0.0
|
||||||
|
* Phase 7 | PC 脚本显示 10/10 sent/received | 断连、数据错乱
|
||||||
|
* Phase 8 | 70/70 成功率 100% | 任何连接失败或丢包
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CH395F_TEST_H
|
||||||
|
#define __CH395F_TEST_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 阶段使能开关(取消注释即启用对应阶段)
|
||||||
|
* 注意:Phase 6 (DHCP) 会改变 IP,建议独立运行
|
||||||
|
*/
|
||||||
|
//#define ENABLE_PHASE1_TESTS /* 寄存器读写 + 中断一致性 */
|
||||||
|
//#define ENABLE_PHASE2_TESTS /* TCP Client 收发 + 关闭重连 */
|
||||||
|
//#define ENABLE_PHASE3_TESTS /* UDP Server Echo */
|
||||||
|
#define ENABLE_PHASE4_TESTS /* NET 层 TCP Echo(netTask 中运行) */
|
||||||
|
//#define ENABLE_PHASE5_TESTS /* NET 层 UDP Echo(netTask 中运行) */
|
||||||
|
//#define ENABLE_PHASE6_TESTS /* DHCP 自动获取 IP(会改 IP!) */
|
||||||
|
//#define ENABLE_PHASE7_TESTS /* Select/Poll I/O 多路复用(netTask 中运行) */
|
||||||
|
|
||||||
|
/* 测试统计 */
|
||||||
|
typedef struct {
|
||||||
|
uint16_t total;
|
||||||
|
uint16_t passed;
|
||||||
|
uint16_t failed;
|
||||||
|
} test_stats_t;
|
||||||
|
|
||||||
|
extern test_stats_t g_test_stats;
|
||||||
|
|
||||||
|
#define TEST_CHECK(cond, fmt, ...) do { \
|
||||||
|
g_test_stats.total++; \
|
||||||
|
if (cond) { \
|
||||||
|
g_test_stats.passed++; \
|
||||||
|
DBG_INFO("[PASS] " fmt, ##__VA_ARGS__); \
|
||||||
|
} else { \
|
||||||
|
g_test_stats.failed++; \
|
||||||
|
DBG_ERROR("[FAIL] " fmt, ##__VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define TEST_REPORT(name) do { \
|
||||||
|
DBG_INFO("=== %s: %d/%d PASSED (failed=%d) ===", \
|
||||||
|
name, g_test_stats.passed, g_test_stats.total, g_test_stats.failed); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Phase 1: 底层寄存器测试
|
||||||
|
* 通过: 9 项全部打印 OK/SUCCESS/YES/0x00
|
||||||
|
* 失败: 任何一项 FAIL/ERROR/MISMATCH
|
||||||
|
*/
|
||||||
|
void ch395f_phase1_tests(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Phase 2: TCP Client 收发 + 关闭重连 ×3 轮
|
||||||
|
* 通过: 日志打印 3 轮 "PASS"
|
||||||
|
* 失败: 任何一轮打印 "FAIL" 或超时
|
||||||
|
* PC 端预启动:
|
||||||
|
* python test/ch395f_socket_test.py tcp_server --port 8081
|
||||||
|
*/
|
||||||
|
void ch395f_phase2_tests(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Phase 3: UDP Server Echo + PING + 大包
|
||||||
|
* 通过: 20/20 回显 + PING 5/5 + 大包 10/10
|
||||||
|
* 失败: 任何回显超时或丢包
|
||||||
|
* PC 端:
|
||||||
|
* ping 192.168.1.100
|
||||||
|
* python test/ch395f_socket_test.py udp_client --ip 192.168.1.100 --port 60000
|
||||||
|
*/
|
||||||
|
void ch395f_phase3_tests(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Phase 4: NET 层 TCP Echo(netTask 中运行)
|
||||||
|
* 通过: PC 脚本 10/10 sent/received
|
||||||
|
* 失败: 断连或数据错乱
|
||||||
|
* PC 端:
|
||||||
|
* python test/ch395f_socket_test.py tcp_client --ip 192.168.1.100 --port 8080
|
||||||
|
*/
|
||||||
|
void ch395f_phase4_tests(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Phase 5: NET 层 UDP Echo(netTask 中运行)
|
||||||
|
* 通过: PC 脚本 10/10 sent/received
|
||||||
|
* 失败: 断连或数据错乱
|
||||||
|
* 注:init 在 USER CODE BEGIN 2 中调用,echo 在 netTask 中运行
|
||||||
|
* PC 端:
|
||||||
|
* python test/ch395f_socket_test.py udp_client --ip 192.168.1.100 --port 60000
|
||||||
|
*/
|
||||||
|
void ch395f_phase5_init(void);
|
||||||
|
void ch395f_phase5_tests(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Phase 6: DHCP 自动获取 IP
|
||||||
|
* 通过: DHCP SUCCESS + IP 非零 + 广播宣告 + HELLO 回显
|
||||||
|
* 失败: DHCP timeout 或宣告/HELLO 失败
|
||||||
|
* 注意: 会改变 IP,需独立运行
|
||||||
|
* PC 端:管理员权限
|
||||||
|
* python test/ch395f_socket_test.py dhcp_server --dhcp-iface 192.168.1.2 --ip 192.168.1.100
|
||||||
|
*/
|
||||||
|
void ch395f_phase6_tests(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Phase 7: Select/Poll 测试(netTask 中运行)
|
||||||
|
* 通过: PC 脚本 10/10 sent/received
|
||||||
|
* 失败: 断连或数据错乱
|
||||||
|
* PC 端:
|
||||||
|
* python test/ch395f_socket_test.py tcp_client --ip 192.168.1.100 --port 8080
|
||||||
|
*/
|
||||||
|
void ch395f_phase7_tests(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __CH395F_TEST_H */
|
||||||
@@ -13,6 +13,12 @@
|
|||||||
#include "gd5f2gq5ue.h"
|
#include "gd5f2gq5ue.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 调试输出配置
|
||||||
|
*/
|
||||||
|
#define DBG_TAG "[NAND]"
|
||||||
|
#include "dbg_log.h"
|
||||||
|
|
||||||
/* 私有宏定义区 */
|
/* 私有宏定义区 */
|
||||||
#define GD5F_SPI_TIMEOUT 100
|
#define GD5F_SPI_TIMEOUT 100
|
||||||
|
|
||||||
@@ -295,28 +301,39 @@ int gd5f2gq5ue_init(void)
|
|||||||
|
|
||||||
HAL_Delay(10);
|
HAL_Delay(10);
|
||||||
|
|
||||||
|
DBG_INFO("Resetting NAND...");
|
||||||
ret = gd5f2gq5ue_reset();
|
ret = gd5f2gq5ue_reset();
|
||||||
if (ret != GD5F_OK) {
|
if (ret != GD5F_OK) {
|
||||||
|
DBG_ERROR("Reset failed: %d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
HAL_Delay(5);
|
HAL_Delay(5);
|
||||||
|
|
||||||
|
DBG_INFO("Reading NAND ID...");
|
||||||
ret = gd5f2gq5ue_read_id(&mid, &did);
|
ret = gd5f2gq5ue_read_id(&mid, &did);
|
||||||
if (ret != GD5F_OK) {
|
if (ret != GD5F_OK) {
|
||||||
|
DBG_ERROR("Read ID failed: %d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DBG_INFO("NAND ID: MID=0x%02X, DID=0x%02X", mid, did);
|
||||||
|
|
||||||
if (mid != GD5F_MANUFACTURER_ID || did != GD5F_DEVICE_ID) {
|
if (mid != GD5F_MANUFACTURER_ID || did != GD5F_DEVICE_ID) {
|
||||||
|
DBG_ERROR("ID mismatch: expected MID=0x%02X DID=0x%02X, got MID=0x%02X DID=0x%02X",
|
||||||
|
GD5F_MANUFACTURER_ID, GD5F_DEVICE_ID, mid, did);
|
||||||
return GD5F_ID_MISMATCH;
|
return GD5F_ID_MISMATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DBG_INFO("Enabling ECC...");
|
||||||
gd5f_set_feature(0xB0, 0x10);
|
gd5f_set_feature(0xB0, 0x10);
|
||||||
gd5f_wait_busy(100);
|
gd5f_wait_busy(100);
|
||||||
|
|
||||||
|
DBG_INFO("Unlocking block protection...");
|
||||||
gd5f_set_feature(GD5F_REG_PROTECT, 0x00);
|
gd5f_set_feature(GD5F_REG_PROTECT, 0x00);
|
||||||
gd5f_wait_busy(100);
|
gd5f_wait_busy(100);
|
||||||
|
|
||||||
|
DBG_INFO("NAND init OK");
|
||||||
return GD5F_OK;
|
return GD5F_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
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 */
|
||||||
1279
Drivers/BSP/NET/net_socket.c
Normal file
1279
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,13 @@
|
|||||||
|
|
||||||
/* 头文件包含区 */
|
/* 头文件包含区 */
|
||||||
#include "tpafe5160.h"
|
#include "tpafe5160.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 调试输出配置
|
||||||
|
*/
|
||||||
|
#define DBG_TAG "[ADC]"
|
||||||
|
#include "dbg_log.h"
|
||||||
|
|
||||||
/* ======================== 私有宏定义 ======================== */
|
/* ======================== 私有宏定义 ======================== */
|
||||||
|
|
||||||
@@ -68,7 +75,13 @@ int tpafe5160_init(void)
|
|||||||
TPAFE5160_CONVST_LOW();
|
TPAFE5160_CONVST_LOW();
|
||||||
|
|
||||||
/* 等待 BUSY 释放,确保上电后无残留转换 */
|
/* 等待 BUSY 释放,确保上电后无残留转换 */
|
||||||
return tpafe5160_wait_busy(TPAFE5160_CONV_TIMEOUT_MS);
|
int ret = tpafe5160_wait_busy(TPAFE5160_CONV_TIMEOUT_MS);
|
||||||
|
if (ret != TPAFE5160_OK) {
|
||||||
|
DBG_ERROR("Init wait BUSY timeout");
|
||||||
|
} else {
|
||||||
|
DBG_INFO("Init OK");
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -149,6 +162,7 @@ int tpafe5160_read_all(int16_t *buf)
|
|||||||
/* 等待转换完成 */
|
/* 等待转换完成 */
|
||||||
ret = tpafe5160_wait_busy(TPAFE5160_CONV_TIMEOUT_MS);
|
ret = tpafe5160_wait_busy(TPAFE5160_CONV_TIMEOUT_MS);
|
||||||
if (ret != TPAFE5160_OK) {
|
if (ret != TPAFE5160_OK) {
|
||||||
|
DBG_ERROR("read_all BUSY timeout");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,13 +339,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
|
||||||
|
|||||||
35
Drivers/BSP/dbg_cfg.h
Normal file
35
Drivers/BSP/dbg_cfg.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:Debug Output Configuration
|
||||||
|
* 模块功能:全局调试输出配置,定义各调试级别的编译开关
|
||||||
|
* 参考 FlashDB fdb_cfg.h 设计模式
|
||||||
|
* 使用方法:
|
||||||
|
* - DBG_ENABLE 总开关,定义后启用 DBG_ERROR / DBG_INFO
|
||||||
|
* - DBG_DEBUG_ENABLE 子开关,同时定义 DBG_ENABLE 后启用 DBG_DEBUG(含 __func__:__LINE__)
|
||||||
|
* - 两者都不定义:所有 DBG_* 宏为空操作(release 版本)
|
||||||
|
*
|
||||||
|
* 用户可在本文件中直接控制,也可在编译器预定义中覆盖
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DBG_CFG_H
|
||||||
|
#define __DBG_CFG_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 总开关:取消注释启用所有调试输出
|
||||||
|
*/
|
||||||
|
#define DBG_ENABLE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 调试级别开关:取消注释额外输出 DBG_DEBUG 级别
|
||||||
|
* 仅在 DBG_ENABLE 定义时生效
|
||||||
|
*/
|
||||||
|
/* #define DBG_DEBUG_ENABLE */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __DBG_CFG_H */
|
||||||
84
Drivers/BSP/dbg_log.h
Normal file
84
Drivers/BSP/dbg_log.h
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:Unified Debug Logging
|
||||||
|
* 模块功能:提供统一的调试输出宏,支持 DEBUG / INFO / ERROR 三级日志控制
|
||||||
|
* 参考 FlashDB FDB_DEBUG/FDB_INFO 设计模式
|
||||||
|
* 使用方法:
|
||||||
|
* 1. 在 dbg_cfg.h 中定义 DBG_ENABLE(总开关)和 DBG_DEBUG_ENABLE(DEBUG 级别)
|
||||||
|
* 2. 每个 .c 文件在包含本文件前定义 DBG_TAG,如:
|
||||||
|
* #define DBG_TAG "[CH395]"
|
||||||
|
* #include "dbg_log.h"
|
||||||
|
* 适用平台:所有 BSP 驱动
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DBG_LOG_H
|
||||||
|
#define __DBG_LOG_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "dbg_cfg.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 总开关:DBG_ENABLE
|
||||||
|
* 定义 → 输出 DBG_ERROR / DBG_INFO;若 DBG_DEBUG_ENABLE 也定义则输出 DBG_DEBUG
|
||||||
|
* 不定义 → 所有输出宏为空操作(release 版本)
|
||||||
|
* 在 net_config.h 或编译器预定义中控制
|
||||||
|
*/
|
||||||
|
#ifdef DBG_ENABLE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 可重定向的打印函数,用户可在编译选项或 net_config.h 中预定义
|
||||||
|
* #define DBG_PRINT(...) my_printf(__VA_ARGS__)
|
||||||
|
*/
|
||||||
|
#ifndef DBG_PRINT
|
||||||
|
#define DBG_PRINT(...) printf(__VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 模块标签默认值,每个 .c 文件应在包含本文件前定义 DBG_TAG
|
||||||
|
* #define DBG_TAG "[CH395]"
|
||||||
|
*/
|
||||||
|
#ifndef DBG_TAG
|
||||||
|
#define DBG_TAG ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DBG_ERROR - 错误输出,受 DBG_ENABLE 控制
|
||||||
|
*/
|
||||||
|
#define DBG_ERROR(fmt, ...) do { \
|
||||||
|
DBG_PRINT("[ERR]" DBG_TAG " " fmt "\r\n", ##__VA_ARGS__); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DBG_INFO - 信息输出,受 DBG_ENABLE 控制
|
||||||
|
*/
|
||||||
|
#define DBG_INFO(fmt, ...) do { \
|
||||||
|
DBG_PRINT(DBG_TAG " " fmt "\r\n", ##__VA_ARGS__); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DBG_DEBUG - 调试输出,需 DBG_ENABLE + DBG_DEBUG_ENABLE 同时定义
|
||||||
|
*/
|
||||||
|
#ifdef DBG_DEBUG_ENABLE
|
||||||
|
#define DBG_DEBUG(fmt, ...) do { \
|
||||||
|
DBG_PRINT(DBG_TAG "(%s:%d) " fmt "\r\n", __func__, __LINE__, ##__VA_ARGS__); \
|
||||||
|
} while(0)
|
||||||
|
#else
|
||||||
|
#define DBG_DEBUG(fmt, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else /* DBG_ENABLE not defined — all debug output disabled */
|
||||||
|
|
||||||
|
#define DBG_ERROR(fmt, ...)
|
||||||
|
#define DBG_INFO(fmt, ...)
|
||||||
|
#define DBG_DEBUG(fmt, ...)
|
||||||
|
|
||||||
|
#endif /* DBG_ENABLE */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __DBG_LOG_H */
|
||||||
2157
Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_tim.h
Normal file
2157
Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_tim.h
Normal file
File diff suppressed because it is too large
Load Diff
357
Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_tim_ex.h
Normal file
357
Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_tim_ex.h
Normal file
@@ -0,0 +1,357 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @file stm32f4xx_hal_tim_ex.h
|
||||||
|
* @author MCD Application Team
|
||||||
|
* @brief Header file of TIM HAL Extended module.
|
||||||
|
******************************************************************************
|
||||||
|
* @attention
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016 STMicroelectronics.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This software is licensed under terms that can be found in the LICENSE file
|
||||||
|
* in the root directory of this software component.
|
||||||
|
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||||
|
#ifndef STM32F4xx_HAL_TIM_EX_H
|
||||||
|
#define STM32F4xx_HAL_TIM_EX_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Includes ------------------------------------------------------------------*/
|
||||||
|
#include "stm32f4xx_hal_def.h"
|
||||||
|
|
||||||
|
/** @addtogroup STM32F4xx_HAL_Driver
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup TIMEx
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Exported types ------------------------------------------------------------*/
|
||||||
|
/** @defgroup TIMEx_Exported_Types TIM Extended Exported Types
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief TIM Hall sensor Configuration Structure definition
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t IC1Polarity; /*!< Specifies the active edge of the input signal.
|
||||||
|
This parameter can be a value of @ref TIM_Input_Capture_Polarity */
|
||||||
|
|
||||||
|
uint32_t IC1Prescaler; /*!< Specifies the Input Capture Prescaler.
|
||||||
|
This parameter can be a value of @ref TIM_Input_Capture_Prescaler */
|
||||||
|
|
||||||
|
uint32_t IC1Filter; /*!< Specifies the input capture filter.
|
||||||
|
This parameter can be a number between Min_Data = 0x0 and Max_Data = 0xF */
|
||||||
|
|
||||||
|
uint32_t Commutation_Delay; /*!< Specifies the pulse value to be loaded into the Capture Compare Register.
|
||||||
|
This parameter can be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */
|
||||||
|
} TIM_HallSensor_InitTypeDef;
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
/* End of exported types -----------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Exported constants --------------------------------------------------------*/
|
||||||
|
/** @defgroup TIMEx_Exported_Constants TIM Extended Exported Constants
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @defgroup TIMEx_Remap TIM Extended Remapping
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#if defined (TIM2)
|
||||||
|
#if defined(TIM8)
|
||||||
|
#define TIM_TIM2_TIM8_TRGO 0x00000000U /*!< TIM2 ITR1 is connected to TIM8 TRGO */
|
||||||
|
#endif /* TIM8 */
|
||||||
|
#define TIM_TIM2_ETH_PTP TIM_OR_ITR1_RMP_0 /*!< TIM2 ITR1 is connected to PTP trigger output */
|
||||||
|
#define TIM_TIM2_USBFS_SOF TIM_OR_ITR1_RMP_1 /*!< TIM2 ITR1 is connected to OTG FS SOF */
|
||||||
|
#define TIM_TIM2_USBHS_SOF (TIM_OR_ITR1_RMP_1 | TIM_OR_ITR1_RMP_0) /*!< TIM2 ITR1 is connected to OTG HS SOF */
|
||||||
|
#endif /* TIM2 */
|
||||||
|
|
||||||
|
#define TIM_TIM5_GPIO 0x00000000U /*!< TIM5 TI4 is connected to GPIO */
|
||||||
|
#define TIM_TIM5_LSI TIM_OR_TI4_RMP_0 /*!< TIM5 TI4 is connected to LSI */
|
||||||
|
#define TIM_TIM5_LSE TIM_OR_TI4_RMP_1 /*!< TIM5 TI4 is connected to LSE */
|
||||||
|
#define TIM_TIM5_RTC (TIM_OR_TI4_RMP_1 | TIM_OR_TI4_RMP_0) /*!< TIM5 TI4 is connected to the RTC wakeup interrupt */
|
||||||
|
|
||||||
|
#define TIM_TIM11_GPIO 0x00000000U /*!< TIM11 TI1 is connected to GPIO */
|
||||||
|
#define TIM_TIM11_HSE TIM_OR_TI1_RMP_1 /*!< TIM11 TI1 is connected to HSE_RTC clock */
|
||||||
|
#if defined(SPDIFRX)
|
||||||
|
#define TIM_TIM11_SPDIFRX TIM_OR_TI1_RMP_0 /*!< TIM11 TI1 is connected to SPDIFRX_FRAME_SYNC */
|
||||||
|
#endif /* SPDIFRX*/
|
||||||
|
|
||||||
|
#if defined(LPTIM_OR_TIM1_ITR2_RMP) && defined(LPTIM_OR_TIM5_ITR1_RMP) && defined(LPTIM_OR_TIM5_ITR1_RMP)
|
||||||
|
#define LPTIM_REMAP_MASK 0x10000000U
|
||||||
|
|
||||||
|
#define TIM_TIM9_TIM3_TRGO LPTIM_REMAP_MASK /*!< TIM9 ITR1 is connected to TIM3 TRGO */
|
||||||
|
#define TIM_TIM9_LPTIM (LPTIM_REMAP_MASK | LPTIM_OR_TIM9_ITR1_RMP) /*!< TIM9 ITR1 is connected to LPTIM1 output */
|
||||||
|
|
||||||
|
#define TIM_TIM5_TIM3_TRGO LPTIM_REMAP_MASK /*!< TIM5 ITR1 is connected to TIM3 TRGO */
|
||||||
|
#define TIM_TIM5_LPTIM (LPTIM_REMAP_MASK | LPTIM_OR_TIM5_ITR1_RMP) /*!< TIM5 ITR1 is connected to LPTIM1 output */
|
||||||
|
|
||||||
|
#define TIM_TIM1_TIM3_TRGO LPTIM_REMAP_MASK /*!< TIM1 ITR2 is connected to TIM3 TRGO */
|
||||||
|
#define TIM_TIM1_LPTIM (LPTIM_REMAP_MASK | LPTIM_OR_TIM1_ITR2_RMP) /*!< TIM1 ITR2 is connected to LPTIM1 output */
|
||||||
|
#endif /* LPTIM_OR_TIM1_ITR2_RMP && LPTIM_OR_TIM5_ITR1_RMP && LPTIM_OR_TIM5_ITR1_RMP */
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
/* End of exported constants -------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Exported macro ------------------------------------------------------------*/
|
||||||
|
/** @defgroup TIMEx_Exported_Macros TIM Extended Exported Macros
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
/* End of exported macro -----------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Private macro -------------------------------------------------------------*/
|
||||||
|
/** @defgroup TIMEx_Private_Macros TIM Extended Private Macros
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#if defined(SPDIFRX)
|
||||||
|
#define IS_TIM_REMAP(INSTANCE, TIM_REMAP) \
|
||||||
|
((((INSTANCE) == TIM2) && (((TIM_REMAP) == TIM_TIM2_TIM8_TRGO) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM2_USBFS_SOF) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM2_USBHS_SOF))) || \
|
||||||
|
(((INSTANCE) == TIM5) && (((TIM_REMAP) == TIM_TIM5_GPIO) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM5_LSI) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM5_LSE) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM5_RTC))) || \
|
||||||
|
(((INSTANCE) == TIM11) && (((TIM_REMAP) == TIM_TIM11_GPIO) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM11_SPDIFRX) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM11_HSE))))
|
||||||
|
#elif defined(TIM2)
|
||||||
|
#if defined(LPTIM_OR_TIM1_ITR2_RMP) && defined(LPTIM_OR_TIM5_ITR1_RMP) && defined(LPTIM_OR_TIM5_ITR1_RMP)
|
||||||
|
#define IS_TIM_REMAP(INSTANCE, TIM_REMAP) \
|
||||||
|
((((INSTANCE) == TIM2) && (((TIM_REMAP) == TIM_TIM2_TIM8_TRGO) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM2_ETH_PTP) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM2_USBFS_SOF) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM2_USBHS_SOF))) || \
|
||||||
|
(((INSTANCE) == TIM5) && (((TIM_REMAP) == TIM_TIM5_GPIO) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM5_LSI) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM5_LSE) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM5_RTC))) || \
|
||||||
|
(((INSTANCE) == TIM11) && (((TIM_REMAP) == TIM_TIM11_GPIO) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM11_HSE))) || \
|
||||||
|
(((INSTANCE) == TIM1) && (((TIM_REMAP) == TIM_TIM1_TIM3_TRGO) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM1_LPTIM))) || \
|
||||||
|
(((INSTANCE) == TIM5) && (((TIM_REMAP) == TIM_TIM5_TIM3_TRGO) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM5_LPTIM))) || \
|
||||||
|
(((INSTANCE) == TIM9) && (((TIM_REMAP) == TIM_TIM9_TIM3_TRGO) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM9_LPTIM))))
|
||||||
|
#elif defined(TIM8)
|
||||||
|
#define IS_TIM_REMAP(INSTANCE, TIM_REMAP) \
|
||||||
|
((((INSTANCE) == TIM2) && (((TIM_REMAP) == TIM_TIM2_TIM8_TRGO) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM2_ETH_PTP) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM2_USBFS_SOF) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM2_USBHS_SOF))) || \
|
||||||
|
(((INSTANCE) == TIM5) && (((TIM_REMAP) == TIM_TIM5_GPIO) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM5_LSI) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM5_LSE) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM5_RTC))) || \
|
||||||
|
(((INSTANCE) == TIM11) && (((TIM_REMAP) == TIM_TIM11_GPIO) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM11_HSE))))
|
||||||
|
#else
|
||||||
|
#define IS_TIM_REMAP(INSTANCE, TIM_REMAP) \
|
||||||
|
((((INSTANCE) == TIM2) && (((TIM_REMAP) == TIM_TIM2_ETH_PTP) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM2_USBFS_SOF) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM2_USBHS_SOF))) || \
|
||||||
|
(((INSTANCE) == TIM5) && (((TIM_REMAP) == TIM_TIM5_GPIO) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM5_LSI) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM5_LSE) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM5_RTC))) || \
|
||||||
|
(((INSTANCE) == TIM11) && (((TIM_REMAP) == TIM_TIM11_GPIO) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM11_HSE))))
|
||||||
|
#endif /* LPTIM_OR_TIM1_ITR2_RMP && LPTIM_OR_TIM5_ITR1_RMP && LPTIM_OR_TIM5_ITR1_RMP */
|
||||||
|
#else
|
||||||
|
#define IS_TIM_REMAP(INSTANCE, TIM_REMAP) \
|
||||||
|
((((INSTANCE) == TIM5) && (((TIM_REMAP) == TIM_TIM5_GPIO) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM5_LSI) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM5_LSE) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM5_RTC))) || \
|
||||||
|
(((INSTANCE) == TIM11) && (((TIM_REMAP) == TIM_TIM11_GPIO) || \
|
||||||
|
((TIM_REMAP) == TIM_TIM11_HSE))))
|
||||||
|
#endif /* SPDIFRX */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
/* End of private macro ------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Exported functions --------------------------------------------------------*/
|
||||||
|
/** @addtogroup TIMEx_Exported_Functions TIM Extended Exported Functions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup TIMEx_Exported_Functions_Group1 Extended Timer Hall Sensor functions
|
||||||
|
* @brief Timer Hall Sensor functions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/* Timer Hall Sensor functions **********************************************/
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_HallSensor_Init(TIM_HandleTypeDef *htim, const TIM_HallSensor_InitTypeDef *sConfig);
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_HallSensor_DeInit(TIM_HandleTypeDef *htim);
|
||||||
|
|
||||||
|
void HAL_TIMEx_HallSensor_MspInit(TIM_HandleTypeDef *htim);
|
||||||
|
void HAL_TIMEx_HallSensor_MspDeInit(TIM_HandleTypeDef *htim);
|
||||||
|
|
||||||
|
/* Blocking mode: Polling */
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_HallSensor_Start(TIM_HandleTypeDef *htim);
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_HallSensor_Stop(TIM_HandleTypeDef *htim);
|
||||||
|
/* Non-Blocking mode: Interrupt */
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_HallSensor_Start_IT(TIM_HandleTypeDef *htim);
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_HallSensor_Stop_IT(TIM_HandleTypeDef *htim);
|
||||||
|
/* Non-Blocking mode: DMA */
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_HallSensor_Start_DMA(TIM_HandleTypeDef *htim, uint32_t *pData, uint16_t Length);
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_HallSensor_Stop_DMA(TIM_HandleTypeDef *htim);
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup TIMEx_Exported_Functions_Group2 Extended Timer Complementary Output Compare functions
|
||||||
|
* @brief Timer Complementary Output Compare functions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/* Timer Complementary Output Compare functions *****************************/
|
||||||
|
/* Blocking mode: Polling */
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_OCN_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_OCN_Stop(TIM_HandleTypeDef *htim, uint32_t Channel);
|
||||||
|
|
||||||
|
/* Non-Blocking mode: Interrupt */
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_OCN_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_OCN_Stop_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
|
||||||
|
|
||||||
|
/* Non-Blocking mode: DMA */
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_OCN_Start_DMA(TIM_HandleTypeDef *htim, uint32_t Channel, const uint32_t *pData,
|
||||||
|
uint16_t Length);
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_OCN_Stop_DMA(TIM_HandleTypeDef *htim, uint32_t Channel);
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup TIMEx_Exported_Functions_Group3 Extended Timer Complementary PWM functions
|
||||||
|
* @brief Timer Complementary PWM functions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/* Timer Complementary PWM functions ****************************************/
|
||||||
|
/* Blocking mode: Polling */
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_PWMN_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_PWMN_Stop(TIM_HandleTypeDef *htim, uint32_t Channel);
|
||||||
|
|
||||||
|
/* Non-Blocking mode: Interrupt */
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_PWMN_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_PWMN_Stop_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
|
||||||
|
/* Non-Blocking mode: DMA */
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_PWMN_Start_DMA(TIM_HandleTypeDef *htim, uint32_t Channel, const uint32_t *pData,
|
||||||
|
uint16_t Length);
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_PWMN_Stop_DMA(TIM_HandleTypeDef *htim, uint32_t Channel);
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup TIMEx_Exported_Functions_Group4 Extended Timer Complementary One Pulse functions
|
||||||
|
* @brief Timer Complementary One Pulse functions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/* Timer Complementary One Pulse functions **********************************/
|
||||||
|
/* Blocking mode: Polling */
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_OnePulseN_Start(TIM_HandleTypeDef *htim, uint32_t OutputChannel);
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_OnePulseN_Stop(TIM_HandleTypeDef *htim, uint32_t OutputChannel);
|
||||||
|
|
||||||
|
/* Non-Blocking mode: Interrupt */
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_OnePulseN_Start_IT(TIM_HandleTypeDef *htim, uint32_t OutputChannel);
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_OnePulseN_Stop_IT(TIM_HandleTypeDef *htim, uint32_t OutputChannel);
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup TIMEx_Exported_Functions_Group5 Extended Peripheral Control functions
|
||||||
|
* @brief Peripheral Control functions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/* Extended Control functions ************************************************/
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_ConfigCommutEvent(TIM_HandleTypeDef *htim, uint32_t InputTrigger,
|
||||||
|
uint32_t CommutationSource);
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_ConfigCommutEvent_IT(TIM_HandleTypeDef *htim, uint32_t InputTrigger,
|
||||||
|
uint32_t CommutationSource);
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_ConfigCommutEvent_DMA(TIM_HandleTypeDef *htim, uint32_t InputTrigger,
|
||||||
|
uint32_t CommutationSource);
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_MasterConfigSynchronization(TIM_HandleTypeDef *htim,
|
||||||
|
const TIM_MasterConfigTypeDef *sMasterConfig);
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_ConfigBreakDeadTime(TIM_HandleTypeDef *htim,
|
||||||
|
const TIM_BreakDeadTimeConfigTypeDef *sBreakDeadTimeConfig);
|
||||||
|
HAL_StatusTypeDef HAL_TIMEx_RemapConfig(TIM_HandleTypeDef *htim, uint32_t Remap);
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup TIMEx_Exported_Functions_Group6 Extended Callbacks functions
|
||||||
|
* @brief Extended Callbacks functions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/* Extended Callback **********************************************************/
|
||||||
|
void HAL_TIMEx_CommutCallback(TIM_HandleTypeDef *htim);
|
||||||
|
void HAL_TIMEx_CommutHalfCpltCallback(TIM_HandleTypeDef *htim);
|
||||||
|
void HAL_TIMEx_BreakCallback(TIM_HandleTypeDef *htim);
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup TIMEx_Exported_Functions_Group7 Extended Peripheral State functions
|
||||||
|
* @brief Extended Peripheral State functions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/* Extended Peripheral State functions ***************************************/
|
||||||
|
HAL_TIM_StateTypeDef HAL_TIMEx_HallSensor_GetState(const TIM_HandleTypeDef *htim);
|
||||||
|
HAL_TIM_ChannelStateTypeDef HAL_TIMEx_GetChannelNState(const TIM_HandleTypeDef *htim, uint32_t ChannelN);
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
/* End of exported functions -------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Private functions----------------------------------------------------------*/
|
||||||
|
/** @addtogroup TIMEx_Private_Functions TIM Extended Private Functions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
void TIMEx_DMACommutationCplt(DMA_HandleTypeDef *hdma);
|
||||||
|
void TIMEx_DMACommutationHalfCplt(DMA_HandleTypeDef *hdma);
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
/* End of private functions --------------------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* STM32F4xx_HAL_TIM_EX_H */
|
||||||
7629
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c
Normal file
7629
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c
Normal file
File diff suppressed because it is too large
Load Diff
2410
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim_ex.c
Normal file
2410
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim_ex.c
Normal file
File diff suppressed because it is too large
Load Diff
170
Inc/FreeRTOSConfig.h
Normal file
170
Inc/FreeRTOSConfig.h
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
/* USER CODE BEGIN Header */
|
||||||
|
/*
|
||||||
|
* FreeRTOS Kernel V10.3.1
|
||||||
|
* Portion Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Portion Copyright (C) 2019 StMicroelectronics, Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org
|
||||||
|
* http://aws.amazon.com/freertos
|
||||||
|
*
|
||||||
|
* 1 tab == 4 spaces!
|
||||||
|
*/
|
||||||
|
/* USER CODE END Header */
|
||||||
|
|
||||||
|
#ifndef FREERTOS_CONFIG_H
|
||||||
|
#define FREERTOS_CONFIG_H
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------
|
||||||
|
* Application specific definitions.
|
||||||
|
*
|
||||||
|
* These definitions should be adjusted for your particular hardware and
|
||||||
|
* application requirements.
|
||||||
|
*
|
||||||
|
* These parameters and more are described within the 'configuration' section of the
|
||||||
|
* FreeRTOS API documentation available on the FreeRTOS.org web site.
|
||||||
|
*
|
||||||
|
* See http://www.freertos.org/a00110.html
|
||||||
|
*----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* USER CODE BEGIN Includes */
|
||||||
|
/* Section where include file can be added */
|
||||||
|
/* USER CODE END Includes */
|
||||||
|
|
||||||
|
/* Ensure definitions are only used by the compiler, and not by the assembler. */
|
||||||
|
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
|
||||||
|
#include <stdint.h>
|
||||||
|
extern uint32_t SystemCoreClock;
|
||||||
|
#endif
|
||||||
|
#ifndef CMSIS_device_header
|
||||||
|
#define CMSIS_device_header "stm32f4xx.h"
|
||||||
|
#endif /* CMSIS_device_header */
|
||||||
|
|
||||||
|
#define configENABLE_FPU 1
|
||||||
|
#define configENABLE_MPU 0
|
||||||
|
|
||||||
|
#define configUSE_PREEMPTION 1
|
||||||
|
#define configSUPPORT_STATIC_ALLOCATION 1
|
||||||
|
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||||
|
#define configUSE_IDLE_HOOK 0
|
||||||
|
#define configUSE_TICK_HOOK 0
|
||||||
|
#define configCPU_CLOCK_HZ ( SystemCoreClock )
|
||||||
|
#define configTICK_RATE_HZ ((TickType_t)1000)
|
||||||
|
#define configMAX_PRIORITIES ( 56 )
|
||||||
|
#define configMINIMAL_STACK_SIZE ((uint16_t)128)
|
||||||
|
#define configTOTAL_HEAP_SIZE ((size_t)30720)
|
||||||
|
#define configMAX_TASK_NAME_LEN ( 16 )
|
||||||
|
#define configUSE_TRACE_FACILITY 1
|
||||||
|
#define configUSE_16_BIT_TICKS 0
|
||||||
|
#define configUSE_MUTEXES 1
|
||||||
|
#define configQUEUE_REGISTRY_SIZE 8
|
||||||
|
#define configUSE_RECURSIVE_MUTEXES 1
|
||||||
|
#define configUSE_COUNTING_SEMAPHORES 1
|
||||||
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
/* USER CODE BEGIN MESSAGE_BUFFER_LENGTH_TYPE */
|
||||||
|
/* Defaults to size_t for backward compatibility, but can be changed
|
||||||
|
if lengths will always be less than the number of bytes in a size_t. */
|
||||||
|
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t
|
||||||
|
/* USER CODE END MESSAGE_BUFFER_LENGTH_TYPE */
|
||||||
|
|
||||||
|
/* Co-routine definitions. */
|
||||||
|
#define configUSE_CO_ROUTINES 0
|
||||||
|
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
|
||||||
|
|
||||||
|
/* Software timer definitions. */
|
||||||
|
#define configUSE_TIMERS 1
|
||||||
|
#define configTIMER_TASK_PRIORITY ( 2 )
|
||||||
|
#define configTIMER_QUEUE_LENGTH 10
|
||||||
|
#define configTIMER_TASK_STACK_DEPTH 256
|
||||||
|
|
||||||
|
/* CMSIS-RTOS V2 flags */
|
||||||
|
#define configUSE_OS2_THREAD_SUSPEND_RESUME 1
|
||||||
|
#define configUSE_OS2_THREAD_ENUMERATE 1
|
||||||
|
#define configUSE_OS2_EVENTFLAGS_FROM_ISR 1
|
||||||
|
#define configUSE_OS2_THREAD_FLAGS 1
|
||||||
|
#define configUSE_OS2_TIMER 1
|
||||||
|
#define configUSE_OS2_MUTEX 1
|
||||||
|
|
||||||
|
/* Set the following definitions to 1 to include the API function, or zero
|
||||||
|
to exclude the API function. */
|
||||||
|
#define INCLUDE_vTaskPrioritySet 1
|
||||||
|
#define INCLUDE_uxTaskPriorityGet 1
|
||||||
|
#define INCLUDE_vTaskDelete 1
|
||||||
|
#define INCLUDE_vTaskCleanUpResources 0
|
||||||
|
#define INCLUDE_vTaskSuspend 1
|
||||||
|
#define INCLUDE_vTaskDelayUntil 1
|
||||||
|
#define INCLUDE_vTaskDelay 1
|
||||||
|
#define INCLUDE_xTaskGetSchedulerState 1
|
||||||
|
#define INCLUDE_xTimerPendFunctionCall 1
|
||||||
|
#define INCLUDE_xQueueGetMutexHolder 1
|
||||||
|
#define INCLUDE_uxTaskGetStackHighWaterMark 1
|
||||||
|
#define INCLUDE_xTaskGetCurrentTaskHandle 1
|
||||||
|
#define INCLUDE_eTaskGetState 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The CMSIS-RTOS V2 FreeRTOS wrapper is dependent on the heap implementation used
|
||||||
|
* by the application thus the correct define need to be enabled below
|
||||||
|
*/
|
||||||
|
#define USE_FreeRTOS_HEAP_4
|
||||||
|
|
||||||
|
/* Cortex-M specific definitions. */
|
||||||
|
#ifdef __NVIC_PRIO_BITS
|
||||||
|
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
|
||||||
|
#define configPRIO_BITS __NVIC_PRIO_BITS
|
||||||
|
#else
|
||||||
|
#define configPRIO_BITS 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The lowest interrupt priority that can be used in a call to a "set priority"
|
||||||
|
function. */
|
||||||
|
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
|
||||||
|
|
||||||
|
/* The highest interrupt priority that can be used by any interrupt service
|
||||||
|
routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
|
||||||
|
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
|
||||||
|
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
|
||||||
|
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
|
||||||
|
|
||||||
|
/* Interrupt priorities used by the kernel port layer itself. These are generic
|
||||||
|
to all Cortex-M ports, and do not rely on any particular library functions. */
|
||||||
|
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
|
||||||
|
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
|
||||||
|
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
|
||||||
|
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
|
||||||
|
|
||||||
|
/* Normal assert() semantics without relying on the provision of an assert.h
|
||||||
|
header file. */
|
||||||
|
/* USER CODE BEGIN 1 */
|
||||||
|
#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );}
|
||||||
|
/* USER CODE END 1 */
|
||||||
|
|
||||||
|
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
|
||||||
|
standard names. */
|
||||||
|
#define vPortSVCHandler SVC_Handler
|
||||||
|
#define xPortPendSVHandler PendSV_Handler
|
||||||
|
|
||||||
|
/* IMPORTANT: After 10.3.1 update, Systick_Handler comes from NVIC (if SYS timebase = systick), otherwise from cmsis_os2.c */
|
||||||
|
|
||||||
|
#define USE_CUSTOM_SYSTICK_HANDLER_IMPLEMENTATION 0
|
||||||
|
|
||||||
|
/* USER CODE BEGIN Defines */
|
||||||
|
/* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */
|
||||||
|
/* USER CODE END Defines */
|
||||||
|
|
||||||
|
#endif /* FREERTOS_CONFIG_H */
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -63,7 +63,7 @@
|
|||||||
/* #define HAL_SD_MODULE_ENABLED */
|
/* #define HAL_SD_MODULE_ENABLED */
|
||||||
/* #define HAL_MMC_MODULE_ENABLED */
|
/* #define HAL_MMC_MODULE_ENABLED */
|
||||||
#define HAL_SPI_MODULE_ENABLED
|
#define HAL_SPI_MODULE_ENABLED
|
||||||
/* #define HAL_TIM_MODULE_ENABLED */
|
#define HAL_TIM_MODULE_ENABLED
|
||||||
#define HAL_UART_MODULE_ENABLED
|
#define HAL_UART_MODULE_ENABLED
|
||||||
/* #define HAL_USART_MODULE_ENABLED */
|
/* #define HAL_USART_MODULE_ENABLED */
|
||||||
/* #define HAL_IRDA_MODULE_ENABLED */
|
/* #define HAL_IRDA_MODULE_ENABLED */
|
||||||
|
|||||||
@@ -51,16 +51,17 @@ void HardFault_Handler(void);
|
|||||||
void MemManage_Handler(void);
|
void MemManage_Handler(void);
|
||||||
void BusFault_Handler(void);
|
void BusFault_Handler(void);
|
||||||
void UsageFault_Handler(void);
|
void UsageFault_Handler(void);
|
||||||
void SVC_Handler(void);
|
|
||||||
void DebugMon_Handler(void);
|
void DebugMon_Handler(void);
|
||||||
void PendSV_Handler(void);
|
void DMA1_Stream3_IRQHandler(void);
|
||||||
void SysTick_Handler(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);
|
||||||
void UART4_IRQHandler(void);
|
void UART4_IRQHandler(void);
|
||||||
void UART5_IRQHandler(void);
|
void UART5_IRQHandler(void);
|
||||||
|
void TIM7_IRQHandler(void);
|
||||||
void DMA2_Stream2_IRQHandler(void);
|
void DMA2_Stream2_IRQHandler(void);
|
||||||
void DMA2_Stream7_IRQHandler(void);
|
void DMA2_Stream7_IRQHandler(void);
|
||||||
/* USER CODE BEGIN EFP */
|
/* USER CODE BEGIN EFP */
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
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%
|
||||||
4
MDK-ARM/build_log.txt
Normal file
4
MDK-ARM/build_log.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
*** Using Compiler 'V5.06 update 7 (build 960)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
|
||||||
|
Build target 'STM32F407-Demo'
|
||||||
|
".\STM32F407-Demo\STM32F407-Demo.axf" - 0 Error(s), 0 Warning(s).
|
||||||
|
Build Time Elapsed: 00:00:00
|
||||||
846
Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os.h
vendored
Normal file
846
Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os.h
vendored
Normal file
@@ -0,0 +1,846 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2019 ARM Limited. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* $Date: 10. January 2017
|
||||||
|
* $Revision: V2.1.0
|
||||||
|
*
|
||||||
|
* Project: CMSIS-RTOS API
|
||||||
|
* Title: cmsis_os.h FreeRTOS header file
|
||||||
|
*
|
||||||
|
* Version 0.02
|
||||||
|
* Initial Proposal Phase
|
||||||
|
* Version 0.03
|
||||||
|
* osKernelStart added, optional feature: main started as thread
|
||||||
|
* osSemaphores have standard behavior
|
||||||
|
* osTimerCreate does not start the timer, added osTimerStart
|
||||||
|
* osThreadPass is renamed to osThreadYield
|
||||||
|
* Version 1.01
|
||||||
|
* Support for C++ interface
|
||||||
|
* - const attribute removed from the osXxxxDef_t typedefs
|
||||||
|
* - const attribute added to the osXxxxDef macros
|
||||||
|
* Added: osTimerDelete, osMutexDelete, osSemaphoreDelete
|
||||||
|
* Added: osKernelInitialize
|
||||||
|
* Version 1.02
|
||||||
|
* Control functions for short timeouts in microsecond resolution:
|
||||||
|
* Added: osKernelSysTick, osKernelSysTickFrequency, osKernelSysTickMicroSec
|
||||||
|
* Removed: osSignalGet
|
||||||
|
* Version 2.0.0
|
||||||
|
* OS objects creation without macros (dynamic creation and resource allocation):
|
||||||
|
* - added: osXxxxNew functions which replace osXxxxCreate
|
||||||
|
* - added: osXxxxAttr_t structures
|
||||||
|
* - deprecated: osXxxxCreate functions, osXxxxDef_t structures
|
||||||
|
* - deprecated: osXxxxDef and osXxxx macros
|
||||||
|
* osStatus codes simplified and renamed to osStatus_t
|
||||||
|
* osEvent return structure deprecated
|
||||||
|
* Kernel:
|
||||||
|
* - added: osKernelInfo_t and osKernelGetInfo
|
||||||
|
* - added: osKernelState_t and osKernelGetState (replaces osKernelRunning)
|
||||||
|
* - added: osKernelLock, osKernelUnlock
|
||||||
|
* - added: osKernelSuspend, osKernelResume
|
||||||
|
* - added: osKernelGetTickCount, osKernelGetTickFreq
|
||||||
|
* - renamed osKernelSysTick to osKernelGetSysTimerCount
|
||||||
|
* - replaced osKernelSysTickFrequency with osKernelGetSysTimerFreq
|
||||||
|
* - deprecated osKernelSysTickMicroSec
|
||||||
|
* Thread:
|
||||||
|
* - extended number of thread priorities
|
||||||
|
* - renamed osPrioriry to osPrioriry_t
|
||||||
|
* - replaced osThreadCreate with osThreadNew
|
||||||
|
* - added: osThreadGetName
|
||||||
|
* - added: osThreadState_t and osThreadGetState
|
||||||
|
* - added: osThreadGetStackSize, osThreadGetStackSpace
|
||||||
|
* - added: osThreadSuspend, osThreadResume
|
||||||
|
* - added: osThreadJoin, osThreadDetach, osThreadExit
|
||||||
|
* - added: osThreadGetCount, osThreadEnumerate
|
||||||
|
* - added: Thread Flags (moved from Signals)
|
||||||
|
* Signals:
|
||||||
|
* - renamed osSignals to osThreadFlags (moved to Thread Flags)
|
||||||
|
* - changed return value of Set/Clear/Wait functions
|
||||||
|
* - Clear function limited to current running thread
|
||||||
|
* - extended Wait function (options)
|
||||||
|
* - added: osThreadFlagsGet
|
||||||
|
* Event Flags:
|
||||||
|
* - added new independent object for handling Event Flags
|
||||||
|
* Delay and Wait functions:
|
||||||
|
* - added: osDelayUntil
|
||||||
|
* - deprecated: osWait
|
||||||
|
* Timer:
|
||||||
|
* - replaced osTimerCreate with osTimerNew
|
||||||
|
* - added: osTimerGetName, osTimerIsRunning
|
||||||
|
* Mutex:
|
||||||
|
* - extended: attributes (Recursive, Priority Inherit, Robust)
|
||||||
|
* - replaced osMutexCreate with osMutexNew
|
||||||
|
* - renamed osMutexWait to osMutexAcquire
|
||||||
|
* - added: osMutexGetName, osMutexGetOwner
|
||||||
|
* Semaphore:
|
||||||
|
* - extended: maximum and initial token count
|
||||||
|
* - replaced osSemaphoreCreate with osSemaphoreNew
|
||||||
|
* - renamed osSemaphoreWait to osSemaphoreAcquire (changed return value)
|
||||||
|
* - added: osSemaphoreGetName, osSemaphoreGetCount
|
||||||
|
* Memory Pool:
|
||||||
|
* - using osMemoryPool prefix instead of osPool
|
||||||
|
* - replaced osPoolCreate with osMemoryPoolNew
|
||||||
|
* - extended osMemoryPoolAlloc (timeout)
|
||||||
|
* - added: osMemoryPoolGetName
|
||||||
|
* - added: osMemoryPoolGetCapacity, osMemoryPoolGetBlockSize
|
||||||
|
* - added: osMemoryPoolGetCount, osMemoryPoolGetSpace
|
||||||
|
* - added: osMemoryPoolDelete
|
||||||
|
* - deprecated: osPoolCAlloc
|
||||||
|
* Message Queue:
|
||||||
|
* - extended: fixed size message instead of a single 32-bit value
|
||||||
|
* - using osMessageQueue prefix instead of osMessage
|
||||||
|
* - replaced osMessageCreate with osMessageQueueNew
|
||||||
|
* - updated: osMessageQueuePut, osMessageQueueGet
|
||||||
|
* - added: osMessageQueueGetName
|
||||||
|
* - added: osMessageQueueGetCapacity, osMessageQueueGetMsgSize
|
||||||
|
* - added: osMessageQueueGetCount, osMessageQueueGetSpace
|
||||||
|
* - added: osMessageQueueReset, osMessageQueueDelete
|
||||||
|
* Mail Queue:
|
||||||
|
* - deprecated (superseded by extended Message Queue functionality)
|
||||||
|
* Version 2.1.0
|
||||||
|
* Support for critical and uncritical sections (nesting safe):
|
||||||
|
* - updated: osKernelLock, osKernelUnlock
|
||||||
|
* - added: osKernelRestoreLock
|
||||||
|
* Updated Thread and Event Flags:
|
||||||
|
* - changed flags parameter and return type from int32_t to uint32_t
|
||||||
|
*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef CMSIS_OS_H_
|
||||||
|
#define CMSIS_OS_H_
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
|
||||||
|
#define RTOS_ID_n ((tskKERNEL_VERSION_MAJOR << 16) | (tskKERNEL_VERSION_MINOR))
|
||||||
|
#define RTOS_ID_s ("FreeRTOS " tskKERNEL_VERSION_NUMBER)
|
||||||
|
|
||||||
|
#define osCMSIS 0x20001U ///< API version (main[31:16].sub[15:0])
|
||||||
|
|
||||||
|
#define osCMSIS_FreeRTOS RTOS_ID_n ///< RTOS identification and version (main[31:16].sub[15:0])
|
||||||
|
|
||||||
|
#define osKernelSystemId RTOS_ID_s ///< RTOS identification string
|
||||||
|
|
||||||
|
#define osFeature_MainThread 0 ///< main thread 1=main can be thread, 0=not available
|
||||||
|
#define osFeature_Signals 24U ///< maximum number of Signal Flags available per thread
|
||||||
|
#define osFeature_Semaphore 65535U ///< maximum count for \ref osSemaphoreCreate function
|
||||||
|
#define osFeature_Wait 0 ///< osWait function: 1=available, 0=not available
|
||||||
|
#define osFeature_SysTick 1 ///< osKernelSysTick functions: 1=available, 0=not available
|
||||||
|
#define osFeature_Pool 0 ///< Memory Pools: 1=available, 0=not available
|
||||||
|
#define osFeature_MessageQ 1 ///< Message Queues: 1=available, 0=not available
|
||||||
|
#define osFeature_MailQ 0 ///< Mail Queues: 1=available, 0=not available
|
||||||
|
|
||||||
|
#if defined(__CC_ARM)
|
||||||
|
#define os_InRegs __value_in_regs
|
||||||
|
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
|
||||||
|
#define os_InRegs __attribute__((value_in_regs))
|
||||||
|
#else
|
||||||
|
#define os_InRegs
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "cmsis_os2.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// ==== Enumerations, structures, defines ====
|
||||||
|
|
||||||
|
/// Priority values.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
typedef enum {
|
||||||
|
osPriorityIdle = -3, ///< Priority: idle (lowest)
|
||||||
|
osPriorityLow = -2, ///< Priority: low
|
||||||
|
osPriorityBelowNormal = -1, ///< Priority: below normal
|
||||||
|
osPriorityNormal = 0, ///< Priority: normal (default)
|
||||||
|
osPriorityAboveNormal = +1, ///< Priority: above normal
|
||||||
|
osPriorityHigh = +2, ///< Priority: high
|
||||||
|
osPriorityRealtime = +3, ///< Priority: realtime (highest)
|
||||||
|
osPriorityError = 0x84, ///< System cannot determine priority or illegal priority.
|
||||||
|
osPriorityReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization.
|
||||||
|
} osPriority;
|
||||||
|
#else
|
||||||
|
#define osPriority osPriority_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Entry point of a thread.
|
||||||
|
typedef void (*os_pthread) (void const *argument);
|
||||||
|
|
||||||
|
/// Entry point of a timer call back function.
|
||||||
|
typedef void (*os_ptimer) (void const *argument);
|
||||||
|
|
||||||
|
/// Timer type.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
typedef enum {
|
||||||
|
osTimerOnce = 0, ///< One-shot timer.
|
||||||
|
osTimerPeriodic = 1 ///< Repeating timer.
|
||||||
|
} os_timer_type;
|
||||||
|
#else
|
||||||
|
#define os_timer_type osTimerType_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Timeout value.
|
||||||
|
#define osWaitForever 0xFFFFFFFFU ///< Wait forever timeout value.
|
||||||
|
|
||||||
|
/// Status code values returned by CMSIS-RTOS functions.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
typedef enum {
|
||||||
|
osOK = 0, ///< Function completed; no error or event occurred.
|
||||||
|
osEventSignal = 0x08, ///< Function completed; signal event occurred.
|
||||||
|
osEventMessage = 0x10, ///< Function completed; message event occurred.
|
||||||
|
osEventMail = 0x20, ///< Function completed; mail event occurred.
|
||||||
|
osEventTimeout = 0x40, ///< Function completed; timeout occurred.
|
||||||
|
osErrorParameter = 0x80, ///< Parameter error: a mandatory parameter was missing or specified an incorrect object.
|
||||||
|
osErrorResource = 0x81, ///< Resource not available: a specified resource was not available.
|
||||||
|
osErrorTimeoutResource = 0xC1, ///< Resource not available within given time: a specified resource was not available within the timeout period.
|
||||||
|
osErrorISR = 0x82, ///< Not allowed in ISR context: the function cannot be called from interrupt service routines.
|
||||||
|
osErrorISRRecursive = 0x83, ///< Function called multiple times from ISR with same object.
|
||||||
|
osErrorPriority = 0x84, ///< System cannot determine priority or thread has illegal priority.
|
||||||
|
osErrorNoMemory = 0x85, ///< System is out of memory: it was impossible to allocate or reserve memory for the operation.
|
||||||
|
osErrorValue = 0x86, ///< Value of a parameter is out of range.
|
||||||
|
osErrorOS = 0xFF, ///< Unspecified RTOS error: run-time error but no other error message fits.
|
||||||
|
osStatusReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization.
|
||||||
|
} osStatus;
|
||||||
|
#else
|
||||||
|
typedef int32_t osStatus;
|
||||||
|
#define osEventSignal (0x08)
|
||||||
|
#define osEventMessage (0x10)
|
||||||
|
#define osEventMail (0x20)
|
||||||
|
#define osEventTimeout (0x40)
|
||||||
|
#define osErrorOS osError
|
||||||
|
#define osErrorTimeoutResource osErrorTimeout
|
||||||
|
#define osErrorISRRecursive (-126)
|
||||||
|
#define osErrorValue (-127)
|
||||||
|
#define osErrorPriority (-128)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// >>> the following data type definitions may be adapted towards a specific RTOS
|
||||||
|
|
||||||
|
/// Thread ID identifies the thread.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
typedef void *osThreadId;
|
||||||
|
#else
|
||||||
|
#define osThreadId osThreadId_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Timer ID identifies the timer.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
typedef void *osTimerId;
|
||||||
|
#else
|
||||||
|
#define osTimerId osTimerId_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Mutex ID identifies the mutex.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
typedef void *osMutexId;
|
||||||
|
#else
|
||||||
|
#define osMutexId osMutexId_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Semaphore ID identifies the semaphore.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
typedef void *osSemaphoreId;
|
||||||
|
#else
|
||||||
|
#define osSemaphoreId osSemaphoreId_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Pool ID identifies the memory pool.
|
||||||
|
typedef void *osPoolId;
|
||||||
|
|
||||||
|
/// Message ID identifies the message queue.
|
||||||
|
typedef void *osMessageQId;
|
||||||
|
|
||||||
|
/// Mail ID identifies the mail queue.
|
||||||
|
typedef void *osMailQId;
|
||||||
|
|
||||||
|
|
||||||
|
/// Thread Definition structure contains startup information of a thread.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
typedef struct os_thread_def {
|
||||||
|
os_pthread pthread; ///< start address of thread function
|
||||||
|
osPriority tpriority; ///< initial thread priority
|
||||||
|
uint32_t instances; ///< maximum number of instances of that thread function
|
||||||
|
uint32_t stacksize; ///< stack size requirements in bytes; 0 is default stack size
|
||||||
|
} osThreadDef_t;
|
||||||
|
#else
|
||||||
|
typedef struct os_thread_def {
|
||||||
|
os_pthread pthread; ///< start address of thread function
|
||||||
|
osThreadAttr_t attr; ///< thread attributes
|
||||||
|
} osThreadDef_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Timer Definition structure contains timer parameters.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
typedef struct os_timer_def {
|
||||||
|
os_ptimer ptimer; ///< start address of a timer function
|
||||||
|
} osTimerDef_t;
|
||||||
|
#else
|
||||||
|
typedef struct os_timer_def {
|
||||||
|
os_ptimer ptimer; ///< start address of a timer function
|
||||||
|
osTimerAttr_t attr; ///< timer attributes
|
||||||
|
} osTimerDef_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Mutex Definition structure contains setup information for a mutex.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
typedef struct os_mutex_def {
|
||||||
|
uint32_t dummy; ///< dummy value
|
||||||
|
} osMutexDef_t;
|
||||||
|
#else
|
||||||
|
#define osMutexDef_t osMutexAttr_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Semaphore Definition structure contains setup information for a semaphore.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
typedef struct os_semaphore_def {
|
||||||
|
uint32_t dummy; ///< dummy value
|
||||||
|
} osSemaphoreDef_t;
|
||||||
|
#else
|
||||||
|
#define osSemaphoreDef_t osSemaphoreAttr_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Definition structure for memory block allocation.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
typedef struct os_pool_def {
|
||||||
|
uint32_t pool_sz; ///< number of items (elements) in the pool
|
||||||
|
uint32_t item_sz; ///< size of an item
|
||||||
|
void *pool; ///< pointer to memory for pool
|
||||||
|
} osPoolDef_t;
|
||||||
|
#else
|
||||||
|
typedef struct os_pool_def {
|
||||||
|
uint32_t pool_sz; ///< number of items (elements) in the pool
|
||||||
|
uint32_t item_sz; ///< size of an item
|
||||||
|
osMemoryPoolAttr_t attr; ///< memory pool attributes
|
||||||
|
} osPoolDef_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Definition structure for message queue.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
typedef struct os_messageQ_def {
|
||||||
|
uint32_t queue_sz; ///< number of elements in the queue
|
||||||
|
void *pool; ///< memory array for messages
|
||||||
|
} osMessageQDef_t;
|
||||||
|
#else
|
||||||
|
typedef struct os_messageQ_def {
|
||||||
|
uint32_t queue_sz; ///< number of elements in the queue
|
||||||
|
osMessageQueueAttr_t attr; ///< message queue attributes
|
||||||
|
} osMessageQDef_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Definition structure for mail queue.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
typedef struct os_mailQ_def {
|
||||||
|
uint32_t queue_sz; ///< number of elements in the queue
|
||||||
|
uint32_t item_sz; ///< size of an item
|
||||||
|
void *pool; ///< memory array for mail
|
||||||
|
} osMailQDef_t;
|
||||||
|
#else
|
||||||
|
typedef struct os_mailQ_def {
|
||||||
|
uint32_t queue_sz; ///< number of elements in the queue
|
||||||
|
uint32_t item_sz; ///< size of an item
|
||||||
|
void *mail; ///< pointer to mail
|
||||||
|
osMemoryPoolAttr_t mp_attr; ///< memory pool attributes
|
||||||
|
osMessageQueueAttr_t mq_attr; ///< message queue attributes
|
||||||
|
} osMailQDef_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/// Event structure contains detailed information about an event.
|
||||||
|
typedef struct {
|
||||||
|
osStatus status; ///< status code: event or error information
|
||||||
|
union {
|
||||||
|
uint32_t v; ///< message as 32-bit value
|
||||||
|
void *p; ///< message or mail as void pointer
|
||||||
|
int32_t signals; ///< signal flags
|
||||||
|
} value; ///< event value
|
||||||
|
union {
|
||||||
|
osMailQId mail_id; ///< mail id obtained by \ref osMailCreate
|
||||||
|
osMessageQId message_id; ///< message id obtained by \ref osMessageCreate
|
||||||
|
} def; ///< event definition
|
||||||
|
} osEvent;
|
||||||
|
|
||||||
|
|
||||||
|
// ==== Kernel Management Functions ====
|
||||||
|
|
||||||
|
/// Initialize the RTOS Kernel for creating objects.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
osStatus osKernelInitialize (void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Start the RTOS Kernel scheduler.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
osStatus osKernelStart (void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Check if the RTOS kernel is already started.
|
||||||
|
/// \return 0 RTOS is not started, 1 RTOS is started.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
int32_t osKernelRunning(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(osFeature_SysTick) && (osFeature_SysTick != 0)) // System Timer available
|
||||||
|
|
||||||
|
/// Get the RTOS kernel system timer counter.
|
||||||
|
/// \return RTOS kernel system timer as 32-bit value
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
uint32_t osKernelSysTick (void);
|
||||||
|
#else
|
||||||
|
#define osKernelSysTick osKernelGetSysTimerCount
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// The RTOS kernel system timer frequency in Hz.
|
||||||
|
/// \note Reflects the system timer setting and is typically defined in a configuration file.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
#define osKernelSysTickFrequency 100000000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Convert a microseconds value to a RTOS kernel system timer value.
|
||||||
|
/// \param microsec time value in microseconds.
|
||||||
|
/// \return time value normalized to the \ref osKernelSysTickFrequency
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
#define osKernelSysTickMicroSec(microsec) (((uint64_t)microsec * (osKernelSysTickFrequency)) / 1000000)
|
||||||
|
#else
|
||||||
|
#define osKernelSysTickMicroSec(microsec) (((uint64_t)microsec * osKernelGetSysTimerFreq()) / 1000000)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // System Timer available
|
||||||
|
|
||||||
|
|
||||||
|
// ==== Thread Management Functions ====
|
||||||
|
|
||||||
|
/// Create a Thread Definition with function, priority, and stack requirements.
|
||||||
|
/// \param name name of the thread function.
|
||||||
|
/// \param priority initial priority of the thread function.
|
||||||
|
/// \param instances number of possible thread instances.
|
||||||
|
/// \param stacksz stack size (in bytes) requirements for the thread function.
|
||||||
|
#if defined (osObjectsExternal) // object is external
|
||||||
|
#define osThreadDef(name, priority, instances, stacksz) \
|
||||||
|
extern const osThreadDef_t os_thread_def_##name
|
||||||
|
#else // define the object
|
||||||
|
#define osThreadDef(name, priority, instances, stacksz) \
|
||||||
|
static uint64_t os_thread_stack##name[(stacksz)?(((stacksz+7)/8)):1]; \
|
||||||
|
static StaticTask_t os_thread_cb_##name; \
|
||||||
|
const osThreadDef_t os_thread_def_##name = \
|
||||||
|
{ (name), \
|
||||||
|
{ NULL, osThreadDetached, \
|
||||||
|
(instances == 1) ? (&os_thread_cb_##name) : NULL,\
|
||||||
|
(instances == 1) ? sizeof(StaticTask_t) : 0U, \
|
||||||
|
((stacksz) && (instances == 1)) ? (&os_thread_stack##name) : NULL, \
|
||||||
|
8*((stacksz+7)/8), \
|
||||||
|
(priority), 0U, 0U } }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Access a Thread definition.
|
||||||
|
/// \param name name of the thread definition object.
|
||||||
|
#define osThread(name) \
|
||||||
|
&os_thread_def_##name
|
||||||
|
|
||||||
|
/// Create a thread and add it to Active Threads and set it to state READY.
|
||||||
|
/// \param[in] thread_def thread definition referenced with \ref osThread.
|
||||||
|
/// \param[in] argument pointer that is passed to the thread function as start argument.
|
||||||
|
/// \return thread ID for reference by other functions or NULL in case of error.
|
||||||
|
osThreadId osThreadCreate (const osThreadDef_t *thread_def, void *argument);
|
||||||
|
|
||||||
|
/// Return the thread ID of the current running thread.
|
||||||
|
/// \return thread ID for reference by other functions or NULL in case of error.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
osThreadId osThreadGetId (void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Change priority of a thread.
|
||||||
|
/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
|
||||||
|
/// \param[in] priority new priority value for the thread function.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
osStatus osThreadSetPriority (osThreadId thread_id, osPriority priority);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Get current priority of a thread.
|
||||||
|
/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
|
||||||
|
/// \return current priority value of the specified thread.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
osPriority osThreadGetPriority (osThreadId thread_id);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Pass control to next thread that is in state \b READY.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
osStatus osThreadYield (void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Terminate execution of a thread.
|
||||||
|
/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
osStatus osThreadTerminate (osThreadId thread_id);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// ==== Signal Management ====
|
||||||
|
|
||||||
|
/// Set the specified Signal Flags of an active thread.
|
||||||
|
/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
|
||||||
|
/// \param[in] signals specifies the signal flags of the thread that should be set.
|
||||||
|
/// \return previous signal flags of the specified thread or 0x80000000 in case of incorrect parameters.
|
||||||
|
int32_t osSignalSet (osThreadId thread_id, int32_t signals);
|
||||||
|
|
||||||
|
/// Clear the specified Signal Flags of an active thread.
|
||||||
|
/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
|
||||||
|
/// \param[in] signals specifies the signal flags of the thread that shall be cleared.
|
||||||
|
/// \return previous signal flags of the specified thread or 0x80000000 in case of incorrect parameters or call from ISR.
|
||||||
|
int32_t osSignalClear (osThreadId thread_id, int32_t signals);
|
||||||
|
|
||||||
|
/// Wait for one or more Signal Flags to become signaled for the current \b RUNNING thread.
|
||||||
|
/// \param[in] signals wait until all specified signal flags set or 0 for any single signal flag.
|
||||||
|
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||||
|
/// \return event flag information or error code.
|
||||||
|
os_InRegs osEvent osSignalWait (int32_t signals, uint32_t millisec);
|
||||||
|
|
||||||
|
|
||||||
|
// ==== Generic Wait Functions ====
|
||||||
|
|
||||||
|
/// Wait for Timeout (Time Delay).
|
||||||
|
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue "time delay" value
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
osStatus osDelay (uint32_t millisec);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined (osFeature_Wait) && (osFeature_Wait != 0)) // Generic Wait available
|
||||||
|
|
||||||
|
/// Wait for Signal, Message, Mail, or Timeout.
|
||||||
|
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out
|
||||||
|
/// \return event that contains signal, message, or mail information or error code.
|
||||||
|
os_InRegs osEvent osWait (uint32_t millisec);
|
||||||
|
|
||||||
|
#endif // Generic Wait available
|
||||||
|
|
||||||
|
|
||||||
|
// ==== Timer Management Functions ====
|
||||||
|
|
||||||
|
/// Define a Timer object.
|
||||||
|
/// \param name name of the timer object.
|
||||||
|
/// \param function name of the timer call back function.
|
||||||
|
#if defined (osObjectsExternal) // object is external
|
||||||
|
#define osTimerDef(name, function) \
|
||||||
|
extern const osTimerDef_t os_timer_def_##name
|
||||||
|
#else // define the object
|
||||||
|
#define osTimerDef(name, function) \
|
||||||
|
static StaticTimer_t os_timer_cb_##name; \
|
||||||
|
const osTimerDef_t os_timer_def_##name = \
|
||||||
|
{ (function), { NULL, 0U, (&os_timer_cb_##name), sizeof(StaticTimer_t) } }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Access a Timer definition.
|
||||||
|
/// \param name name of the timer object.
|
||||||
|
#define osTimer(name) \
|
||||||
|
&os_timer_def_##name
|
||||||
|
|
||||||
|
/// Create and Initialize a timer.
|
||||||
|
/// \param[in] timer_def timer object referenced with \ref osTimer.
|
||||||
|
/// \param[in] type osTimerOnce for one-shot or osTimerPeriodic for periodic behavior.
|
||||||
|
/// \param[in] argument argument to the timer call back function.
|
||||||
|
/// \return timer ID for reference by other functions or NULL in case of error.
|
||||||
|
osTimerId osTimerCreate (const osTimerDef_t *timer_def, os_timer_type type, void *argument);
|
||||||
|
|
||||||
|
/// Start or restart a timer.
|
||||||
|
/// \param[in] timer_id timer ID obtained by \ref osTimerCreate.
|
||||||
|
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue "time delay" value of the timer.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
osStatus osTimerStart (osTimerId timer_id, uint32_t millisec);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Stop a timer.
|
||||||
|
/// \param[in] timer_id timer ID obtained by \ref osTimerCreate.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
osStatus osTimerStop (osTimerId timer_id);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Delete a timer.
|
||||||
|
/// \param[in] timer_id timer ID obtained by \ref osTimerCreate.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
osStatus osTimerDelete (osTimerId timer_id);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// ==== Mutex Management Functions ====
|
||||||
|
|
||||||
|
/// Define a Mutex.
|
||||||
|
/// \param name name of the mutex object.
|
||||||
|
#if defined (osObjectsExternal) // object is external
|
||||||
|
#define osMutexDef(name) \
|
||||||
|
extern const osMutexDef_t os_mutex_def_##name
|
||||||
|
#else // define the object
|
||||||
|
#define osMutexDef(name) \
|
||||||
|
static StaticSemaphore_t os_mutex_cb_##name; \
|
||||||
|
const osMutexDef_t os_mutex_def_##name = \
|
||||||
|
{ NULL, osMutexRecursive | osMutexPrioInherit, (&os_mutex_cb_##name), sizeof(StaticSemaphore_t) }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Access a Mutex definition.
|
||||||
|
/// \param name name of the mutex object.
|
||||||
|
#define osMutex(name) \
|
||||||
|
&os_mutex_def_##name
|
||||||
|
|
||||||
|
/// Create and Initialize a Mutex object.
|
||||||
|
/// \param[in] mutex_def mutex definition referenced with \ref osMutex.
|
||||||
|
/// \return mutex ID for reference by other functions or NULL in case of error.
|
||||||
|
osMutexId osMutexCreate (const osMutexDef_t *mutex_def);
|
||||||
|
|
||||||
|
/// Wait until a Mutex becomes available.
|
||||||
|
/// \param[in] mutex_id mutex ID obtained by \ref osMutexCreate.
|
||||||
|
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
osStatus osMutexWait (osMutexId mutex_id, uint32_t millisec);
|
||||||
|
#else
|
||||||
|
#define osMutexWait osMutexAcquire
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Release a Mutex that was obtained by \ref osMutexWait.
|
||||||
|
/// \param[in] mutex_id mutex ID obtained by \ref osMutexCreate.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
osStatus osMutexRelease (osMutexId mutex_id);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Delete a Mutex object.
|
||||||
|
/// \param[in] mutex_id mutex ID obtained by \ref osMutexCreate.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
osStatus osMutexDelete (osMutexId mutex_id);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// ==== Semaphore Management Functions ====
|
||||||
|
|
||||||
|
#if (defined (osFeature_Semaphore) && (osFeature_Semaphore != 0U)) // Semaphore available
|
||||||
|
|
||||||
|
/// Define a Semaphore object.
|
||||||
|
/// \param name name of the semaphore object.
|
||||||
|
#if defined (osObjectsExternal) // object is external
|
||||||
|
#define osSemaphoreDef(name) \
|
||||||
|
extern const osSemaphoreDef_t os_semaphore_def_##name
|
||||||
|
#else // define the object
|
||||||
|
#define osSemaphoreDef(name) \
|
||||||
|
static StaticSemaphore_t os_semaphore_cb_##name; \
|
||||||
|
const osSemaphoreDef_t os_semaphore_def_##name = \
|
||||||
|
{ NULL, 0U, (&os_semaphore_cb_##name), sizeof(StaticSemaphore_t) }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Access a Semaphore definition.
|
||||||
|
/// \param name name of the semaphore object.
|
||||||
|
#define osSemaphore(name) \
|
||||||
|
&os_semaphore_def_##name
|
||||||
|
|
||||||
|
/// Create and Initialize a Semaphore object.
|
||||||
|
/// \param[in] semaphore_def semaphore definition referenced with \ref osSemaphore.
|
||||||
|
/// \param[in] count maximum and initial number of available tokens.
|
||||||
|
/// \return semaphore ID for reference by other functions or NULL in case of error.
|
||||||
|
osSemaphoreId osSemaphoreCreate (const osSemaphoreDef_t *semaphore_def, int32_t count);
|
||||||
|
|
||||||
|
/// Wait until a Semaphore token becomes available.
|
||||||
|
/// \param[in] semaphore_id semaphore object referenced with \ref osSemaphoreCreate.
|
||||||
|
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||||
|
/// \return number of available tokens, or -1 in case of incorrect parameters.
|
||||||
|
int32_t osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec);
|
||||||
|
|
||||||
|
/// Release a Semaphore token.
|
||||||
|
/// \param[in] semaphore_id semaphore object referenced with \ref osSemaphoreCreate.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
osStatus osSemaphoreRelease (osSemaphoreId semaphore_id);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Delete a Semaphore object.
|
||||||
|
/// \param[in] semaphore_id semaphore object referenced with \ref osSemaphoreCreate.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
#if (osCMSIS < 0x20000U)
|
||||||
|
osStatus osSemaphoreDelete (osSemaphoreId semaphore_id);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // Semaphore available
|
||||||
|
|
||||||
|
|
||||||
|
// ==== Memory Pool Management Functions ====
|
||||||
|
|
||||||
|
#if (defined(osFeature_Pool) && (osFeature_Pool != 0)) // Memory Pool available
|
||||||
|
|
||||||
|
/// \brief Define a Memory Pool.
|
||||||
|
/// \param name name of the memory pool.
|
||||||
|
/// \param no maximum number of blocks (objects) in the memory pool.
|
||||||
|
/// \param type data type of a single block (object).
|
||||||
|
#if defined (osObjectsExternal) // object is external
|
||||||
|
#define osPoolDef(name, no, type) \
|
||||||
|
extern const osPoolDef_t os_pool_def_##name
|
||||||
|
#else // define the object
|
||||||
|
#define osPoolDef(name, no, type) \
|
||||||
|
const osPoolDef_t os_pool_def_##name = \
|
||||||
|
{ (no), sizeof(type), {NULL} }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// \brief Access a Memory Pool definition.
|
||||||
|
/// \param name name of the memory pool
|
||||||
|
#define osPool(name) \
|
||||||
|
&os_pool_def_##name
|
||||||
|
|
||||||
|
/// Create and Initialize a Memory Pool object.
|
||||||
|
/// \param[in] pool_def memory pool definition referenced with \ref osPool.
|
||||||
|
/// \return memory pool ID for reference by other functions or NULL in case of error.
|
||||||
|
osPoolId osPoolCreate (const osPoolDef_t *pool_def);
|
||||||
|
|
||||||
|
/// Allocate a memory block from a Memory Pool.
|
||||||
|
/// \param[in] pool_id memory pool ID obtain referenced with \ref osPoolCreate.
|
||||||
|
/// \return address of the allocated memory block or NULL in case of no memory available.
|
||||||
|
void *osPoolAlloc (osPoolId pool_id);
|
||||||
|
|
||||||
|
/// Allocate a memory block from a Memory Pool and set memory block to zero.
|
||||||
|
/// \param[in] pool_id memory pool ID obtain referenced with \ref osPoolCreate.
|
||||||
|
/// \return address of the allocated memory block or NULL in case of no memory available.
|
||||||
|
void *osPoolCAlloc (osPoolId pool_id);
|
||||||
|
|
||||||
|
/// Return an allocated memory block back to a Memory Pool.
|
||||||
|
/// \param[in] pool_id memory pool ID obtain referenced with \ref osPoolCreate.
|
||||||
|
/// \param[in] block address of the allocated memory block to be returned to the memory pool.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus osPoolFree (osPoolId pool_id, void *block);
|
||||||
|
|
||||||
|
#endif // Memory Pool available
|
||||||
|
|
||||||
|
|
||||||
|
// ==== Message Queue Management Functions ====
|
||||||
|
|
||||||
|
#if (defined(osFeature_MessageQ) && (osFeature_MessageQ != 0)) // Message Queue available
|
||||||
|
|
||||||
|
/// \brief Create a Message Queue Definition.
|
||||||
|
/// \param name name of the queue.
|
||||||
|
/// \param queue_sz maximum number of messages in the queue.
|
||||||
|
/// \param type data type of a single message element (for debugger).
|
||||||
|
#if defined (osObjectsExternal) // object is external
|
||||||
|
#define osMessageQDef(name, queue_sz, type) \
|
||||||
|
extern const osMessageQDef_t os_messageQ_def_##name
|
||||||
|
#else // define the object
|
||||||
|
#define osMessageQDef(name, queue_sz, type) \
|
||||||
|
static StaticQueue_t os_mq_cb_##name; \
|
||||||
|
static uint32_t os_mq_data_##name[(queue_sz) * sizeof(type)]; \
|
||||||
|
const osMessageQDef_t os_messageQ_def_##name = \
|
||||||
|
{ (queue_sz), \
|
||||||
|
{ NULL, 0U, (&os_mq_cb_##name), sizeof(StaticQueue_t), \
|
||||||
|
(&os_mq_data_##name), sizeof(os_mq_data_##name) } }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// \brief Access a Message Queue Definition.
|
||||||
|
/// \param name name of the queue
|
||||||
|
#define osMessageQ(name) \
|
||||||
|
&os_messageQ_def_##name
|
||||||
|
|
||||||
|
/// Create and Initialize a Message Queue object.
|
||||||
|
/// \param[in] queue_def message queue definition referenced with \ref osMessageQ.
|
||||||
|
/// \param[in] thread_id thread ID (obtained by \ref osThreadCreate or \ref osThreadGetId) or NULL.
|
||||||
|
/// \return message queue ID for reference by other functions or NULL in case of error.
|
||||||
|
osMessageQId osMessageCreate (const osMessageQDef_t *queue_def, osThreadId thread_id);
|
||||||
|
|
||||||
|
/// Put a Message to a Queue.
|
||||||
|
/// \param[in] queue_id message queue ID obtained with \ref osMessageCreate.
|
||||||
|
/// \param[in] info message information.
|
||||||
|
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec);
|
||||||
|
|
||||||
|
/// Get a Message from a Queue or timeout if Queue is empty.
|
||||||
|
/// \param[in] queue_id message queue ID obtained with \ref osMessageCreate.
|
||||||
|
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||||
|
/// \return event information that includes status code.
|
||||||
|
os_InRegs osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec);
|
||||||
|
|
||||||
|
#endif // Message Queue available
|
||||||
|
|
||||||
|
|
||||||
|
// ==== Mail Queue Management Functions ====
|
||||||
|
|
||||||
|
#if (defined(osFeature_MailQ) && (osFeature_MailQ != 0)) // Mail Queue available
|
||||||
|
|
||||||
|
/// \brief Create a Mail Queue Definition.
|
||||||
|
/// \param name name of the queue.
|
||||||
|
/// \param queue_sz maximum number of mails in the queue.
|
||||||
|
/// \param type data type of a single mail element.
|
||||||
|
#if defined (osObjectsExternal) // object is external
|
||||||
|
#define osMailQDef(name, queue_sz, type) \
|
||||||
|
extern const osMailQDef_t os_mailQ_def_##name
|
||||||
|
#else // define the object
|
||||||
|
#define osMailQDef(name, queue_sz, type) \
|
||||||
|
const osMailQDef_t os_mailQ_def_##name = \
|
||||||
|
{ (queue_sz), sizeof(type), NULL }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// \brief Access a Mail Queue Definition.
|
||||||
|
/// \param name name of the queue
|
||||||
|
#define osMailQ(name) \
|
||||||
|
&os_mailQ_def_##name
|
||||||
|
|
||||||
|
/// Create and Initialize a Mail Queue object.
|
||||||
|
/// \param[in] queue_def mail queue definition referenced with \ref osMailQ.
|
||||||
|
/// \param[in] thread_id thread ID (obtained by \ref osThreadCreate or \ref osThreadGetId) or NULL.
|
||||||
|
/// \return mail queue ID for reference by other functions or NULL in case of error.
|
||||||
|
osMailQId osMailCreate (const osMailQDef_t *queue_def, osThreadId thread_id);
|
||||||
|
|
||||||
|
/// Allocate a memory block for mail from a mail memory pool.
|
||||||
|
/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
|
||||||
|
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out
|
||||||
|
/// \return pointer to memory block that can be filled with mail or NULL in case of error.
|
||||||
|
void *osMailAlloc (osMailQId queue_id, uint32_t millisec);
|
||||||
|
|
||||||
|
/// Allocate a memory block for mail from a mail memory pool and set memory block to zero.
|
||||||
|
/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
|
||||||
|
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out
|
||||||
|
/// \return pointer to memory block that can be filled with mail or NULL in case of error.
|
||||||
|
void *osMailCAlloc (osMailQId queue_id, uint32_t millisec);
|
||||||
|
|
||||||
|
/// Put a Mail into a Queue.
|
||||||
|
/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
|
||||||
|
/// \param[in] mail pointer to memory with mail to put into a queue.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus osMailPut (osMailQId queue_id, const void *mail);
|
||||||
|
|
||||||
|
/// Get a Mail from a Queue or timeout if Queue is empty.
|
||||||
|
/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
|
||||||
|
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||||
|
/// \return event information that includes status code.
|
||||||
|
os_InRegs osEvent osMailGet (osMailQId queue_id, uint32_t millisec);
|
||||||
|
|
||||||
|
/// Free a memory block by returning it to a mail memory pool.
|
||||||
|
/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
|
||||||
|
/// \param[in] mail pointer to memory block that was obtained with \ref osMailGet.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus osMailFree (osMailQId queue_id, void *mail);
|
||||||
|
|
||||||
|
#endif // Mail Queue available
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // CMSIS_OS_H_
|
||||||
2482
Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c
vendored
Normal file
2482
Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
734
Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.h
vendored
Normal file
734
Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.h
vendored
Normal file
@@ -0,0 +1,734 @@
|
|||||||
|
/* --------------------------------------------------------------------------
|
||||||
|
* Portions Copyright © 2017 STMicroelectronics International N.V. All rights reserved.
|
||||||
|
* Portions Copyright (c) 2013-2017 ARM Limited. All rights reserved.
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Name: cmsis_os2.h
|
||||||
|
* Purpose: CMSIS RTOS2 wrapper for FreeRTOS
|
||||||
|
*
|
||||||
|
*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef CMSIS_OS2_H_
|
||||||
|
#define CMSIS_OS2_H_
|
||||||
|
|
||||||
|
#ifndef __NO_RETURN
|
||||||
|
#if defined(__CC_ARM)
|
||||||
|
#define __NO_RETURN __declspec(noreturn)
|
||||||
|
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
|
||||||
|
#define __NO_RETURN __attribute__((__noreturn__))
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
#define __NO_RETURN __attribute__((__noreturn__))
|
||||||
|
#elif defined(__ICCARM__)
|
||||||
|
#define __NO_RETURN __noreturn
|
||||||
|
#else
|
||||||
|
#define __NO_RETURN
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// ==== Enumerations, structures, defines ====
|
||||||
|
|
||||||
|
/// Version information.
|
||||||
|
typedef struct {
|
||||||
|
uint32_t api; ///< API version (major.minor.rev: mmnnnrrrr dec).
|
||||||
|
uint32_t kernel; ///< Kernel version (major.minor.rev: mmnnnrrrr dec).
|
||||||
|
} osVersion_t;
|
||||||
|
|
||||||
|
/// Kernel state.
|
||||||
|
typedef enum {
|
||||||
|
osKernelInactive = 0, ///< Inactive.
|
||||||
|
osKernelReady = 1, ///< Ready.
|
||||||
|
osKernelRunning = 2, ///< Running.
|
||||||
|
osKernelLocked = 3, ///< Locked.
|
||||||
|
osKernelSuspended = 4, ///< Suspended.
|
||||||
|
osKernelError = -1, ///< Error.
|
||||||
|
osKernelReserved = 0x7FFFFFFFU ///< Prevents enum down-size compiler optimization.
|
||||||
|
} osKernelState_t;
|
||||||
|
|
||||||
|
/// Thread state.
|
||||||
|
typedef enum {
|
||||||
|
osThreadInactive = 0, ///< Inactive.
|
||||||
|
osThreadReady = 1, ///< Ready.
|
||||||
|
osThreadRunning = 2, ///< Running.
|
||||||
|
osThreadBlocked = 3, ///< Blocked.
|
||||||
|
osThreadTerminated = 4, ///< Terminated.
|
||||||
|
osThreadError = -1, ///< Error.
|
||||||
|
osThreadReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization.
|
||||||
|
} osThreadState_t;
|
||||||
|
|
||||||
|
/// Priority values.
|
||||||
|
typedef enum {
|
||||||
|
osPriorityNone = 0, ///< No priority (not initialized).
|
||||||
|
osPriorityIdle = 1, ///< Reserved for Idle thread.
|
||||||
|
osPriorityLow = 8, ///< Priority: low
|
||||||
|
osPriorityLow1 = 8+1, ///< Priority: low + 1
|
||||||
|
osPriorityLow2 = 8+2, ///< Priority: low + 2
|
||||||
|
osPriorityLow3 = 8+3, ///< Priority: low + 3
|
||||||
|
osPriorityLow4 = 8+4, ///< Priority: low + 4
|
||||||
|
osPriorityLow5 = 8+5, ///< Priority: low + 5
|
||||||
|
osPriorityLow6 = 8+6, ///< Priority: low + 6
|
||||||
|
osPriorityLow7 = 8+7, ///< Priority: low + 7
|
||||||
|
osPriorityBelowNormal = 16, ///< Priority: below normal
|
||||||
|
osPriorityBelowNormal1 = 16+1, ///< Priority: below normal + 1
|
||||||
|
osPriorityBelowNormal2 = 16+2, ///< Priority: below normal + 2
|
||||||
|
osPriorityBelowNormal3 = 16+3, ///< Priority: below normal + 3
|
||||||
|
osPriorityBelowNormal4 = 16+4, ///< Priority: below normal + 4
|
||||||
|
osPriorityBelowNormal5 = 16+5, ///< Priority: below normal + 5
|
||||||
|
osPriorityBelowNormal6 = 16+6, ///< Priority: below normal + 6
|
||||||
|
osPriorityBelowNormal7 = 16+7, ///< Priority: below normal + 7
|
||||||
|
osPriorityNormal = 24, ///< Priority: normal
|
||||||
|
osPriorityNormal1 = 24+1, ///< Priority: normal + 1
|
||||||
|
osPriorityNormal2 = 24+2, ///< Priority: normal + 2
|
||||||
|
osPriorityNormal3 = 24+3, ///< Priority: normal + 3
|
||||||
|
osPriorityNormal4 = 24+4, ///< Priority: normal + 4
|
||||||
|
osPriorityNormal5 = 24+5, ///< Priority: normal + 5
|
||||||
|
osPriorityNormal6 = 24+6, ///< Priority: normal + 6
|
||||||
|
osPriorityNormal7 = 24+7, ///< Priority: normal + 7
|
||||||
|
osPriorityAboveNormal = 32, ///< Priority: above normal
|
||||||
|
osPriorityAboveNormal1 = 32+1, ///< Priority: above normal + 1
|
||||||
|
osPriorityAboveNormal2 = 32+2, ///< Priority: above normal + 2
|
||||||
|
osPriorityAboveNormal3 = 32+3, ///< Priority: above normal + 3
|
||||||
|
osPriorityAboveNormal4 = 32+4, ///< Priority: above normal + 4
|
||||||
|
osPriorityAboveNormal5 = 32+5, ///< Priority: above normal + 5
|
||||||
|
osPriorityAboveNormal6 = 32+6, ///< Priority: above normal + 6
|
||||||
|
osPriorityAboveNormal7 = 32+7, ///< Priority: above normal + 7
|
||||||
|
osPriorityHigh = 40, ///< Priority: high
|
||||||
|
osPriorityHigh1 = 40+1, ///< Priority: high + 1
|
||||||
|
osPriorityHigh2 = 40+2, ///< Priority: high + 2
|
||||||
|
osPriorityHigh3 = 40+3, ///< Priority: high + 3
|
||||||
|
osPriorityHigh4 = 40+4, ///< Priority: high + 4
|
||||||
|
osPriorityHigh5 = 40+5, ///< Priority: high + 5
|
||||||
|
osPriorityHigh6 = 40+6, ///< Priority: high + 6
|
||||||
|
osPriorityHigh7 = 40+7, ///< Priority: high + 7
|
||||||
|
osPriorityRealtime = 48, ///< Priority: realtime
|
||||||
|
osPriorityRealtime1 = 48+1, ///< Priority: realtime + 1
|
||||||
|
osPriorityRealtime2 = 48+2, ///< Priority: realtime + 2
|
||||||
|
osPriorityRealtime3 = 48+3, ///< Priority: realtime + 3
|
||||||
|
osPriorityRealtime4 = 48+4, ///< Priority: realtime + 4
|
||||||
|
osPriorityRealtime5 = 48+5, ///< Priority: realtime + 5
|
||||||
|
osPriorityRealtime6 = 48+6, ///< Priority: realtime + 6
|
||||||
|
osPriorityRealtime7 = 48+7, ///< Priority: realtime + 7
|
||||||
|
osPriorityISR = 56, ///< Reserved for ISR deferred thread.
|
||||||
|
osPriorityError = -1, ///< System cannot determine priority or illegal priority.
|
||||||
|
osPriorityReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization.
|
||||||
|
} osPriority_t;
|
||||||
|
|
||||||
|
/// Entry point of a thread.
|
||||||
|
typedef void (*osThreadFunc_t) (void *argument);
|
||||||
|
|
||||||
|
/// Timer callback function.
|
||||||
|
typedef void (*osTimerFunc_t) (void *argument);
|
||||||
|
|
||||||
|
/// Timer type.
|
||||||
|
typedef enum {
|
||||||
|
osTimerOnce = 0, ///< One-shot timer.
|
||||||
|
osTimerPeriodic = 1 ///< Repeating timer.
|
||||||
|
} osTimerType_t;
|
||||||
|
|
||||||
|
// Timeout value.
|
||||||
|
#define osWaitForever 0xFFFFFFFFU ///< Wait forever timeout value.
|
||||||
|
|
||||||
|
// Flags options (\ref osThreadFlagsWait and \ref osEventFlagsWait).
|
||||||
|
#define osFlagsWaitAny 0x00000000U ///< Wait for any flag (default).
|
||||||
|
#define osFlagsWaitAll 0x00000001U ///< Wait for all flags.
|
||||||
|
#define osFlagsNoClear 0x00000002U ///< Do not clear flags which have been specified to wait for.
|
||||||
|
|
||||||
|
// Flags errors (returned by osThreadFlagsXxxx and osEventFlagsXxxx).
|
||||||
|
#define osFlagsError 0x80000000U ///< Error indicator.
|
||||||
|
#define osFlagsErrorUnknown 0xFFFFFFFFU ///< osError (-1).
|
||||||
|
#define osFlagsErrorTimeout 0xFFFFFFFEU ///< osErrorTimeout (-2).
|
||||||
|
#define osFlagsErrorResource 0xFFFFFFFDU ///< osErrorResource (-3).
|
||||||
|
#define osFlagsErrorParameter 0xFFFFFFFCU ///< osErrorParameter (-4).
|
||||||
|
#define osFlagsErrorISR 0xFFFFFFFAU ///< osErrorISR (-6).
|
||||||
|
|
||||||
|
// Thread attributes (attr_bits in \ref osThreadAttr_t).
|
||||||
|
#define osThreadDetached 0x00000000U ///< Thread created in detached mode (default)
|
||||||
|
#define osThreadJoinable 0x00000001U ///< Thread created in joinable mode
|
||||||
|
|
||||||
|
// Mutex attributes (attr_bits in \ref osMutexAttr_t).
|
||||||
|
#define osMutexRecursive 0x00000001U ///< Recursive mutex.
|
||||||
|
#define osMutexPrioInherit 0x00000002U ///< Priority inherit protocol.
|
||||||
|
#define osMutexRobust 0x00000008U ///< Robust mutex.
|
||||||
|
|
||||||
|
/// Status code values returned by CMSIS-RTOS functions.
|
||||||
|
typedef enum {
|
||||||
|
osOK = 0, ///< Operation completed successfully.
|
||||||
|
osError = -1, ///< Unspecified RTOS error: run-time error but no other error message fits.
|
||||||
|
osErrorTimeout = -2, ///< Operation not completed within the timeout period.
|
||||||
|
osErrorResource = -3, ///< Resource not available.
|
||||||
|
osErrorParameter = -4, ///< Parameter error.
|
||||||
|
osErrorNoMemory = -5, ///< System is out of memory: it was impossible to allocate or reserve memory for the operation.
|
||||||
|
osErrorISR = -6, ///< Not allowed in ISR context: the function cannot be called from interrupt service routines.
|
||||||
|
osStatusReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization.
|
||||||
|
} osStatus_t;
|
||||||
|
|
||||||
|
|
||||||
|
/// \details Thread ID identifies the thread.
|
||||||
|
typedef void *osThreadId_t;
|
||||||
|
|
||||||
|
/// \details Timer ID identifies the timer.
|
||||||
|
typedef void *osTimerId_t;
|
||||||
|
|
||||||
|
/// \details Event Flags ID identifies the event flags.
|
||||||
|
typedef void *osEventFlagsId_t;
|
||||||
|
|
||||||
|
/// \details Mutex ID identifies the mutex.
|
||||||
|
typedef void *osMutexId_t;
|
||||||
|
|
||||||
|
/// \details Semaphore ID identifies the semaphore.
|
||||||
|
typedef void *osSemaphoreId_t;
|
||||||
|
|
||||||
|
/// \details Memory Pool ID identifies the memory pool.
|
||||||
|
typedef void *osMemoryPoolId_t;
|
||||||
|
|
||||||
|
/// \details Message Queue ID identifies the message queue.
|
||||||
|
typedef void *osMessageQueueId_t;
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef TZ_MODULEID_T
|
||||||
|
#define TZ_MODULEID_T
|
||||||
|
/// \details Data type that identifies secure software modules called by a process.
|
||||||
|
typedef uint32_t TZ_ModuleId_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/// Attributes structure for thread.
|
||||||
|
typedef struct {
|
||||||
|
const char *name; ///< name of the thread
|
||||||
|
uint32_t attr_bits; ///< attribute bits
|
||||||
|
void *cb_mem; ///< memory for control block
|
||||||
|
uint32_t cb_size; ///< size of provided memory for control block
|
||||||
|
void *stack_mem; ///< memory for stack
|
||||||
|
uint32_t stack_size; ///< size of stack
|
||||||
|
osPriority_t priority; ///< initial thread priority (default: osPriorityNormal)
|
||||||
|
TZ_ModuleId_t tz_module; ///< TrustZone module identifier
|
||||||
|
uint32_t reserved; ///< reserved (must be 0)
|
||||||
|
} osThreadAttr_t;
|
||||||
|
|
||||||
|
/// Attributes structure for timer.
|
||||||
|
typedef struct {
|
||||||
|
const char *name; ///< name of the timer
|
||||||
|
uint32_t attr_bits; ///< attribute bits
|
||||||
|
void *cb_mem; ///< memory for control block
|
||||||
|
uint32_t cb_size; ///< size of provided memory for control block
|
||||||
|
} osTimerAttr_t;
|
||||||
|
|
||||||
|
/// Attributes structure for event flags.
|
||||||
|
typedef struct {
|
||||||
|
const char *name; ///< name of the event flags
|
||||||
|
uint32_t attr_bits; ///< attribute bits
|
||||||
|
void *cb_mem; ///< memory for control block
|
||||||
|
uint32_t cb_size; ///< size of provided memory for control block
|
||||||
|
} osEventFlagsAttr_t;
|
||||||
|
|
||||||
|
/// Attributes structure for mutex.
|
||||||
|
typedef struct {
|
||||||
|
const char *name; ///< name of the mutex
|
||||||
|
uint32_t attr_bits; ///< attribute bits
|
||||||
|
void *cb_mem; ///< memory for control block
|
||||||
|
uint32_t cb_size; ///< size of provided memory for control block
|
||||||
|
} osMutexAttr_t;
|
||||||
|
|
||||||
|
/// Attributes structure for semaphore.
|
||||||
|
typedef struct {
|
||||||
|
const char *name; ///< name of the semaphore
|
||||||
|
uint32_t attr_bits; ///< attribute bits
|
||||||
|
void *cb_mem; ///< memory for control block
|
||||||
|
uint32_t cb_size; ///< size of provided memory for control block
|
||||||
|
} osSemaphoreAttr_t;
|
||||||
|
|
||||||
|
/// Attributes structure for memory pool.
|
||||||
|
typedef struct {
|
||||||
|
const char *name; ///< name of the memory pool
|
||||||
|
uint32_t attr_bits; ///< attribute bits
|
||||||
|
void *cb_mem; ///< memory for control block
|
||||||
|
uint32_t cb_size; ///< size of provided memory for control block
|
||||||
|
void *mp_mem; ///< memory for data storage
|
||||||
|
uint32_t mp_size; ///< size of provided memory for data storage
|
||||||
|
} osMemoryPoolAttr_t;
|
||||||
|
|
||||||
|
/// Attributes structure for message queue.
|
||||||
|
typedef struct {
|
||||||
|
const char *name; ///< name of the message queue
|
||||||
|
uint32_t attr_bits; ///< attribute bits
|
||||||
|
void *cb_mem; ///< memory for control block
|
||||||
|
uint32_t cb_size; ///< size of provided memory for control block
|
||||||
|
void *mq_mem; ///< memory for data storage
|
||||||
|
uint32_t mq_size; ///< size of provided memory for data storage
|
||||||
|
} osMessageQueueAttr_t;
|
||||||
|
|
||||||
|
|
||||||
|
// ==== Kernel Management Functions ====
|
||||||
|
|
||||||
|
/// Initialize the RTOS Kernel.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osKernelInitialize (void);
|
||||||
|
|
||||||
|
/// Get RTOS Kernel Information.
|
||||||
|
/// \param[out] version pointer to buffer for retrieving version information.
|
||||||
|
/// \param[out] id_buf pointer to buffer for retrieving kernel identification string.
|
||||||
|
/// \param[in] id_size size of buffer for kernel identification string.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osKernelGetInfo (osVersion_t *version, char *id_buf, uint32_t id_size);
|
||||||
|
|
||||||
|
/// Get the current RTOS Kernel state.
|
||||||
|
/// \return current RTOS Kernel state.
|
||||||
|
osKernelState_t osKernelGetState (void);
|
||||||
|
|
||||||
|
/// Start the RTOS Kernel scheduler.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osKernelStart (void);
|
||||||
|
|
||||||
|
/// Lock the RTOS Kernel scheduler.
|
||||||
|
/// \return previous lock state (1 - locked, 0 - not locked, error code if negative).
|
||||||
|
int32_t osKernelLock (void);
|
||||||
|
|
||||||
|
/// Unlock the RTOS Kernel scheduler.
|
||||||
|
/// \return previous lock state (1 - locked, 0 - not locked, error code if negative).
|
||||||
|
int32_t osKernelUnlock (void);
|
||||||
|
|
||||||
|
/// Restore the RTOS Kernel scheduler lock state.
|
||||||
|
/// \param[in] lock lock state obtained by \ref osKernelLock or \ref osKernelUnlock.
|
||||||
|
/// \return new lock state (1 - locked, 0 - not locked, error code if negative).
|
||||||
|
int32_t osKernelRestoreLock (int32_t lock);
|
||||||
|
|
||||||
|
/// Suspend the RTOS Kernel scheduler.
|
||||||
|
/// \return time in ticks, for how long the system can sleep or power-down.
|
||||||
|
uint32_t osKernelSuspend (void);
|
||||||
|
|
||||||
|
/// Resume the RTOS Kernel scheduler.
|
||||||
|
/// \param[in] sleep_ticks time in ticks for how long the system was in sleep or power-down mode.
|
||||||
|
void osKernelResume (uint32_t sleep_ticks);
|
||||||
|
|
||||||
|
/// Get the RTOS kernel tick count.
|
||||||
|
/// \return RTOS kernel current tick count.
|
||||||
|
uint32_t osKernelGetTickCount (void);
|
||||||
|
|
||||||
|
/// Get the RTOS kernel tick frequency.
|
||||||
|
/// \return frequency of the kernel tick in hertz, i.e. kernel ticks per second.
|
||||||
|
uint32_t osKernelGetTickFreq (void);
|
||||||
|
|
||||||
|
/// Get the RTOS kernel system timer count.
|
||||||
|
/// \return RTOS kernel current system timer count as 32-bit value.
|
||||||
|
uint32_t osKernelGetSysTimerCount (void);
|
||||||
|
|
||||||
|
/// Get the RTOS kernel system timer frequency.
|
||||||
|
/// \return frequency of the system timer in hertz, i.e. timer ticks per second.
|
||||||
|
uint32_t osKernelGetSysTimerFreq (void);
|
||||||
|
|
||||||
|
|
||||||
|
// ==== Thread Management Functions ====
|
||||||
|
|
||||||
|
/// Create a thread and add it to Active Threads.
|
||||||
|
/// \param[in] func thread function.
|
||||||
|
/// \param[in] argument pointer that is passed to the thread function as start argument.
|
||||||
|
/// \param[in] attr thread attributes; NULL: default values.
|
||||||
|
/// \return thread ID for reference by other functions or NULL in case of error.
|
||||||
|
osThreadId_t osThreadNew (osThreadFunc_t func, void *argument, const osThreadAttr_t *attr);
|
||||||
|
|
||||||
|
/// Get name of a thread.
|
||||||
|
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||||
|
/// \return name as NULL terminated string.
|
||||||
|
const char *osThreadGetName (osThreadId_t thread_id);
|
||||||
|
|
||||||
|
/// Return the thread ID of the current running thread.
|
||||||
|
/// \return thread ID for reference by other functions or NULL in case of error.
|
||||||
|
osThreadId_t osThreadGetId (void);
|
||||||
|
|
||||||
|
/// Get current thread state of a thread.
|
||||||
|
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||||
|
/// \return current thread state of the specified thread.
|
||||||
|
osThreadState_t osThreadGetState (osThreadId_t thread_id);
|
||||||
|
|
||||||
|
/// Get stack size of a thread.
|
||||||
|
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||||
|
/// \return stack size in bytes.
|
||||||
|
uint32_t osThreadGetStackSize (osThreadId_t thread_id);
|
||||||
|
|
||||||
|
/// Get available stack space of a thread based on stack watermark recording during execution.
|
||||||
|
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||||
|
/// \return remaining stack space in bytes.
|
||||||
|
uint32_t osThreadGetStackSpace (osThreadId_t thread_id);
|
||||||
|
|
||||||
|
/// Change priority of a thread.
|
||||||
|
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||||
|
/// \param[in] priority new priority value for the thread function.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osThreadSetPriority (osThreadId_t thread_id, osPriority_t priority);
|
||||||
|
|
||||||
|
/// Get current priority of a thread.
|
||||||
|
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||||
|
/// \return current priority value of the specified thread.
|
||||||
|
osPriority_t osThreadGetPriority (osThreadId_t thread_id);
|
||||||
|
|
||||||
|
/// Pass control to next thread that is in state \b READY.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osThreadYield (void);
|
||||||
|
|
||||||
|
/// Suspend execution of a thread.
|
||||||
|
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osThreadSuspend (osThreadId_t thread_id);
|
||||||
|
|
||||||
|
/// Resume execution of a thread.
|
||||||
|
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osThreadResume (osThreadId_t thread_id);
|
||||||
|
|
||||||
|
/// Detach a thread (thread storage can be reclaimed when thread terminates).
|
||||||
|
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osThreadDetach (osThreadId_t thread_id);
|
||||||
|
|
||||||
|
/// Wait for specified thread to terminate.
|
||||||
|
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osThreadJoin (osThreadId_t thread_id);
|
||||||
|
|
||||||
|
/// Terminate execution of current running thread.
|
||||||
|
__NO_RETURN void osThreadExit (void);
|
||||||
|
|
||||||
|
/// Terminate execution of a thread.
|
||||||
|
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osThreadTerminate (osThreadId_t thread_id);
|
||||||
|
|
||||||
|
/// Get number of active threads.
|
||||||
|
/// \return number of active threads.
|
||||||
|
uint32_t osThreadGetCount (void);
|
||||||
|
|
||||||
|
/// Enumerate active threads.
|
||||||
|
/// \param[out] thread_array pointer to array for retrieving thread IDs.
|
||||||
|
/// \param[in] array_items maximum number of items in array for retrieving thread IDs.
|
||||||
|
/// \return number of enumerated threads.
|
||||||
|
uint32_t osThreadEnumerate (osThreadId_t *thread_array, uint32_t array_items);
|
||||||
|
|
||||||
|
|
||||||
|
// ==== Thread Flags Functions ====
|
||||||
|
|
||||||
|
/// Set the specified Thread Flags of a thread.
|
||||||
|
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||||
|
/// \param[in] flags specifies the flags of the thread that shall be set.
|
||||||
|
/// \return thread flags after setting or error code if highest bit set.
|
||||||
|
uint32_t osThreadFlagsSet (osThreadId_t thread_id, uint32_t flags);
|
||||||
|
|
||||||
|
/// Clear the specified Thread Flags of current running thread.
|
||||||
|
/// \param[in] flags specifies the flags of the thread that shall be cleared.
|
||||||
|
/// \return thread flags before clearing or error code if highest bit set.
|
||||||
|
uint32_t osThreadFlagsClear (uint32_t flags);
|
||||||
|
|
||||||
|
/// Get the current Thread Flags of current running thread.
|
||||||
|
/// \return current thread flags.
|
||||||
|
uint32_t osThreadFlagsGet (void);
|
||||||
|
|
||||||
|
/// Wait for one or more Thread Flags of the current running thread to become signaled.
|
||||||
|
/// \param[in] flags specifies the flags to wait for.
|
||||||
|
/// \param[in] options specifies flags options (osFlagsXxxx).
|
||||||
|
/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||||
|
/// \return thread flags before clearing or error code if highest bit set.
|
||||||
|
uint32_t osThreadFlagsWait (uint32_t flags, uint32_t options, uint32_t timeout);
|
||||||
|
|
||||||
|
|
||||||
|
// ==== Generic Wait Functions ====
|
||||||
|
|
||||||
|
/// Wait for Timeout (Time Delay).
|
||||||
|
/// \param[in] ticks \ref CMSIS_RTOS_TimeOutValue "time ticks" value
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osDelay (uint32_t ticks);
|
||||||
|
|
||||||
|
/// Wait until specified time.
|
||||||
|
/// \param[in] ticks absolute time in ticks
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osDelayUntil (uint32_t ticks);
|
||||||
|
|
||||||
|
|
||||||
|
// ==== Timer Management Functions ====
|
||||||
|
|
||||||
|
/// Create and Initialize a timer.
|
||||||
|
/// \param[in] func function pointer to callback function.
|
||||||
|
/// \param[in] type \ref osTimerOnce for one-shot or \ref osTimerPeriodic for periodic behavior.
|
||||||
|
/// \param[in] argument argument to the timer callback function.
|
||||||
|
/// \param[in] attr timer attributes; NULL: default values.
|
||||||
|
/// \return timer ID for reference by other functions or NULL in case of error.
|
||||||
|
osTimerId_t osTimerNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr);
|
||||||
|
|
||||||
|
/// Get name of a timer.
|
||||||
|
/// \param[in] timer_id timer ID obtained by \ref osTimerNew.
|
||||||
|
/// \return name as NULL terminated string.
|
||||||
|
const char *osTimerGetName (osTimerId_t timer_id);
|
||||||
|
|
||||||
|
/// Start or restart a timer.
|
||||||
|
/// \param[in] timer_id timer ID obtained by \ref osTimerNew.
|
||||||
|
/// \param[in] ticks \ref CMSIS_RTOS_TimeOutValue "time ticks" value of the timer.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osTimerStart (osTimerId_t timer_id, uint32_t ticks);
|
||||||
|
|
||||||
|
/// Stop a timer.
|
||||||
|
/// \param[in] timer_id timer ID obtained by \ref osTimerNew.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osTimerStop (osTimerId_t timer_id);
|
||||||
|
|
||||||
|
/// Check if a timer is running.
|
||||||
|
/// \param[in] timer_id timer ID obtained by \ref osTimerNew.
|
||||||
|
/// \return 0 not running, 1 running.
|
||||||
|
uint32_t osTimerIsRunning (osTimerId_t timer_id);
|
||||||
|
|
||||||
|
/// Delete a timer.
|
||||||
|
/// \param[in] timer_id timer ID obtained by \ref osTimerNew.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osTimerDelete (osTimerId_t timer_id);
|
||||||
|
|
||||||
|
|
||||||
|
// ==== Event Flags Management Functions ====
|
||||||
|
|
||||||
|
/// Create and Initialize an Event Flags object.
|
||||||
|
/// \param[in] attr event flags attributes; NULL: default values.
|
||||||
|
/// \return event flags ID for reference by other functions or NULL in case of error.
|
||||||
|
osEventFlagsId_t osEventFlagsNew (const osEventFlagsAttr_t *attr);
|
||||||
|
|
||||||
|
/// Get name of an Event Flags object.
|
||||||
|
/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew.
|
||||||
|
/// \return name as NULL terminated string.
|
||||||
|
const char *osEventFlagsGetName (osEventFlagsId_t ef_id);
|
||||||
|
|
||||||
|
/// Set the specified Event Flags.
|
||||||
|
/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew.
|
||||||
|
/// \param[in] flags specifies the flags that shall be set.
|
||||||
|
/// \return event flags after setting or error code if highest bit set.
|
||||||
|
uint32_t osEventFlagsSet (osEventFlagsId_t ef_id, uint32_t flags);
|
||||||
|
|
||||||
|
/// Clear the specified Event Flags.
|
||||||
|
/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew.
|
||||||
|
/// \param[in] flags specifies the flags that shall be cleared.
|
||||||
|
/// \return event flags before clearing or error code if highest bit set.
|
||||||
|
uint32_t osEventFlagsClear (osEventFlagsId_t ef_id, uint32_t flags);
|
||||||
|
|
||||||
|
/// Get the current Event Flags.
|
||||||
|
/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew.
|
||||||
|
/// \return current event flags.
|
||||||
|
uint32_t osEventFlagsGet (osEventFlagsId_t ef_id);
|
||||||
|
|
||||||
|
/// Wait for one or more Event Flags to become signaled.
|
||||||
|
/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew.
|
||||||
|
/// \param[in] flags specifies the flags to wait for.
|
||||||
|
/// \param[in] options specifies flags options (osFlagsXxxx).
|
||||||
|
/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||||
|
/// \return event flags before clearing or error code if highest bit set.
|
||||||
|
uint32_t osEventFlagsWait (osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout);
|
||||||
|
|
||||||
|
/// Delete an Event Flags object.
|
||||||
|
/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osEventFlagsDelete (osEventFlagsId_t ef_id);
|
||||||
|
|
||||||
|
|
||||||
|
// ==== Mutex Management Functions ====
|
||||||
|
|
||||||
|
/// Create and Initialize a Mutex object.
|
||||||
|
/// \param[in] attr mutex attributes; NULL: default values.
|
||||||
|
/// \return mutex ID for reference by other functions or NULL in case of error.
|
||||||
|
osMutexId_t osMutexNew (const osMutexAttr_t *attr);
|
||||||
|
|
||||||
|
/// Get name of a Mutex object.
|
||||||
|
/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew.
|
||||||
|
/// \return name as NULL terminated string.
|
||||||
|
const char *osMutexGetName (osMutexId_t mutex_id);
|
||||||
|
|
||||||
|
/// Acquire a Mutex or timeout if it is locked.
|
||||||
|
/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew.
|
||||||
|
/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout);
|
||||||
|
|
||||||
|
/// Release a Mutex that was acquired by \ref osMutexAcquire.
|
||||||
|
/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osMutexRelease (osMutexId_t mutex_id);
|
||||||
|
|
||||||
|
/// Get Thread which owns a Mutex object.
|
||||||
|
/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew.
|
||||||
|
/// \return thread ID of owner thread or NULL when mutex was not acquired.
|
||||||
|
osThreadId_t osMutexGetOwner (osMutexId_t mutex_id);
|
||||||
|
|
||||||
|
/// Delete a Mutex object.
|
||||||
|
/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osMutexDelete (osMutexId_t mutex_id);
|
||||||
|
|
||||||
|
|
||||||
|
// ==== Semaphore Management Functions ====
|
||||||
|
|
||||||
|
/// Create and Initialize a Semaphore object.
|
||||||
|
/// \param[in] max_count maximum number of available tokens.
|
||||||
|
/// \param[in] initial_count initial number of available tokens.
|
||||||
|
/// \param[in] attr semaphore attributes; NULL: default values.
|
||||||
|
/// \return semaphore ID for reference by other functions or NULL in case of error.
|
||||||
|
osSemaphoreId_t osSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr);
|
||||||
|
|
||||||
|
/// Get name of a Semaphore object.
|
||||||
|
/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew.
|
||||||
|
/// \return name as NULL terminated string.
|
||||||
|
const char *osSemaphoreGetName (osSemaphoreId_t semaphore_id);
|
||||||
|
|
||||||
|
/// Acquire a Semaphore token or timeout if no tokens are available.
|
||||||
|
/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew.
|
||||||
|
/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout);
|
||||||
|
|
||||||
|
/// Release a Semaphore token up to the initial maximum count.
|
||||||
|
/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osSemaphoreRelease (osSemaphoreId_t semaphore_id);
|
||||||
|
|
||||||
|
/// Get current Semaphore token count.
|
||||||
|
/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew.
|
||||||
|
/// \return number of tokens available.
|
||||||
|
uint32_t osSemaphoreGetCount (osSemaphoreId_t semaphore_id);
|
||||||
|
|
||||||
|
/// Delete a Semaphore object.
|
||||||
|
/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osSemaphoreDelete (osSemaphoreId_t semaphore_id);
|
||||||
|
|
||||||
|
|
||||||
|
// ==== Memory Pool Management Functions ====
|
||||||
|
|
||||||
|
/// Create and Initialize a Memory Pool object.
|
||||||
|
/// \param[in] block_count maximum number of memory blocks in memory pool.
|
||||||
|
/// \param[in] block_size memory block size in bytes.
|
||||||
|
/// \param[in] attr memory pool attributes; NULL: default values.
|
||||||
|
/// \return memory pool ID for reference by other functions or NULL in case of error.
|
||||||
|
osMemoryPoolId_t osMemoryPoolNew (uint32_t block_count, uint32_t block_size, const osMemoryPoolAttr_t *attr);
|
||||||
|
|
||||||
|
/// Get name of a Memory Pool object.
|
||||||
|
/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew.
|
||||||
|
/// \return name as NULL terminated string.
|
||||||
|
const char *osMemoryPoolGetName (osMemoryPoolId_t mp_id);
|
||||||
|
|
||||||
|
/// Allocate a memory block from a Memory Pool.
|
||||||
|
/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew.
|
||||||
|
/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||||
|
/// \return address of the allocated memory block or NULL in case of no memory is available.
|
||||||
|
void *osMemoryPoolAlloc (osMemoryPoolId_t mp_id, uint32_t timeout);
|
||||||
|
|
||||||
|
/// Return an allocated memory block back to a Memory Pool.
|
||||||
|
/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew.
|
||||||
|
/// \param[in] block address of the allocated memory block to be returned to the memory pool.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osMemoryPoolFree (osMemoryPoolId_t mp_id, void *block);
|
||||||
|
|
||||||
|
/// Get maximum number of memory blocks in a Memory Pool.
|
||||||
|
/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew.
|
||||||
|
/// \return maximum number of memory blocks.
|
||||||
|
uint32_t osMemoryPoolGetCapacity (osMemoryPoolId_t mp_id);
|
||||||
|
|
||||||
|
/// Get memory block size in a Memory Pool.
|
||||||
|
/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew.
|
||||||
|
/// \return memory block size in bytes.
|
||||||
|
uint32_t osMemoryPoolGetBlockSize (osMemoryPoolId_t mp_id);
|
||||||
|
|
||||||
|
/// Get number of memory blocks used in a Memory Pool.
|
||||||
|
/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew.
|
||||||
|
/// \return number of memory blocks used.
|
||||||
|
uint32_t osMemoryPoolGetCount (osMemoryPoolId_t mp_id);
|
||||||
|
|
||||||
|
/// Get number of memory blocks available in a Memory Pool.
|
||||||
|
/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew.
|
||||||
|
/// \return number of memory blocks available.
|
||||||
|
uint32_t osMemoryPoolGetSpace (osMemoryPoolId_t mp_id);
|
||||||
|
|
||||||
|
/// Delete a Memory Pool object.
|
||||||
|
/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osMemoryPoolDelete (osMemoryPoolId_t mp_id);
|
||||||
|
|
||||||
|
|
||||||
|
// ==== Message Queue Management Functions ====
|
||||||
|
|
||||||
|
/// Create and Initialize a Message Queue object.
|
||||||
|
/// \param[in] msg_count maximum number of messages in queue.
|
||||||
|
/// \param[in] msg_size maximum message size in bytes.
|
||||||
|
/// \param[in] attr message queue attributes; NULL: default values.
|
||||||
|
/// \return message queue ID for reference by other functions or NULL in case of error.
|
||||||
|
osMessageQueueId_t osMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr);
|
||||||
|
|
||||||
|
/// Get name of a Message Queue object.
|
||||||
|
/// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew.
|
||||||
|
/// \return name as NULL terminated string.
|
||||||
|
const char *osMessageQueueGetName (osMessageQueueId_t mq_id);
|
||||||
|
|
||||||
|
/// Put a Message into a Queue or timeout if Queue is full.
|
||||||
|
/// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew.
|
||||||
|
/// \param[in] msg_ptr pointer to buffer with message to put into a queue.
|
||||||
|
/// \param[in] msg_prio message priority.
|
||||||
|
/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout);
|
||||||
|
|
||||||
|
/// Get a Message from a Queue or timeout if Queue is empty.
|
||||||
|
/// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew.
|
||||||
|
/// \param[out] msg_ptr pointer to buffer for message to get from a queue.
|
||||||
|
/// \param[out] msg_prio pointer to buffer for message priority or NULL.
|
||||||
|
/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout);
|
||||||
|
|
||||||
|
/// Get maximum number of messages in a Message Queue.
|
||||||
|
/// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew.
|
||||||
|
/// \return maximum number of messages.
|
||||||
|
uint32_t osMessageQueueGetCapacity (osMessageQueueId_t mq_id);
|
||||||
|
|
||||||
|
/// Get maximum message size in a Memory Pool.
|
||||||
|
/// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew.
|
||||||
|
/// \return maximum message size in bytes.
|
||||||
|
uint32_t osMessageQueueGetMsgSize (osMessageQueueId_t mq_id);
|
||||||
|
|
||||||
|
/// Get number of queued messages in a Message Queue.
|
||||||
|
/// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew.
|
||||||
|
/// \return number of queued messages.
|
||||||
|
uint32_t osMessageQueueGetCount (osMessageQueueId_t mq_id);
|
||||||
|
|
||||||
|
/// Get number of available slots for messages in a Message Queue.
|
||||||
|
/// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew.
|
||||||
|
/// \return number of available slots for messages.
|
||||||
|
uint32_t osMessageQueueGetSpace (osMessageQueueId_t mq_id);
|
||||||
|
|
||||||
|
/// Reset a Message Queue to initial empty state.
|
||||||
|
/// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osMessageQueueReset (osMessageQueueId_t mq_id);
|
||||||
|
|
||||||
|
/// Delete a Message Queue object.
|
||||||
|
/// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew.
|
||||||
|
/// \return status code that indicates the execution status of the function.
|
||||||
|
osStatus_t osMessageQueueDelete (osMessageQueueId_t mq_id);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // CMSIS_OS2_H_
|
||||||
63
Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/freertos_mpool.h
vendored
Normal file
63
Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/freertos_mpool.h
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/* --------------------------------------------------------------------------
|
||||||
|
* Copyright (c) 2013-2020 Arm Limited. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Name: freertos_mpool.h
|
||||||
|
* Purpose: CMSIS RTOS2 wrapper for FreeRTOS
|
||||||
|
*
|
||||||
|
*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef FREERTOS_MPOOL_H_
|
||||||
|
#define FREERTOS_MPOOL_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "semphr.h"
|
||||||
|
|
||||||
|
/* Memory Pool implementation definitions */
|
||||||
|
#define MPOOL_STATUS 0x5EED0000U
|
||||||
|
|
||||||
|
/* Memory Block header */
|
||||||
|
typedef struct {
|
||||||
|
void *next; /* Pointer to next block */
|
||||||
|
} MemPoolBlock_t;
|
||||||
|
|
||||||
|
/* Memory Pool control block */
|
||||||
|
typedef struct MemPoolDef_t {
|
||||||
|
MemPoolBlock_t *head; /* Pointer to head block */
|
||||||
|
SemaphoreHandle_t sem; /* Pool semaphore handle */
|
||||||
|
uint8_t *mem_arr; /* Pool memory array */
|
||||||
|
uint32_t mem_sz; /* Pool memory array size */
|
||||||
|
const char *name; /* Pointer to name string */
|
||||||
|
uint32_t bl_sz; /* Size of a single block */
|
||||||
|
uint32_t bl_cnt; /* Number of blocks */
|
||||||
|
uint32_t n; /* Block allocation index */
|
||||||
|
volatile uint32_t status; /* Object status flags */
|
||||||
|
#if (configSUPPORT_STATIC_ALLOCATION == 1)
|
||||||
|
StaticSemaphore_t mem_sem; /* Semaphore object memory */
|
||||||
|
#endif
|
||||||
|
} MemPool_t;
|
||||||
|
|
||||||
|
/* No need to hide static object type, just align to coding style */
|
||||||
|
#define StaticMemPool_t MemPool_t
|
||||||
|
|
||||||
|
/* Define memory pool control block size */
|
||||||
|
#define MEMPOOL_CB_SIZE (sizeof(StaticMemPool_t))
|
||||||
|
|
||||||
|
/* Define size of the byte array required to create count of blocks of given size */
|
||||||
|
#define MEMPOOL_ARR_SIZE(bl_count, bl_size) (((((bl_size) + (4 - 1)) / 4) * 4)*(bl_count))
|
||||||
|
|
||||||
|
#endif /* FREERTOS_MPOOL_H_ */
|
||||||
310
Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/freertos_os2.h
vendored
Normal file
310
Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/freertos_os2.h
vendored
Normal file
@@ -0,0 +1,310 @@
|
|||||||
|
/* --------------------------------------------------------------------------
|
||||||
|
* Copyright (c) 2013-2020 Arm Limited. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Name: freertos_os2.h
|
||||||
|
* Purpose: CMSIS RTOS2 wrapper for FreeRTOS
|
||||||
|
*
|
||||||
|
*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef FREERTOS_OS2_H_
|
||||||
|
#define FREERTOS_OS2_H_
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "FreeRTOS.h" // ARM.FreeRTOS::RTOS:Core
|
||||||
|
|
||||||
|
#include CMSIS_device_header
|
||||||
|
|
||||||
|
/*
|
||||||
|
CMSIS-RTOS2 FreeRTOS image size optimization definitions.
|
||||||
|
|
||||||
|
Note: Definitions configUSE_OS2 can be used to optimize FreeRTOS image size when
|
||||||
|
certain functionality is not required when using CMSIS-RTOS2 API.
|
||||||
|
In general optimization decisions are left to the tool chain but in cases
|
||||||
|
when coding style prevents it to optimize the code following optional
|
||||||
|
definitions can be used.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Option to exclude CMSIS-RTOS2 functions osThreadSuspend and osThreadResume from
|
||||||
|
the application image.
|
||||||
|
*/
|
||||||
|
#ifndef configUSE_OS2_THREAD_SUSPEND_RESUME
|
||||||
|
#define configUSE_OS2_THREAD_SUSPEND_RESUME 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
Option to exclude CMSIS-RTOS2 function osThreadEnumerate from the application image.
|
||||||
|
*/
|
||||||
|
#ifndef configUSE_OS2_THREAD_ENUMERATE
|
||||||
|
#define configUSE_OS2_THREAD_ENUMERATE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
Option to disable CMSIS-RTOS2 function osEventFlagsSet and osEventFlagsClear
|
||||||
|
operation from ISR.
|
||||||
|
*/
|
||||||
|
#ifndef configUSE_OS2_EVENTFLAGS_FROM_ISR
|
||||||
|
#define configUSE_OS2_EVENTFLAGS_FROM_ISR 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
Option to exclude CMSIS-RTOS2 Thread Flags API functions from the application image.
|
||||||
|
*/
|
||||||
|
#ifndef configUSE_OS2_THREAD_FLAGS
|
||||||
|
#define configUSE_OS2_THREAD_FLAGS configUSE_TASK_NOTIFICATIONS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
Option to exclude CMSIS-RTOS2 Timer API functions from the application image.
|
||||||
|
*/
|
||||||
|
#ifndef configUSE_OS2_TIMER
|
||||||
|
#define configUSE_OS2_TIMER configUSE_TIMERS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
Option to exclude CMSIS-RTOS2 Mutex API functions from the application image.
|
||||||
|
*/
|
||||||
|
#ifndef configUSE_OS2_MUTEX
|
||||||
|
#define configUSE_OS2_MUTEX configUSE_MUTEXES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
CMSIS-RTOS2 FreeRTOS configuration check (FreeRTOSConfig.h).
|
||||||
|
|
||||||
|
Note: CMSIS-RTOS API requires functions included by using following definitions.
|
||||||
|
In case if certain API function is not used compiler will optimize it away.
|
||||||
|
*/
|
||||||
|
#if (INCLUDE_xSemaphoreGetMutexHolder == 0)
|
||||||
|
/*
|
||||||
|
CMSIS-RTOS2 function osMutexGetOwner uses FreeRTOS function xSemaphoreGetMutexHolder. In case if
|
||||||
|
osMutexGetOwner is not used in the application image, compiler will optimize it away.
|
||||||
|
Set #define INCLUDE_xSemaphoreGetMutexHolder 1 to fix this error.
|
||||||
|
*/
|
||||||
|
#error "Definition INCLUDE_xSemaphoreGetMutexHolder must equal 1 to implement Mutex Management API."
|
||||||
|
#endif
|
||||||
|
#if (INCLUDE_vTaskDelay == 0)
|
||||||
|
/*
|
||||||
|
CMSIS-RTOS2 function osDelay uses FreeRTOS function vTaskDelay. In case if
|
||||||
|
osDelay is not used in the application image, compiler will optimize it away.
|
||||||
|
Set #define INCLUDE_vTaskDelay 1 to fix this error.
|
||||||
|
*/
|
||||||
|
#error "Definition INCLUDE_vTaskDelay must equal 1 to implement Generic Wait Functions API."
|
||||||
|
#endif
|
||||||
|
#if (INCLUDE_vTaskDelayUntil == 0)
|
||||||
|
/*
|
||||||
|
CMSIS-RTOS2 function osDelayUntil uses FreeRTOS function vTaskDelayUntil. In case if
|
||||||
|
osDelayUntil is not used in the application image, compiler will optimize it away.
|
||||||
|
Set #define INCLUDE_vTaskDelayUntil 1 to fix this error.
|
||||||
|
*/
|
||||||
|
#error "Definition INCLUDE_vTaskDelayUntil must equal 1 to implement Generic Wait Functions API."
|
||||||
|
#endif
|
||||||
|
#if (INCLUDE_vTaskDelete == 0)
|
||||||
|
/*
|
||||||
|
CMSIS-RTOS2 function osThreadTerminate and osThreadExit uses FreeRTOS function
|
||||||
|
vTaskDelete. In case if they are not used in the application image, compiler
|
||||||
|
will optimize them away.
|
||||||
|
Set #define INCLUDE_vTaskDelete 1 to fix this error.
|
||||||
|
*/
|
||||||
|
#error "Definition INCLUDE_vTaskDelete must equal 1 to implement Thread Management API."
|
||||||
|
#endif
|
||||||
|
#if (INCLUDE_xTaskGetCurrentTaskHandle == 0)
|
||||||
|
/*
|
||||||
|
CMSIS-RTOS2 API uses FreeRTOS function xTaskGetCurrentTaskHandle to implement
|
||||||
|
functions osThreadGetId, osThreadFlagsClear and osThreadFlagsGet. In case if these
|
||||||
|
functions are not used in the application image, compiler will optimize them away.
|
||||||
|
Set #define INCLUDE_xTaskGetCurrentTaskHandle 1 to fix this error.
|
||||||
|
*/
|
||||||
|
#error "Definition INCLUDE_xTaskGetCurrentTaskHandle must equal 1 to implement Thread Management API."
|
||||||
|
#endif
|
||||||
|
#if (INCLUDE_xTaskGetSchedulerState == 0)
|
||||||
|
/*
|
||||||
|
CMSIS-RTOS2 API uses FreeRTOS function xTaskGetSchedulerState to implement Kernel
|
||||||
|
tick handling and therefore it is vital that xTaskGetSchedulerState is included into
|
||||||
|
the application image.
|
||||||
|
Set #define INCLUDE_xTaskGetSchedulerState 1 to fix this error.
|
||||||
|
*/
|
||||||
|
#error "Definition INCLUDE_xTaskGetSchedulerState must equal 1 to implement Kernel Information and Control API."
|
||||||
|
#endif
|
||||||
|
#if (INCLUDE_uxTaskGetStackHighWaterMark == 0)
|
||||||
|
/*
|
||||||
|
CMSIS-RTOS2 function osThreadGetStackSpace uses FreeRTOS function uxTaskGetStackHighWaterMark.
|
||||||
|
In case if osThreadGetStackSpace is not used in the application image, compiler will
|
||||||
|
optimize it away.
|
||||||
|
Set #define INCLUDE_uxTaskGetStackHighWaterMark 1 to fix this error.
|
||||||
|
*/
|
||||||
|
#error "Definition INCLUDE_uxTaskGetStackHighWaterMark must equal 1 to implement Thread Management API."
|
||||||
|
#endif
|
||||||
|
#if (INCLUDE_uxTaskPriorityGet == 0)
|
||||||
|
/*
|
||||||
|
CMSIS-RTOS2 function osThreadGetPriority uses FreeRTOS function uxTaskPriorityGet. In case if
|
||||||
|
osThreadGetPriority is not used in the application image, compiler will optimize it away.
|
||||||
|
Set #define INCLUDE_uxTaskPriorityGet 1 to fix this error.
|
||||||
|
*/
|
||||||
|
#error "Definition INCLUDE_uxTaskPriorityGet must equal 1 to implement Thread Management API."
|
||||||
|
#endif
|
||||||
|
#if (INCLUDE_vTaskPrioritySet == 0)
|
||||||
|
/*
|
||||||
|
CMSIS-RTOS2 function osThreadSetPriority uses FreeRTOS function vTaskPrioritySet. In case if
|
||||||
|
osThreadSetPriority is not used in the application image, compiler will optimize it away.
|
||||||
|
Set #define INCLUDE_vTaskPrioritySet 1 to fix this error.
|
||||||
|
*/
|
||||||
|
#error "Definition INCLUDE_vTaskPrioritySet must equal 1 to implement Thread Management API."
|
||||||
|
#endif
|
||||||
|
#if (INCLUDE_eTaskGetState == 0)
|
||||||
|
/*
|
||||||
|
CMSIS-RTOS2 API uses FreeRTOS function vTaskDelayUntil to implement functions osThreadGetState
|
||||||
|
and osThreadTerminate. In case if these functions are not used in the application image,
|
||||||
|
compiler will optimize them away.
|
||||||
|
Set #define INCLUDE_eTaskGetState 1 to fix this error.
|
||||||
|
*/
|
||||||
|
#error "Definition INCLUDE_eTaskGetState must equal 1 to implement Thread Management API."
|
||||||
|
#endif
|
||||||
|
#if (INCLUDE_vTaskSuspend == 0)
|
||||||
|
/*
|
||||||
|
CMSIS-RTOS2 API uses FreeRTOS functions vTaskSuspend and vTaskResume to implement
|
||||||
|
functions osThreadSuspend and osThreadResume. In case if these functions are not
|
||||||
|
used in the application image, compiler will optimize them away.
|
||||||
|
Set #define INCLUDE_vTaskSuspend 1 to fix this error.
|
||||||
|
|
||||||
|
Alternatively, if the application does not use osThreadSuspend and
|
||||||
|
osThreadResume they can be excluded from the image code by setting:
|
||||||
|
#define configUSE_OS2_THREAD_SUSPEND_RESUME 0 (in FreeRTOSConfig.h)
|
||||||
|
*/
|
||||||
|
#if (configUSE_OS2_THREAD_SUSPEND_RESUME == 1)
|
||||||
|
#error "Definition INCLUDE_vTaskSuspend must equal 1 to implement Kernel Information and Control API."
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if (INCLUDE_xTimerPendFunctionCall == 0)
|
||||||
|
/*
|
||||||
|
CMSIS-RTOS2 function osEventFlagsSet and osEventFlagsClear, when called from
|
||||||
|
the ISR, call FreeRTOS functions xEventGroupSetBitsFromISR and
|
||||||
|
xEventGroupClearBitsFromISR which are only enabled if timers are operational and
|
||||||
|
xTimerPendFunctionCall in enabled.
|
||||||
|
Set #define INCLUDE_xTimerPendFunctionCall 1 and #define configUSE_TIMERS 1
|
||||||
|
to fix this error.
|
||||||
|
|
||||||
|
Alternatively, if the application does not use osEventFlagsSet and osEventFlagsClear
|
||||||
|
from the ISR their operation from ISR can be restricted by setting:
|
||||||
|
#define configUSE_OS2_EVENTFLAGS_FROM_ISR 0 (in FreeRTOSConfig.h)
|
||||||
|
*/
|
||||||
|
#if (configUSE_OS2_EVENTFLAGS_FROM_ISR == 1)
|
||||||
|
#error "Definition INCLUDE_xTimerPendFunctionCall must equal 1 to implement Event Flags API."
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (configUSE_TIMERS == 0)
|
||||||
|
/*
|
||||||
|
CMSIS-RTOS2 Timer Management API functions use FreeRTOS timer functions to implement
|
||||||
|
timer management. In case if these functions are not used in the application image,
|
||||||
|
compiler will optimize them away.
|
||||||
|
Set #define configUSE_TIMERS 1 to fix this error.
|
||||||
|
|
||||||
|
Alternatively, if the application does not use timer functions they can be
|
||||||
|
excluded from the image code by setting:
|
||||||
|
#define configUSE_OS2_TIMER 0 (in FreeRTOSConfig.h)
|
||||||
|
*/
|
||||||
|
#if (configUSE_OS2_TIMER == 1)
|
||||||
|
#error "Definition configUSE_TIMERS must equal 1 to implement Timer Management API."
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (configUSE_MUTEXES == 0)
|
||||||
|
/*
|
||||||
|
CMSIS-RTOS2 Mutex Management API functions use FreeRTOS mutex functions to implement
|
||||||
|
mutex management. In case if these functions are not used in the application image,
|
||||||
|
compiler will optimize them away.
|
||||||
|
Set #define configUSE_MUTEXES 1 to fix this error.
|
||||||
|
|
||||||
|
Alternatively, if the application does not use mutex functions they can be
|
||||||
|
excluded from the image code by setting:
|
||||||
|
#define configUSE_OS2_MUTEX 0 (in FreeRTOSConfig.h)
|
||||||
|
*/
|
||||||
|
#if (configUSE_OS2_MUTEX == 1)
|
||||||
|
#error "Definition configUSE_MUTEXES must equal 1 to implement Mutex Management API."
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (configUSE_COUNTING_SEMAPHORES == 0)
|
||||||
|
/*
|
||||||
|
CMSIS-RTOS2 Memory Pool functions use FreeRTOS function xSemaphoreCreateCounting
|
||||||
|
to implement memory pools. In case if these functions are not used in the application image,
|
||||||
|
compiler will optimize them away.
|
||||||
|
Set #define configUSE_COUNTING_SEMAPHORES 1 to fix this error.
|
||||||
|
*/
|
||||||
|
#error "Definition configUSE_COUNTING_SEMAPHORES must equal 1 to implement Memory Pool API."
|
||||||
|
#endif
|
||||||
|
#if (configUSE_TASK_NOTIFICATIONS == 0)
|
||||||
|
/*
|
||||||
|
CMSIS-RTOS2 Thread Flags API functions use FreeRTOS Task Notification functions to implement
|
||||||
|
thread flag management. In case if these functions are not used in the application image,
|
||||||
|
compiler will optimize them away.
|
||||||
|
Set #define configUSE_TASK_NOTIFICATIONS 1 to fix this error.
|
||||||
|
|
||||||
|
Alternatively, if the application does not use thread flags functions they can be
|
||||||
|
excluded from the image code by setting:
|
||||||
|
#define configUSE_OS2_THREAD_FLAGS 0 (in FreeRTOSConfig.h)
|
||||||
|
*/
|
||||||
|
#if (configUSE_OS2_THREAD_FLAGS == 1)
|
||||||
|
#error "Definition configUSE_TASK_NOTIFICATIONS must equal 1 to implement Thread Flags API."
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (configUSE_TRACE_FACILITY == 0)
|
||||||
|
/*
|
||||||
|
CMSIS-RTOS2 function osThreadEnumerate requires FreeRTOS function uxTaskGetSystemState
|
||||||
|
which is only enabled if configUSE_TRACE_FACILITY == 1.
|
||||||
|
Set #define configUSE_TRACE_FACILITY 1 to fix this error.
|
||||||
|
|
||||||
|
Alternatively, if the application does not use osThreadEnumerate it can be
|
||||||
|
excluded from the image code by setting:
|
||||||
|
#define configUSE_OS2_THREAD_ENUMERATE 0 (in FreeRTOSConfig.h)
|
||||||
|
*/
|
||||||
|
#if (configUSE_OS2_THREAD_ENUMERATE == 1)
|
||||||
|
#error "Definition configUSE_TRACE_FACILITY must equal 1 to implement osThreadEnumerate."
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (configUSE_16_BIT_TICKS == 1)
|
||||||
|
/*
|
||||||
|
CMSIS-RTOS2 wrapper for FreeRTOS relies on 32-bit tick timer which is also optimal on
|
||||||
|
a 32-bit CPU architectures.
|
||||||
|
Set #define configUSE_16_BIT_TICKS 0 to fix this error.
|
||||||
|
*/
|
||||||
|
#error "Definition configUSE_16_BIT_TICKS must be zero to implement CMSIS-RTOS2 API."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (configMAX_PRIORITIES != 56)
|
||||||
|
/*
|
||||||
|
CMSIS-RTOS2 defines 56 different priorities (see osPriority_t) and portable CMSIS-RTOS2
|
||||||
|
implementation should implement the same number of priorities.
|
||||||
|
Set #define configMAX_PRIORITIES 56 to fix this error.
|
||||||
|
*/
|
||||||
|
#error "Definition configMAX_PRIORITIES must equal 56 to implement Thread Management API."
|
||||||
|
#endif
|
||||||
|
#if (configUSE_PORT_OPTIMISED_TASK_SELECTION != 0)
|
||||||
|
/*
|
||||||
|
CMSIS-RTOS2 requires handling of 56 different priorities (see osPriority_t) while FreeRTOS port
|
||||||
|
optimised selection for Cortex core only handles 32 different priorities.
|
||||||
|
Set #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 to fix this error.
|
||||||
|
*/
|
||||||
|
#error "Definition configUSE_PORT_OPTIMISED_TASK_SELECTION must be zero to implement Thread Management API."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* FREERTOS_OS2_H_ */
|
||||||
18
Middlewares/Third_Party/FreeRTOS/Source/LICENSE
vendored
Normal file
18
Middlewares/Third_Party/FreeRTOS/Source/LICENSE
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
353
Middlewares/Third_Party/FreeRTOS/Source/croutine.c
vendored
Normal file
353
Middlewares/Third_Party/FreeRTOS/Source/croutine.c
vendored
Normal file
@@ -0,0 +1,353 @@
|
|||||||
|
/*
|
||||||
|
* FreeRTOS Kernel V10.3.1
|
||||||
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org
|
||||||
|
* http://aws.amazon.com/freertos
|
||||||
|
*
|
||||||
|
* 1 tab == 4 spaces!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
#include "croutine.h"
|
||||||
|
|
||||||
|
/* Remove the whole file is co-routines are not being used. */
|
||||||
|
#if( configUSE_CO_ROUTINES != 0 )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some kernel aware debuggers require data to be viewed to be global, rather
|
||||||
|
* than file scope.
|
||||||
|
*/
|
||||||
|
#ifdef portREMOVE_STATIC_QUALIFIER
|
||||||
|
#define static
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Lists for ready and blocked co-routines. --------------------*/
|
||||||
|
static List_t pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ]; /*< Prioritised ready co-routines. */
|
||||||
|
static List_t xDelayedCoRoutineList1; /*< Delayed co-routines. */
|
||||||
|
static List_t xDelayedCoRoutineList2; /*< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */
|
||||||
|
static List_t * pxDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used. */
|
||||||
|
static List_t * pxOverflowDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */
|
||||||
|
static List_t xPendingReadyCoRoutineList; /*< Holds co-routines that have been readied by an external event. They cannot be added directly to the ready lists as the ready lists cannot be accessed by interrupts. */
|
||||||
|
|
||||||
|
/* Other file private variables. --------------------------------*/
|
||||||
|
CRCB_t * pxCurrentCoRoutine = NULL;
|
||||||
|
static UBaseType_t uxTopCoRoutineReadyPriority = 0;
|
||||||
|
static TickType_t xCoRoutineTickCount = 0, xLastTickCount = 0, xPassedTicks = 0;
|
||||||
|
|
||||||
|
/* The initial state of the co-routine when it is created. */
|
||||||
|
#define corINITIAL_STATE ( 0 )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Place the co-routine represented by pxCRCB into the appropriate ready queue
|
||||||
|
* for the priority. It is inserted at the end of the list.
|
||||||
|
*
|
||||||
|
* This macro accesses the co-routine ready lists and therefore must not be
|
||||||
|
* used from within an ISR.
|
||||||
|
*/
|
||||||
|
#define prvAddCoRoutineToReadyQueue( pxCRCB ) \
|
||||||
|
{ \
|
||||||
|
if( pxCRCB->uxPriority > uxTopCoRoutineReadyPriority ) \
|
||||||
|
{ \
|
||||||
|
uxTopCoRoutineReadyPriority = pxCRCB->uxPriority; \
|
||||||
|
} \
|
||||||
|
vListInsertEnd( ( List_t * ) &( pxReadyCoRoutineLists[ pxCRCB->uxPriority ] ), &( pxCRCB->xGenericListItem ) ); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Utility to ready all the lists used by the scheduler. This is called
|
||||||
|
* automatically upon the creation of the first co-routine.
|
||||||
|
*/
|
||||||
|
static void prvInitialiseCoRoutineLists( void );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Co-routines that are readied by an interrupt cannot be placed directly into
|
||||||
|
* the ready lists (there is no mutual exclusion). Instead they are placed in
|
||||||
|
* in the pending ready list in order that they can later be moved to the ready
|
||||||
|
* list by the co-routine scheduler.
|
||||||
|
*/
|
||||||
|
static void prvCheckPendingReadyList( void );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macro that looks at the list of co-routines that are currently delayed to
|
||||||
|
* see if any require waking.
|
||||||
|
*
|
||||||
|
* Co-routines are stored in the queue in the order of their wake time -
|
||||||
|
* meaning once one co-routine has been found whose timer has not expired
|
||||||
|
* we need not look any further down the list.
|
||||||
|
*/
|
||||||
|
static void prvCheckDelayedList( void );
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
BaseType_t xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, UBaseType_t uxPriority, UBaseType_t uxIndex )
|
||||||
|
{
|
||||||
|
BaseType_t xReturn;
|
||||||
|
CRCB_t *pxCoRoutine;
|
||||||
|
|
||||||
|
/* Allocate the memory that will store the co-routine control block. */
|
||||||
|
pxCoRoutine = ( CRCB_t * ) pvPortMalloc( sizeof( CRCB_t ) );
|
||||||
|
if( pxCoRoutine )
|
||||||
|
{
|
||||||
|
/* If pxCurrentCoRoutine is NULL then this is the first co-routine to
|
||||||
|
be created and the co-routine data structures need initialising. */
|
||||||
|
if( pxCurrentCoRoutine == NULL )
|
||||||
|
{
|
||||||
|
pxCurrentCoRoutine = pxCoRoutine;
|
||||||
|
prvInitialiseCoRoutineLists();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the priority is within limits. */
|
||||||
|
if( uxPriority >= configMAX_CO_ROUTINE_PRIORITIES )
|
||||||
|
{
|
||||||
|
uxPriority = configMAX_CO_ROUTINE_PRIORITIES - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill out the co-routine control block from the function parameters. */
|
||||||
|
pxCoRoutine->uxState = corINITIAL_STATE;
|
||||||
|
pxCoRoutine->uxPriority = uxPriority;
|
||||||
|
pxCoRoutine->uxIndex = uxIndex;
|
||||||
|
pxCoRoutine->pxCoRoutineFunction = pxCoRoutineCode;
|
||||||
|
|
||||||
|
/* Initialise all the other co-routine control block parameters. */
|
||||||
|
vListInitialiseItem( &( pxCoRoutine->xGenericListItem ) );
|
||||||
|
vListInitialiseItem( &( pxCoRoutine->xEventListItem ) );
|
||||||
|
|
||||||
|
/* Set the co-routine control block as a link back from the ListItem_t.
|
||||||
|
This is so we can get back to the containing CRCB from a generic item
|
||||||
|
in a list. */
|
||||||
|
listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xGenericListItem ), pxCoRoutine );
|
||||||
|
listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xEventListItem ), pxCoRoutine );
|
||||||
|
|
||||||
|
/* Event lists are always in priority order. */
|
||||||
|
listSET_LIST_ITEM_VALUE( &( pxCoRoutine->xEventListItem ), ( ( TickType_t ) configMAX_CO_ROUTINE_PRIORITIES - ( TickType_t ) uxPriority ) );
|
||||||
|
|
||||||
|
/* Now the co-routine has been initialised it can be added to the ready
|
||||||
|
list at the correct priority. */
|
||||||
|
prvAddCoRoutineToReadyQueue( pxCoRoutine );
|
||||||
|
|
||||||
|
xReturn = pdPASS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return xReturn;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vCoRoutineAddToDelayedList( TickType_t xTicksToDelay, List_t *pxEventList )
|
||||||
|
{
|
||||||
|
TickType_t xTimeToWake;
|
||||||
|
|
||||||
|
/* Calculate the time to wake - this may overflow but this is
|
||||||
|
not a problem. */
|
||||||
|
xTimeToWake = xCoRoutineTickCount + xTicksToDelay;
|
||||||
|
|
||||||
|
/* We must remove ourselves from the ready list before adding
|
||||||
|
ourselves to the blocked list as the same list item is used for
|
||||||
|
both lists. */
|
||||||
|
( void ) uxListRemove( ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) );
|
||||||
|
|
||||||
|
/* The list item will be inserted in wake time order. */
|
||||||
|
listSET_LIST_ITEM_VALUE( &( pxCurrentCoRoutine->xGenericListItem ), xTimeToWake );
|
||||||
|
|
||||||
|
if( xTimeToWake < xCoRoutineTickCount )
|
||||||
|
{
|
||||||
|
/* Wake time has overflowed. Place this item in the
|
||||||
|
overflow list. */
|
||||||
|
vListInsert( ( List_t * ) pxOverflowDelayedCoRoutineList, ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* The wake time has not overflowed, so we can use the
|
||||||
|
current block list. */
|
||||||
|
vListInsert( ( List_t * ) pxDelayedCoRoutineList, ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( pxEventList )
|
||||||
|
{
|
||||||
|
/* Also add the co-routine to an event list. If this is done then the
|
||||||
|
function must be called with interrupts disabled. */
|
||||||
|
vListInsert( pxEventList, &( pxCurrentCoRoutine->xEventListItem ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static void prvCheckPendingReadyList( void )
|
||||||
|
{
|
||||||
|
/* Are there any co-routines waiting to get moved to the ready list? These
|
||||||
|
are co-routines that have been readied by an ISR. The ISR cannot access
|
||||||
|
the ready lists itself. */
|
||||||
|
while( listLIST_IS_EMPTY( &xPendingReadyCoRoutineList ) == pdFALSE )
|
||||||
|
{
|
||||||
|
CRCB_t *pxUnblockedCRCB;
|
||||||
|
|
||||||
|
/* The pending ready list can be accessed by an ISR. */
|
||||||
|
portDISABLE_INTERRUPTS();
|
||||||
|
{
|
||||||
|
pxUnblockedCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( (&xPendingReadyCoRoutineList) );
|
||||||
|
( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) );
|
||||||
|
}
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
|
||||||
|
( void ) uxListRemove( &( pxUnblockedCRCB->xGenericListItem ) );
|
||||||
|
prvAddCoRoutineToReadyQueue( pxUnblockedCRCB );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static void prvCheckDelayedList( void )
|
||||||
|
{
|
||||||
|
CRCB_t *pxCRCB;
|
||||||
|
|
||||||
|
xPassedTicks = xTaskGetTickCount() - xLastTickCount;
|
||||||
|
while( xPassedTicks )
|
||||||
|
{
|
||||||
|
xCoRoutineTickCount++;
|
||||||
|
xPassedTicks--;
|
||||||
|
|
||||||
|
/* If the tick count has overflowed we need to swap the ready lists. */
|
||||||
|
if( xCoRoutineTickCount == 0 )
|
||||||
|
{
|
||||||
|
List_t * pxTemp;
|
||||||
|
|
||||||
|
/* Tick count has overflowed so we need to swap the delay lists. If there are
|
||||||
|
any items in pxDelayedCoRoutineList here then there is an error! */
|
||||||
|
pxTemp = pxDelayedCoRoutineList;
|
||||||
|
pxDelayedCoRoutineList = pxOverflowDelayedCoRoutineList;
|
||||||
|
pxOverflowDelayedCoRoutineList = pxTemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if this tick has made a timeout expire. */
|
||||||
|
while( listLIST_IS_EMPTY( pxDelayedCoRoutineList ) == pdFALSE )
|
||||||
|
{
|
||||||
|
pxCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList );
|
||||||
|
|
||||||
|
if( xCoRoutineTickCount < listGET_LIST_ITEM_VALUE( &( pxCRCB->xGenericListItem ) ) )
|
||||||
|
{
|
||||||
|
/* Timeout not yet expired. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
portDISABLE_INTERRUPTS();
|
||||||
|
{
|
||||||
|
/* The event could have occurred just before this critical
|
||||||
|
section. If this is the case then the generic list item will
|
||||||
|
have been moved to the pending ready list and the following
|
||||||
|
line is still valid. Also the pvContainer parameter will have
|
||||||
|
been set to NULL so the following lines are also valid. */
|
||||||
|
( void ) uxListRemove( &( pxCRCB->xGenericListItem ) );
|
||||||
|
|
||||||
|
/* Is the co-routine waiting on an event also? */
|
||||||
|
if( pxCRCB->xEventListItem.pxContainer )
|
||||||
|
{
|
||||||
|
( void ) uxListRemove( &( pxCRCB->xEventListItem ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
|
||||||
|
prvAddCoRoutineToReadyQueue( pxCRCB );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xLastTickCount = xCoRoutineTickCount;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vCoRoutineSchedule( void )
|
||||||
|
{
|
||||||
|
/* See if any co-routines readied by events need moving to the ready lists. */
|
||||||
|
prvCheckPendingReadyList();
|
||||||
|
|
||||||
|
/* See if any delayed co-routines have timed out. */
|
||||||
|
prvCheckDelayedList();
|
||||||
|
|
||||||
|
/* Find the highest priority queue that contains ready co-routines. */
|
||||||
|
while( listLIST_IS_EMPTY( &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ) )
|
||||||
|
{
|
||||||
|
if( uxTopCoRoutineReadyPriority == 0 )
|
||||||
|
{
|
||||||
|
/* No more co-routines to check. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
--uxTopCoRoutineReadyPriority;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the co-routines
|
||||||
|
of the same priority get an equal share of the processor time. */
|
||||||
|
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentCoRoutine, &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) );
|
||||||
|
|
||||||
|
/* Call the co-routine. */
|
||||||
|
( pxCurrentCoRoutine->pxCoRoutineFunction )( pxCurrentCoRoutine, pxCurrentCoRoutine->uxIndex );
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static void prvInitialiseCoRoutineLists( void )
|
||||||
|
{
|
||||||
|
UBaseType_t uxPriority;
|
||||||
|
|
||||||
|
for( uxPriority = 0; uxPriority < configMAX_CO_ROUTINE_PRIORITIES; uxPriority++ )
|
||||||
|
{
|
||||||
|
vListInitialise( ( List_t * ) &( pxReadyCoRoutineLists[ uxPriority ] ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
vListInitialise( ( List_t * ) &xDelayedCoRoutineList1 );
|
||||||
|
vListInitialise( ( List_t * ) &xDelayedCoRoutineList2 );
|
||||||
|
vListInitialise( ( List_t * ) &xPendingReadyCoRoutineList );
|
||||||
|
|
||||||
|
/* Start with pxDelayedCoRoutineList using list1 and the
|
||||||
|
pxOverflowDelayedCoRoutineList using list2. */
|
||||||
|
pxDelayedCoRoutineList = &xDelayedCoRoutineList1;
|
||||||
|
pxOverflowDelayedCoRoutineList = &xDelayedCoRoutineList2;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
BaseType_t xCoRoutineRemoveFromEventList( const List_t *pxEventList )
|
||||||
|
{
|
||||||
|
CRCB_t *pxUnblockedCRCB;
|
||||||
|
BaseType_t xReturn;
|
||||||
|
|
||||||
|
/* This function is called from within an interrupt. It can only access
|
||||||
|
event lists and the pending ready list. This function assumes that a
|
||||||
|
check has already been made to ensure pxEventList is not empty. */
|
||||||
|
pxUnblockedCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
|
||||||
|
( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) );
|
||||||
|
vListInsertEnd( ( List_t * ) &( xPendingReadyCoRoutineList ), &( pxUnblockedCRCB->xEventListItem ) );
|
||||||
|
|
||||||
|
if( pxUnblockedCRCB->uxPriority >= pxCurrentCoRoutine->uxPriority )
|
||||||
|
{
|
||||||
|
xReturn = pdTRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xReturn = pdFALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return xReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* configUSE_CO_ROUTINES == 0 */
|
||||||
|
|
||||||
753
Middlewares/Third_Party/FreeRTOS/Source/event_groups.c
vendored
Normal file
753
Middlewares/Third_Party/FreeRTOS/Source/event_groups.c
vendored
Normal file
@@ -0,0 +1,753 @@
|
|||||||
|
/*
|
||||||
|
* FreeRTOS Kernel V10.3.1
|
||||||
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org
|
||||||
|
* http://aws.amazon.com/freertos
|
||||||
|
*
|
||||||
|
* 1 tab == 4 spaces!
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Standard includes. */
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
|
||||||
|
all the API functions to use the MPU wrappers. That should only be done when
|
||||||
|
task.h is included from an application file. */
|
||||||
|
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||||
|
|
||||||
|
/* FreeRTOS includes. */
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
#include "timers.h"
|
||||||
|
#include "event_groups.h"
|
||||||
|
|
||||||
|
/* Lint e961, e750 and e9021 are suppressed as a MISRA exception justified
|
||||||
|
because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined
|
||||||
|
for the header files above, but not in this file, in order to generate the
|
||||||
|
correct privileged Vs unprivileged linkage and placement. */
|
||||||
|
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021 See comment above. */
|
||||||
|
|
||||||
|
/* The following bit fields convey control information in a task's event list
|
||||||
|
item value. It is important they don't clash with the
|
||||||
|
taskEVENT_LIST_ITEM_VALUE_IN_USE definition. */
|
||||||
|
#if configUSE_16_BIT_TICKS == 1
|
||||||
|
#define eventCLEAR_EVENTS_ON_EXIT_BIT 0x0100U
|
||||||
|
#define eventUNBLOCKED_DUE_TO_BIT_SET 0x0200U
|
||||||
|
#define eventWAIT_FOR_ALL_BITS 0x0400U
|
||||||
|
#define eventEVENT_BITS_CONTROL_BYTES 0xff00U
|
||||||
|
#else
|
||||||
|
#define eventCLEAR_EVENTS_ON_EXIT_BIT 0x01000000UL
|
||||||
|
#define eventUNBLOCKED_DUE_TO_BIT_SET 0x02000000UL
|
||||||
|
#define eventWAIT_FOR_ALL_BITS 0x04000000UL
|
||||||
|
#define eventEVENT_BITS_CONTROL_BYTES 0xff000000UL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct EventGroupDef_t
|
||||||
|
{
|
||||||
|
EventBits_t uxEventBits;
|
||||||
|
List_t xTasksWaitingForBits; /*< List of tasks waiting for a bit to be set. */
|
||||||
|
|
||||||
|
#if( configUSE_TRACE_FACILITY == 1 )
|
||||||
|
UBaseType_t uxEventGroupNumber;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
|
||||||
|
uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the event group is statically allocated to ensure no attempt is made to free the memory. */
|
||||||
|
#endif
|
||||||
|
} EventGroup_t;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test the bits set in uxCurrentEventBits to see if the wait condition is met.
|
||||||
|
* The wait condition is defined by xWaitForAllBits. If xWaitForAllBits is
|
||||||
|
* pdTRUE then the wait condition is met if all the bits set in uxBitsToWaitFor
|
||||||
|
* are also set in uxCurrentEventBits. If xWaitForAllBits is pdFALSE then the
|
||||||
|
* wait condition is met if any of the bits set in uxBitsToWait for are also set
|
||||||
|
* in uxCurrentEventBits.
|
||||||
|
*/
|
||||||
|
static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||||
|
|
||||||
|
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer )
|
||||||
|
{
|
||||||
|
EventGroup_t *pxEventBits;
|
||||||
|
|
||||||
|
/* A StaticEventGroup_t object must be provided. */
|
||||||
|
configASSERT( pxEventGroupBuffer );
|
||||||
|
|
||||||
|
#if( configASSERT_DEFINED == 1 )
|
||||||
|
{
|
||||||
|
/* Sanity check that the size of the structure used to declare a
|
||||||
|
variable of type StaticEventGroup_t equals the size of the real
|
||||||
|
event group structure. */
|
||||||
|
volatile size_t xSize = sizeof( StaticEventGroup_t );
|
||||||
|
configASSERT( xSize == sizeof( EventGroup_t ) );
|
||||||
|
} /*lint !e529 xSize is referenced if configASSERT() is defined. */
|
||||||
|
#endif /* configASSERT_DEFINED */
|
||||||
|
|
||||||
|
/* The user has provided a statically allocated event group - use it. */
|
||||||
|
pxEventBits = ( EventGroup_t * ) pxEventGroupBuffer; /*lint !e740 !e9087 EventGroup_t and StaticEventGroup_t are deliberately aliased for data hiding purposes and guaranteed to have the same size and alignment requirement - checked by configASSERT(). */
|
||||||
|
|
||||||
|
if( pxEventBits != NULL )
|
||||||
|
{
|
||||||
|
pxEventBits->uxEventBits = 0;
|
||||||
|
vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );
|
||||||
|
|
||||||
|
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||||
|
{
|
||||||
|
/* Both static and dynamic allocation can be used, so note that
|
||||||
|
this event group was created statically in case the event group
|
||||||
|
is later deleted. */
|
||||||
|
pxEventBits->ucStaticallyAllocated = pdTRUE;
|
||||||
|
}
|
||||||
|
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
|
||||||
|
|
||||||
|
traceEVENT_GROUP_CREATE( pxEventBits );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* xEventGroupCreateStatic should only ever be called with
|
||||||
|
pxEventGroupBuffer pointing to a pre-allocated (compile time
|
||||||
|
allocated) StaticEventGroup_t variable. */
|
||||||
|
traceEVENT_GROUP_CREATE_FAILED();
|
||||||
|
}
|
||||||
|
|
||||||
|
return pxEventBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||||
|
|
||||||
|
EventGroupHandle_t xEventGroupCreate( void )
|
||||||
|
{
|
||||||
|
EventGroup_t *pxEventBits;
|
||||||
|
|
||||||
|
/* Allocate the event group. Justification for MISRA deviation as
|
||||||
|
follows: pvPortMalloc() always ensures returned memory blocks are
|
||||||
|
aligned per the requirements of the MCU stack. In this case
|
||||||
|
pvPortMalloc() must return a pointer that is guaranteed to meet the
|
||||||
|
alignment requirements of the EventGroup_t structure - which (if you
|
||||||
|
follow it through) is the alignment requirements of the TickType_t type
|
||||||
|
(EventBits_t being of TickType_t itself). Therefore, whenever the
|
||||||
|
stack alignment requirements are greater than or equal to the
|
||||||
|
TickType_t alignment requirements the cast is safe. In other cases,
|
||||||
|
where the natural word size of the architecture is less than
|
||||||
|
sizeof( TickType_t ), the TickType_t variables will be accessed in two
|
||||||
|
or more reads operations, and the alignment requirements is only that
|
||||||
|
of each individual read. */
|
||||||
|
pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) ); /*lint !e9087 !e9079 see comment above. */
|
||||||
|
|
||||||
|
if( pxEventBits != NULL )
|
||||||
|
{
|
||||||
|
pxEventBits->uxEventBits = 0;
|
||||||
|
vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );
|
||||||
|
|
||||||
|
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||||
|
{
|
||||||
|
/* Both static and dynamic allocation can be used, so note this
|
||||||
|
event group was allocated statically in case the event group is
|
||||||
|
later deleted. */
|
||||||
|
pxEventBits->ucStaticallyAllocated = pdFALSE;
|
||||||
|
}
|
||||||
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||||
|
|
||||||
|
traceEVENT_GROUP_CREATE( pxEventBits );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
traceEVENT_GROUP_CREATE_FAILED(); /*lint !e9063 Else branch only exists to allow tracing and does not generate code if trace macros are not defined. */
|
||||||
|
}
|
||||||
|
|
||||||
|
return pxEventBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait )
|
||||||
|
{
|
||||||
|
EventBits_t uxOriginalBitValue, uxReturn;
|
||||||
|
EventGroup_t *pxEventBits = xEventGroup;
|
||||||
|
BaseType_t xAlreadyYielded;
|
||||||
|
BaseType_t xTimeoutOccurred = pdFALSE;
|
||||||
|
|
||||||
|
configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
|
||||||
|
configASSERT( uxBitsToWaitFor != 0 );
|
||||||
|
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
|
||||||
|
{
|
||||||
|
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
vTaskSuspendAll();
|
||||||
|
{
|
||||||
|
uxOriginalBitValue = pxEventBits->uxEventBits;
|
||||||
|
|
||||||
|
( void ) xEventGroupSetBits( xEventGroup, uxBitsToSet );
|
||||||
|
|
||||||
|
if( ( ( uxOriginalBitValue | uxBitsToSet ) & uxBitsToWaitFor ) == uxBitsToWaitFor )
|
||||||
|
{
|
||||||
|
/* All the rendezvous bits are now set - no need to block. */
|
||||||
|
uxReturn = ( uxOriginalBitValue | uxBitsToSet );
|
||||||
|
|
||||||
|
/* Rendezvous always clear the bits. They will have been cleared
|
||||||
|
already unless this is the only task in the rendezvous. */
|
||||||
|
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
|
||||||
|
|
||||||
|
xTicksToWait = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( xTicksToWait != ( TickType_t ) 0 )
|
||||||
|
{
|
||||||
|
traceEVENT_GROUP_SYNC_BLOCK( xEventGroup, uxBitsToSet, uxBitsToWaitFor );
|
||||||
|
|
||||||
|
/* Store the bits that the calling task is waiting for in the
|
||||||
|
task's event list item so the kernel knows when a match is
|
||||||
|
found. Then enter the blocked state. */
|
||||||
|
vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | eventCLEAR_EVENTS_ON_EXIT_BIT | eventWAIT_FOR_ALL_BITS ), xTicksToWait );
|
||||||
|
|
||||||
|
/* This assignment is obsolete as uxReturn will get set after
|
||||||
|
the task unblocks, but some compilers mistakenly generate a
|
||||||
|
warning about uxReturn being returned without being set if the
|
||||||
|
assignment is omitted. */
|
||||||
|
uxReturn = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* The rendezvous bits were not set, but no block time was
|
||||||
|
specified - just return the current event bit value. */
|
||||||
|
uxReturn = pxEventBits->uxEventBits;
|
||||||
|
xTimeoutOccurred = pdTRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xAlreadyYielded = xTaskResumeAll();
|
||||||
|
|
||||||
|
if( xTicksToWait != ( TickType_t ) 0 )
|
||||||
|
{
|
||||||
|
if( xAlreadyYielded == pdFALSE )
|
||||||
|
{
|
||||||
|
portYIELD_WITHIN_API();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The task blocked to wait for its required bits to be set - at this
|
||||||
|
point either the required bits were set or the block time expired. If
|
||||||
|
the required bits were set they will have been stored in the task's
|
||||||
|
event list item, and they should now be retrieved then cleared. */
|
||||||
|
uxReturn = uxTaskResetEventItemValue();
|
||||||
|
|
||||||
|
if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )
|
||||||
|
{
|
||||||
|
/* The task timed out, just return the current event bit value. */
|
||||||
|
taskENTER_CRITICAL();
|
||||||
|
{
|
||||||
|
uxReturn = pxEventBits->uxEventBits;
|
||||||
|
|
||||||
|
/* Although the task got here because it timed out before the
|
||||||
|
bits it was waiting for were set, it is possible that since it
|
||||||
|
unblocked another task has set the bits. If this is the case
|
||||||
|
then it needs to clear the bits before exiting. */
|
||||||
|
if( ( uxReturn & uxBitsToWaitFor ) == uxBitsToWaitFor )
|
||||||
|
{
|
||||||
|
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
taskEXIT_CRITICAL();
|
||||||
|
|
||||||
|
xTimeoutOccurred = pdTRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* The task unblocked because the bits were set. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Control bits might be set as the task had blocked should not be
|
||||||
|
returned. */
|
||||||
|
uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;
|
||||||
|
}
|
||||||
|
|
||||||
|
traceEVENT_GROUP_SYNC_END( xEventGroup, uxBitsToSet, uxBitsToWaitFor, xTimeoutOccurred );
|
||||||
|
|
||||||
|
/* Prevent compiler warnings when trace macros are not used. */
|
||||||
|
( void ) xTimeoutOccurred;
|
||||||
|
|
||||||
|
return uxReturn;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait )
|
||||||
|
{
|
||||||
|
EventGroup_t *pxEventBits = xEventGroup;
|
||||||
|
EventBits_t uxReturn, uxControlBits = 0;
|
||||||
|
BaseType_t xWaitConditionMet, xAlreadyYielded;
|
||||||
|
BaseType_t xTimeoutOccurred = pdFALSE;
|
||||||
|
|
||||||
|
/* Check the user is not attempting to wait on the bits used by the kernel
|
||||||
|
itself, and that at least one bit is being requested. */
|
||||||
|
configASSERT( xEventGroup );
|
||||||
|
configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
|
||||||
|
configASSERT( uxBitsToWaitFor != 0 );
|
||||||
|
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
|
||||||
|
{
|
||||||
|
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
vTaskSuspendAll();
|
||||||
|
{
|
||||||
|
const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits;
|
||||||
|
|
||||||
|
/* Check to see if the wait condition is already met or not. */
|
||||||
|
xWaitConditionMet = prvTestWaitCondition( uxCurrentEventBits, uxBitsToWaitFor, xWaitForAllBits );
|
||||||
|
|
||||||
|
if( xWaitConditionMet != pdFALSE )
|
||||||
|
{
|
||||||
|
/* The wait condition has already been met so there is no need to
|
||||||
|
block. */
|
||||||
|
uxReturn = uxCurrentEventBits;
|
||||||
|
xTicksToWait = ( TickType_t ) 0;
|
||||||
|
|
||||||
|
/* Clear the wait bits if requested to do so. */
|
||||||
|
if( xClearOnExit != pdFALSE )
|
||||||
|
{
|
||||||
|
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( xTicksToWait == ( TickType_t ) 0 )
|
||||||
|
{
|
||||||
|
/* The wait condition has not been met, but no block time was
|
||||||
|
specified, so just return the current value. */
|
||||||
|
uxReturn = uxCurrentEventBits;
|
||||||
|
xTimeoutOccurred = pdTRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* The task is going to block to wait for its required bits to be
|
||||||
|
set. uxControlBits are used to remember the specified behaviour of
|
||||||
|
this call to xEventGroupWaitBits() - for use when the event bits
|
||||||
|
unblock the task. */
|
||||||
|
if( xClearOnExit != pdFALSE )
|
||||||
|
{
|
||||||
|
uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
|
||||||
|
if( xWaitForAllBits != pdFALSE )
|
||||||
|
{
|
||||||
|
uxControlBits |= eventWAIT_FOR_ALL_BITS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store the bits that the calling task is waiting for in the
|
||||||
|
task's event list item so the kernel knows when a match is
|
||||||
|
found. Then enter the blocked state. */
|
||||||
|
vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait );
|
||||||
|
|
||||||
|
/* This is obsolete as it will get set after the task unblocks, but
|
||||||
|
some compilers mistakenly generate a warning about the variable
|
||||||
|
being returned without being set if it is not done. */
|
||||||
|
uxReturn = 0;
|
||||||
|
|
||||||
|
traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xAlreadyYielded = xTaskResumeAll();
|
||||||
|
|
||||||
|
if( xTicksToWait != ( TickType_t ) 0 )
|
||||||
|
{
|
||||||
|
if( xAlreadyYielded == pdFALSE )
|
||||||
|
{
|
||||||
|
portYIELD_WITHIN_API();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The task blocked to wait for its required bits to be set - at this
|
||||||
|
point either the required bits were set or the block time expired. If
|
||||||
|
the required bits were set they will have been stored in the task's
|
||||||
|
event list item, and they should now be retrieved then cleared. */
|
||||||
|
uxReturn = uxTaskResetEventItemValue();
|
||||||
|
|
||||||
|
if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )
|
||||||
|
{
|
||||||
|
taskENTER_CRITICAL();
|
||||||
|
{
|
||||||
|
/* The task timed out, just return the current event bit value. */
|
||||||
|
uxReturn = pxEventBits->uxEventBits;
|
||||||
|
|
||||||
|
/* It is possible that the event bits were updated between this
|
||||||
|
task leaving the Blocked state and running again. */
|
||||||
|
if( prvTestWaitCondition( uxReturn, uxBitsToWaitFor, xWaitForAllBits ) != pdFALSE )
|
||||||
|
{
|
||||||
|
if( xClearOnExit != pdFALSE )
|
||||||
|
{
|
||||||
|
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
xTimeoutOccurred = pdTRUE;
|
||||||
|
}
|
||||||
|
taskEXIT_CRITICAL();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* The task unblocked because the bits were set. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The task blocked so control bits may have been set. */
|
||||||
|
uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;
|
||||||
|
}
|
||||||
|
traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred );
|
||||||
|
|
||||||
|
/* Prevent compiler warnings when trace macros are not used. */
|
||||||
|
( void ) xTimeoutOccurred;
|
||||||
|
|
||||||
|
return uxReturn;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
|
||||||
|
{
|
||||||
|
EventGroup_t *pxEventBits = xEventGroup;
|
||||||
|
EventBits_t uxReturn;
|
||||||
|
|
||||||
|
/* Check the user is not attempting to clear the bits used by the kernel
|
||||||
|
itself. */
|
||||||
|
configASSERT( xEventGroup );
|
||||||
|
configASSERT( ( uxBitsToClear & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
|
||||||
|
|
||||||
|
taskENTER_CRITICAL();
|
||||||
|
{
|
||||||
|
traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear );
|
||||||
|
|
||||||
|
/* The value returned is the event group value prior to the bits being
|
||||||
|
cleared. */
|
||||||
|
uxReturn = pxEventBits->uxEventBits;
|
||||||
|
|
||||||
|
/* Clear the bits. */
|
||||||
|
pxEventBits->uxEventBits &= ~uxBitsToClear;
|
||||||
|
}
|
||||||
|
taskEXIT_CRITICAL();
|
||||||
|
|
||||||
|
return uxReturn;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )
|
||||||
|
|
||||||
|
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
|
||||||
|
{
|
||||||
|
BaseType_t xReturn;
|
||||||
|
|
||||||
|
traceEVENT_GROUP_CLEAR_BITS_FROM_ISR( xEventGroup, uxBitsToClear );
|
||||||
|
xReturn = xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL ); /*lint !e9087 Can't avoid cast to void* as a generic callback function not specific to this use case. Callback casts back to original type so safe. */
|
||||||
|
|
||||||
|
return xReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup )
|
||||||
|
{
|
||||||
|
UBaseType_t uxSavedInterruptStatus;
|
||||||
|
EventGroup_t const * const pxEventBits = xEventGroup;
|
||||||
|
EventBits_t uxReturn;
|
||||||
|
|
||||||
|
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
{
|
||||||
|
uxReturn = pxEventBits->uxEventBits;
|
||||||
|
}
|
||||||
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
|
||||||
|
|
||||||
|
return uxReturn;
|
||||||
|
} /*lint !e818 EventGroupHandle_t is a typedef used in other functions to so can't be pointer to const. */
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )
|
||||||
|
{
|
||||||
|
ListItem_t *pxListItem, *pxNext;
|
||||||
|
ListItem_t const *pxListEnd;
|
||||||
|
List_t const * pxList;
|
||||||
|
EventBits_t uxBitsToClear = 0, uxBitsWaitedFor, uxControlBits;
|
||||||
|
EventGroup_t *pxEventBits = xEventGroup;
|
||||||
|
BaseType_t xMatchFound = pdFALSE;
|
||||||
|
|
||||||
|
/* Check the user is not attempting to set the bits used by the kernel
|
||||||
|
itself. */
|
||||||
|
configASSERT( xEventGroup );
|
||||||
|
configASSERT( ( uxBitsToSet & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
|
||||||
|
|
||||||
|
pxList = &( pxEventBits->xTasksWaitingForBits );
|
||||||
|
pxListEnd = listGET_END_MARKER( pxList ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */
|
||||||
|
vTaskSuspendAll();
|
||||||
|
{
|
||||||
|
traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet );
|
||||||
|
|
||||||
|
pxListItem = listGET_HEAD_ENTRY( pxList );
|
||||||
|
|
||||||
|
/* Set the bits. */
|
||||||
|
pxEventBits->uxEventBits |= uxBitsToSet;
|
||||||
|
|
||||||
|
/* See if the new bit value should unblock any tasks. */
|
||||||
|
while( pxListItem != pxListEnd )
|
||||||
|
{
|
||||||
|
pxNext = listGET_NEXT( pxListItem );
|
||||||
|
uxBitsWaitedFor = listGET_LIST_ITEM_VALUE( pxListItem );
|
||||||
|
xMatchFound = pdFALSE;
|
||||||
|
|
||||||
|
/* Split the bits waited for from the control bits. */
|
||||||
|
uxControlBits = uxBitsWaitedFor & eventEVENT_BITS_CONTROL_BYTES;
|
||||||
|
uxBitsWaitedFor &= ~eventEVENT_BITS_CONTROL_BYTES;
|
||||||
|
|
||||||
|
if( ( uxControlBits & eventWAIT_FOR_ALL_BITS ) == ( EventBits_t ) 0 )
|
||||||
|
{
|
||||||
|
/* Just looking for single bit being set. */
|
||||||
|
if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) != ( EventBits_t ) 0 )
|
||||||
|
{
|
||||||
|
xMatchFound = pdTRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) == uxBitsWaitedFor )
|
||||||
|
{
|
||||||
|
/* All bits are set. */
|
||||||
|
xMatchFound = pdTRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Need all bits to be set, but not all the bits were set. */
|
||||||
|
}
|
||||||
|
|
||||||
|
if( xMatchFound != pdFALSE )
|
||||||
|
{
|
||||||
|
/* The bits match. Should the bits be cleared on exit? */
|
||||||
|
if( ( uxControlBits & eventCLEAR_EVENTS_ON_EXIT_BIT ) != ( EventBits_t ) 0 )
|
||||||
|
{
|
||||||
|
uxBitsToClear |= uxBitsWaitedFor;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store the actual event flag value in the task's event list
|
||||||
|
item before removing the task from the event list. The
|
||||||
|
eventUNBLOCKED_DUE_TO_BIT_SET bit is set so the task knows
|
||||||
|
that is was unblocked due to its required bits matching, rather
|
||||||
|
than because it timed out. */
|
||||||
|
vTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move onto the next list item. Note pxListItem->pxNext is not
|
||||||
|
used here as the list item may have been removed from the event list
|
||||||
|
and inserted into the ready/pending reading list. */
|
||||||
|
pxListItem = pxNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear any bits that matched when the eventCLEAR_EVENTS_ON_EXIT_BIT
|
||||||
|
bit was set in the control word. */
|
||||||
|
pxEventBits->uxEventBits &= ~uxBitsToClear;
|
||||||
|
}
|
||||||
|
( void ) xTaskResumeAll();
|
||||||
|
|
||||||
|
return pxEventBits->uxEventBits;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vEventGroupDelete( EventGroupHandle_t xEventGroup )
|
||||||
|
{
|
||||||
|
EventGroup_t *pxEventBits = xEventGroup;
|
||||||
|
const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits );
|
||||||
|
|
||||||
|
vTaskSuspendAll();
|
||||||
|
{
|
||||||
|
traceEVENT_GROUP_DELETE( xEventGroup );
|
||||||
|
|
||||||
|
while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( UBaseType_t ) 0 )
|
||||||
|
{
|
||||||
|
/* Unblock the task, returning 0 as the event list is being deleted
|
||||||
|
and cannot therefore have any bits set. */
|
||||||
|
configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( const ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) );
|
||||||
|
vTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET );
|
||||||
|
}
|
||||||
|
|
||||||
|
#if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) )
|
||||||
|
{
|
||||||
|
/* The event group can only have been allocated dynamically - free
|
||||||
|
it again. */
|
||||||
|
vPortFree( pxEventBits );
|
||||||
|
}
|
||||||
|
#elif( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
|
||||||
|
{
|
||||||
|
/* The event group could have been allocated statically or
|
||||||
|
dynamically, so check before attempting to free the memory. */
|
||||||
|
if( pxEventBits->ucStaticallyAllocated == ( uint8_t ) pdFALSE )
|
||||||
|
{
|
||||||
|
vPortFree( pxEventBits );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
|
||||||
|
}
|
||||||
|
( void ) xTaskResumeAll();
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* For internal use only - execute a 'set bits' command that was pended from
|
||||||
|
an interrupt. */
|
||||||
|
void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet )
|
||||||
|
{
|
||||||
|
( void ) xEventGroupSetBits( pvEventGroup, ( EventBits_t ) ulBitsToSet ); /*lint !e9079 Can't avoid cast to void* as a generic timer callback prototype. Callback casts back to original type so safe. */
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* For internal use only - execute a 'clear bits' command that was pended from
|
||||||
|
an interrupt. */
|
||||||
|
void vEventGroupClearBitsCallback( void *pvEventGroup, const uint32_t ulBitsToClear )
|
||||||
|
{
|
||||||
|
( void ) xEventGroupClearBits( pvEventGroup, ( EventBits_t ) ulBitsToClear ); /*lint !e9079 Can't avoid cast to void* as a generic timer callback prototype. Callback casts back to original type so safe. */
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits )
|
||||||
|
{
|
||||||
|
BaseType_t xWaitConditionMet = pdFALSE;
|
||||||
|
|
||||||
|
if( xWaitForAllBits == pdFALSE )
|
||||||
|
{
|
||||||
|
/* Task only has to wait for one bit within uxBitsToWaitFor to be
|
||||||
|
set. Is one already set? */
|
||||||
|
if( ( uxCurrentEventBits & uxBitsToWaitFor ) != ( EventBits_t ) 0 )
|
||||||
|
{
|
||||||
|
xWaitConditionMet = pdTRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Task has to wait for all the bits in uxBitsToWaitFor to be set.
|
||||||
|
Are they set already? */
|
||||||
|
if( ( uxCurrentEventBits & uxBitsToWaitFor ) == uxBitsToWaitFor )
|
||||||
|
{
|
||||||
|
xWaitConditionMet = pdTRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return xWaitConditionMet;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )
|
||||||
|
|
||||||
|
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken )
|
||||||
|
{
|
||||||
|
BaseType_t xReturn;
|
||||||
|
|
||||||
|
traceEVENT_GROUP_SET_BITS_FROM_ISR( xEventGroup, uxBitsToSet );
|
||||||
|
xReturn = xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken ); /*lint !e9087 Can't avoid cast to void* as a generic callback function not specific to this use case. Callback casts back to original type so safe. */
|
||||||
|
|
||||||
|
return xReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if (configUSE_TRACE_FACILITY == 1)
|
||||||
|
|
||||||
|
UBaseType_t uxEventGroupGetNumber( void* xEventGroup )
|
||||||
|
{
|
||||||
|
UBaseType_t xReturn;
|
||||||
|
EventGroup_t const *pxEventBits = ( EventGroup_t * ) xEventGroup; /*lint !e9087 !e9079 EventGroupHandle_t is a pointer to an EventGroup_t, but EventGroupHandle_t is kept opaque outside of this file for data hiding purposes. */
|
||||||
|
|
||||||
|
if( xEventGroup == NULL )
|
||||||
|
{
|
||||||
|
xReturn = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xReturn = pxEventBits->uxEventGroupNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
return xReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* configUSE_TRACE_FACILITY */
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||||
|
|
||||||
|
void vEventGroupSetNumber( void * xEventGroup, UBaseType_t uxEventGroupNumber )
|
||||||
|
{
|
||||||
|
( ( EventGroup_t * ) xEventGroup )->uxEventGroupNumber = uxEventGroupNumber; /*lint !e9087 !e9079 EventGroupHandle_t is a pointer to an EventGroup_t, but EventGroupHandle_t is kept opaque outside of this file for data hiding purposes. */
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* configUSE_TRACE_FACILITY */
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
1295
Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h
vendored
Normal file
1295
Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
133
Middlewares/Third_Party/FreeRTOS/Source/include/StackMacros.h
vendored
Normal file
133
Middlewares/Third_Party/FreeRTOS/Source/include/StackMacros.h
vendored
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* FreeRTOS Kernel V10.3.1
|
||||||
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org
|
||||||
|
* http://aws.amazon.com/freertos
|
||||||
|
*
|
||||||
|
* 1 tab == 4 spaces!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STACK_MACROS_H
|
||||||
|
#define STACK_MACROS_H
|
||||||
|
|
||||||
|
#ifndef _MSC_VER /* Visual Studio doesn't support #warning. */
|
||||||
|
#warning The name of this file has changed to stack_macros.h. Please update your code accordingly. This source file (which has the original name) will be removed in future released.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call the stack overflow hook function if the stack of the task being swapped
|
||||||
|
* out is currently overflowed, or looks like it might have overflowed in the
|
||||||
|
* past.
|
||||||
|
*
|
||||||
|
* Setting configCHECK_FOR_STACK_OVERFLOW to 1 will cause the macro to check
|
||||||
|
* the current stack state only - comparing the current top of stack value to
|
||||||
|
* the stack limit. Setting configCHECK_FOR_STACK_OVERFLOW to greater than 1
|
||||||
|
* will also cause the last few stack bytes to be checked to ensure the value
|
||||||
|
* to which the bytes were set when the task was created have not been
|
||||||
|
* overwritten. Note this second test does not guarantee that an overflowed
|
||||||
|
* stack will always be recognised.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH < 0 ) )
|
||||||
|
|
||||||
|
/* Only the current stack state is to be checked. */
|
||||||
|
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||||
|
{ \
|
||||||
|
/* Is the currently saved stack pointer within the stack limit? */ \
|
||||||
|
if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack ) \
|
||||||
|
{ \
|
||||||
|
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH > 0 ) )
|
||||||
|
|
||||||
|
/* Only the current stack state is to be checked. */
|
||||||
|
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||||
|
{ \
|
||||||
|
\
|
||||||
|
/* Is the currently saved stack pointer within the stack limit? */ \
|
||||||
|
if( pxCurrentTCB->pxTopOfStack >= pxCurrentTCB->pxEndOfStack ) \
|
||||||
|
{ \
|
||||||
|
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH < 0 ) )
|
||||||
|
|
||||||
|
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||||
|
{ \
|
||||||
|
const uint32_t * const pulStack = ( uint32_t * ) pxCurrentTCB->pxStack; \
|
||||||
|
const uint32_t ulCheckValue = ( uint32_t ) 0xa5a5a5a5; \
|
||||||
|
\
|
||||||
|
if( ( pulStack[ 0 ] != ulCheckValue ) || \
|
||||||
|
( pulStack[ 1 ] != ulCheckValue ) || \
|
||||||
|
( pulStack[ 2 ] != ulCheckValue ) || \
|
||||||
|
( pulStack[ 3 ] != ulCheckValue ) ) \
|
||||||
|
{ \
|
||||||
|
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH > 0 ) )
|
||||||
|
|
||||||
|
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||||
|
{ \
|
||||||
|
int8_t *pcEndOfStack = ( int8_t * ) pxCurrentTCB->pxEndOfStack; \
|
||||||
|
static const uint8_t ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||||
|
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||||
|
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||||
|
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||||
|
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \
|
||||||
|
\
|
||||||
|
\
|
||||||
|
pcEndOfStack -= sizeof( ucExpectedStackBytes ); \
|
||||||
|
\
|
||||||
|
/* Has the extremity of the task stack ever been written over? */ \
|
||||||
|
if( memcmp( ( void * ) pcEndOfStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \
|
||||||
|
{ \
|
||||||
|
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Remove stack overflow macro if not being used. */
|
||||||
|
#ifndef taskCHECK_FOR_STACK_OVERFLOW
|
||||||
|
#define taskCHECK_FOR_STACK_OVERFLOW()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* STACK_MACROS_H */
|
||||||
|
|
||||||
414
Middlewares/Third_Party/FreeRTOS/Source/include/atomic.h
vendored
Normal file
414
Middlewares/Third_Party/FreeRTOS/Source/include/atomic.h
vendored
Normal file
@@ -0,0 +1,414 @@
|
|||||||
|
/*
|
||||||
|
* FreeRTOS Kernel V10.3.1
|
||||||
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org
|
||||||
|
* http://aws.amazon.com/freertos
|
||||||
|
*
|
||||||
|
* 1 tab == 4 spaces!
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file atomic.h
|
||||||
|
* @brief FreeRTOS atomic operation support.
|
||||||
|
*
|
||||||
|
* This file implements atomic functions by disabling interrupts globally.
|
||||||
|
* Implementations with architecture specific atomic instructions can be
|
||||||
|
* provided under each compiler directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ATOMIC_H
|
||||||
|
#define ATOMIC_H
|
||||||
|
|
||||||
|
#ifndef INC_FREERTOS_H
|
||||||
|
#error "include FreeRTOS.h must appear in source files before include atomic.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Standard includes. */
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Port specific definitions -- entering/exiting critical section.
|
||||||
|
* Refer template -- ./lib/FreeRTOS/portable/Compiler/Arch/portmacro.h
|
||||||
|
*
|
||||||
|
* Every call to ATOMIC_EXIT_CRITICAL() must be closely paired with
|
||||||
|
* ATOMIC_ENTER_CRITICAL().
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#if defined( portSET_INTERRUPT_MASK_FROM_ISR )
|
||||||
|
|
||||||
|
/* Nested interrupt scheme is supported in this port. */
|
||||||
|
#define ATOMIC_ENTER_CRITICAL() \
|
||||||
|
UBaseType_t uxCriticalSectionType = portSET_INTERRUPT_MASK_FROM_ISR()
|
||||||
|
|
||||||
|
#define ATOMIC_EXIT_CRITICAL() \
|
||||||
|
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxCriticalSectionType )
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Nested interrupt scheme is NOT supported in this port. */
|
||||||
|
#define ATOMIC_ENTER_CRITICAL() portENTER_CRITICAL()
|
||||||
|
#define ATOMIC_EXIT_CRITICAL() portEXIT_CRITICAL()
|
||||||
|
|
||||||
|
#endif /* portSET_INTERRUPT_MASK_FROM_ISR() */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Port specific definition -- "always inline".
|
||||||
|
* Inline is compiler specific, and may not always get inlined depending on your
|
||||||
|
* optimization level. Also, inline is considered as performance optimization
|
||||||
|
* for atomic. Thus, if portFORCE_INLINE is not provided by portmacro.h,
|
||||||
|
* instead of resulting error, simply define it away.
|
||||||
|
*/
|
||||||
|
#ifndef portFORCE_INLINE
|
||||||
|
#define portFORCE_INLINE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ATOMIC_COMPARE_AND_SWAP_SUCCESS 0x1U /**< Compare and swap succeeded, swapped. */
|
||||||
|
#define ATOMIC_COMPARE_AND_SWAP_FAILURE 0x0U /**< Compare and swap failed, did not swap. */
|
||||||
|
|
||||||
|
/*----------------------------- Swap && CAS ------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Atomic compare-and-swap
|
||||||
|
*
|
||||||
|
* @brief Performs an atomic compare-and-swap operation on the specified values.
|
||||||
|
*
|
||||||
|
* @param[in, out] pulDestination Pointer to memory location from where value is
|
||||||
|
* to be loaded and checked.
|
||||||
|
* @param[in] ulExchange If condition meets, write this value to memory.
|
||||||
|
* @param[in] ulComparand Swap condition.
|
||||||
|
*
|
||||||
|
* @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped.
|
||||||
|
*
|
||||||
|
* @note This function only swaps *pulDestination with ulExchange, if previous
|
||||||
|
* *pulDestination value equals ulComparand.
|
||||||
|
*/
|
||||||
|
static portFORCE_INLINE uint32_t Atomic_CompareAndSwap_u32( uint32_t volatile * pulDestination,
|
||||||
|
uint32_t ulExchange,
|
||||||
|
uint32_t ulComparand )
|
||||||
|
{
|
||||||
|
uint32_t ulReturnValue;
|
||||||
|
|
||||||
|
ATOMIC_ENTER_CRITICAL();
|
||||||
|
{
|
||||||
|
if( *pulDestination == ulComparand )
|
||||||
|
{
|
||||||
|
*pulDestination = ulExchange;
|
||||||
|
ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ATOMIC_EXIT_CRITICAL();
|
||||||
|
|
||||||
|
return ulReturnValue;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Atomic swap (pointers)
|
||||||
|
*
|
||||||
|
* @brief Atomically sets the address pointed to by *ppvDestination to the value
|
||||||
|
* of *pvExchange.
|
||||||
|
*
|
||||||
|
* @param[in, out] ppvDestination Pointer to memory location from where a pointer
|
||||||
|
* value is to be loaded and written back to.
|
||||||
|
* @param[in] pvExchange Pointer value to be written to *ppvDestination.
|
||||||
|
*
|
||||||
|
* @return The initial value of *ppvDestination.
|
||||||
|
*/
|
||||||
|
static portFORCE_INLINE void * Atomic_SwapPointers_p32( void * volatile * ppvDestination,
|
||||||
|
void * pvExchange )
|
||||||
|
{
|
||||||
|
void * pReturnValue;
|
||||||
|
|
||||||
|
ATOMIC_ENTER_CRITICAL();
|
||||||
|
{
|
||||||
|
pReturnValue = *ppvDestination;
|
||||||
|
*ppvDestination = pvExchange;
|
||||||
|
}
|
||||||
|
ATOMIC_EXIT_CRITICAL();
|
||||||
|
|
||||||
|
return pReturnValue;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Atomic compare-and-swap (pointers)
|
||||||
|
*
|
||||||
|
* @brief Performs an atomic compare-and-swap operation on the specified pointer
|
||||||
|
* values.
|
||||||
|
*
|
||||||
|
* @param[in, out] ppvDestination Pointer to memory location from where a pointer
|
||||||
|
* value is to be loaded and checked.
|
||||||
|
* @param[in] pvExchange If condition meets, write this value to memory.
|
||||||
|
* @param[in] pvComparand Swap condition.
|
||||||
|
*
|
||||||
|
* @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped.
|
||||||
|
*
|
||||||
|
* @note This function only swaps *ppvDestination with pvExchange, if previous
|
||||||
|
* *ppvDestination value equals pvComparand.
|
||||||
|
*/
|
||||||
|
static portFORCE_INLINE uint32_t Atomic_CompareAndSwapPointers_p32( void * volatile * ppvDestination,
|
||||||
|
void * pvExchange,
|
||||||
|
void * pvComparand )
|
||||||
|
{
|
||||||
|
uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE;
|
||||||
|
|
||||||
|
ATOMIC_ENTER_CRITICAL();
|
||||||
|
{
|
||||||
|
if( *ppvDestination == pvComparand )
|
||||||
|
{
|
||||||
|
*ppvDestination = pvExchange;
|
||||||
|
ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ATOMIC_EXIT_CRITICAL();
|
||||||
|
|
||||||
|
return ulReturnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------- Arithmetic ------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Atomic add
|
||||||
|
*
|
||||||
|
* @brief Atomically adds count to the value of the specified pointer points to.
|
||||||
|
*
|
||||||
|
* @param[in,out] pulAddend Pointer to memory location from where value is to be
|
||||||
|
* loaded and written back to.
|
||||||
|
* @param[in] ulCount Value to be added to *pulAddend.
|
||||||
|
*
|
||||||
|
* @return previous *pulAddend value.
|
||||||
|
*/
|
||||||
|
static portFORCE_INLINE uint32_t Atomic_Add_u32( uint32_t volatile * pulAddend,
|
||||||
|
uint32_t ulCount )
|
||||||
|
{
|
||||||
|
uint32_t ulCurrent;
|
||||||
|
|
||||||
|
ATOMIC_ENTER_CRITICAL();
|
||||||
|
{
|
||||||
|
ulCurrent = *pulAddend;
|
||||||
|
*pulAddend += ulCount;
|
||||||
|
}
|
||||||
|
ATOMIC_EXIT_CRITICAL();
|
||||||
|
|
||||||
|
return ulCurrent;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Atomic subtract
|
||||||
|
*
|
||||||
|
* @brief Atomically subtracts count from the value of the specified pointer
|
||||||
|
* pointers to.
|
||||||
|
*
|
||||||
|
* @param[in,out] pulAddend Pointer to memory location from where value is to be
|
||||||
|
* loaded and written back to.
|
||||||
|
* @param[in] ulCount Value to be subtract from *pulAddend.
|
||||||
|
*
|
||||||
|
* @return previous *pulAddend value.
|
||||||
|
*/
|
||||||
|
static portFORCE_INLINE uint32_t Atomic_Subtract_u32( uint32_t volatile * pulAddend,
|
||||||
|
uint32_t ulCount )
|
||||||
|
{
|
||||||
|
uint32_t ulCurrent;
|
||||||
|
|
||||||
|
ATOMIC_ENTER_CRITICAL();
|
||||||
|
{
|
||||||
|
ulCurrent = *pulAddend;
|
||||||
|
*pulAddend -= ulCount;
|
||||||
|
}
|
||||||
|
ATOMIC_EXIT_CRITICAL();
|
||||||
|
|
||||||
|
return ulCurrent;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Atomic increment
|
||||||
|
*
|
||||||
|
* @brief Atomically increments the value of the specified pointer points to.
|
||||||
|
*
|
||||||
|
* @param[in,out] pulAddend Pointer to memory location from where value is to be
|
||||||
|
* loaded and written back to.
|
||||||
|
*
|
||||||
|
* @return *pulAddend value before increment.
|
||||||
|
*/
|
||||||
|
static portFORCE_INLINE uint32_t Atomic_Increment_u32( uint32_t volatile * pulAddend )
|
||||||
|
{
|
||||||
|
uint32_t ulCurrent;
|
||||||
|
|
||||||
|
ATOMIC_ENTER_CRITICAL();
|
||||||
|
{
|
||||||
|
ulCurrent = *pulAddend;
|
||||||
|
*pulAddend += 1;
|
||||||
|
}
|
||||||
|
ATOMIC_EXIT_CRITICAL();
|
||||||
|
|
||||||
|
return ulCurrent;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Atomic decrement
|
||||||
|
*
|
||||||
|
* @brief Atomically decrements the value of the specified pointer points to
|
||||||
|
*
|
||||||
|
* @param[in,out] pulAddend Pointer to memory location from where value is to be
|
||||||
|
* loaded and written back to.
|
||||||
|
*
|
||||||
|
* @return *pulAddend value before decrement.
|
||||||
|
*/
|
||||||
|
static portFORCE_INLINE uint32_t Atomic_Decrement_u32( uint32_t volatile * pulAddend )
|
||||||
|
{
|
||||||
|
uint32_t ulCurrent;
|
||||||
|
|
||||||
|
ATOMIC_ENTER_CRITICAL();
|
||||||
|
{
|
||||||
|
ulCurrent = *pulAddend;
|
||||||
|
*pulAddend -= 1;
|
||||||
|
}
|
||||||
|
ATOMIC_EXIT_CRITICAL();
|
||||||
|
|
||||||
|
return ulCurrent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------- Bitwise Logical ------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Atomic OR
|
||||||
|
*
|
||||||
|
* @brief Performs an atomic OR operation on the specified values.
|
||||||
|
*
|
||||||
|
* @param [in, out] pulDestination Pointer to memory location from where value is
|
||||||
|
* to be loaded and written back to.
|
||||||
|
* @param [in] ulValue Value to be ORed with *pulDestination.
|
||||||
|
*
|
||||||
|
* @return The original value of *pulDestination.
|
||||||
|
*/
|
||||||
|
static portFORCE_INLINE uint32_t Atomic_OR_u32( uint32_t volatile * pulDestination,
|
||||||
|
uint32_t ulValue )
|
||||||
|
{
|
||||||
|
uint32_t ulCurrent;
|
||||||
|
|
||||||
|
ATOMIC_ENTER_CRITICAL();
|
||||||
|
{
|
||||||
|
ulCurrent = *pulDestination;
|
||||||
|
*pulDestination |= ulValue;
|
||||||
|
}
|
||||||
|
ATOMIC_EXIT_CRITICAL();
|
||||||
|
|
||||||
|
return ulCurrent;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Atomic AND
|
||||||
|
*
|
||||||
|
* @brief Performs an atomic AND operation on the specified values.
|
||||||
|
*
|
||||||
|
* @param [in, out] pulDestination Pointer to memory location from where value is
|
||||||
|
* to be loaded and written back to.
|
||||||
|
* @param [in] ulValue Value to be ANDed with *pulDestination.
|
||||||
|
*
|
||||||
|
* @return The original value of *pulDestination.
|
||||||
|
*/
|
||||||
|
static portFORCE_INLINE uint32_t Atomic_AND_u32( uint32_t volatile * pulDestination,
|
||||||
|
uint32_t ulValue )
|
||||||
|
{
|
||||||
|
uint32_t ulCurrent;
|
||||||
|
|
||||||
|
ATOMIC_ENTER_CRITICAL();
|
||||||
|
{
|
||||||
|
ulCurrent = *pulDestination;
|
||||||
|
*pulDestination &= ulValue;
|
||||||
|
}
|
||||||
|
ATOMIC_EXIT_CRITICAL();
|
||||||
|
|
||||||
|
return ulCurrent;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Atomic NAND
|
||||||
|
*
|
||||||
|
* @brief Performs an atomic NAND operation on the specified values.
|
||||||
|
*
|
||||||
|
* @param [in, out] pulDestination Pointer to memory location from where value is
|
||||||
|
* to be loaded and written back to.
|
||||||
|
* @param [in] ulValue Value to be NANDed with *pulDestination.
|
||||||
|
*
|
||||||
|
* @return The original value of *pulDestination.
|
||||||
|
*/
|
||||||
|
static portFORCE_INLINE uint32_t Atomic_NAND_u32( uint32_t volatile * pulDestination,
|
||||||
|
uint32_t ulValue )
|
||||||
|
{
|
||||||
|
uint32_t ulCurrent;
|
||||||
|
|
||||||
|
ATOMIC_ENTER_CRITICAL();
|
||||||
|
{
|
||||||
|
ulCurrent = *pulDestination;
|
||||||
|
*pulDestination = ~( ulCurrent & ulValue );
|
||||||
|
}
|
||||||
|
ATOMIC_EXIT_CRITICAL();
|
||||||
|
|
||||||
|
return ulCurrent;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Atomic XOR
|
||||||
|
*
|
||||||
|
* @brief Performs an atomic XOR operation on the specified values.
|
||||||
|
*
|
||||||
|
* @param [in, out] pulDestination Pointer to memory location from where value is
|
||||||
|
* to be loaded and written back to.
|
||||||
|
* @param [in] ulValue Value to be XORed with *pulDestination.
|
||||||
|
*
|
||||||
|
* @return The original value of *pulDestination.
|
||||||
|
*/
|
||||||
|
static portFORCE_INLINE uint32_t Atomic_XOR_u32( uint32_t volatile * pulDestination,
|
||||||
|
uint32_t ulValue )
|
||||||
|
{
|
||||||
|
uint32_t ulCurrent;
|
||||||
|
|
||||||
|
ATOMIC_ENTER_CRITICAL();
|
||||||
|
{
|
||||||
|
ulCurrent = *pulDestination;
|
||||||
|
*pulDestination ^= ulValue;
|
||||||
|
}
|
||||||
|
ATOMIC_EXIT_CRITICAL();
|
||||||
|
|
||||||
|
return ulCurrent;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ATOMIC_H */
|
||||||
720
Middlewares/Third_Party/FreeRTOS/Source/include/croutine.h
vendored
Normal file
720
Middlewares/Third_Party/FreeRTOS/Source/include/croutine.h
vendored
Normal file
@@ -0,0 +1,720 @@
|
|||||||
|
/*
|
||||||
|
* FreeRTOS Kernel V10.3.1
|
||||||
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org
|
||||||
|
* http://aws.amazon.com/freertos
|
||||||
|
*
|
||||||
|
* 1 tab == 4 spaces!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CO_ROUTINE_H
|
||||||
|
#define CO_ROUTINE_H
|
||||||
|
|
||||||
|
#ifndef INC_FREERTOS_H
|
||||||
|
#error "include FreeRTOS.h must appear in source files before include croutine.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Used to hide the implementation of the co-routine control block. The
|
||||||
|
control block structure however has to be included in the header due to
|
||||||
|
the macro implementation of the co-routine functionality. */
|
||||||
|
typedef void * CoRoutineHandle_t;
|
||||||
|
|
||||||
|
/* Defines the prototype to which co-routine functions must conform. */
|
||||||
|
typedef void (*crCOROUTINE_CODE)( CoRoutineHandle_t, UBaseType_t );
|
||||||
|
|
||||||
|
typedef struct corCoRoutineControlBlock
|
||||||
|
{
|
||||||
|
crCOROUTINE_CODE pxCoRoutineFunction;
|
||||||
|
ListItem_t xGenericListItem; /*< List item used to place the CRCB in ready and blocked queues. */
|
||||||
|
ListItem_t xEventListItem; /*< List item used to place the CRCB in event lists. */
|
||||||
|
UBaseType_t uxPriority; /*< The priority of the co-routine in relation to other co-routines. */
|
||||||
|
UBaseType_t uxIndex; /*< Used to distinguish between co-routines when multiple co-routines use the same co-routine function. */
|
||||||
|
uint16_t uxState; /*< Used internally by the co-routine implementation. */
|
||||||
|
} CRCB_t; /* Co-routine control block. Note must be identical in size down to uxPriority with TCB_t. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* croutine. h
|
||||||
|
*<pre>
|
||||||
|
BaseType_t xCoRoutineCreate(
|
||||||
|
crCOROUTINE_CODE pxCoRoutineCode,
|
||||||
|
UBaseType_t uxPriority,
|
||||||
|
UBaseType_t uxIndex
|
||||||
|
);</pre>
|
||||||
|
*
|
||||||
|
* Create a new co-routine and add it to the list of co-routines that are
|
||||||
|
* ready to run.
|
||||||
|
*
|
||||||
|
* @param pxCoRoutineCode Pointer to the co-routine function. Co-routine
|
||||||
|
* functions require special syntax - see the co-routine section of the WEB
|
||||||
|
* documentation for more information.
|
||||||
|
*
|
||||||
|
* @param uxPriority The priority with respect to other co-routines at which
|
||||||
|
* the co-routine will run.
|
||||||
|
*
|
||||||
|
* @param uxIndex Used to distinguish between different co-routines that
|
||||||
|
* execute the same function. See the example below and the co-routine section
|
||||||
|
* of the WEB documentation for further information.
|
||||||
|
*
|
||||||
|
* @return pdPASS if the co-routine was successfully created and added to a ready
|
||||||
|
* list, otherwise an error code defined with ProjDefs.h.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
// Co-routine to be created.
|
||||||
|
void vFlashCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
|
||||||
|
{
|
||||||
|
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
|
||||||
|
// This may not be necessary for const variables.
|
||||||
|
static const char cLedToFlash[ 2 ] = { 5, 6 };
|
||||||
|
static const TickType_t uxFlashRates[ 2 ] = { 200, 400 };
|
||||||
|
|
||||||
|
// Must start every co-routine with a call to crSTART();
|
||||||
|
crSTART( xHandle );
|
||||||
|
|
||||||
|
for( ;; )
|
||||||
|
{
|
||||||
|
// This co-routine just delays for a fixed period, then toggles
|
||||||
|
// an LED. Two co-routines are created using this function, so
|
||||||
|
// the uxIndex parameter is used to tell the co-routine which
|
||||||
|
// LED to flash and how int32_t to delay. This assumes xQueue has
|
||||||
|
// already been created.
|
||||||
|
vParTestToggleLED( cLedToFlash[ uxIndex ] );
|
||||||
|
crDELAY( xHandle, uxFlashRates[ uxIndex ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must end every co-routine with a call to crEND();
|
||||||
|
crEND();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function that creates two co-routines.
|
||||||
|
void vOtherFunction( void )
|
||||||
|
{
|
||||||
|
uint8_t ucParameterToPass;
|
||||||
|
TaskHandle_t xHandle;
|
||||||
|
|
||||||
|
// Create two co-routines at priority 0. The first is given index 0
|
||||||
|
// so (from the code above) toggles LED 5 every 200 ticks. The second
|
||||||
|
// is given index 1 so toggles LED 6 every 400 ticks.
|
||||||
|
for( uxIndex = 0; uxIndex < 2; uxIndex++ )
|
||||||
|
{
|
||||||
|
xCoRoutineCreate( vFlashCoRoutine, 0, uxIndex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xCoRoutineCreate xCoRoutineCreate
|
||||||
|
* \ingroup Tasks
|
||||||
|
*/
|
||||||
|
BaseType_t xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, UBaseType_t uxPriority, UBaseType_t uxIndex );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* croutine. h
|
||||||
|
*<pre>
|
||||||
|
void vCoRoutineSchedule( void );</pre>
|
||||||
|
*
|
||||||
|
* Run a co-routine.
|
||||||
|
*
|
||||||
|
* vCoRoutineSchedule() executes the highest priority co-routine that is able
|
||||||
|
* to run. The co-routine will execute until it either blocks, yields or is
|
||||||
|
* preempted by a task. Co-routines execute cooperatively so one
|
||||||
|
* co-routine cannot be preempted by another, but can be preempted by a task.
|
||||||
|
*
|
||||||
|
* If an application comprises of both tasks and co-routines then
|
||||||
|
* vCoRoutineSchedule should be called from the idle task (in an idle task
|
||||||
|
* hook).
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
// This idle task hook will schedule a co-routine each time it is called.
|
||||||
|
// The rest of the idle task will execute between co-routine calls.
|
||||||
|
void vApplicationIdleHook( void )
|
||||||
|
{
|
||||||
|
vCoRoutineSchedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alternatively, if you do not require any other part of the idle task to
|
||||||
|
// execute, the idle task hook can call vCoRoutineSchedule() within an
|
||||||
|
// infinite loop.
|
||||||
|
void vApplicationIdleHook( void )
|
||||||
|
{
|
||||||
|
for( ;; )
|
||||||
|
{
|
||||||
|
vCoRoutineSchedule();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup vCoRoutineSchedule vCoRoutineSchedule
|
||||||
|
* \ingroup Tasks
|
||||||
|
*/
|
||||||
|
void vCoRoutineSchedule( void );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* croutine. h
|
||||||
|
* <pre>
|
||||||
|
crSTART( CoRoutineHandle_t xHandle );</pre>
|
||||||
|
*
|
||||||
|
* This macro MUST always be called at the start of a co-routine function.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
// Co-routine to be created.
|
||||||
|
void vACoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
|
||||||
|
{
|
||||||
|
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
|
||||||
|
static int32_t ulAVariable;
|
||||||
|
|
||||||
|
// Must start every co-routine with a call to crSTART();
|
||||||
|
crSTART( xHandle );
|
||||||
|
|
||||||
|
for( ;; )
|
||||||
|
{
|
||||||
|
// Co-routine functionality goes here.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must end every co-routine with a call to crEND();
|
||||||
|
crEND();
|
||||||
|
}</pre>
|
||||||
|
* \defgroup crSTART crSTART
|
||||||
|
* \ingroup Tasks
|
||||||
|
*/
|
||||||
|
#define crSTART( pxCRCB ) switch( ( ( CRCB_t * )( pxCRCB ) )->uxState ) { case 0:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* croutine. h
|
||||||
|
* <pre>
|
||||||
|
crEND();</pre>
|
||||||
|
*
|
||||||
|
* This macro MUST always be called at the end of a co-routine function.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
// Co-routine to be created.
|
||||||
|
void vACoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
|
||||||
|
{
|
||||||
|
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
|
||||||
|
static int32_t ulAVariable;
|
||||||
|
|
||||||
|
// Must start every co-routine with a call to crSTART();
|
||||||
|
crSTART( xHandle );
|
||||||
|
|
||||||
|
for( ;; )
|
||||||
|
{
|
||||||
|
// Co-routine functionality goes here.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must end every co-routine with a call to crEND();
|
||||||
|
crEND();
|
||||||
|
}</pre>
|
||||||
|
* \defgroup crSTART crSTART
|
||||||
|
* \ingroup Tasks
|
||||||
|
*/
|
||||||
|
#define crEND() }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These macros are intended for internal use by the co-routine implementation
|
||||||
|
* only. The macros should not be used directly by application writers.
|
||||||
|
*/
|
||||||
|
#define crSET_STATE0( xHandle ) ( ( CRCB_t * )( xHandle ) )->uxState = (__LINE__ * 2); return; case (__LINE__ * 2):
|
||||||
|
#define crSET_STATE1( xHandle ) ( ( CRCB_t * )( xHandle ) )->uxState = ((__LINE__ * 2)+1); return; case ((__LINE__ * 2)+1):
|
||||||
|
|
||||||
|
/**
|
||||||
|
* croutine. h
|
||||||
|
*<pre>
|
||||||
|
crDELAY( CoRoutineHandle_t xHandle, TickType_t xTicksToDelay );</pre>
|
||||||
|
*
|
||||||
|
* Delay a co-routine for a fixed period of time.
|
||||||
|
*
|
||||||
|
* crDELAY can only be called from the co-routine function itself - not
|
||||||
|
* from within a function called by the co-routine function. This is because
|
||||||
|
* co-routines do not maintain their own stack.
|
||||||
|
*
|
||||||
|
* @param xHandle The handle of the co-routine to delay. This is the xHandle
|
||||||
|
* parameter of the co-routine function.
|
||||||
|
*
|
||||||
|
* @param xTickToDelay The number of ticks that the co-routine should delay
|
||||||
|
* for. The actual amount of time this equates to is defined by
|
||||||
|
* configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant portTICK_PERIOD_MS
|
||||||
|
* can be used to convert ticks to milliseconds.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
// Co-routine to be created.
|
||||||
|
void vACoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
|
||||||
|
{
|
||||||
|
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
|
||||||
|
// This may not be necessary for const variables.
|
||||||
|
// We are to delay for 200ms.
|
||||||
|
static const xTickType xDelayTime = 200 / portTICK_PERIOD_MS;
|
||||||
|
|
||||||
|
// Must start every co-routine with a call to crSTART();
|
||||||
|
crSTART( xHandle );
|
||||||
|
|
||||||
|
for( ;; )
|
||||||
|
{
|
||||||
|
// Delay for 200ms.
|
||||||
|
crDELAY( xHandle, xDelayTime );
|
||||||
|
|
||||||
|
// Do something here.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must end every co-routine with a call to crEND();
|
||||||
|
crEND();
|
||||||
|
}</pre>
|
||||||
|
* \defgroup crDELAY crDELAY
|
||||||
|
* \ingroup Tasks
|
||||||
|
*/
|
||||||
|
#define crDELAY( xHandle, xTicksToDelay ) \
|
||||||
|
if( ( xTicksToDelay ) > 0 ) \
|
||||||
|
{ \
|
||||||
|
vCoRoutineAddToDelayedList( ( xTicksToDelay ), NULL ); \
|
||||||
|
} \
|
||||||
|
crSET_STATE0( ( xHandle ) );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
crQUEUE_SEND(
|
||||||
|
CoRoutineHandle_t xHandle,
|
||||||
|
QueueHandle_t pxQueue,
|
||||||
|
void *pvItemToQueue,
|
||||||
|
TickType_t xTicksToWait,
|
||||||
|
BaseType_t *pxResult
|
||||||
|
)</pre>
|
||||||
|
*
|
||||||
|
* The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine
|
||||||
|
* equivalent to the xQueueSend() and xQueueReceive() functions used by tasks.
|
||||||
|
*
|
||||||
|
* crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas
|
||||||
|
* xQueueSend() and xQueueReceive() can only be used from tasks.
|
||||||
|
*
|
||||||
|
* crQUEUE_SEND can only be called from the co-routine function itself - not
|
||||||
|
* from within a function called by the co-routine function. This is because
|
||||||
|
* co-routines do not maintain their own stack.
|
||||||
|
*
|
||||||
|
* See the co-routine section of the WEB documentation for information on
|
||||||
|
* passing data between tasks and co-routines and between ISR's and
|
||||||
|
* co-routines.
|
||||||
|
*
|
||||||
|
* @param xHandle The handle of the calling co-routine. This is the xHandle
|
||||||
|
* parameter of the co-routine function.
|
||||||
|
*
|
||||||
|
* @param pxQueue The handle of the queue on which the data will be posted.
|
||||||
|
* The handle is obtained as the return value when the queue is created using
|
||||||
|
* the xQueueCreate() API function.
|
||||||
|
*
|
||||||
|
* @param pvItemToQueue A pointer to the data being posted onto the queue.
|
||||||
|
* The number of bytes of each queued item is specified when the queue is
|
||||||
|
* created. This number of bytes is copied from pvItemToQueue into the queue
|
||||||
|
* itself.
|
||||||
|
*
|
||||||
|
* @param xTickToDelay The number of ticks that the co-routine should block
|
||||||
|
* to wait for space to become available on the queue, should space not be
|
||||||
|
* available immediately. The actual amount of time this equates to is defined
|
||||||
|
* by configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant
|
||||||
|
* portTICK_PERIOD_MS can be used to convert ticks to milliseconds (see example
|
||||||
|
* below).
|
||||||
|
*
|
||||||
|
* @param pxResult The variable pointed to by pxResult will be set to pdPASS if
|
||||||
|
* data was successfully posted onto the queue, otherwise it will be set to an
|
||||||
|
* error defined within ProjDefs.h.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
// Co-routine function that blocks for a fixed period then posts a number onto
|
||||||
|
// a queue.
|
||||||
|
static void prvCoRoutineFlashTask( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
|
||||||
|
{
|
||||||
|
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
|
||||||
|
static BaseType_t xNumberToPost = 0;
|
||||||
|
static BaseType_t xResult;
|
||||||
|
|
||||||
|
// Co-routines must begin with a call to crSTART().
|
||||||
|
crSTART( xHandle );
|
||||||
|
|
||||||
|
for( ;; )
|
||||||
|
{
|
||||||
|
// This assumes the queue has already been created.
|
||||||
|
crQUEUE_SEND( xHandle, xCoRoutineQueue, &xNumberToPost, NO_DELAY, &xResult );
|
||||||
|
|
||||||
|
if( xResult != pdPASS )
|
||||||
|
{
|
||||||
|
// The message was not posted!
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment the number to be posted onto the queue.
|
||||||
|
xNumberToPost++;
|
||||||
|
|
||||||
|
// Delay for 100 ticks.
|
||||||
|
crDELAY( xHandle, 100 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Co-routines must end with a call to crEND().
|
||||||
|
crEND();
|
||||||
|
}</pre>
|
||||||
|
* \defgroup crQUEUE_SEND crQUEUE_SEND
|
||||||
|
* \ingroup Tasks
|
||||||
|
*/
|
||||||
|
#define crQUEUE_SEND( xHandle, pxQueue, pvItemToQueue, xTicksToWait, pxResult ) \
|
||||||
|
{ \
|
||||||
|
*( pxResult ) = xQueueCRSend( ( pxQueue) , ( pvItemToQueue) , ( xTicksToWait ) ); \
|
||||||
|
if( *( pxResult ) == errQUEUE_BLOCKED ) \
|
||||||
|
{ \
|
||||||
|
crSET_STATE0( ( xHandle ) ); \
|
||||||
|
*pxResult = xQueueCRSend( ( pxQueue ), ( pvItemToQueue ), 0 ); \
|
||||||
|
} \
|
||||||
|
if( *pxResult == errQUEUE_YIELD ) \
|
||||||
|
{ \
|
||||||
|
crSET_STATE1( ( xHandle ) ); \
|
||||||
|
*pxResult = pdPASS; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* croutine. h
|
||||||
|
* <pre>
|
||||||
|
crQUEUE_RECEIVE(
|
||||||
|
CoRoutineHandle_t xHandle,
|
||||||
|
QueueHandle_t pxQueue,
|
||||||
|
void *pvBuffer,
|
||||||
|
TickType_t xTicksToWait,
|
||||||
|
BaseType_t *pxResult
|
||||||
|
)</pre>
|
||||||
|
*
|
||||||
|
* The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine
|
||||||
|
* equivalent to the xQueueSend() and xQueueReceive() functions used by tasks.
|
||||||
|
*
|
||||||
|
* crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas
|
||||||
|
* xQueueSend() and xQueueReceive() can only be used from tasks.
|
||||||
|
*
|
||||||
|
* crQUEUE_RECEIVE can only be called from the co-routine function itself - not
|
||||||
|
* from within a function called by the co-routine function. This is because
|
||||||
|
* co-routines do not maintain their own stack.
|
||||||
|
*
|
||||||
|
* See the co-routine section of the WEB documentation for information on
|
||||||
|
* passing data between tasks and co-routines and between ISR's and
|
||||||
|
* co-routines.
|
||||||
|
*
|
||||||
|
* @param xHandle The handle of the calling co-routine. This is the xHandle
|
||||||
|
* parameter of the co-routine function.
|
||||||
|
*
|
||||||
|
* @param pxQueue The handle of the queue from which the data will be received.
|
||||||
|
* The handle is obtained as the return value when the queue is created using
|
||||||
|
* the xQueueCreate() API function.
|
||||||
|
*
|
||||||
|
* @param pvBuffer The buffer into which the received item is to be copied.
|
||||||
|
* The number of bytes of each queued item is specified when the queue is
|
||||||
|
* created. This number of bytes is copied into pvBuffer.
|
||||||
|
*
|
||||||
|
* @param xTickToDelay The number of ticks that the co-routine should block
|
||||||
|
* to wait for data to become available from the queue, should data not be
|
||||||
|
* available immediately. The actual amount of time this equates to is defined
|
||||||
|
* by configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant
|
||||||
|
* portTICK_PERIOD_MS can be used to convert ticks to milliseconds (see the
|
||||||
|
* crQUEUE_SEND example).
|
||||||
|
*
|
||||||
|
* @param pxResult The variable pointed to by pxResult will be set to pdPASS if
|
||||||
|
* data was successfully retrieved from the queue, otherwise it will be set to
|
||||||
|
* an error code as defined within ProjDefs.h.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
// A co-routine receives the number of an LED to flash from a queue. It
|
||||||
|
// blocks on the queue until the number is received.
|
||||||
|
static void prvCoRoutineFlashWorkTask( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
|
||||||
|
{
|
||||||
|
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
|
||||||
|
static BaseType_t xResult;
|
||||||
|
static UBaseType_t uxLEDToFlash;
|
||||||
|
|
||||||
|
// All co-routines must start with a call to crSTART().
|
||||||
|
crSTART( xHandle );
|
||||||
|
|
||||||
|
for( ;; )
|
||||||
|
{
|
||||||
|
// Wait for data to become available on the queue.
|
||||||
|
crQUEUE_RECEIVE( xHandle, xCoRoutineQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
|
||||||
|
|
||||||
|
if( xResult == pdPASS )
|
||||||
|
{
|
||||||
|
// We received the LED to flash - flash it!
|
||||||
|
vParTestToggleLED( uxLEDToFlash );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
crEND();
|
||||||
|
}</pre>
|
||||||
|
* \defgroup crQUEUE_RECEIVE crQUEUE_RECEIVE
|
||||||
|
* \ingroup Tasks
|
||||||
|
*/
|
||||||
|
#define crQUEUE_RECEIVE( xHandle, pxQueue, pvBuffer, xTicksToWait, pxResult ) \
|
||||||
|
{ \
|
||||||
|
*( pxResult ) = xQueueCRReceive( ( pxQueue) , ( pvBuffer ), ( xTicksToWait ) ); \
|
||||||
|
if( *( pxResult ) == errQUEUE_BLOCKED ) \
|
||||||
|
{ \
|
||||||
|
crSET_STATE0( ( xHandle ) ); \
|
||||||
|
*( pxResult ) = xQueueCRReceive( ( pxQueue) , ( pvBuffer ), 0 ); \
|
||||||
|
} \
|
||||||
|
if( *( pxResult ) == errQUEUE_YIELD ) \
|
||||||
|
{ \
|
||||||
|
crSET_STATE1( ( xHandle ) ); \
|
||||||
|
*( pxResult ) = pdPASS; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* croutine. h
|
||||||
|
* <pre>
|
||||||
|
crQUEUE_SEND_FROM_ISR(
|
||||||
|
QueueHandle_t pxQueue,
|
||||||
|
void *pvItemToQueue,
|
||||||
|
BaseType_t xCoRoutinePreviouslyWoken
|
||||||
|
)</pre>
|
||||||
|
*
|
||||||
|
* The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the
|
||||||
|
* co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR()
|
||||||
|
* functions used by tasks.
|
||||||
|
*
|
||||||
|
* crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to
|
||||||
|
* pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and
|
||||||
|
* xQueueReceiveFromISR() can only be used to pass data between a task and and
|
||||||
|
* ISR.
|
||||||
|
*
|
||||||
|
* crQUEUE_SEND_FROM_ISR can only be called from an ISR to send data to a queue
|
||||||
|
* that is being used from within a co-routine.
|
||||||
|
*
|
||||||
|
* See the co-routine section of the WEB documentation for information on
|
||||||
|
* passing data between tasks and co-routines and between ISR's and
|
||||||
|
* co-routines.
|
||||||
|
*
|
||||||
|
* @param xQueue The handle to the queue on which the item is to be posted.
|
||||||
|
*
|
||||||
|
* @param pvItemToQueue A pointer to the item that is to be placed on the
|
||||||
|
* queue. The size of the items the queue will hold was defined when the
|
||||||
|
* queue was created, so this many bytes will be copied from pvItemToQueue
|
||||||
|
* into the queue storage area.
|
||||||
|
*
|
||||||
|
* @param xCoRoutinePreviouslyWoken This is included so an ISR can post onto
|
||||||
|
* the same queue multiple times from a single interrupt. The first call
|
||||||
|
* should always pass in pdFALSE. Subsequent calls should pass in
|
||||||
|
* the value returned from the previous call.
|
||||||
|
*
|
||||||
|
* @return pdTRUE if a co-routine was woken by posting onto the queue. This is
|
||||||
|
* used by the ISR to determine if a context switch may be required following
|
||||||
|
* the ISR.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
// A co-routine that blocks on a queue waiting for characters to be received.
|
||||||
|
static void vReceivingCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
|
||||||
|
{
|
||||||
|
char cRxedChar;
|
||||||
|
BaseType_t xResult;
|
||||||
|
|
||||||
|
// All co-routines must start with a call to crSTART().
|
||||||
|
crSTART( xHandle );
|
||||||
|
|
||||||
|
for( ;; )
|
||||||
|
{
|
||||||
|
// Wait for data to become available on the queue. This assumes the
|
||||||
|
// queue xCommsRxQueue has already been created!
|
||||||
|
crQUEUE_RECEIVE( xHandle, xCommsRxQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
|
||||||
|
|
||||||
|
// Was a character received?
|
||||||
|
if( xResult == pdPASS )
|
||||||
|
{
|
||||||
|
// Process the character here.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// All co-routines must end with a call to crEND().
|
||||||
|
crEND();
|
||||||
|
}
|
||||||
|
|
||||||
|
// An ISR that uses a queue to send characters received on a serial port to
|
||||||
|
// a co-routine.
|
||||||
|
void vUART_ISR( void )
|
||||||
|
{
|
||||||
|
char cRxedChar;
|
||||||
|
BaseType_t xCRWokenByPost = pdFALSE;
|
||||||
|
|
||||||
|
// We loop around reading characters until there are none left in the UART.
|
||||||
|
while( UART_RX_REG_NOT_EMPTY() )
|
||||||
|
{
|
||||||
|
// Obtain the character from the UART.
|
||||||
|
cRxedChar = UART_RX_REG;
|
||||||
|
|
||||||
|
// Post the character onto a queue. xCRWokenByPost will be pdFALSE
|
||||||
|
// the first time around the loop. If the post causes a co-routine
|
||||||
|
// to be woken (unblocked) then xCRWokenByPost will be set to pdTRUE.
|
||||||
|
// In this manner we can ensure that if more than one co-routine is
|
||||||
|
// blocked on the queue only one is woken by this ISR no matter how
|
||||||
|
// many characters are posted to the queue.
|
||||||
|
xCRWokenByPost = crQUEUE_SEND_FROM_ISR( xCommsRxQueue, &cRxedChar, xCRWokenByPost );
|
||||||
|
}
|
||||||
|
}</pre>
|
||||||
|
* \defgroup crQUEUE_SEND_FROM_ISR crQUEUE_SEND_FROM_ISR
|
||||||
|
* \ingroup Tasks
|
||||||
|
*/
|
||||||
|
#define crQUEUE_SEND_FROM_ISR( pxQueue, pvItemToQueue, xCoRoutinePreviouslyWoken ) xQueueCRSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( xCoRoutinePreviouslyWoken ) )
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* croutine. h
|
||||||
|
* <pre>
|
||||||
|
crQUEUE_SEND_FROM_ISR(
|
||||||
|
QueueHandle_t pxQueue,
|
||||||
|
void *pvBuffer,
|
||||||
|
BaseType_t * pxCoRoutineWoken
|
||||||
|
)</pre>
|
||||||
|
*
|
||||||
|
* The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the
|
||||||
|
* co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR()
|
||||||
|
* functions used by tasks.
|
||||||
|
*
|
||||||
|
* crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to
|
||||||
|
* pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and
|
||||||
|
* xQueueReceiveFromISR() can only be used to pass data between a task and and
|
||||||
|
* ISR.
|
||||||
|
*
|
||||||
|
* crQUEUE_RECEIVE_FROM_ISR can only be called from an ISR to receive data
|
||||||
|
* from a queue that is being used from within a co-routine (a co-routine
|
||||||
|
* posted to the queue).
|
||||||
|
*
|
||||||
|
* See the co-routine section of the WEB documentation for information on
|
||||||
|
* passing data between tasks and co-routines and between ISR's and
|
||||||
|
* co-routines.
|
||||||
|
*
|
||||||
|
* @param xQueue The handle to the queue on which the item is to be posted.
|
||||||
|
*
|
||||||
|
* @param pvBuffer A pointer to a buffer into which the received item will be
|
||||||
|
* placed. The size of the items the queue will hold was defined when the
|
||||||
|
* queue was created, so this many bytes will be copied from the queue into
|
||||||
|
* pvBuffer.
|
||||||
|
*
|
||||||
|
* @param pxCoRoutineWoken A co-routine may be blocked waiting for space to become
|
||||||
|
* available on the queue. If crQUEUE_RECEIVE_FROM_ISR causes such a
|
||||||
|
* co-routine to unblock *pxCoRoutineWoken will get set to pdTRUE, otherwise
|
||||||
|
* *pxCoRoutineWoken will remain unchanged.
|
||||||
|
*
|
||||||
|
* @return pdTRUE an item was successfully received from the queue, otherwise
|
||||||
|
* pdFALSE.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
// A co-routine that posts a character to a queue then blocks for a fixed
|
||||||
|
// period. The character is incremented each time.
|
||||||
|
static void vSendingCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
|
||||||
|
{
|
||||||
|
// cChar holds its value while this co-routine is blocked and must therefore
|
||||||
|
// be declared static.
|
||||||
|
static char cCharToTx = 'a';
|
||||||
|
BaseType_t xResult;
|
||||||
|
|
||||||
|
// All co-routines must start with a call to crSTART().
|
||||||
|
crSTART( xHandle );
|
||||||
|
|
||||||
|
for( ;; )
|
||||||
|
{
|
||||||
|
// Send the next character to the queue.
|
||||||
|
crQUEUE_SEND( xHandle, xCoRoutineQueue, &cCharToTx, NO_DELAY, &xResult );
|
||||||
|
|
||||||
|
if( xResult == pdPASS )
|
||||||
|
{
|
||||||
|
// The character was successfully posted to the queue.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Could not post the character to the queue.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable the UART Tx interrupt to cause an interrupt in this
|
||||||
|
// hypothetical UART. The interrupt will obtain the character
|
||||||
|
// from the queue and send it.
|
||||||
|
ENABLE_RX_INTERRUPT();
|
||||||
|
|
||||||
|
// Increment to the next character then block for a fixed period.
|
||||||
|
// cCharToTx will maintain its value across the delay as it is
|
||||||
|
// declared static.
|
||||||
|
cCharToTx++;
|
||||||
|
if( cCharToTx > 'x' )
|
||||||
|
{
|
||||||
|
cCharToTx = 'a';
|
||||||
|
}
|
||||||
|
crDELAY( 100 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// All co-routines must end with a call to crEND().
|
||||||
|
crEND();
|
||||||
|
}
|
||||||
|
|
||||||
|
// An ISR that uses a queue to receive characters to send on a UART.
|
||||||
|
void vUART_ISR( void )
|
||||||
|
{
|
||||||
|
char cCharToTx;
|
||||||
|
BaseType_t xCRWokenByPost = pdFALSE;
|
||||||
|
|
||||||
|
while( UART_TX_REG_EMPTY() )
|
||||||
|
{
|
||||||
|
// Are there any characters in the queue waiting to be sent?
|
||||||
|
// xCRWokenByPost will automatically be set to pdTRUE if a co-routine
|
||||||
|
// is woken by the post - ensuring that only a single co-routine is
|
||||||
|
// woken no matter how many times we go around this loop.
|
||||||
|
if( crQUEUE_RECEIVE_FROM_ISR( pxQueue, &cCharToTx, &xCRWokenByPost ) )
|
||||||
|
{
|
||||||
|
SEND_CHARACTER( cCharToTx );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}</pre>
|
||||||
|
* \defgroup crQUEUE_RECEIVE_FROM_ISR crQUEUE_RECEIVE_FROM_ISR
|
||||||
|
* \ingroup Tasks
|
||||||
|
*/
|
||||||
|
#define crQUEUE_RECEIVE_FROM_ISR( pxQueue, pvBuffer, pxCoRoutineWoken ) xQueueCRReceiveFromISR( ( pxQueue ), ( pvBuffer ), ( pxCoRoutineWoken ) )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function is intended for internal use by the co-routine macros only.
|
||||||
|
* The macro nature of the co-routine implementation requires that the
|
||||||
|
* prototype appears here. The function should not be used by application
|
||||||
|
* writers.
|
||||||
|
*
|
||||||
|
* Removes the current co-routine from its ready list and places it in the
|
||||||
|
* appropriate delayed list.
|
||||||
|
*/
|
||||||
|
void vCoRoutineAddToDelayedList( TickType_t xTicksToDelay, List_t *pxEventList );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function is intended for internal use by the queue implementation only.
|
||||||
|
* The function should not be used by application writers.
|
||||||
|
*
|
||||||
|
* Removes the highest priority co-routine from the event list and places it in
|
||||||
|
* the pending ready list.
|
||||||
|
*/
|
||||||
|
BaseType_t xCoRoutineRemoveFromEventList( const List_t *pxEventList );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* CO_ROUTINE_H */
|
||||||
279
Middlewares/Third_Party/FreeRTOS/Source/include/deprecated_definitions.h
vendored
Normal file
279
Middlewares/Third_Party/FreeRTOS/Source/include/deprecated_definitions.h
vendored
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
/*
|
||||||
|
* FreeRTOS Kernel V10.3.1
|
||||||
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org
|
||||||
|
* http://aws.amazon.com/freertos
|
||||||
|
*
|
||||||
|
* 1 tab == 4 spaces!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DEPRECATED_DEFINITIONS_H
|
||||||
|
#define DEPRECATED_DEFINITIONS_H
|
||||||
|
|
||||||
|
|
||||||
|
/* Each FreeRTOS port has a unique portmacro.h header file. Originally a
|
||||||
|
pre-processor definition was used to ensure the pre-processor found the correct
|
||||||
|
portmacro.h file for the port being used. That scheme was deprecated in favour
|
||||||
|
of setting the compiler's include path such that it found the correct
|
||||||
|
portmacro.h file - removing the need for the constant and allowing the
|
||||||
|
portmacro.h file to be located anywhere in relation to the port being used. The
|
||||||
|
definitions below remain in the code for backward compatibility only. New
|
||||||
|
projects should not use them. */
|
||||||
|
|
||||||
|
#ifdef OPEN_WATCOM_INDUSTRIAL_PC_PORT
|
||||||
|
#include "..\..\Source\portable\owatcom\16bitdos\pc\portmacro.h"
|
||||||
|
typedef void ( __interrupt __far *pxISR )();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef OPEN_WATCOM_FLASH_LITE_186_PORT
|
||||||
|
#include "..\..\Source\portable\owatcom\16bitdos\flsh186\portmacro.h"
|
||||||
|
typedef void ( __interrupt __far *pxISR )();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GCC_MEGA_AVR
|
||||||
|
#include "../portable/GCC/ATMega323/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef IAR_MEGA_AVR
|
||||||
|
#include "../portable/IAR/ATMega323/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MPLAB_PIC24_PORT
|
||||||
|
#include "../../Source/portable/MPLAB/PIC24_dsPIC/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MPLAB_DSPIC_PORT
|
||||||
|
#include "../../Source/portable/MPLAB/PIC24_dsPIC/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MPLAB_PIC18F_PORT
|
||||||
|
#include "../../Source/portable/MPLAB/PIC18F/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MPLAB_PIC32MX_PORT
|
||||||
|
#include "../../Source/portable/MPLAB/PIC32MX/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _FEDPICC
|
||||||
|
#include "libFreeRTOS/Include/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SDCC_CYGNAL
|
||||||
|
#include "../../Source/portable/SDCC/Cygnal/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GCC_ARM7
|
||||||
|
#include "../../Source/portable/GCC/ARM7_LPC2000/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GCC_ARM7_ECLIPSE
|
||||||
|
#include "portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ROWLEY_LPC23xx
|
||||||
|
#include "../../Source/portable/GCC/ARM7_LPC23xx/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef IAR_MSP430
|
||||||
|
#include "..\..\Source\portable\IAR\MSP430\portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GCC_MSP430
|
||||||
|
#include "../../Source/portable/GCC/MSP430F449/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ROWLEY_MSP430
|
||||||
|
#include "../../Source/portable/Rowley/MSP430F449/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ARM7_LPC21xx_KEIL_RVDS
|
||||||
|
#include "..\..\Source\portable\RVDS\ARM7_LPC21xx\portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SAM7_GCC
|
||||||
|
#include "../../Source/portable/GCC/ARM7_AT91SAM7S/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SAM7_IAR
|
||||||
|
#include "..\..\Source\portable\IAR\AtmelSAM7S64\portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SAM9XE_IAR
|
||||||
|
#include "..\..\Source\portable\IAR\AtmelSAM9XE\portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LPC2000_IAR
|
||||||
|
#include "..\..\Source\portable\IAR\LPC2000\portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef STR71X_IAR
|
||||||
|
#include "..\..\Source\portable\IAR\STR71x\portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef STR75X_IAR
|
||||||
|
#include "..\..\Source\portable\IAR\STR75x\portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef STR75X_GCC
|
||||||
|
#include "..\..\Source\portable\GCC\STR75x\portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef STR91X_IAR
|
||||||
|
#include "..\..\Source\portable\IAR\STR91x\portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GCC_H8S
|
||||||
|
#include "../../Source/portable/GCC/H8S2329/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GCC_AT91FR40008
|
||||||
|
#include "../../Source/portable/GCC/ARM7_AT91FR40008/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RVDS_ARMCM3_LM3S102
|
||||||
|
#include "../../Source/portable/RVDS/ARM_CM3/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GCC_ARMCM3_LM3S102
|
||||||
|
#include "../../Source/portable/GCC/ARM_CM3/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GCC_ARMCM3
|
||||||
|
#include "../../Source/portable/GCC/ARM_CM3/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef IAR_ARM_CM3
|
||||||
|
#include "../../Source/portable/IAR/ARM_CM3/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef IAR_ARMCM3_LM
|
||||||
|
#include "../../Source/portable/IAR/ARM_CM3/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HCS12_CODE_WARRIOR
|
||||||
|
#include "../../Source/portable/CodeWarrior/HCS12/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MICROBLAZE_GCC
|
||||||
|
#include "../../Source/portable/GCC/MicroBlaze/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TERN_EE
|
||||||
|
#include "..\..\Source\portable\Paradigm\Tern_EE\small\portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GCC_HCS12
|
||||||
|
#include "../../Source/portable/GCC/HCS12/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GCC_MCF5235
|
||||||
|
#include "../../Source/portable/GCC/MCF5235/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef COLDFIRE_V2_GCC
|
||||||
|
#include "../../../Source/portable/GCC/ColdFire_V2/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef COLDFIRE_V2_CODEWARRIOR
|
||||||
|
#include "../../Source/portable/CodeWarrior/ColdFire_V2/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GCC_PPC405
|
||||||
|
#include "../../Source/portable/GCC/PPC405_Xilinx/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GCC_PPC440
|
||||||
|
#include "../../Source/portable/GCC/PPC440_Xilinx/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _16FX_SOFTUNE
|
||||||
|
#include "..\..\Source\portable\Softune\MB96340\portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BCC_INDUSTRIAL_PC_PORT
|
||||||
|
/* A short file name has to be used in place of the normal
|
||||||
|
FreeRTOSConfig.h when using the Borland compiler. */
|
||||||
|
#include "frconfig.h"
|
||||||
|
#include "..\portable\BCC\16BitDOS\PC\prtmacro.h"
|
||||||
|
typedef void ( __interrupt __far *pxISR )();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BCC_FLASH_LITE_186_PORT
|
||||||
|
/* A short file name has to be used in place of the normal
|
||||||
|
FreeRTOSConfig.h when using the Borland compiler. */
|
||||||
|
#include "frconfig.h"
|
||||||
|
#include "..\portable\BCC\16BitDOS\flsh186\prtmacro.h"
|
||||||
|
typedef void ( __interrupt __far *pxISR )();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#ifdef __AVR32_AVR32A__
|
||||||
|
#include "portmacro.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __ICCAVR32__
|
||||||
|
#ifdef __CORE__
|
||||||
|
#if __CORE__ == __AVR32A__
|
||||||
|
#include "portmacro.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __91467D
|
||||||
|
#include "portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __96340
|
||||||
|
#include "portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __IAR_V850ES_Fx3__
|
||||||
|
#include "../../Source/portable/IAR/V850ES/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __IAR_V850ES_Jx3__
|
||||||
|
#include "../../Source/portable/IAR/V850ES/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __IAR_V850ES_Jx3_L__
|
||||||
|
#include "../../Source/portable/IAR/V850ES/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __IAR_V850ES_Jx2__
|
||||||
|
#include "../../Source/portable/IAR/V850ES/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __IAR_V850ES_Hx2__
|
||||||
|
#include "../../Source/portable/IAR/V850ES/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __IAR_78K0R_Kx3__
|
||||||
|
#include "../../Source/portable/IAR/78K0R/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __IAR_78K0R_Kx3L__
|
||||||
|
#include "../../Source/portable/IAR/78K0R/portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* DEPRECATED_DEFINITIONS_H */
|
||||||
|
|
||||||
757
Middlewares/Third_Party/FreeRTOS/Source/include/event_groups.h
vendored
Normal file
757
Middlewares/Third_Party/FreeRTOS/Source/include/event_groups.h
vendored
Normal file
@@ -0,0 +1,757 @@
|
|||||||
|
/*
|
||||||
|
* FreeRTOS Kernel V10.3.1
|
||||||
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org
|
||||||
|
* http://aws.amazon.com/freertos
|
||||||
|
*
|
||||||
|
* 1 tab == 4 spaces!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EVENT_GROUPS_H
|
||||||
|
#define EVENT_GROUPS_H
|
||||||
|
|
||||||
|
#ifndef INC_FREERTOS_H
|
||||||
|
#error "include FreeRTOS.h" must appear in source files before "include event_groups.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* FreeRTOS includes. */
|
||||||
|
#include "timers.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event group is a collection of bits to which an application can assign a
|
||||||
|
* meaning. For example, an application may create an event group to convey
|
||||||
|
* the status of various CAN bus related events in which bit 0 might mean "A CAN
|
||||||
|
* message has been received and is ready for processing", bit 1 might mean "The
|
||||||
|
* application has queued a message that is ready for sending onto the CAN
|
||||||
|
* network", and bit 2 might mean "It is time to send a SYNC message onto the
|
||||||
|
* CAN network" etc. A task can then test the bit values to see which events
|
||||||
|
* are active, and optionally enter the Blocked state to wait for a specified
|
||||||
|
* bit or a group of specified bits to be active. To continue the CAN bus
|
||||||
|
* example, a CAN controlling task can enter the Blocked state (and therefore
|
||||||
|
* not consume any processing time) until either bit 0, bit 1 or bit 2 are
|
||||||
|
* active, at which time the bit that was actually active would inform the task
|
||||||
|
* which action it had to take (process a received message, send a message, or
|
||||||
|
* send a SYNC).
|
||||||
|
*
|
||||||
|
* The event groups implementation contains intelligence to avoid race
|
||||||
|
* conditions that would otherwise occur were an application to use a simple
|
||||||
|
* variable for the same purpose. This is particularly important with respect
|
||||||
|
* to when a bit within an event group is to be cleared, and when bits have to
|
||||||
|
* be set and then tested atomically - as is the case where event groups are
|
||||||
|
* used to create a synchronisation point between multiple tasks (a
|
||||||
|
* 'rendezvous').
|
||||||
|
*
|
||||||
|
* \defgroup EventGroup
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* event_groups.h
|
||||||
|
*
|
||||||
|
* Type by which event groups are referenced. For example, a call to
|
||||||
|
* xEventGroupCreate() returns an EventGroupHandle_t variable that can then
|
||||||
|
* be used as a parameter to other event group functions.
|
||||||
|
*
|
||||||
|
* \defgroup EventGroupHandle_t EventGroupHandle_t
|
||||||
|
* \ingroup EventGroup
|
||||||
|
*/
|
||||||
|
struct EventGroupDef_t;
|
||||||
|
typedef struct EventGroupDef_t * EventGroupHandle_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The type that holds event bits always matches TickType_t - therefore the
|
||||||
|
* number of bits it holds is set by configUSE_16_BIT_TICKS (16 bits if set to 1,
|
||||||
|
* 32 bits if set to 0.
|
||||||
|
*
|
||||||
|
* \defgroup EventBits_t EventBits_t
|
||||||
|
* \ingroup EventGroup
|
||||||
|
*/
|
||||||
|
typedef TickType_t EventBits_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* event_groups.h
|
||||||
|
*<pre>
|
||||||
|
EventGroupHandle_t xEventGroupCreate( void );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Create a new event group.
|
||||||
|
*
|
||||||
|
* Internally, within the FreeRTOS implementation, event groups use a [small]
|
||||||
|
* block of memory, in which the event group's structure is stored. If an event
|
||||||
|
* groups is created using xEventGropuCreate() then the required memory is
|
||||||
|
* automatically dynamically allocated inside the xEventGroupCreate() function.
|
||||||
|
* (see http://www.freertos.org/a00111.html). If an event group is created
|
||||||
|
* using xEventGropuCreateStatic() then the application writer must instead
|
||||||
|
* provide the memory that will get used by the event group.
|
||||||
|
* xEventGroupCreateStatic() therefore allows an event group to be created
|
||||||
|
* without using any dynamic memory allocation.
|
||||||
|
*
|
||||||
|
* Although event groups are not related to ticks, for internal implementation
|
||||||
|
* reasons the number of bits available for use in an event group is dependent
|
||||||
|
* on the configUSE_16_BIT_TICKS setting in FreeRTOSConfig.h. If
|
||||||
|
* configUSE_16_BIT_TICKS is 1 then each event group contains 8 usable bits (bit
|
||||||
|
* 0 to bit 7). If configUSE_16_BIT_TICKS is set to 0 then each event group has
|
||||||
|
* 24 usable bits (bit 0 to bit 23). The EventBits_t type is used to store
|
||||||
|
* event bits within an event group.
|
||||||
|
*
|
||||||
|
* @return If the event group was created then a handle to the event group is
|
||||||
|
* returned. If there was insufficient FreeRTOS heap available to create the
|
||||||
|
* event group then NULL is returned. See http://www.freertos.org/a00111.html
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
// Declare a variable to hold the created event group.
|
||||||
|
EventGroupHandle_t xCreatedEventGroup;
|
||||||
|
|
||||||
|
// Attempt to create the event group.
|
||||||
|
xCreatedEventGroup = xEventGroupCreate();
|
||||||
|
|
||||||
|
// Was the event group created successfully?
|
||||||
|
if( xCreatedEventGroup == NULL )
|
||||||
|
{
|
||||||
|
// The event group was not created because there was insufficient
|
||||||
|
// FreeRTOS heap available.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The event group was created.
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xEventGroupCreate xEventGroupCreate
|
||||||
|
* \ingroup EventGroup
|
||||||
|
*/
|
||||||
|
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||||
|
EventGroupHandle_t xEventGroupCreate( void ) PRIVILEGED_FUNCTION;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* event_groups.h
|
||||||
|
*<pre>
|
||||||
|
EventGroupHandle_t xEventGroupCreateStatic( EventGroupHandle_t * pxEventGroupBuffer );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Create a new event group.
|
||||||
|
*
|
||||||
|
* Internally, within the FreeRTOS implementation, event groups use a [small]
|
||||||
|
* block of memory, in which the event group's structure is stored. If an event
|
||||||
|
* groups is created using xEventGropuCreate() then the required memory is
|
||||||
|
* automatically dynamically allocated inside the xEventGroupCreate() function.
|
||||||
|
* (see http://www.freertos.org/a00111.html). If an event group is created
|
||||||
|
* using xEventGropuCreateStatic() then the application writer must instead
|
||||||
|
* provide the memory that will get used by the event group.
|
||||||
|
* xEventGroupCreateStatic() therefore allows an event group to be created
|
||||||
|
* without using any dynamic memory allocation.
|
||||||
|
*
|
||||||
|
* Although event groups are not related to ticks, for internal implementation
|
||||||
|
* reasons the number of bits available for use in an event group is dependent
|
||||||
|
* on the configUSE_16_BIT_TICKS setting in FreeRTOSConfig.h. If
|
||||||
|
* configUSE_16_BIT_TICKS is 1 then each event group contains 8 usable bits (bit
|
||||||
|
* 0 to bit 7). If configUSE_16_BIT_TICKS is set to 0 then each event group has
|
||||||
|
* 24 usable bits (bit 0 to bit 23). The EventBits_t type is used to store
|
||||||
|
* event bits within an event group.
|
||||||
|
*
|
||||||
|
* @param pxEventGroupBuffer pxEventGroupBuffer must point to a variable of type
|
||||||
|
* StaticEventGroup_t, which will be then be used to hold the event group's data
|
||||||
|
* structures, removing the need for the memory to be allocated dynamically.
|
||||||
|
*
|
||||||
|
* @return If the event group was created then a handle to the event group is
|
||||||
|
* returned. If pxEventGroupBuffer was NULL then NULL is returned.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
// StaticEventGroup_t is a publicly accessible structure that has the same
|
||||||
|
// size and alignment requirements as the real event group structure. It is
|
||||||
|
// provided as a mechanism for applications to know the size of the event
|
||||||
|
// group (which is dependent on the architecture and configuration file
|
||||||
|
// settings) without breaking the strict data hiding policy by exposing the
|
||||||
|
// real event group internals. This StaticEventGroup_t variable is passed
|
||||||
|
// into the xSemaphoreCreateEventGroupStatic() function and is used to store
|
||||||
|
// the event group's data structures
|
||||||
|
StaticEventGroup_t xEventGroupBuffer;
|
||||||
|
|
||||||
|
// Create the event group without dynamically allocating any memory.
|
||||||
|
xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer );
|
||||||
|
</pre>
|
||||||
|
*/
|
||||||
|
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||||
|
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer ) PRIVILEGED_FUNCTION;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* event_groups.h
|
||||||
|
*<pre>
|
||||||
|
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
|
||||||
|
const EventBits_t uxBitsToWaitFor,
|
||||||
|
const BaseType_t xClearOnExit,
|
||||||
|
const BaseType_t xWaitForAllBits,
|
||||||
|
const TickType_t xTicksToWait );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* [Potentially] block to wait for one or more bits to be set within a
|
||||||
|
* previously created event group.
|
||||||
|
*
|
||||||
|
* This function cannot be called from an interrupt.
|
||||||
|
*
|
||||||
|
* @param xEventGroup The event group in which the bits are being tested. The
|
||||||
|
* event group must have previously been created using a call to
|
||||||
|
* xEventGroupCreate().
|
||||||
|
*
|
||||||
|
* @param uxBitsToWaitFor A bitwise value that indicates the bit or bits to test
|
||||||
|
* inside the event group. For example, to wait for bit 0 and/or bit 2 set
|
||||||
|
* uxBitsToWaitFor to 0x05. To wait for bits 0 and/or bit 1 and/or bit 2 set
|
||||||
|
* uxBitsToWaitFor to 0x07. Etc.
|
||||||
|
*
|
||||||
|
* @param xClearOnExit If xClearOnExit is set to pdTRUE then any bits within
|
||||||
|
* uxBitsToWaitFor that are set within the event group will be cleared before
|
||||||
|
* xEventGroupWaitBits() returns if the wait condition was met (if the function
|
||||||
|
* returns for a reason other than a timeout). If xClearOnExit is set to
|
||||||
|
* pdFALSE then the bits set in the event group are not altered when the call to
|
||||||
|
* xEventGroupWaitBits() returns.
|
||||||
|
*
|
||||||
|
* @param xWaitForAllBits If xWaitForAllBits is set to pdTRUE then
|
||||||
|
* xEventGroupWaitBits() will return when either all the bits in uxBitsToWaitFor
|
||||||
|
* are set or the specified block time expires. If xWaitForAllBits is set to
|
||||||
|
* pdFALSE then xEventGroupWaitBits() will return when any one of the bits set
|
||||||
|
* in uxBitsToWaitFor is set or the specified block time expires. The block
|
||||||
|
* time is specified by the xTicksToWait parameter.
|
||||||
|
*
|
||||||
|
* @param xTicksToWait The maximum amount of time (specified in 'ticks') to wait
|
||||||
|
* for one/all (depending on the xWaitForAllBits value) of the bits specified by
|
||||||
|
* uxBitsToWaitFor to become set.
|
||||||
|
*
|
||||||
|
* @return The value of the event group at the time either the bits being waited
|
||||||
|
* for became set, or the block time expired. Test the return value to know
|
||||||
|
* which bits were set. If xEventGroupWaitBits() returned because its timeout
|
||||||
|
* expired then not all the bits being waited for will be set. If
|
||||||
|
* xEventGroupWaitBits() returned because the bits it was waiting for were set
|
||||||
|
* then the returned value is the event group value before any bits were
|
||||||
|
* automatically cleared in the case that xClearOnExit parameter was set to
|
||||||
|
* pdTRUE.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
#define BIT_0 ( 1 << 0 )
|
||||||
|
#define BIT_4 ( 1 << 4 )
|
||||||
|
|
||||||
|
void aFunction( EventGroupHandle_t xEventGroup )
|
||||||
|
{
|
||||||
|
EventBits_t uxBits;
|
||||||
|
const TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;
|
||||||
|
|
||||||
|
// Wait a maximum of 100ms for either bit 0 or bit 4 to be set within
|
||||||
|
// the event group. Clear the bits before exiting.
|
||||||
|
uxBits = xEventGroupWaitBits(
|
||||||
|
xEventGroup, // The event group being tested.
|
||||||
|
BIT_0 | BIT_4, // The bits within the event group to wait for.
|
||||||
|
pdTRUE, // BIT_0 and BIT_4 should be cleared before returning.
|
||||||
|
pdFALSE, // Don't wait for both bits, either bit will do.
|
||||||
|
xTicksToWait ); // Wait a maximum of 100ms for either bit to be set.
|
||||||
|
|
||||||
|
if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
|
||||||
|
{
|
||||||
|
// xEventGroupWaitBits() returned because both bits were set.
|
||||||
|
}
|
||||||
|
else if( ( uxBits & BIT_0 ) != 0 )
|
||||||
|
{
|
||||||
|
// xEventGroupWaitBits() returned because just BIT_0 was set.
|
||||||
|
}
|
||||||
|
else if( ( uxBits & BIT_4 ) != 0 )
|
||||||
|
{
|
||||||
|
// xEventGroupWaitBits() returned because just BIT_4 was set.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// xEventGroupWaitBits() returned because xTicksToWait ticks passed
|
||||||
|
// without either BIT_0 or BIT_4 becoming set.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xEventGroupWaitBits xEventGroupWaitBits
|
||||||
|
* \ingroup EventGroup
|
||||||
|
*/
|
||||||
|
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* event_groups.h
|
||||||
|
*<pre>
|
||||||
|
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Clear bits within an event group. This function cannot be called from an
|
||||||
|
* interrupt.
|
||||||
|
*
|
||||||
|
* @param xEventGroup The event group in which the bits are to be cleared.
|
||||||
|
*
|
||||||
|
* @param uxBitsToClear A bitwise value that indicates the bit or bits to clear
|
||||||
|
* in the event group. For example, to clear bit 3 only, set uxBitsToClear to
|
||||||
|
* 0x08. To clear bit 3 and bit 0 set uxBitsToClear to 0x09.
|
||||||
|
*
|
||||||
|
* @return The value of the event group before the specified bits were cleared.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
#define BIT_0 ( 1 << 0 )
|
||||||
|
#define BIT_4 ( 1 << 4 )
|
||||||
|
|
||||||
|
void aFunction( EventGroupHandle_t xEventGroup )
|
||||||
|
{
|
||||||
|
EventBits_t uxBits;
|
||||||
|
|
||||||
|
// Clear bit 0 and bit 4 in xEventGroup.
|
||||||
|
uxBits = xEventGroupClearBits(
|
||||||
|
xEventGroup, // The event group being updated.
|
||||||
|
BIT_0 | BIT_4 );// The bits being cleared.
|
||||||
|
|
||||||
|
if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
|
||||||
|
{
|
||||||
|
// Both bit 0 and bit 4 were set before xEventGroupClearBits() was
|
||||||
|
// called. Both will now be clear (not set).
|
||||||
|
}
|
||||||
|
else if( ( uxBits & BIT_0 ) != 0 )
|
||||||
|
{
|
||||||
|
// Bit 0 was set before xEventGroupClearBits() was called. It will
|
||||||
|
// now be clear.
|
||||||
|
}
|
||||||
|
else if( ( uxBits & BIT_4 ) != 0 )
|
||||||
|
{
|
||||||
|
// Bit 4 was set before xEventGroupClearBits() was called. It will
|
||||||
|
// now be clear.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Neither bit 0 nor bit 4 were set in the first place.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xEventGroupClearBits xEventGroupClearBits
|
||||||
|
* \ingroup EventGroup
|
||||||
|
*/
|
||||||
|
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* event_groups.h
|
||||||
|
*<pre>
|
||||||
|
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* A version of xEventGroupClearBits() that can be called from an interrupt.
|
||||||
|
*
|
||||||
|
* Setting bits in an event group is not a deterministic operation because there
|
||||||
|
* are an unknown number of tasks that may be waiting for the bit or bits being
|
||||||
|
* set. FreeRTOS does not allow nondeterministic operations to be performed
|
||||||
|
* while interrupts are disabled, so protects event groups that are accessed
|
||||||
|
* from tasks by suspending the scheduler rather than disabling interrupts. As
|
||||||
|
* a result event groups cannot be accessed directly from an interrupt service
|
||||||
|
* routine. Therefore xEventGroupClearBitsFromISR() sends a message to the
|
||||||
|
* timer task to have the clear operation performed in the context of the timer
|
||||||
|
* task.
|
||||||
|
*
|
||||||
|
* @param xEventGroup The event group in which the bits are to be cleared.
|
||||||
|
*
|
||||||
|
* @param uxBitsToClear A bitwise value that indicates the bit or bits to clear.
|
||||||
|
* For example, to clear bit 3 only, set uxBitsToClear to 0x08. To clear bit 3
|
||||||
|
* and bit 0 set uxBitsToClear to 0x09.
|
||||||
|
*
|
||||||
|
* @return If the request to execute the function was posted successfully then
|
||||||
|
* pdPASS is returned, otherwise pdFALSE is returned. pdFALSE will be returned
|
||||||
|
* if the timer service queue was full.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
#define BIT_0 ( 1 << 0 )
|
||||||
|
#define BIT_4 ( 1 << 4 )
|
||||||
|
|
||||||
|
// An event group which it is assumed has already been created by a call to
|
||||||
|
// xEventGroupCreate().
|
||||||
|
EventGroupHandle_t xEventGroup;
|
||||||
|
|
||||||
|
void anInterruptHandler( void )
|
||||||
|
{
|
||||||
|
// Clear bit 0 and bit 4 in xEventGroup.
|
||||||
|
xResult = xEventGroupClearBitsFromISR(
|
||||||
|
xEventGroup, // The event group being updated.
|
||||||
|
BIT_0 | BIT_4 ); // The bits being set.
|
||||||
|
|
||||||
|
if( xResult == pdPASS )
|
||||||
|
{
|
||||||
|
// The message was posted successfully.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xEventGroupClearBitsFromISR xEventGroupClearBitsFromISR
|
||||||
|
* \ingroup EventGroup
|
||||||
|
*/
|
||||||
|
#if( configUSE_TRACE_FACILITY == 1 )
|
||||||
|
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) PRIVILEGED_FUNCTION;
|
||||||
|
#else
|
||||||
|
#define xEventGroupClearBitsFromISR( xEventGroup, uxBitsToClear ) xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* event_groups.h
|
||||||
|
*<pre>
|
||||||
|
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Set bits within an event group.
|
||||||
|
* This function cannot be called from an interrupt. xEventGroupSetBitsFromISR()
|
||||||
|
* is a version that can be called from an interrupt.
|
||||||
|
*
|
||||||
|
* Setting bits in an event group will automatically unblock tasks that are
|
||||||
|
* blocked waiting for the bits.
|
||||||
|
*
|
||||||
|
* @param xEventGroup The event group in which the bits are to be set.
|
||||||
|
*
|
||||||
|
* @param uxBitsToSet A bitwise value that indicates the bit or bits to set.
|
||||||
|
* For example, to set bit 3 only, set uxBitsToSet to 0x08. To set bit 3
|
||||||
|
* and bit 0 set uxBitsToSet to 0x09.
|
||||||
|
*
|
||||||
|
* @return The value of the event group at the time the call to
|
||||||
|
* xEventGroupSetBits() returns. There are two reasons why the returned value
|
||||||
|
* might have the bits specified by the uxBitsToSet parameter cleared. First,
|
||||||
|
* if setting a bit results in a task that was waiting for the bit leaving the
|
||||||
|
* blocked state then it is possible the bit will be cleared automatically
|
||||||
|
* (see the xClearBitOnExit parameter of xEventGroupWaitBits()). Second, any
|
||||||
|
* unblocked (or otherwise Ready state) task that has a priority above that of
|
||||||
|
* the task that called xEventGroupSetBits() will execute and may change the
|
||||||
|
* event group value before the call to xEventGroupSetBits() returns.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
#define BIT_0 ( 1 << 0 )
|
||||||
|
#define BIT_4 ( 1 << 4 )
|
||||||
|
|
||||||
|
void aFunction( EventGroupHandle_t xEventGroup )
|
||||||
|
{
|
||||||
|
EventBits_t uxBits;
|
||||||
|
|
||||||
|
// Set bit 0 and bit 4 in xEventGroup.
|
||||||
|
uxBits = xEventGroupSetBits(
|
||||||
|
xEventGroup, // The event group being updated.
|
||||||
|
BIT_0 | BIT_4 );// The bits being set.
|
||||||
|
|
||||||
|
if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
|
||||||
|
{
|
||||||
|
// Both bit 0 and bit 4 remained set when the function returned.
|
||||||
|
}
|
||||||
|
else if( ( uxBits & BIT_0 ) != 0 )
|
||||||
|
{
|
||||||
|
// Bit 0 remained set when the function returned, but bit 4 was
|
||||||
|
// cleared. It might be that bit 4 was cleared automatically as a
|
||||||
|
// task that was waiting for bit 4 was removed from the Blocked
|
||||||
|
// state.
|
||||||
|
}
|
||||||
|
else if( ( uxBits & BIT_4 ) != 0 )
|
||||||
|
{
|
||||||
|
// Bit 4 remained set when the function returned, but bit 0 was
|
||||||
|
// cleared. It might be that bit 0 was cleared automatically as a
|
||||||
|
// task that was waiting for bit 0 was removed from the Blocked
|
||||||
|
// state.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Neither bit 0 nor bit 4 remained set. It might be that a task
|
||||||
|
// was waiting for both of the bits to be set, and the bits were
|
||||||
|
// cleared as the task left the Blocked state.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xEventGroupSetBits xEventGroupSetBits
|
||||||
|
* \ingroup EventGroup
|
||||||
|
*/
|
||||||
|
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* event_groups.h
|
||||||
|
*<pre>
|
||||||
|
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* A version of xEventGroupSetBits() that can be called from an interrupt.
|
||||||
|
*
|
||||||
|
* Setting bits in an event group is not a deterministic operation because there
|
||||||
|
* are an unknown number of tasks that may be waiting for the bit or bits being
|
||||||
|
* set. FreeRTOS does not allow nondeterministic operations to be performed in
|
||||||
|
* interrupts or from critical sections. Therefore xEventGroupSetBitsFromISR()
|
||||||
|
* sends a message to the timer task to have the set operation performed in the
|
||||||
|
* context of the timer task - where a scheduler lock is used in place of a
|
||||||
|
* critical section.
|
||||||
|
*
|
||||||
|
* @param xEventGroup The event group in which the bits are to be set.
|
||||||
|
*
|
||||||
|
* @param uxBitsToSet A bitwise value that indicates the bit or bits to set.
|
||||||
|
* For example, to set bit 3 only, set uxBitsToSet to 0x08. To set bit 3
|
||||||
|
* and bit 0 set uxBitsToSet to 0x09.
|
||||||
|
*
|
||||||
|
* @param pxHigherPriorityTaskWoken As mentioned above, calling this function
|
||||||
|
* will result in a message being sent to the timer daemon task. If the
|
||||||
|
* priority of the timer daemon task is higher than the priority of the
|
||||||
|
* currently running task (the task the interrupt interrupted) then
|
||||||
|
* *pxHigherPriorityTaskWoken will be set to pdTRUE by
|
||||||
|
* xEventGroupSetBitsFromISR(), indicating that a context switch should be
|
||||||
|
* requested before the interrupt exits. For that reason
|
||||||
|
* *pxHigherPriorityTaskWoken must be initialised to pdFALSE. See the
|
||||||
|
* example code below.
|
||||||
|
*
|
||||||
|
* @return If the request to execute the function was posted successfully then
|
||||||
|
* pdPASS is returned, otherwise pdFALSE is returned. pdFALSE will be returned
|
||||||
|
* if the timer service queue was full.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
#define BIT_0 ( 1 << 0 )
|
||||||
|
#define BIT_4 ( 1 << 4 )
|
||||||
|
|
||||||
|
// An event group which it is assumed has already been created by a call to
|
||||||
|
// xEventGroupCreate().
|
||||||
|
EventGroupHandle_t xEventGroup;
|
||||||
|
|
||||||
|
void anInterruptHandler( void )
|
||||||
|
{
|
||||||
|
BaseType_t xHigherPriorityTaskWoken, xResult;
|
||||||
|
|
||||||
|
// xHigherPriorityTaskWoken must be initialised to pdFALSE.
|
||||||
|
xHigherPriorityTaskWoken = pdFALSE;
|
||||||
|
|
||||||
|
// Set bit 0 and bit 4 in xEventGroup.
|
||||||
|
xResult = xEventGroupSetBitsFromISR(
|
||||||
|
xEventGroup, // The event group being updated.
|
||||||
|
BIT_0 | BIT_4 // The bits being set.
|
||||||
|
&xHigherPriorityTaskWoken );
|
||||||
|
|
||||||
|
// Was the message posted successfully?
|
||||||
|
if( xResult == pdPASS )
|
||||||
|
{
|
||||||
|
// If xHigherPriorityTaskWoken is now set to pdTRUE then a context
|
||||||
|
// switch should be requested. The macro used is port specific and
|
||||||
|
// will be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() -
|
||||||
|
// refer to the documentation page for the port being used.
|
||||||
|
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xEventGroupSetBitsFromISR xEventGroupSetBitsFromISR
|
||||||
|
* \ingroup EventGroup
|
||||||
|
*/
|
||||||
|
#if( configUSE_TRACE_FACILITY == 1 )
|
||||||
|
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
|
||||||
|
#else
|
||||||
|
#define xEventGroupSetBitsFromISR( xEventGroup, uxBitsToSet, pxHigherPriorityTaskWoken ) xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* event_groups.h
|
||||||
|
*<pre>
|
||||||
|
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,
|
||||||
|
const EventBits_t uxBitsToSet,
|
||||||
|
const EventBits_t uxBitsToWaitFor,
|
||||||
|
TickType_t xTicksToWait );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Atomically set bits within an event group, then wait for a combination of
|
||||||
|
* bits to be set within the same event group. This functionality is typically
|
||||||
|
* used to synchronise multiple tasks, where each task has to wait for the other
|
||||||
|
* tasks to reach a synchronisation point before proceeding.
|
||||||
|
*
|
||||||
|
* This function cannot be used from an interrupt.
|
||||||
|
*
|
||||||
|
* The function will return before its block time expires if the bits specified
|
||||||
|
* by the uxBitsToWait parameter are set, or become set within that time. In
|
||||||
|
* this case all the bits specified by uxBitsToWait will be automatically
|
||||||
|
* cleared before the function returns.
|
||||||
|
*
|
||||||
|
* @param xEventGroup The event group in which the bits are being tested. The
|
||||||
|
* event group must have previously been created using a call to
|
||||||
|
* xEventGroupCreate().
|
||||||
|
*
|
||||||
|
* @param uxBitsToSet The bits to set in the event group before determining
|
||||||
|
* if, and possibly waiting for, all the bits specified by the uxBitsToWait
|
||||||
|
* parameter are set.
|
||||||
|
*
|
||||||
|
* @param uxBitsToWaitFor A bitwise value that indicates the bit or bits to test
|
||||||
|
* inside the event group. For example, to wait for bit 0 and bit 2 set
|
||||||
|
* uxBitsToWaitFor to 0x05. To wait for bits 0 and bit 1 and bit 2 set
|
||||||
|
* uxBitsToWaitFor to 0x07. Etc.
|
||||||
|
*
|
||||||
|
* @param xTicksToWait The maximum amount of time (specified in 'ticks') to wait
|
||||||
|
* for all of the bits specified by uxBitsToWaitFor to become set.
|
||||||
|
*
|
||||||
|
* @return The value of the event group at the time either the bits being waited
|
||||||
|
* for became set, or the block time expired. Test the return value to know
|
||||||
|
* which bits were set. If xEventGroupSync() returned because its timeout
|
||||||
|
* expired then not all the bits being waited for will be set. If
|
||||||
|
* xEventGroupSync() returned because all the bits it was waiting for were
|
||||||
|
* set then the returned value is the event group value before any bits were
|
||||||
|
* automatically cleared.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
// Bits used by the three tasks.
|
||||||
|
#define TASK_0_BIT ( 1 << 0 )
|
||||||
|
#define TASK_1_BIT ( 1 << 1 )
|
||||||
|
#define TASK_2_BIT ( 1 << 2 )
|
||||||
|
|
||||||
|
#define ALL_SYNC_BITS ( TASK_0_BIT | TASK_1_BIT | TASK_2_BIT )
|
||||||
|
|
||||||
|
// Use an event group to synchronise three tasks. It is assumed this event
|
||||||
|
// group has already been created elsewhere.
|
||||||
|
EventGroupHandle_t xEventBits;
|
||||||
|
|
||||||
|
void vTask0( void *pvParameters )
|
||||||
|
{
|
||||||
|
EventBits_t uxReturn;
|
||||||
|
TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;
|
||||||
|
|
||||||
|
for( ;; )
|
||||||
|
{
|
||||||
|
// Perform task functionality here.
|
||||||
|
|
||||||
|
// Set bit 0 in the event flag to note this task has reached the
|
||||||
|
// sync point. The other two tasks will set the other two bits defined
|
||||||
|
// by ALL_SYNC_BITS. All three tasks have reached the synchronisation
|
||||||
|
// point when all the ALL_SYNC_BITS are set. Wait a maximum of 100ms
|
||||||
|
// for this to happen.
|
||||||
|
uxReturn = xEventGroupSync( xEventBits, TASK_0_BIT, ALL_SYNC_BITS, xTicksToWait );
|
||||||
|
|
||||||
|
if( ( uxReturn & ALL_SYNC_BITS ) == ALL_SYNC_BITS )
|
||||||
|
{
|
||||||
|
// All three tasks reached the synchronisation point before the call
|
||||||
|
// to xEventGroupSync() timed out.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vTask1( void *pvParameters )
|
||||||
|
{
|
||||||
|
for( ;; )
|
||||||
|
{
|
||||||
|
// Perform task functionality here.
|
||||||
|
|
||||||
|
// Set bit 1 in the event flag to note this task has reached the
|
||||||
|
// synchronisation point. The other two tasks will set the other two
|
||||||
|
// bits defined by ALL_SYNC_BITS. All three tasks have reached the
|
||||||
|
// synchronisation point when all the ALL_SYNC_BITS are set. Wait
|
||||||
|
// indefinitely for this to happen.
|
||||||
|
xEventGroupSync( xEventBits, TASK_1_BIT, ALL_SYNC_BITS, portMAX_DELAY );
|
||||||
|
|
||||||
|
// xEventGroupSync() was called with an indefinite block time, so
|
||||||
|
// this task will only reach here if the syncrhonisation was made by all
|
||||||
|
// three tasks, so there is no need to test the return value.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vTask2( void *pvParameters )
|
||||||
|
{
|
||||||
|
for( ;; )
|
||||||
|
{
|
||||||
|
// Perform task functionality here.
|
||||||
|
|
||||||
|
// Set bit 2 in the event flag to note this task has reached the
|
||||||
|
// synchronisation point. The other two tasks will set the other two
|
||||||
|
// bits defined by ALL_SYNC_BITS. All three tasks have reached the
|
||||||
|
// synchronisation point when all the ALL_SYNC_BITS are set. Wait
|
||||||
|
// indefinitely for this to happen.
|
||||||
|
xEventGroupSync( xEventBits, TASK_2_BIT, ALL_SYNC_BITS, portMAX_DELAY );
|
||||||
|
|
||||||
|
// xEventGroupSync() was called with an indefinite block time, so
|
||||||
|
// this task will only reach here if the syncrhonisation was made by all
|
||||||
|
// three tasks, so there is no need to test the return value.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
* \defgroup xEventGroupSync xEventGroupSync
|
||||||
|
* \ingroup EventGroup
|
||||||
|
*/
|
||||||
|
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* event_groups.h
|
||||||
|
*<pre>
|
||||||
|
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Returns the current value of the bits in an event group. This function
|
||||||
|
* cannot be used from an interrupt.
|
||||||
|
*
|
||||||
|
* @param xEventGroup The event group being queried.
|
||||||
|
*
|
||||||
|
* @return The event group bits at the time xEventGroupGetBits() was called.
|
||||||
|
*
|
||||||
|
* \defgroup xEventGroupGetBits xEventGroupGetBits
|
||||||
|
* \ingroup EventGroup
|
||||||
|
*/
|
||||||
|
#define xEventGroupGetBits( xEventGroup ) xEventGroupClearBits( xEventGroup, 0 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* event_groups.h
|
||||||
|
*<pre>
|
||||||
|
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* A version of xEventGroupGetBits() that can be called from an ISR.
|
||||||
|
*
|
||||||
|
* @param xEventGroup The event group being queried.
|
||||||
|
*
|
||||||
|
* @return The event group bits at the time xEventGroupGetBitsFromISR() was called.
|
||||||
|
*
|
||||||
|
* \defgroup xEventGroupGetBitsFromISR xEventGroupGetBitsFromISR
|
||||||
|
* \ingroup EventGroup
|
||||||
|
*/
|
||||||
|
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* event_groups.h
|
||||||
|
*<pre>
|
||||||
|
void xEventGroupDelete( EventGroupHandle_t xEventGroup );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Delete an event group that was previously created by a call to
|
||||||
|
* xEventGroupCreate(). Tasks that are blocked on the event group will be
|
||||||
|
* unblocked and obtain 0 as the event group's value.
|
||||||
|
*
|
||||||
|
* @param xEventGroup The event group being deleted.
|
||||||
|
*/
|
||||||
|
void vEventGroupDelete( EventGroupHandle_t xEventGroup ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/* For internal use only. */
|
||||||
|
void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet ) PRIVILEGED_FUNCTION;
|
||||||
|
void vEventGroupClearBitsCallback( void *pvEventGroup, const uint32_t ulBitsToClear ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
|
||||||
|
#if (configUSE_TRACE_FACILITY == 1)
|
||||||
|
UBaseType_t uxEventGroupGetNumber( void* xEventGroup ) PRIVILEGED_FUNCTION;
|
||||||
|
void vEventGroupSetNumber( void* xEventGroup, UBaseType_t uxEventGroupNumber ) PRIVILEGED_FUNCTION;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* EVENT_GROUPS_H */
|
||||||
|
|
||||||
|
|
||||||
412
Middlewares/Third_Party/FreeRTOS/Source/include/list.h
vendored
Normal file
412
Middlewares/Third_Party/FreeRTOS/Source/include/list.h
vendored
Normal file
@@ -0,0 +1,412 @@
|
|||||||
|
/*
|
||||||
|
* FreeRTOS Kernel V10.3.1
|
||||||
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org
|
||||||
|
* http://aws.amazon.com/freertos
|
||||||
|
*
|
||||||
|
* 1 tab == 4 spaces!
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the list implementation used by the scheduler. While it is tailored
|
||||||
|
* heavily for the schedulers needs, it is also available for use by
|
||||||
|
* application code.
|
||||||
|
*
|
||||||
|
* list_ts can only store pointers to list_item_ts. Each ListItem_t contains a
|
||||||
|
* numeric value (xItemValue). Most of the time the lists are sorted in
|
||||||
|
* descending item value order.
|
||||||
|
*
|
||||||
|
* Lists are created already containing one list item. The value of this
|
||||||
|
* item is the maximum possible that can be stored, it is therefore always at
|
||||||
|
* the end of the list and acts as a marker. The list member pxHead always
|
||||||
|
* points to this marker - even though it is at the tail of the list. This
|
||||||
|
* is because the tail contains a wrap back pointer to the true head of
|
||||||
|
* the list.
|
||||||
|
*
|
||||||
|
* In addition to it's value, each list item contains a pointer to the next
|
||||||
|
* item in the list (pxNext), a pointer to the list it is in (pxContainer)
|
||||||
|
* and a pointer to back to the object that contains it. These later two
|
||||||
|
* pointers are included for efficiency of list manipulation. There is
|
||||||
|
* effectively a two way link between the object containing the list item and
|
||||||
|
* the list item itself.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* \page ListIntroduction List Implementation
|
||||||
|
* \ingroup FreeRTOSIntro
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INC_FREERTOS_H
|
||||||
|
#error FreeRTOS.h must be included before list.h
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LIST_H
|
||||||
|
#define LIST_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The list structure members are modified from within interrupts, and therefore
|
||||||
|
* by rights should be declared volatile. However, they are only modified in a
|
||||||
|
* functionally atomic way (within critical sections of with the scheduler
|
||||||
|
* suspended) and are either passed by reference into a function or indexed via
|
||||||
|
* a volatile variable. Therefore, in all use cases tested so far, the volatile
|
||||||
|
* qualifier can be omitted in order to provide a moderate performance
|
||||||
|
* improvement without adversely affecting functional behaviour. The assembly
|
||||||
|
* instructions generated by the IAR, ARM and GCC compilers when the respective
|
||||||
|
* compiler's options were set for maximum optimisation has been inspected and
|
||||||
|
* deemed to be as intended. That said, as compiler technology advances, and
|
||||||
|
* especially if aggressive cross module optimisation is used (a use case that
|
||||||
|
* has not been exercised to any great extend) then it is feasible that the
|
||||||
|
* volatile qualifier will be needed for correct optimisation. It is expected
|
||||||
|
* that a compiler removing essential code because, without the volatile
|
||||||
|
* qualifier on the list structure members and with aggressive cross module
|
||||||
|
* optimisation, the compiler deemed the code unnecessary will result in
|
||||||
|
* complete and obvious failure of the scheduler. If this is ever experienced
|
||||||
|
* then the volatile qualifier can be inserted in the relevant places within the
|
||||||
|
* list structures by simply defining configLIST_VOLATILE to volatile in
|
||||||
|
* FreeRTOSConfig.h (as per the example at the bottom of this comment block).
|
||||||
|
* If configLIST_VOLATILE is not defined then the preprocessor directives below
|
||||||
|
* will simply #define configLIST_VOLATILE away completely.
|
||||||
|
*
|
||||||
|
* To use volatile list structure members then add the following line to
|
||||||
|
* FreeRTOSConfig.h (without the quotes):
|
||||||
|
* "#define configLIST_VOLATILE volatile"
|
||||||
|
*/
|
||||||
|
#ifndef configLIST_VOLATILE
|
||||||
|
#define configLIST_VOLATILE
|
||||||
|
#endif /* configSUPPORT_CROSS_MODULE_OPTIMISATION */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Macros that can be used to place known values within the list structures,
|
||||||
|
then check that the known values do not get corrupted during the execution of
|
||||||
|
the application. These may catch the list data structures being overwritten in
|
||||||
|
memory. They will not catch data errors caused by incorrect configuration or
|
||||||
|
use of FreeRTOS.*/
|
||||||
|
#if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 )
|
||||||
|
/* Define the macros to do nothing. */
|
||||||
|
#define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
|
||||||
|
#define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
|
||||||
|
#define listFIRST_LIST_INTEGRITY_CHECK_VALUE
|
||||||
|
#define listSECOND_LIST_INTEGRITY_CHECK_VALUE
|
||||||
|
#define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )
|
||||||
|
#define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )
|
||||||
|
#define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList )
|
||||||
|
#define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList )
|
||||||
|
#define listTEST_LIST_ITEM_INTEGRITY( pxItem )
|
||||||
|
#define listTEST_LIST_INTEGRITY( pxList )
|
||||||
|
#else
|
||||||
|
/* Define macros that add new members into the list structures. */
|
||||||
|
#define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue1;
|
||||||
|
#define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue2;
|
||||||
|
#define listFIRST_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue1;
|
||||||
|
#define listSECOND_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue2;
|
||||||
|
|
||||||
|
/* Define macros that set the new structure members to known values. */
|
||||||
|
#define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) ( pxItem )->xListItemIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
|
||||||
|
#define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) ( pxItem )->xListItemIntegrityValue2 = pdINTEGRITY_CHECK_VALUE
|
||||||
|
#define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ) ( pxList )->xListIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
|
||||||
|
#define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ) ( pxList )->xListIntegrityValue2 = pdINTEGRITY_CHECK_VALUE
|
||||||
|
|
||||||
|
/* Define macros that will assert if one of the structure members does not
|
||||||
|
contain its expected value. */
|
||||||
|
#define listTEST_LIST_ITEM_INTEGRITY( pxItem ) configASSERT( ( ( pxItem )->xListItemIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxItem )->xListItemIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
|
||||||
|
#define listTEST_LIST_INTEGRITY( pxList ) configASSERT( ( ( pxList )->xListIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxList )->xListIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
|
||||||
|
#endif /* configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Definition of the only type of object that a list can contain.
|
||||||
|
*/
|
||||||
|
struct xLIST;
|
||||||
|
struct xLIST_ITEM
|
||||||
|
{
|
||||||
|
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||||
|
configLIST_VOLATILE TickType_t xItemValue; /*< The value being listed. In most cases this is used to sort the list in descending order. */
|
||||||
|
struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*< Pointer to the next ListItem_t in the list. */
|
||||||
|
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*< Pointer to the previous ListItem_t in the list. */
|
||||||
|
void * pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */
|
||||||
|
struct xLIST * configLIST_VOLATILE pxContainer; /*< Pointer to the list in which this list item is placed (if any). */
|
||||||
|
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||||
|
};
|
||||||
|
typedef struct xLIST_ITEM ListItem_t; /* For some reason lint wants this as two separate definitions. */
|
||||||
|
|
||||||
|
struct xMINI_LIST_ITEM
|
||||||
|
{
|
||||||
|
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||||
|
configLIST_VOLATILE TickType_t xItemValue;
|
||||||
|
struct xLIST_ITEM * configLIST_VOLATILE pxNext;
|
||||||
|
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
|
||||||
|
};
|
||||||
|
typedef struct xMINI_LIST_ITEM MiniListItem_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Definition of the type of queue used by the scheduler.
|
||||||
|
*/
|
||||||
|
typedef struct xLIST
|
||||||
|
{
|
||||||
|
listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||||
|
volatile UBaseType_t uxNumberOfItems;
|
||||||
|
ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */
|
||||||
|
MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
|
||||||
|
listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||||
|
} List_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Access macro to set the owner of a list item. The owner of a list item
|
||||||
|
* is the object (usually a TCB) that contains the list item.
|
||||||
|
*
|
||||||
|
* \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER
|
||||||
|
* \ingroup LinkedList
|
||||||
|
*/
|
||||||
|
#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Access macro to get the owner of a list item. The owner of a list item
|
||||||
|
* is the object (usually a TCB) that contains the list item.
|
||||||
|
*
|
||||||
|
* \page listGET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER
|
||||||
|
* \ingroup LinkedList
|
||||||
|
*/
|
||||||
|
#define listGET_LIST_ITEM_OWNER( pxListItem ) ( ( pxListItem )->pvOwner )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Access macro to set the value of the list item. In most cases the value is
|
||||||
|
* used to sort the list in descending order.
|
||||||
|
*
|
||||||
|
* \page listSET_LIST_ITEM_VALUE listSET_LIST_ITEM_VALUE
|
||||||
|
* \ingroup LinkedList
|
||||||
|
*/
|
||||||
|
#define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) ( ( pxListItem )->xItemValue = ( xValue ) )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Access macro to retrieve the value of the list item. The value can
|
||||||
|
* represent anything - for example the priority of a task, or the time at
|
||||||
|
* which a task should be unblocked.
|
||||||
|
*
|
||||||
|
* \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE
|
||||||
|
* \ingroup LinkedList
|
||||||
|
*/
|
||||||
|
#define listGET_LIST_ITEM_VALUE( pxListItem ) ( ( pxListItem )->xItemValue )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Access macro to retrieve the value of the list item at the head of a given
|
||||||
|
* list.
|
||||||
|
*
|
||||||
|
* \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE
|
||||||
|
* \ingroup LinkedList
|
||||||
|
*/
|
||||||
|
#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext->xItemValue )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the list item at the head of the list.
|
||||||
|
*
|
||||||
|
* \page listGET_HEAD_ENTRY listGET_HEAD_ENTRY
|
||||||
|
* \ingroup LinkedList
|
||||||
|
*/
|
||||||
|
#define listGET_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the next list item.
|
||||||
|
*
|
||||||
|
* \page listGET_NEXT listGET_NEXT
|
||||||
|
* \ingroup LinkedList
|
||||||
|
*/
|
||||||
|
#define listGET_NEXT( pxListItem ) ( ( pxListItem )->pxNext )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the list item that marks the end of the list
|
||||||
|
*
|
||||||
|
* \page listGET_END_MARKER listGET_END_MARKER
|
||||||
|
* \ingroup LinkedList
|
||||||
|
*/
|
||||||
|
#define listGET_END_MARKER( pxList ) ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Access macro to determine if a list contains any items. The macro will
|
||||||
|
* only have the value true if the list is empty.
|
||||||
|
*
|
||||||
|
* \page listLIST_IS_EMPTY listLIST_IS_EMPTY
|
||||||
|
* \ingroup LinkedList
|
||||||
|
*/
|
||||||
|
#define listLIST_IS_EMPTY( pxList ) ( ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ? pdTRUE : pdFALSE )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Access macro to return the number of items in the list.
|
||||||
|
*/
|
||||||
|
#define listCURRENT_LIST_LENGTH( pxList ) ( ( pxList )->uxNumberOfItems )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Access function to obtain the owner of the next entry in a list.
|
||||||
|
*
|
||||||
|
* The list member pxIndex is used to walk through a list. Calling
|
||||||
|
* listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list
|
||||||
|
* and returns that entry's pxOwner parameter. Using multiple calls to this
|
||||||
|
* function it is therefore possible to move through every item contained in
|
||||||
|
* a list.
|
||||||
|
*
|
||||||
|
* The pxOwner parameter of a list item is a pointer to the object that owns
|
||||||
|
* the list item. In the scheduler this is normally a task control block.
|
||||||
|
* The pxOwner parameter effectively creates a two way link between the list
|
||||||
|
* item and its owner.
|
||||||
|
*
|
||||||
|
* @param pxTCB pxTCB is set to the address of the owner of the next list item.
|
||||||
|
* @param pxList The list from which the next item owner is to be returned.
|
||||||
|
*
|
||||||
|
* \page listGET_OWNER_OF_NEXT_ENTRY listGET_OWNER_OF_NEXT_ENTRY
|
||||||
|
* \ingroup LinkedList
|
||||||
|
*/
|
||||||
|
#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) \
|
||||||
|
{ \
|
||||||
|
List_t * const pxConstList = ( pxList ); \
|
||||||
|
/* Increment the index to the next item and return the item, ensuring */ \
|
||||||
|
/* we don't return the marker used at the end of the list. */ \
|
||||||
|
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
|
||||||
|
if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \
|
||||||
|
{ \
|
||||||
|
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
|
||||||
|
} \
|
||||||
|
( pxTCB ) = ( pxConstList )->pxIndex->pvOwner; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Access function to obtain the owner of the first entry in a list. Lists
|
||||||
|
* are normally sorted in ascending item value order.
|
||||||
|
*
|
||||||
|
* This function returns the pxOwner member of the first item in the list.
|
||||||
|
* The pxOwner parameter of a list item is a pointer to the object that owns
|
||||||
|
* the list item. In the scheduler this is normally a task control block.
|
||||||
|
* The pxOwner parameter effectively creates a two way link between the list
|
||||||
|
* item and its owner.
|
||||||
|
*
|
||||||
|
* @param pxList The list from which the owner of the head item is to be
|
||||||
|
* returned.
|
||||||
|
*
|
||||||
|
* \page listGET_OWNER_OF_HEAD_ENTRY listGET_OWNER_OF_HEAD_ENTRY
|
||||||
|
* \ingroup LinkedList
|
||||||
|
*/
|
||||||
|
#define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( (&( ( pxList )->xListEnd ))->pxNext->pvOwner )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check to see if a list item is within a list. The list item maintains a
|
||||||
|
* "container" pointer that points to the list it is in. All this macro does
|
||||||
|
* is check to see if the container and the list match.
|
||||||
|
*
|
||||||
|
* @param pxList The list we want to know if the list item is within.
|
||||||
|
* @param pxListItem The list item we want to know if is in the list.
|
||||||
|
* @return pdTRUE if the list item is in the list, otherwise pdFALSE.
|
||||||
|
*/
|
||||||
|
#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( ( pxListItem )->pxContainer == ( pxList ) ) ? ( pdTRUE ) : ( pdFALSE ) )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the list a list item is contained within (referenced from).
|
||||||
|
*
|
||||||
|
* @param pxListItem The list item being queried.
|
||||||
|
* @return A pointer to the List_t object that references the pxListItem
|
||||||
|
*/
|
||||||
|
#define listLIST_ITEM_CONTAINER( pxListItem ) ( ( pxListItem )->pxContainer )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This provides a crude means of knowing if a list has been initialised, as
|
||||||
|
* pxList->xListEnd.xItemValue is set to portMAX_DELAY by the vListInitialise()
|
||||||
|
* function.
|
||||||
|
*/
|
||||||
|
#define listLIST_IS_INITIALISED( pxList ) ( ( pxList )->xListEnd.xItemValue == portMAX_DELAY )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Must be called before a list is used! This initialises all the members
|
||||||
|
* of the list structure and inserts the xListEnd item into the list as a
|
||||||
|
* marker to the back of the list.
|
||||||
|
*
|
||||||
|
* @param pxList Pointer to the list being initialised.
|
||||||
|
*
|
||||||
|
* \page vListInitialise vListInitialise
|
||||||
|
* \ingroup LinkedList
|
||||||
|
*/
|
||||||
|
void vListInitialise( List_t * const pxList ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Must be called before a list item is used. This sets the list container to
|
||||||
|
* null so the item does not think that it is already contained in a list.
|
||||||
|
*
|
||||||
|
* @param pxItem Pointer to the list item being initialised.
|
||||||
|
*
|
||||||
|
* \page vListInitialiseItem vListInitialiseItem
|
||||||
|
* \ingroup LinkedList
|
||||||
|
*/
|
||||||
|
void vListInitialiseItem( ListItem_t * const pxItem ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insert a list item into a list. The item will be inserted into the list in
|
||||||
|
* a position determined by its item value (descending item value order).
|
||||||
|
*
|
||||||
|
* @param pxList The list into which the item is to be inserted.
|
||||||
|
*
|
||||||
|
* @param pxNewListItem The item that is to be placed in the list.
|
||||||
|
*
|
||||||
|
* \page vListInsert vListInsert
|
||||||
|
* \ingroup LinkedList
|
||||||
|
*/
|
||||||
|
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insert a list item into a list. The item will be inserted in a position
|
||||||
|
* such that it will be the last item within the list returned by multiple
|
||||||
|
* calls to listGET_OWNER_OF_NEXT_ENTRY.
|
||||||
|
*
|
||||||
|
* The list member pxIndex is used to walk through a list. Calling
|
||||||
|
* listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list.
|
||||||
|
* Placing an item in a list using vListInsertEnd effectively places the item
|
||||||
|
* in the list position pointed to by pxIndex. This means that every other
|
||||||
|
* item within the list will be returned by listGET_OWNER_OF_NEXT_ENTRY before
|
||||||
|
* the pxIndex parameter again points to the item being inserted.
|
||||||
|
*
|
||||||
|
* @param pxList The list into which the item is to be inserted.
|
||||||
|
*
|
||||||
|
* @param pxNewListItem The list item to be inserted into the list.
|
||||||
|
*
|
||||||
|
* \page vListInsertEnd vListInsertEnd
|
||||||
|
* \ingroup LinkedList
|
||||||
|
*/
|
||||||
|
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove an item from a list. The list item has a pointer to the list that
|
||||||
|
* it is in, so only the list item need be passed into the function.
|
||||||
|
*
|
||||||
|
* @param uxListRemove The item to be removed. The item will remove itself from
|
||||||
|
* the list pointed to by it's pxContainer parameter.
|
||||||
|
*
|
||||||
|
* @return The number of items that remain in the list after the list item has
|
||||||
|
* been removed.
|
||||||
|
*
|
||||||
|
* \page uxListRemove uxListRemove
|
||||||
|
* \ingroup LinkedList
|
||||||
|
*/
|
||||||
|
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
803
Middlewares/Third_Party/FreeRTOS/Source/include/message_buffer.h
vendored
Normal file
803
Middlewares/Third_Party/FreeRTOS/Source/include/message_buffer.h
vendored
Normal file
@@ -0,0 +1,803 @@
|
|||||||
|
/*
|
||||||
|
* FreeRTOS Kernel V10.3.1
|
||||||
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org
|
||||||
|
* http://aws.amazon.com/freertos
|
||||||
|
*
|
||||||
|
* 1 tab == 4 spaces!
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Message buffers build functionality on top of FreeRTOS stream buffers.
|
||||||
|
* Whereas stream buffers are used to send a continuous stream of data from one
|
||||||
|
* task or interrupt to another, message buffers are used to send variable
|
||||||
|
* length discrete messages from one task or interrupt to another. Their
|
||||||
|
* implementation is light weight, making them particularly suited for interrupt
|
||||||
|
* to task and core to core communication scenarios.
|
||||||
|
*
|
||||||
|
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
|
||||||
|
* implementation (so also the message buffer implementation, as message buffers
|
||||||
|
* are built on top of stream buffers) assumes there is only one task or
|
||||||
|
* interrupt that will write to the buffer (the writer), and only one task or
|
||||||
|
* interrupt that will read from the buffer (the reader). It is safe for the
|
||||||
|
* writer and reader to be different tasks or interrupts, but, unlike other
|
||||||
|
* FreeRTOS objects, it is not safe to have multiple different writers or
|
||||||
|
* multiple different readers. If there are to be multiple different writers
|
||||||
|
* then the application writer must place each call to a writing API function
|
||||||
|
* (such as xMessageBufferSend()) inside a critical section and set the send
|
||||||
|
* block time to 0. Likewise, if there are to be multiple different readers
|
||||||
|
* then the application writer must place each call to a reading API function
|
||||||
|
* (such as xMessageBufferRead()) inside a critical section and set the receive
|
||||||
|
* timeout to 0.
|
||||||
|
*
|
||||||
|
* Message buffers hold variable length messages. To enable that, when a
|
||||||
|
* message is written to the message buffer an additional sizeof( size_t ) bytes
|
||||||
|
* are also written to store the message's length (that happens internally, with
|
||||||
|
* the API function). sizeof( size_t ) is typically 4 bytes on a 32-bit
|
||||||
|
* architecture, so writing a 10 byte message to a message buffer on a 32-bit
|
||||||
|
* architecture will actually reduce the available space in the message buffer
|
||||||
|
* by 14 bytes (10 byte are used by the message, and 4 bytes to hold the length
|
||||||
|
* of the message).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FREERTOS_MESSAGE_BUFFER_H
|
||||||
|
#define FREERTOS_MESSAGE_BUFFER_H
|
||||||
|
|
||||||
|
#ifndef INC_FREERTOS_H
|
||||||
|
#error "include FreeRTOS.h must appear in source files before include message_buffer.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Message buffers are built onto of stream buffers. */
|
||||||
|
#include "stream_buffer.h"
|
||||||
|
|
||||||
|
#if defined( __cplusplus )
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type by which message buffers are referenced. For example, a call to
|
||||||
|
* xMessageBufferCreate() returns an MessageBufferHandle_t variable that can
|
||||||
|
* then be used as a parameter to xMessageBufferSend(), xMessageBufferReceive(),
|
||||||
|
* etc.
|
||||||
|
*/
|
||||||
|
typedef void * MessageBufferHandle_t;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* message_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
MessageBufferHandle_t xMessageBufferCreate( size_t xBufferSizeBytes );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Creates a new message buffer using dynamically allocated memory. See
|
||||||
|
* xMessageBufferCreateStatic() for a version that uses statically allocated
|
||||||
|
* memory (memory that is allocated at compile time).
|
||||||
|
*
|
||||||
|
* configSUPPORT_DYNAMIC_ALLOCATION must be set to 1 or left undefined in
|
||||||
|
* FreeRTOSConfig.h for xMessageBufferCreate() to be available.
|
||||||
|
*
|
||||||
|
* @param xBufferSizeBytes The total number of bytes (not messages) the message
|
||||||
|
* buffer will be able to hold at any one time. When a message is written to
|
||||||
|
* the message buffer an additional sizeof( size_t ) bytes are also written to
|
||||||
|
* store the message's length. sizeof( size_t ) is typically 4 bytes on a
|
||||||
|
* 32-bit architecture, so on most 32-bit architectures a 10 byte message will
|
||||||
|
* take up 14 bytes of message buffer space.
|
||||||
|
*
|
||||||
|
* @return If NULL is returned, then the message buffer cannot be created
|
||||||
|
* because there is insufficient heap memory available for FreeRTOS to allocate
|
||||||
|
* the message buffer data structures and storage area. A non-NULL value being
|
||||||
|
* returned indicates that the message buffer has been created successfully -
|
||||||
|
* the returned value should be stored as the handle to the created message
|
||||||
|
* buffer.
|
||||||
|
*
|
||||||
|
* Example use:
|
||||||
|
<pre>
|
||||||
|
|
||||||
|
void vAFunction( void )
|
||||||
|
{
|
||||||
|
MessageBufferHandle_t xMessageBuffer;
|
||||||
|
const size_t xMessageBufferSizeBytes = 100;
|
||||||
|
|
||||||
|
// Create a message buffer that can hold 100 bytes. The memory used to hold
|
||||||
|
// both the message buffer structure and the messages themselves is allocated
|
||||||
|
// dynamically. Each message added to the buffer consumes an additional 4
|
||||||
|
// bytes which are used to hold the lengh of the message.
|
||||||
|
xMessageBuffer = xMessageBufferCreate( xMessageBufferSizeBytes );
|
||||||
|
|
||||||
|
if( xMessageBuffer == NULL )
|
||||||
|
{
|
||||||
|
// There was not enough heap memory space available to create the
|
||||||
|
// message buffer.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The message buffer was created successfully and can now be used.
|
||||||
|
}
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
* \defgroup xMessageBufferCreate xMessageBufferCreate
|
||||||
|
* \ingroup MessageBufferManagement
|
||||||
|
*/
|
||||||
|
#define xMessageBufferCreate( xBufferSizeBytes ) ( MessageBufferHandle_t ) xStreamBufferGenericCreate( xBufferSizeBytes, ( size_t ) 0, pdTRUE )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* message_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
MessageBufferHandle_t xMessageBufferCreateStatic( size_t xBufferSizeBytes,
|
||||||
|
uint8_t *pucMessageBufferStorageArea,
|
||||||
|
StaticMessageBuffer_t *pxStaticMessageBuffer );
|
||||||
|
</pre>
|
||||||
|
* Creates a new message buffer using statically allocated memory. See
|
||||||
|
* xMessageBufferCreate() for a version that uses dynamically allocated memory.
|
||||||
|
*
|
||||||
|
* @param xBufferSizeBytes The size, in bytes, of the buffer pointed to by the
|
||||||
|
* pucMessageBufferStorageArea parameter. When a message is written to the
|
||||||
|
* message buffer an additional sizeof( size_t ) bytes are also written to store
|
||||||
|
* the message's length. sizeof( size_t ) is typically 4 bytes on a 32-bit
|
||||||
|
* architecture, so on most 32-bit architecture a 10 byte message will take up
|
||||||
|
* 14 bytes of message buffer space. The maximum number of bytes that can be
|
||||||
|
* stored in the message buffer is actually (xBufferSizeBytes - 1).
|
||||||
|
*
|
||||||
|
* @param pucMessageBufferStorageArea Must point to a uint8_t array that is at
|
||||||
|
* least xBufferSizeBytes + 1 big. This is the array to which messages are
|
||||||
|
* copied when they are written to the message buffer.
|
||||||
|
*
|
||||||
|
* @param pxStaticMessageBuffer Must point to a variable of type
|
||||||
|
* StaticMessageBuffer_t, which will be used to hold the message buffer's data
|
||||||
|
* structure.
|
||||||
|
*
|
||||||
|
* @return If the message buffer is created successfully then a handle to the
|
||||||
|
* created message buffer is returned. If either pucMessageBufferStorageArea or
|
||||||
|
* pxStaticmessageBuffer are NULL then NULL is returned.
|
||||||
|
*
|
||||||
|
* Example use:
|
||||||
|
<pre>
|
||||||
|
|
||||||
|
// Used to dimension the array used to hold the messages. The available space
|
||||||
|
// will actually be one less than this, so 999.
|
||||||
|
#define STORAGE_SIZE_BYTES 1000
|
||||||
|
|
||||||
|
// Defines the memory that will actually hold the messages within the message
|
||||||
|
// buffer.
|
||||||
|
static uint8_t ucStorageBuffer[ STORAGE_SIZE_BYTES ];
|
||||||
|
|
||||||
|
// The variable used to hold the message buffer structure.
|
||||||
|
StaticMessageBuffer_t xMessageBufferStruct;
|
||||||
|
|
||||||
|
void MyFunction( void )
|
||||||
|
{
|
||||||
|
MessageBufferHandle_t xMessageBuffer;
|
||||||
|
|
||||||
|
xMessageBuffer = xMessageBufferCreateStatic( sizeof( ucBufferStorage ),
|
||||||
|
ucBufferStorage,
|
||||||
|
&xMessageBufferStruct );
|
||||||
|
|
||||||
|
// As neither the pucMessageBufferStorageArea or pxStaticMessageBuffer
|
||||||
|
// parameters were NULL, xMessageBuffer will not be NULL, and can be used to
|
||||||
|
// reference the created message buffer in other message buffer API calls.
|
||||||
|
|
||||||
|
// Other code that uses the message buffer can go here.
|
||||||
|
}
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
* \defgroup xMessageBufferCreateStatic xMessageBufferCreateStatic
|
||||||
|
* \ingroup MessageBufferManagement
|
||||||
|
*/
|
||||||
|
#define xMessageBufferCreateStatic( xBufferSizeBytes, pucMessageBufferStorageArea, pxStaticMessageBuffer ) ( MessageBufferHandle_t ) xStreamBufferGenericCreateStatic( xBufferSizeBytes, 0, pdTRUE, pucMessageBufferStorageArea, pxStaticMessageBuffer )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* message_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
size_t xMessageBufferSend( MessageBufferHandle_t xMessageBuffer,
|
||||||
|
const void *pvTxData,
|
||||||
|
size_t xDataLengthBytes,
|
||||||
|
TickType_t xTicksToWait );
|
||||||
|
<pre>
|
||||||
|
*
|
||||||
|
* Sends a discrete message to the message buffer. The message can be any
|
||||||
|
* length that fits within the buffer's free space, and is copied into the
|
||||||
|
* buffer.
|
||||||
|
*
|
||||||
|
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
|
||||||
|
* implementation (so also the message buffer implementation, as message buffers
|
||||||
|
* are built on top of stream buffers) assumes there is only one task or
|
||||||
|
* interrupt that will write to the buffer (the writer), and only one task or
|
||||||
|
* interrupt that will read from the buffer (the reader). It is safe for the
|
||||||
|
* writer and reader to be different tasks or interrupts, but, unlike other
|
||||||
|
* FreeRTOS objects, it is not safe to have multiple different writers or
|
||||||
|
* multiple different readers. If there are to be multiple different writers
|
||||||
|
* then the application writer must place each call to a writing API function
|
||||||
|
* (such as xMessageBufferSend()) inside a critical section and set the send
|
||||||
|
* block time to 0. Likewise, if there are to be multiple different readers
|
||||||
|
* then the application writer must place each call to a reading API function
|
||||||
|
* (such as xMessageBufferRead()) inside a critical section and set the receive
|
||||||
|
* block time to 0.
|
||||||
|
*
|
||||||
|
* Use xMessageBufferSend() to write to a message buffer from a task. Use
|
||||||
|
* xMessageBufferSendFromISR() to write to a message buffer from an interrupt
|
||||||
|
* service routine (ISR).
|
||||||
|
*
|
||||||
|
* @param xMessageBuffer The handle of the message buffer to which a message is
|
||||||
|
* being sent.
|
||||||
|
*
|
||||||
|
* @param pvTxData A pointer to the message that is to be copied into the
|
||||||
|
* message buffer.
|
||||||
|
*
|
||||||
|
* @param xDataLengthBytes The length of the message. That is, the number of
|
||||||
|
* bytes to copy from pvTxData into the message buffer. When a message is
|
||||||
|
* written to the message buffer an additional sizeof( size_t ) bytes are also
|
||||||
|
* written to store the message's length. sizeof( size_t ) is typically 4 bytes
|
||||||
|
* on a 32-bit architecture, so on most 32-bit architecture setting
|
||||||
|
* xDataLengthBytes to 20 will reduce the free space in the message buffer by 24
|
||||||
|
* bytes (20 bytes of message data and 4 bytes to hold the message length).
|
||||||
|
*
|
||||||
|
* @param xTicksToWait The maximum amount of time the calling task should remain
|
||||||
|
* in the Blocked state to wait for enough space to become available in the
|
||||||
|
* message buffer, should the message buffer have insufficient space when
|
||||||
|
* xMessageBufferSend() is called. The calling task will never block if
|
||||||
|
* xTicksToWait is zero. The block time is specified in tick periods, so the
|
||||||
|
* absolute time it represents is dependent on the tick frequency. The macro
|
||||||
|
* pdMS_TO_TICKS() can be used to convert a time specified in milliseconds into
|
||||||
|
* a time specified in ticks. Setting xTicksToWait to portMAX_DELAY will cause
|
||||||
|
* the task to wait indefinitely (without timing out), provided
|
||||||
|
* INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h. Tasks do not use any
|
||||||
|
* CPU time when they are in the Blocked state.
|
||||||
|
*
|
||||||
|
* @return The number of bytes written to the message buffer. If the call to
|
||||||
|
* xMessageBufferSend() times out before there was enough space to write the
|
||||||
|
* message into the message buffer then zero is returned. If the call did not
|
||||||
|
* time out then xDataLengthBytes is returned.
|
||||||
|
*
|
||||||
|
* Example use:
|
||||||
|
<pre>
|
||||||
|
void vAFunction( MessageBufferHandle_t xMessageBuffer )
|
||||||
|
{
|
||||||
|
size_t xBytesSent;
|
||||||
|
uint8_t ucArrayToSend[] = { 0, 1, 2, 3 };
|
||||||
|
char *pcStringToSend = "String to send";
|
||||||
|
const TickType_t x100ms = pdMS_TO_TICKS( 100 );
|
||||||
|
|
||||||
|
// Send an array to the message buffer, blocking for a maximum of 100ms to
|
||||||
|
// wait for enough space to be available in the message buffer.
|
||||||
|
xBytesSent = xMessageBufferSend( xMessageBuffer, ( void * ) ucArrayToSend, sizeof( ucArrayToSend ), x100ms );
|
||||||
|
|
||||||
|
if( xBytesSent != sizeof( ucArrayToSend ) )
|
||||||
|
{
|
||||||
|
// The call to xMessageBufferSend() times out before there was enough
|
||||||
|
// space in the buffer for the data to be written.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the string to the message buffer. Return immediately if there is
|
||||||
|
// not enough space in the buffer.
|
||||||
|
xBytesSent = xMessageBufferSend( xMessageBuffer, ( void * ) pcStringToSend, strlen( pcStringToSend ), 0 );
|
||||||
|
|
||||||
|
if( xBytesSent != strlen( pcStringToSend ) )
|
||||||
|
{
|
||||||
|
// The string could not be added to the message buffer because there was
|
||||||
|
// not enough free space in the buffer.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xMessageBufferSend xMessageBufferSend
|
||||||
|
* \ingroup MessageBufferManagement
|
||||||
|
*/
|
||||||
|
#define xMessageBufferSend( xMessageBuffer, pvTxData, xDataLengthBytes, xTicksToWait ) xStreamBufferSend( ( StreamBufferHandle_t ) xMessageBuffer, pvTxData, xDataLengthBytes, xTicksToWait )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* message_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
size_t xMessageBufferSendFromISR( MessageBufferHandle_t xMessageBuffer,
|
||||||
|
const void *pvTxData,
|
||||||
|
size_t xDataLengthBytes,
|
||||||
|
BaseType_t *pxHigherPriorityTaskWoken );
|
||||||
|
<pre>
|
||||||
|
*
|
||||||
|
* Interrupt safe version of the API function that sends a discrete message to
|
||||||
|
* the message buffer. The message can be any length that fits within the
|
||||||
|
* buffer's free space, and is copied into the buffer.
|
||||||
|
*
|
||||||
|
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
|
||||||
|
* implementation (so also the message buffer implementation, as message buffers
|
||||||
|
* are built on top of stream buffers) assumes there is only one task or
|
||||||
|
* interrupt that will write to the buffer (the writer), and only one task or
|
||||||
|
* interrupt that will read from the buffer (the reader). It is safe for the
|
||||||
|
* writer and reader to be different tasks or interrupts, but, unlike other
|
||||||
|
* FreeRTOS objects, it is not safe to have multiple different writers or
|
||||||
|
* multiple different readers. If there are to be multiple different writers
|
||||||
|
* then the application writer must place each call to a writing API function
|
||||||
|
* (such as xMessageBufferSend()) inside a critical section and set the send
|
||||||
|
* block time to 0. Likewise, if there are to be multiple different readers
|
||||||
|
* then the application writer must place each call to a reading API function
|
||||||
|
* (such as xMessageBufferRead()) inside a critical section and set the receive
|
||||||
|
* block time to 0.
|
||||||
|
*
|
||||||
|
* Use xMessageBufferSend() to write to a message buffer from a task. Use
|
||||||
|
* xMessageBufferSendFromISR() to write to a message buffer from an interrupt
|
||||||
|
* service routine (ISR).
|
||||||
|
*
|
||||||
|
* @param xMessageBuffer The handle of the message buffer to which a message is
|
||||||
|
* being sent.
|
||||||
|
*
|
||||||
|
* @param pvTxData A pointer to the message that is to be copied into the
|
||||||
|
* message buffer.
|
||||||
|
*
|
||||||
|
* @param xDataLengthBytes The length of the message. That is, the number of
|
||||||
|
* bytes to copy from pvTxData into the message buffer. When a message is
|
||||||
|
* written to the message buffer an additional sizeof( size_t ) bytes are also
|
||||||
|
* written to store the message's length. sizeof( size_t ) is typically 4 bytes
|
||||||
|
* on a 32-bit architecture, so on most 32-bit architecture setting
|
||||||
|
* xDataLengthBytes to 20 will reduce the free space in the message buffer by 24
|
||||||
|
* bytes (20 bytes of message data and 4 bytes to hold the message length).
|
||||||
|
*
|
||||||
|
* @param pxHigherPriorityTaskWoken It is possible that a message buffer will
|
||||||
|
* have a task blocked on it waiting for data. Calling
|
||||||
|
* xMessageBufferSendFromISR() can make data available, and so cause a task that
|
||||||
|
* was waiting for data to leave the Blocked state. If calling
|
||||||
|
* xMessageBufferSendFromISR() causes a task to leave the Blocked state, and the
|
||||||
|
* unblocked task has a priority higher than the currently executing task (the
|
||||||
|
* task that was interrupted), then, internally, xMessageBufferSendFromISR()
|
||||||
|
* will set *pxHigherPriorityTaskWoken to pdTRUE. If
|
||||||
|
* xMessageBufferSendFromISR() sets this value to pdTRUE, then normally a
|
||||||
|
* context switch should be performed before the interrupt is exited. This will
|
||||||
|
* ensure that the interrupt returns directly to the highest priority Ready
|
||||||
|
* state task. *pxHigherPriorityTaskWoken should be set to pdFALSE before it
|
||||||
|
* is passed into the function. See the code example below for an example.
|
||||||
|
*
|
||||||
|
* @return The number of bytes actually written to the message buffer. If the
|
||||||
|
* message buffer didn't have enough free space for the message to be stored
|
||||||
|
* then 0 is returned, otherwise xDataLengthBytes is returned.
|
||||||
|
*
|
||||||
|
* Example use:
|
||||||
|
<pre>
|
||||||
|
// A message buffer that has already been created.
|
||||||
|
MessageBufferHandle_t xMessageBuffer;
|
||||||
|
|
||||||
|
void vAnInterruptServiceRoutine( void )
|
||||||
|
{
|
||||||
|
size_t xBytesSent;
|
||||||
|
char *pcStringToSend = "String to send";
|
||||||
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE; // Initialised to pdFALSE.
|
||||||
|
|
||||||
|
// Attempt to send the string to the message buffer.
|
||||||
|
xBytesSent = xMessageBufferSendFromISR( xMessageBuffer,
|
||||||
|
( void * ) pcStringToSend,
|
||||||
|
strlen( pcStringToSend ),
|
||||||
|
&xHigherPriorityTaskWoken );
|
||||||
|
|
||||||
|
if( xBytesSent != strlen( pcStringToSend ) )
|
||||||
|
{
|
||||||
|
// The string could not be added to the message buffer because there was
|
||||||
|
// not enough free space in the buffer.
|
||||||
|
}
|
||||||
|
|
||||||
|
// If xHigherPriorityTaskWoken was set to pdTRUE inside
|
||||||
|
// xMessageBufferSendFromISR() then a task that has a priority above the
|
||||||
|
// priority of the currently executing task was unblocked and a context
|
||||||
|
// switch should be performed to ensure the ISR returns to the unblocked
|
||||||
|
// task. In most FreeRTOS ports this is done by simply passing
|
||||||
|
// xHigherPriorityTaskWoken into portYIELD_FROM_ISR(), which will test the
|
||||||
|
// variables value, and perform the context switch if necessary. Check the
|
||||||
|
// documentation for the port in use for port specific instructions.
|
||||||
|
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xMessageBufferSendFromISR xMessageBufferSendFromISR
|
||||||
|
* \ingroup MessageBufferManagement
|
||||||
|
*/
|
||||||
|
#define xMessageBufferSendFromISR( xMessageBuffer, pvTxData, xDataLengthBytes, pxHigherPriorityTaskWoken ) xStreamBufferSendFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pvTxData, xDataLengthBytes, pxHigherPriorityTaskWoken )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* message_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
size_t xMessageBufferReceive( MessageBufferHandle_t xMessageBuffer,
|
||||||
|
void *pvRxData,
|
||||||
|
size_t xBufferLengthBytes,
|
||||||
|
TickType_t xTicksToWait );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Receives a discrete message from a message buffer. Messages can be of
|
||||||
|
* variable length and are copied out of the buffer.
|
||||||
|
*
|
||||||
|
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
|
||||||
|
* implementation (so also the message buffer implementation, as message buffers
|
||||||
|
* are built on top of stream buffers) assumes there is only one task or
|
||||||
|
* interrupt that will write to the buffer (the writer), and only one task or
|
||||||
|
* interrupt that will read from the buffer (the reader). It is safe for the
|
||||||
|
* writer and reader to be different tasks or interrupts, but, unlike other
|
||||||
|
* FreeRTOS objects, it is not safe to have multiple different writers or
|
||||||
|
* multiple different readers. If there are to be multiple different writers
|
||||||
|
* then the application writer must place each call to a writing API function
|
||||||
|
* (such as xMessageBufferSend()) inside a critical section and set the send
|
||||||
|
* block time to 0. Likewise, if there are to be multiple different readers
|
||||||
|
* then the application writer must place each call to a reading API function
|
||||||
|
* (such as xMessageBufferRead()) inside a critical section and set the receive
|
||||||
|
* block time to 0.
|
||||||
|
*
|
||||||
|
* Use xMessageBufferReceive() to read from a message buffer from a task. Use
|
||||||
|
* xMessageBufferReceiveFromISR() to read from a message buffer from an
|
||||||
|
* interrupt service routine (ISR).
|
||||||
|
*
|
||||||
|
* @param xMessageBuffer The handle of the message buffer from which a message
|
||||||
|
* is being received.
|
||||||
|
*
|
||||||
|
* @param pvRxData A pointer to the buffer into which the received message is
|
||||||
|
* to be copied.
|
||||||
|
*
|
||||||
|
* @param xBufferLengthBytes The length of the buffer pointed to by the pvRxData
|
||||||
|
* parameter. This sets the maximum length of the message that can be received.
|
||||||
|
* If xBufferLengthBytes is too small to hold the next message then the message
|
||||||
|
* will be left in the message buffer and 0 will be returned.
|
||||||
|
*
|
||||||
|
* @param xTicksToWait The maximum amount of time the task should remain in the
|
||||||
|
* Blocked state to wait for a message, should the message buffer be empty.
|
||||||
|
* xMessageBufferReceive() will return immediately if xTicksToWait is zero and
|
||||||
|
* the message buffer is empty. The block time is specified in tick periods, so
|
||||||
|
* the absolute time it represents is dependent on the tick frequency. The
|
||||||
|
* macro pdMS_TO_TICKS() can be used to convert a time specified in milliseconds
|
||||||
|
* into a time specified in ticks. Setting xTicksToWait to portMAX_DELAY will
|
||||||
|
* cause the task to wait indefinitely (without timing out), provided
|
||||||
|
* INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h. Tasks do not use any
|
||||||
|
* CPU time when they are in the Blocked state.
|
||||||
|
*
|
||||||
|
* @return The length, in bytes, of the message read from the message buffer, if
|
||||||
|
* any. If xMessageBufferReceive() times out before a message became available
|
||||||
|
* then zero is returned. If the length of the message is greater than
|
||||||
|
* xBufferLengthBytes then the message will be left in the message buffer and
|
||||||
|
* zero is returned.
|
||||||
|
*
|
||||||
|
* Example use:
|
||||||
|
<pre>
|
||||||
|
void vAFunction( MessageBuffer_t xMessageBuffer )
|
||||||
|
{
|
||||||
|
uint8_t ucRxData[ 20 ];
|
||||||
|
size_t xReceivedBytes;
|
||||||
|
const TickType_t xBlockTime = pdMS_TO_TICKS( 20 );
|
||||||
|
|
||||||
|
// Receive the next message from the message buffer. Wait in the Blocked
|
||||||
|
// state (so not using any CPU processing time) for a maximum of 100ms for
|
||||||
|
// a message to become available.
|
||||||
|
xReceivedBytes = xMessageBufferReceive( xMessageBuffer,
|
||||||
|
( void * ) ucRxData,
|
||||||
|
sizeof( ucRxData ),
|
||||||
|
xBlockTime );
|
||||||
|
|
||||||
|
if( xReceivedBytes > 0 )
|
||||||
|
{
|
||||||
|
// A ucRxData contains a message that is xReceivedBytes long. Process
|
||||||
|
// the message here....
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xMessageBufferReceive xMessageBufferReceive
|
||||||
|
* \ingroup MessageBufferManagement
|
||||||
|
*/
|
||||||
|
#define xMessageBufferReceive( xMessageBuffer, pvRxData, xBufferLengthBytes, xTicksToWait ) xStreamBufferReceive( ( StreamBufferHandle_t ) xMessageBuffer, pvRxData, xBufferLengthBytes, xTicksToWait )
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* message_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
size_t xMessageBufferReceiveFromISR( MessageBufferHandle_t xMessageBuffer,
|
||||||
|
void *pvRxData,
|
||||||
|
size_t xBufferLengthBytes,
|
||||||
|
BaseType_t *pxHigherPriorityTaskWoken );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* An interrupt safe version of the API function that receives a discrete
|
||||||
|
* message from a message buffer. Messages can be of variable length and are
|
||||||
|
* copied out of the buffer.
|
||||||
|
*
|
||||||
|
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
|
||||||
|
* implementation (so also the message buffer implementation, as message buffers
|
||||||
|
* are built on top of stream buffers) assumes there is only one task or
|
||||||
|
* interrupt that will write to the buffer (the writer), and only one task or
|
||||||
|
* interrupt that will read from the buffer (the reader). It is safe for the
|
||||||
|
* writer and reader to be different tasks or interrupts, but, unlike other
|
||||||
|
* FreeRTOS objects, it is not safe to have multiple different writers or
|
||||||
|
* multiple different readers. If there are to be multiple different writers
|
||||||
|
* then the application writer must place each call to a writing API function
|
||||||
|
* (such as xMessageBufferSend()) inside a critical section and set the send
|
||||||
|
* block time to 0. Likewise, if there are to be multiple different readers
|
||||||
|
* then the application writer must place each call to a reading API function
|
||||||
|
* (such as xMessageBufferRead()) inside a critical section and set the receive
|
||||||
|
* block time to 0.
|
||||||
|
*
|
||||||
|
* Use xMessageBufferReceive() to read from a message buffer from a task. Use
|
||||||
|
* xMessageBufferReceiveFromISR() to read from a message buffer from an
|
||||||
|
* interrupt service routine (ISR).
|
||||||
|
*
|
||||||
|
* @param xMessageBuffer The handle of the message buffer from which a message
|
||||||
|
* is being received.
|
||||||
|
*
|
||||||
|
* @param pvRxData A pointer to the buffer into which the received message is
|
||||||
|
* to be copied.
|
||||||
|
*
|
||||||
|
* @param xBufferLengthBytes The length of the buffer pointed to by the pvRxData
|
||||||
|
* parameter. This sets the maximum length of the message that can be received.
|
||||||
|
* If xBufferLengthBytes is too small to hold the next message then the message
|
||||||
|
* will be left in the message buffer and 0 will be returned.
|
||||||
|
*
|
||||||
|
* @param pxHigherPriorityTaskWoken It is possible that a message buffer will
|
||||||
|
* have a task blocked on it waiting for space to become available. Calling
|
||||||
|
* xMessageBufferReceiveFromISR() can make space available, and so cause a task
|
||||||
|
* that is waiting for space to leave the Blocked state. If calling
|
||||||
|
* xMessageBufferReceiveFromISR() causes a task to leave the Blocked state, and
|
||||||
|
* the unblocked task has a priority higher than the currently executing task
|
||||||
|
* (the task that was interrupted), then, internally,
|
||||||
|
* xMessageBufferReceiveFromISR() will set *pxHigherPriorityTaskWoken to pdTRUE.
|
||||||
|
* If xMessageBufferReceiveFromISR() sets this value to pdTRUE, then normally a
|
||||||
|
* context switch should be performed before the interrupt is exited. That will
|
||||||
|
* ensure the interrupt returns directly to the highest priority Ready state
|
||||||
|
* task. *pxHigherPriorityTaskWoken should be set to pdFALSE before it is
|
||||||
|
* passed into the function. See the code example below for an example.
|
||||||
|
*
|
||||||
|
* @return The length, in bytes, of the message read from the message buffer, if
|
||||||
|
* any.
|
||||||
|
*
|
||||||
|
* Example use:
|
||||||
|
<pre>
|
||||||
|
// A message buffer that has already been created.
|
||||||
|
MessageBuffer_t xMessageBuffer;
|
||||||
|
|
||||||
|
void vAnInterruptServiceRoutine( void )
|
||||||
|
{
|
||||||
|
uint8_t ucRxData[ 20 ];
|
||||||
|
size_t xReceivedBytes;
|
||||||
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE; // Initialised to pdFALSE.
|
||||||
|
|
||||||
|
// Receive the next message from the message buffer.
|
||||||
|
xReceivedBytes = xMessageBufferReceiveFromISR( xMessageBuffer,
|
||||||
|
( void * ) ucRxData,
|
||||||
|
sizeof( ucRxData ),
|
||||||
|
&xHigherPriorityTaskWoken );
|
||||||
|
|
||||||
|
if( xReceivedBytes > 0 )
|
||||||
|
{
|
||||||
|
// A ucRxData contains a message that is xReceivedBytes long. Process
|
||||||
|
// the message here....
|
||||||
|
}
|
||||||
|
|
||||||
|
// If xHigherPriorityTaskWoken was set to pdTRUE inside
|
||||||
|
// xMessageBufferReceiveFromISR() then a task that has a priority above the
|
||||||
|
// priority of the currently executing task was unblocked and a context
|
||||||
|
// switch should be performed to ensure the ISR returns to the unblocked
|
||||||
|
// task. In most FreeRTOS ports this is done by simply passing
|
||||||
|
// xHigherPriorityTaskWoken into portYIELD_FROM_ISR(), which will test the
|
||||||
|
// variables value, and perform the context switch if necessary. Check the
|
||||||
|
// documentation for the port in use for port specific instructions.
|
||||||
|
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xMessageBufferReceiveFromISR xMessageBufferReceiveFromISR
|
||||||
|
* \ingroup MessageBufferManagement
|
||||||
|
*/
|
||||||
|
#define xMessageBufferReceiveFromISR( xMessageBuffer, pvRxData, xBufferLengthBytes, pxHigherPriorityTaskWoken ) xStreamBufferReceiveFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pvRxData, xBufferLengthBytes, pxHigherPriorityTaskWoken )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* message_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
void vMessageBufferDelete( MessageBufferHandle_t xMessageBuffer );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Deletes a message buffer that was previously created using a call to
|
||||||
|
* xMessageBufferCreate() or xMessageBufferCreateStatic(). If the message
|
||||||
|
* buffer was created using dynamic memory (that is, by xMessageBufferCreate()),
|
||||||
|
* then the allocated memory is freed.
|
||||||
|
*
|
||||||
|
* A message buffer handle must not be used after the message buffer has been
|
||||||
|
* deleted.
|
||||||
|
*
|
||||||
|
* @param xMessageBuffer The handle of the message buffer to be deleted.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define vMessageBufferDelete( xMessageBuffer ) vStreamBufferDelete( ( StreamBufferHandle_t ) xMessageBuffer )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* message_buffer.h
|
||||||
|
<pre>
|
||||||
|
BaseType_t xMessageBufferIsFull( MessageBufferHandle_t xMessageBuffer ) );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Tests to see if a message buffer is full. A message buffer is full if it
|
||||||
|
* cannot accept any more messages, of any size, until space is made available
|
||||||
|
* by a message being removed from the message buffer.
|
||||||
|
*
|
||||||
|
* @param xMessageBuffer The handle of the message buffer being queried.
|
||||||
|
*
|
||||||
|
* @return If the message buffer referenced by xMessageBuffer is full then
|
||||||
|
* pdTRUE is returned. Otherwise pdFALSE is returned.
|
||||||
|
*/
|
||||||
|
#define xMessageBufferIsFull( xMessageBuffer ) xStreamBufferIsFull( ( StreamBufferHandle_t ) xMessageBuffer )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* message_buffer.h
|
||||||
|
<pre>
|
||||||
|
BaseType_t xMessageBufferIsEmpty( MessageBufferHandle_t xMessageBuffer ) );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Tests to see if a message buffer is empty (does not contain any messages).
|
||||||
|
*
|
||||||
|
* @param xMessageBuffer The handle of the message buffer being queried.
|
||||||
|
*
|
||||||
|
* @return If the message buffer referenced by xMessageBuffer is empty then
|
||||||
|
* pdTRUE is returned. Otherwise pdFALSE is returned.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define xMessageBufferIsEmpty( xMessageBuffer ) xStreamBufferIsEmpty( ( StreamBufferHandle_t ) xMessageBuffer )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* message_buffer.h
|
||||||
|
<pre>
|
||||||
|
BaseType_t xMessageBufferReset( MessageBufferHandle_t xMessageBuffer );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Resets a message buffer to its initial empty state, discarding any message it
|
||||||
|
* contained.
|
||||||
|
*
|
||||||
|
* A message buffer can only be reset if there are no tasks blocked on it.
|
||||||
|
*
|
||||||
|
* @param xMessageBuffer The handle of the message buffer being reset.
|
||||||
|
*
|
||||||
|
* @return If the message buffer was reset then pdPASS is returned. If the
|
||||||
|
* message buffer could not be reset because either there was a task blocked on
|
||||||
|
* the message queue to wait for space to become available, or to wait for a
|
||||||
|
* a message to be available, then pdFAIL is returned.
|
||||||
|
*
|
||||||
|
* \defgroup xMessageBufferReset xMessageBufferReset
|
||||||
|
* \ingroup MessageBufferManagement
|
||||||
|
*/
|
||||||
|
#define xMessageBufferReset( xMessageBuffer ) xStreamBufferReset( ( StreamBufferHandle_t ) xMessageBuffer )
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* message_buffer.h
|
||||||
|
<pre>
|
||||||
|
size_t xMessageBufferSpaceAvailable( MessageBufferHandle_t xMessageBuffer ) );
|
||||||
|
</pre>
|
||||||
|
* Returns the number of bytes of free space in the message buffer.
|
||||||
|
*
|
||||||
|
* @param xMessageBuffer The handle of the message buffer being queried.
|
||||||
|
*
|
||||||
|
* @return The number of bytes that can be written to the message buffer before
|
||||||
|
* the message buffer would be full. When a message is written to the message
|
||||||
|
* buffer an additional sizeof( size_t ) bytes are also written to store the
|
||||||
|
* message's length. sizeof( size_t ) is typically 4 bytes on a 32-bit
|
||||||
|
* architecture, so if xMessageBufferSpacesAvailable() returns 10, then the size
|
||||||
|
* of the largest message that can be written to the message buffer is 6 bytes.
|
||||||
|
*
|
||||||
|
* \defgroup xMessageBufferSpaceAvailable xMessageBufferSpaceAvailable
|
||||||
|
* \ingroup MessageBufferManagement
|
||||||
|
*/
|
||||||
|
#define xMessageBufferSpaceAvailable( xMessageBuffer ) xStreamBufferSpacesAvailable( ( StreamBufferHandle_t ) xMessageBuffer )
|
||||||
|
#define xMessageBufferSpacesAvailable( xMessageBuffer ) xStreamBufferSpacesAvailable( ( StreamBufferHandle_t ) xMessageBuffer ) /* Corrects typo in original macro name. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* message_buffer.h
|
||||||
|
<pre>
|
||||||
|
size_t xMessageBufferNextLengthBytes( MessageBufferHandle_t xMessageBuffer ) );
|
||||||
|
</pre>
|
||||||
|
* Returns the length (in bytes) of the next message in a message buffer.
|
||||||
|
* Useful if xMessageBufferReceive() returned 0 because the size of the buffer
|
||||||
|
* passed into xMessageBufferReceive() was too small to hold the next message.
|
||||||
|
*
|
||||||
|
* @param xMessageBuffer The handle of the message buffer being queried.
|
||||||
|
*
|
||||||
|
* @return The length (in bytes) of the next message in the message buffer, or 0
|
||||||
|
* if the message buffer is empty.
|
||||||
|
*
|
||||||
|
* \defgroup xMessageBufferNextLengthBytes xMessageBufferNextLengthBytes
|
||||||
|
* \ingroup MessageBufferManagement
|
||||||
|
*/
|
||||||
|
#define xMessageBufferNextLengthBytes( xMessageBuffer ) xStreamBufferNextMessageLengthBytes( ( StreamBufferHandle_t ) xMessageBuffer ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* message_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
BaseType_t xMessageBufferSendCompletedFromISR( MessageBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* For advanced users only.
|
||||||
|
*
|
||||||
|
* The sbSEND_COMPLETED() macro is called from within the FreeRTOS APIs when
|
||||||
|
* data is sent to a message buffer or stream buffer. If there was a task that
|
||||||
|
* was blocked on the message or stream buffer waiting for data to arrive then
|
||||||
|
* the sbSEND_COMPLETED() macro sends a notification to the task to remove it
|
||||||
|
* from the Blocked state. xMessageBufferSendCompletedFromISR() does the same
|
||||||
|
* thing. It is provided to enable application writers to implement their own
|
||||||
|
* version of sbSEND_COMPLETED(), and MUST NOT BE USED AT ANY OTHER TIME.
|
||||||
|
*
|
||||||
|
* See the example implemented in FreeRTOS/Demo/Minimal/MessageBufferAMP.c for
|
||||||
|
* additional information.
|
||||||
|
*
|
||||||
|
* @param xStreamBuffer The handle of the stream buffer to which data was
|
||||||
|
* written.
|
||||||
|
*
|
||||||
|
* @param pxHigherPriorityTaskWoken *pxHigherPriorityTaskWoken should be
|
||||||
|
* initialised to pdFALSE before it is passed into
|
||||||
|
* xMessageBufferSendCompletedFromISR(). If calling
|
||||||
|
* xMessageBufferSendCompletedFromISR() removes a task from the Blocked state,
|
||||||
|
* and the task has a priority above the priority of the currently running task,
|
||||||
|
* then *pxHigherPriorityTaskWoken will get set to pdTRUE indicating that a
|
||||||
|
* context switch should be performed before exiting the ISR.
|
||||||
|
*
|
||||||
|
* @return If a task was removed from the Blocked state then pdTRUE is returned.
|
||||||
|
* Otherwise pdFALSE is returned.
|
||||||
|
*
|
||||||
|
* \defgroup xMessageBufferSendCompletedFromISR xMessageBufferSendCompletedFromISR
|
||||||
|
* \ingroup StreamBufferManagement
|
||||||
|
*/
|
||||||
|
#define xMessageBufferSendCompletedFromISR( xMessageBuffer, pxHigherPriorityTaskWoken ) xStreamBufferSendCompletedFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pxHigherPriorityTaskWoken )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* message_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
BaseType_t xMessageBufferReceiveCompletedFromISR( MessageBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* For advanced users only.
|
||||||
|
*
|
||||||
|
* The sbRECEIVE_COMPLETED() macro is called from within the FreeRTOS APIs when
|
||||||
|
* data is read out of a message buffer or stream buffer. If there was a task
|
||||||
|
* that was blocked on the message or stream buffer waiting for data to arrive
|
||||||
|
* then the sbRECEIVE_COMPLETED() macro sends a notification to the task to
|
||||||
|
* remove it from the Blocked state. xMessageBufferReceiveCompletedFromISR()
|
||||||
|
* does the same thing. It is provided to enable application writers to
|
||||||
|
* implement their own version of sbRECEIVE_COMPLETED(), and MUST NOT BE USED AT
|
||||||
|
* ANY OTHER TIME.
|
||||||
|
*
|
||||||
|
* See the example implemented in FreeRTOS/Demo/Minimal/MessageBufferAMP.c for
|
||||||
|
* additional information.
|
||||||
|
*
|
||||||
|
* @param xStreamBuffer The handle of the stream buffer from which data was
|
||||||
|
* read.
|
||||||
|
*
|
||||||
|
* @param pxHigherPriorityTaskWoken *pxHigherPriorityTaskWoken should be
|
||||||
|
* initialised to pdFALSE before it is passed into
|
||||||
|
* xMessageBufferReceiveCompletedFromISR(). If calling
|
||||||
|
* xMessageBufferReceiveCompletedFromISR() removes a task from the Blocked state,
|
||||||
|
* and the task has a priority above the priority of the currently running task,
|
||||||
|
* then *pxHigherPriorityTaskWoken will get set to pdTRUE indicating that a
|
||||||
|
* context switch should be performed before exiting the ISR.
|
||||||
|
*
|
||||||
|
* @return If a task was removed from the Blocked state then pdTRUE is returned.
|
||||||
|
* Otherwise pdFALSE is returned.
|
||||||
|
*
|
||||||
|
* \defgroup xMessageBufferReceiveCompletedFromISR xMessageBufferReceiveCompletedFromISR
|
||||||
|
* \ingroup StreamBufferManagement
|
||||||
|
*/
|
||||||
|
#define xMessageBufferReceiveCompletedFromISR( xMessageBuffer, pxHigherPriorityTaskWoken ) xStreamBufferReceiveCompletedFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pxHigherPriorityTaskWoken )
|
||||||
|
|
||||||
|
#if defined( __cplusplus )
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !defined( FREERTOS_MESSAGE_BUFFER_H ) */
|
||||||
160
Middlewares/Third_Party/FreeRTOS/Source/include/mpu_prototypes.h
vendored
Normal file
160
Middlewares/Third_Party/FreeRTOS/Source/include/mpu_prototypes.h
vendored
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* FreeRTOS Kernel V10.3.1
|
||||||
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org
|
||||||
|
* http://aws.amazon.com/freertos
|
||||||
|
*
|
||||||
|
* 1 tab == 4 spaces!
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When the MPU is used the standard (non MPU) API functions are mapped to
|
||||||
|
* equivalents that start "MPU_", the prototypes for which are defined in this
|
||||||
|
* header files. This will cause the application code to call the MPU_ version
|
||||||
|
* which wraps the non-MPU version with privilege promoting then demoting code,
|
||||||
|
* so the kernel code always runs will full privileges.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef MPU_PROTOTYPES_H
|
||||||
|
#define MPU_PROTOTYPES_H
|
||||||
|
|
||||||
|
/* MPU versions of tasks.h API functions. */
|
||||||
|
BaseType_t MPU_xTaskCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask ) FREERTOS_SYSTEM_CALL;
|
||||||
|
TaskHandle_t MPU_xTaskCreateStatic( TaskFunction_t pxTaskCode, const char * const pcName, const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, StackType_t * const puxStackBuffer, StaticTask_t * const pxTaskBuffer ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vTaskDelete( TaskHandle_t xTaskToDelete ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vTaskDelay( const TickType_t xTicksToDelay ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xTaskAbortDelay( TaskHandle_t xTask ) FREERTOS_SYSTEM_CALL;
|
||||||
|
UBaseType_t MPU_uxTaskPriorityGet( const TaskHandle_t xTask ) FREERTOS_SYSTEM_CALL;
|
||||||
|
eTaskState MPU_eTaskGetState( TaskHandle_t xTask ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vTaskSuspend( TaskHandle_t xTaskToSuspend ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vTaskResume( TaskHandle_t xTaskToResume ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vTaskStartScheduler( void ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vTaskSuspendAll( void ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xTaskResumeAll( void ) FREERTOS_SYSTEM_CALL;
|
||||||
|
TickType_t MPU_xTaskGetTickCount( void ) FREERTOS_SYSTEM_CALL;
|
||||||
|
UBaseType_t MPU_uxTaskGetNumberOfTasks( void ) FREERTOS_SYSTEM_CALL;
|
||||||
|
char * MPU_pcTaskGetName( TaskHandle_t xTaskToQuery ) FREERTOS_SYSTEM_CALL;
|
||||||
|
TaskHandle_t MPU_xTaskGetHandle( const char *pcNameToQuery ) FREERTOS_SYSTEM_CALL;
|
||||||
|
UBaseType_t MPU_uxTaskGetStackHighWaterMark( TaskHandle_t xTask ) FREERTOS_SYSTEM_CALL;
|
||||||
|
configSTACK_DEPTH_TYPE MPU_uxTaskGetStackHighWaterMark2( TaskHandle_t xTask ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction ) FREERTOS_SYSTEM_CALL;
|
||||||
|
TaskHookFunction_t MPU_xTaskGetApplicationTaskTag( TaskHandle_t xTask ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void * MPU_pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter ) FREERTOS_SYSTEM_CALL;
|
||||||
|
TaskHandle_t MPU_xTaskGetIdleTaskHandle( void ) FREERTOS_SYSTEM_CALL;
|
||||||
|
UBaseType_t MPU_uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime ) FREERTOS_SYSTEM_CALL;
|
||||||
|
uint32_t MPU_ulTaskGetIdleRunTimeCounter( void ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vTaskList( char * pcWriteBuffer ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vTaskGetRunTimeStats( char *pcWriteBuffer ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
|
||||||
|
uint32_t MPU_ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xTaskNotifyStateClear( TaskHandle_t xTask ) FREERTOS_SYSTEM_CALL;
|
||||||
|
uint32_t MPU_ulTaskNotifyValueClear( TaskHandle_t xTask, uint32_t ulBitsToClear ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xTaskIncrementTick( void ) FREERTOS_SYSTEM_CALL;
|
||||||
|
TaskHandle_t MPU_xTaskGetCurrentTaskHandle( void ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vTaskMissedYield( void ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xTaskGetSchedulerState( void ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xTaskCatchUpTicks( TickType_t xTicksToCatchUp ) FREERTOS_SYSTEM_CALL;
|
||||||
|
|
||||||
|
/* MPU versions of queue.h API functions. */
|
||||||
|
BaseType_t MPU_xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xQueuePeek( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
|
||||||
|
UBaseType_t MPU_uxQueueMessagesWaiting( const QueueHandle_t xQueue ) FREERTOS_SYSTEM_CALL;
|
||||||
|
UBaseType_t MPU_uxQueueSpacesAvailable( const QueueHandle_t xQueue ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vQueueDelete( QueueHandle_t xQueue ) FREERTOS_SYSTEM_CALL;
|
||||||
|
QueueHandle_t MPU_xQueueCreateMutex( const uint8_t ucQueueType ) FREERTOS_SYSTEM_CALL;
|
||||||
|
QueueHandle_t MPU_xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue ) FREERTOS_SYSTEM_CALL;
|
||||||
|
QueueHandle_t MPU_xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ) FREERTOS_SYSTEM_CALL;
|
||||||
|
QueueHandle_t MPU_xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue ) FREERTOS_SYSTEM_CALL;
|
||||||
|
TaskHandle_t MPU_xQueueGetMutexHolder( QueueHandle_t xSemaphore ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xQueueGiveMutexRecursive( QueueHandle_t pxMutex ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vQueueAddToRegistry( QueueHandle_t xQueue, const char *pcName ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vQueueUnregisterQueue( QueueHandle_t xQueue ) FREERTOS_SYSTEM_CALL;
|
||||||
|
const char * MPU_pcQueueGetName( QueueHandle_t xQueue ) FREERTOS_SYSTEM_CALL;
|
||||||
|
QueueHandle_t MPU_xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ) FREERTOS_SYSTEM_CALL;
|
||||||
|
QueueHandle_t MPU_xQueueGenericCreateStatic( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType ) FREERTOS_SYSTEM_CALL;
|
||||||
|
QueueSetHandle_t MPU_xQueueCreateSet( const UBaseType_t uxEventQueueLength ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ) FREERTOS_SYSTEM_CALL;
|
||||||
|
QueueSetMemberHandle_t MPU_xQueueSelectFromSet( QueueSetHandle_t xQueueSet, const TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vQueueSetQueueNumber( QueueHandle_t xQueue, UBaseType_t uxQueueNumber ) FREERTOS_SYSTEM_CALL;
|
||||||
|
UBaseType_t MPU_uxQueueGetQueueNumber( QueueHandle_t xQueue ) FREERTOS_SYSTEM_CALL;
|
||||||
|
uint8_t MPU_ucQueueGetQueueType( QueueHandle_t xQueue ) FREERTOS_SYSTEM_CALL;
|
||||||
|
|
||||||
|
/* MPU versions of timers.h API functions. */
|
||||||
|
TimerHandle_t MPU_xTimerCreate( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction ) FREERTOS_SYSTEM_CALL;
|
||||||
|
TimerHandle_t MPU_xTimerCreateStatic( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction, StaticTimer_t *pxTimerBuffer ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void * MPU_pvTimerGetTimerID( const TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xTimerIsTimerActive( TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL;
|
||||||
|
TaskHandle_t MPU_xTimerGetTimerDaemonTaskHandle( void ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
|
||||||
|
const char * MPU_pcTimerGetName( TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vTimerSetReloadMode( TimerHandle_t xTimer, const UBaseType_t uxAutoReload ) FREERTOS_SYSTEM_CALL;
|
||||||
|
UBaseType_t MPU_uxTimerGetReloadMode( TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL;
|
||||||
|
TickType_t MPU_xTimerGetPeriod( TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL;
|
||||||
|
TickType_t MPU_xTimerGetExpiryTime( TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xTimerCreateTimerTask( void ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
|
||||||
|
|
||||||
|
/* MPU versions of event_group.h API functions. */
|
||||||
|
EventGroupHandle_t MPU_xEventGroupCreate( void ) FREERTOS_SYSTEM_CALL;
|
||||||
|
EventGroupHandle_t MPU_xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer ) FREERTOS_SYSTEM_CALL;
|
||||||
|
EventBits_t MPU_xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
|
||||||
|
EventBits_t MPU_xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) FREERTOS_SYSTEM_CALL;
|
||||||
|
EventBits_t MPU_xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ) FREERTOS_SYSTEM_CALL;
|
||||||
|
EventBits_t MPU_xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vEventGroupDelete( EventGroupHandle_t xEventGroup ) FREERTOS_SYSTEM_CALL;
|
||||||
|
UBaseType_t MPU_uxEventGroupGetNumber( void* xEventGroup ) FREERTOS_SYSTEM_CALL;
|
||||||
|
|
||||||
|
/* MPU versions of message/stream_buffer.h API functions. */
|
||||||
|
size_t MPU_xStreamBufferSend( StreamBufferHandle_t xStreamBuffer, const void *pvTxData, size_t xDataLengthBytes, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
|
||||||
|
size_t MPU_xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer, void *pvRxData, size_t xBufferLengthBytes, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
|
||||||
|
size_t MPU_xStreamBufferNextMessageLengthBytes( StreamBufferHandle_t xStreamBuffer ) FREERTOS_SYSTEM_CALL;
|
||||||
|
void MPU_vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xStreamBufferReset( StreamBufferHandle_t xStreamBuffer ) FREERTOS_SYSTEM_CALL;
|
||||||
|
size_t MPU_xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer ) FREERTOS_SYSTEM_CALL;
|
||||||
|
size_t MPU_xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer ) FREERTOS_SYSTEM_CALL;
|
||||||
|
BaseType_t MPU_xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, size_t xTriggerLevel ) FREERTOS_SYSTEM_CALL;
|
||||||
|
StreamBufferHandle_t MPU_xStreamBufferGenericCreate( size_t xBufferSizeBytes, size_t xTriggerLevelBytes, BaseType_t xIsMessageBuffer ) FREERTOS_SYSTEM_CALL;
|
||||||
|
StreamBufferHandle_t MPU_xStreamBufferGenericCreateStatic( size_t xBufferSizeBytes, size_t xTriggerLevelBytes, BaseType_t xIsMessageBuffer, uint8_t * const pucStreamBufferStorageArea, StaticStreamBuffer_t * const pxStaticStreamBuffer ) FREERTOS_SYSTEM_CALL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* MPU_PROTOTYPES_H */
|
||||||
|
|
||||||
189
Middlewares/Third_Party/FreeRTOS/Source/include/mpu_wrappers.h
vendored
Normal file
189
Middlewares/Third_Party/FreeRTOS/Source/include/mpu_wrappers.h
vendored
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
/*
|
||||||
|
* FreeRTOS Kernel V10.3.1
|
||||||
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org
|
||||||
|
* http://aws.amazon.com/freertos
|
||||||
|
*
|
||||||
|
* 1 tab == 4 spaces!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MPU_WRAPPERS_H
|
||||||
|
#define MPU_WRAPPERS_H
|
||||||
|
|
||||||
|
/* This file redefines API functions to be called through a wrapper macro, but
|
||||||
|
only for ports that are using the MPU. */
|
||||||
|
#ifdef portUSING_MPU_WRAPPERS
|
||||||
|
|
||||||
|
/* MPU_WRAPPERS_INCLUDED_FROM_API_FILE will be defined when this file is
|
||||||
|
included from queue.c or task.c to prevent it from having an effect within
|
||||||
|
those files. */
|
||||||
|
#ifndef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Map standard (non MPU) API functions to equivalents that start
|
||||||
|
* "MPU_". This will cause the application code to call the MPU_
|
||||||
|
* version, which wraps the non-MPU version with privilege promoting
|
||||||
|
* then demoting code, so the kernel code always runs will full
|
||||||
|
* privileges.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Map standard tasks.h API functions to the MPU equivalents. */
|
||||||
|
#define xTaskCreate MPU_xTaskCreate
|
||||||
|
#define xTaskCreateStatic MPU_xTaskCreateStatic
|
||||||
|
#define xTaskCreateRestricted MPU_xTaskCreateRestricted
|
||||||
|
#define vTaskAllocateMPURegions MPU_vTaskAllocateMPURegions
|
||||||
|
#define vTaskDelete MPU_vTaskDelete
|
||||||
|
#define vTaskDelay MPU_vTaskDelay
|
||||||
|
#define vTaskDelayUntil MPU_vTaskDelayUntil
|
||||||
|
#define xTaskAbortDelay MPU_xTaskAbortDelay
|
||||||
|
#define uxTaskPriorityGet MPU_uxTaskPriorityGet
|
||||||
|
#define eTaskGetState MPU_eTaskGetState
|
||||||
|
#define vTaskGetInfo MPU_vTaskGetInfo
|
||||||
|
#define vTaskPrioritySet MPU_vTaskPrioritySet
|
||||||
|
#define vTaskSuspend MPU_vTaskSuspend
|
||||||
|
#define vTaskResume MPU_vTaskResume
|
||||||
|
#define vTaskSuspendAll MPU_vTaskSuspendAll
|
||||||
|
#define xTaskResumeAll MPU_xTaskResumeAll
|
||||||
|
#define xTaskGetTickCount MPU_xTaskGetTickCount
|
||||||
|
#define uxTaskGetNumberOfTasks MPU_uxTaskGetNumberOfTasks
|
||||||
|
#define pcTaskGetName MPU_pcTaskGetName
|
||||||
|
#define xTaskGetHandle MPU_xTaskGetHandle
|
||||||
|
#define uxTaskGetStackHighWaterMark MPU_uxTaskGetStackHighWaterMark
|
||||||
|
#define uxTaskGetStackHighWaterMark2 MPU_uxTaskGetStackHighWaterMark2
|
||||||
|
#define vTaskSetApplicationTaskTag MPU_vTaskSetApplicationTaskTag
|
||||||
|
#define xTaskGetApplicationTaskTag MPU_xTaskGetApplicationTaskTag
|
||||||
|
#define vTaskSetThreadLocalStoragePointer MPU_vTaskSetThreadLocalStoragePointer
|
||||||
|
#define pvTaskGetThreadLocalStoragePointer MPU_pvTaskGetThreadLocalStoragePointer
|
||||||
|
#define xTaskCallApplicationTaskHook MPU_xTaskCallApplicationTaskHook
|
||||||
|
#define xTaskGetIdleTaskHandle MPU_xTaskGetIdleTaskHandle
|
||||||
|
#define uxTaskGetSystemState MPU_uxTaskGetSystemState
|
||||||
|
#define vTaskList MPU_vTaskList
|
||||||
|
#define vTaskGetRunTimeStats MPU_vTaskGetRunTimeStats
|
||||||
|
#define ulTaskGetIdleRunTimeCounter MPU_ulTaskGetIdleRunTimeCounter
|
||||||
|
#define xTaskGenericNotify MPU_xTaskGenericNotify
|
||||||
|
#define xTaskNotifyWait MPU_xTaskNotifyWait
|
||||||
|
#define ulTaskNotifyTake MPU_ulTaskNotifyTake
|
||||||
|
#define xTaskNotifyStateClear MPU_xTaskNotifyStateClear
|
||||||
|
#define ulTaskNotifyValueClear MPU_ulTaskNotifyValueClear
|
||||||
|
#define xTaskCatchUpTicks MPU_xTaskCatchUpTicks
|
||||||
|
|
||||||
|
#define xTaskGetCurrentTaskHandle MPU_xTaskGetCurrentTaskHandle
|
||||||
|
#define vTaskSetTimeOutState MPU_vTaskSetTimeOutState
|
||||||
|
#define xTaskCheckForTimeOut MPU_xTaskCheckForTimeOut
|
||||||
|
#define xTaskGetSchedulerState MPU_xTaskGetSchedulerState
|
||||||
|
|
||||||
|
/* Map standard queue.h API functions to the MPU equivalents. */
|
||||||
|
#define xQueueGenericSend MPU_xQueueGenericSend
|
||||||
|
#define xQueueReceive MPU_xQueueReceive
|
||||||
|
#define xQueuePeek MPU_xQueuePeek
|
||||||
|
#define xQueueSemaphoreTake MPU_xQueueSemaphoreTake
|
||||||
|
#define uxQueueMessagesWaiting MPU_uxQueueMessagesWaiting
|
||||||
|
#define uxQueueSpacesAvailable MPU_uxQueueSpacesAvailable
|
||||||
|
#define vQueueDelete MPU_vQueueDelete
|
||||||
|
#define xQueueCreateMutex MPU_xQueueCreateMutex
|
||||||
|
#define xQueueCreateMutexStatic MPU_xQueueCreateMutexStatic
|
||||||
|
#define xQueueCreateCountingSemaphore MPU_xQueueCreateCountingSemaphore
|
||||||
|
#define xQueueCreateCountingSemaphoreStatic MPU_xQueueCreateCountingSemaphoreStatic
|
||||||
|
#define xQueueGetMutexHolder MPU_xQueueGetMutexHolder
|
||||||
|
#define xQueueTakeMutexRecursive MPU_xQueueTakeMutexRecursive
|
||||||
|
#define xQueueGiveMutexRecursive MPU_xQueueGiveMutexRecursive
|
||||||
|
#define xQueueGenericCreate MPU_xQueueGenericCreate
|
||||||
|
#define xQueueGenericCreateStatic MPU_xQueueGenericCreateStatic
|
||||||
|
#define xQueueCreateSet MPU_xQueueCreateSet
|
||||||
|
#define xQueueAddToSet MPU_xQueueAddToSet
|
||||||
|
#define xQueueRemoveFromSet MPU_xQueueRemoveFromSet
|
||||||
|
#define xQueueSelectFromSet MPU_xQueueSelectFromSet
|
||||||
|
#define xQueueGenericReset MPU_xQueueGenericReset
|
||||||
|
|
||||||
|
#if( configQUEUE_REGISTRY_SIZE > 0 )
|
||||||
|
#define vQueueAddToRegistry MPU_vQueueAddToRegistry
|
||||||
|
#define vQueueUnregisterQueue MPU_vQueueUnregisterQueue
|
||||||
|
#define pcQueueGetName MPU_pcQueueGetName
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Map standard timer.h API functions to the MPU equivalents. */
|
||||||
|
#define xTimerCreate MPU_xTimerCreate
|
||||||
|
#define xTimerCreateStatic MPU_xTimerCreateStatic
|
||||||
|
#define pvTimerGetTimerID MPU_pvTimerGetTimerID
|
||||||
|
#define vTimerSetTimerID MPU_vTimerSetTimerID
|
||||||
|
#define xTimerIsTimerActive MPU_xTimerIsTimerActive
|
||||||
|
#define xTimerGetTimerDaemonTaskHandle MPU_xTimerGetTimerDaemonTaskHandle
|
||||||
|
#define xTimerPendFunctionCall MPU_xTimerPendFunctionCall
|
||||||
|
#define pcTimerGetName MPU_pcTimerGetName
|
||||||
|
#define vTimerSetReloadMode MPU_vTimerSetReloadMode
|
||||||
|
#define uxTimerGetReloadMode MPU_uxTimerGetReloadMode
|
||||||
|
#define xTimerGetPeriod MPU_xTimerGetPeriod
|
||||||
|
#define xTimerGetExpiryTime MPU_xTimerGetExpiryTime
|
||||||
|
#define xTimerGenericCommand MPU_xTimerGenericCommand
|
||||||
|
|
||||||
|
/* Map standard event_group.h API functions to the MPU equivalents. */
|
||||||
|
#define xEventGroupCreate MPU_xEventGroupCreate
|
||||||
|
#define xEventGroupCreateStatic MPU_xEventGroupCreateStatic
|
||||||
|
#define xEventGroupWaitBits MPU_xEventGroupWaitBits
|
||||||
|
#define xEventGroupClearBits MPU_xEventGroupClearBits
|
||||||
|
#define xEventGroupSetBits MPU_xEventGroupSetBits
|
||||||
|
#define xEventGroupSync MPU_xEventGroupSync
|
||||||
|
#define vEventGroupDelete MPU_vEventGroupDelete
|
||||||
|
|
||||||
|
/* Map standard message/stream_buffer.h API functions to the MPU
|
||||||
|
equivalents. */
|
||||||
|
#define xStreamBufferSend MPU_xStreamBufferSend
|
||||||
|
#define xStreamBufferReceive MPU_xStreamBufferReceive
|
||||||
|
#define xStreamBufferNextMessageLengthBytes MPU_xStreamBufferNextMessageLengthBytes
|
||||||
|
#define vStreamBufferDelete MPU_vStreamBufferDelete
|
||||||
|
#define xStreamBufferIsFull MPU_xStreamBufferIsFull
|
||||||
|
#define xStreamBufferIsEmpty MPU_xStreamBufferIsEmpty
|
||||||
|
#define xStreamBufferReset MPU_xStreamBufferReset
|
||||||
|
#define xStreamBufferSpacesAvailable MPU_xStreamBufferSpacesAvailable
|
||||||
|
#define xStreamBufferBytesAvailable MPU_xStreamBufferBytesAvailable
|
||||||
|
#define xStreamBufferSetTriggerLevel MPU_xStreamBufferSetTriggerLevel
|
||||||
|
#define xStreamBufferGenericCreate MPU_xStreamBufferGenericCreate
|
||||||
|
#define xStreamBufferGenericCreateStatic MPU_xStreamBufferGenericCreateStatic
|
||||||
|
|
||||||
|
|
||||||
|
/* Remove the privileged function macro, but keep the PRIVILEGED_DATA
|
||||||
|
macro so applications can place data in privileged access sections
|
||||||
|
(useful when using statically allocated objects). */
|
||||||
|
#define PRIVILEGED_FUNCTION
|
||||||
|
#define PRIVILEGED_DATA __attribute__((section("privileged_data")))
|
||||||
|
#define FREERTOS_SYSTEM_CALL
|
||||||
|
|
||||||
|
#else /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */
|
||||||
|
|
||||||
|
/* Ensure API functions go in the privileged execution section. */
|
||||||
|
#define PRIVILEGED_FUNCTION __attribute__((section("privileged_functions")))
|
||||||
|
#define PRIVILEGED_DATA __attribute__((section("privileged_data")))
|
||||||
|
#define FREERTOS_SYSTEM_CALL __attribute__((section( "freertos_system_calls")))
|
||||||
|
|
||||||
|
#endif /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */
|
||||||
|
|
||||||
|
#else /* portUSING_MPU_WRAPPERS */
|
||||||
|
|
||||||
|
#define PRIVILEGED_FUNCTION
|
||||||
|
#define PRIVILEGED_DATA
|
||||||
|
#define FREERTOS_SYSTEM_CALL
|
||||||
|
#define portUSING_MPU_WRAPPERS 0
|
||||||
|
|
||||||
|
#endif /* portUSING_MPU_WRAPPERS */
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* MPU_WRAPPERS_H */
|
||||||
|
|
||||||
199
Middlewares/Third_Party/FreeRTOS/Source/include/portable.h
vendored
Normal file
199
Middlewares/Third_Party/FreeRTOS/Source/include/portable.h
vendored
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
/*
|
||||||
|
* FreeRTOS Kernel V10.3.1
|
||||||
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org
|
||||||
|
* http://aws.amazon.com/freertos
|
||||||
|
*
|
||||||
|
* 1 tab == 4 spaces!
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------
|
||||||
|
* Portable layer API. Each function must be defined for each port.
|
||||||
|
*----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef PORTABLE_H
|
||||||
|
#define PORTABLE_H
|
||||||
|
|
||||||
|
/* Each FreeRTOS port has a unique portmacro.h header file. Originally a
|
||||||
|
pre-processor definition was used to ensure the pre-processor found the correct
|
||||||
|
portmacro.h file for the port being used. That scheme was deprecated in favour
|
||||||
|
of setting the compiler's include path such that it found the correct
|
||||||
|
portmacro.h file - removing the need for the constant and allowing the
|
||||||
|
portmacro.h file to be located anywhere in relation to the port being used.
|
||||||
|
Purely for reasons of backward compatibility the old method is still valid, but
|
||||||
|
to make it clear that new projects should not use it, support for the port
|
||||||
|
specific constants has been moved into the deprecated_definitions.h header
|
||||||
|
file. */
|
||||||
|
#include "deprecated_definitions.h"
|
||||||
|
|
||||||
|
/* If portENTER_CRITICAL is not defined then including deprecated_definitions.h
|
||||||
|
did not result in a portmacro.h header file being included - and it should be
|
||||||
|
included here. In this case the path to the correct portmacro.h header file
|
||||||
|
must be set in the compiler's include path. */
|
||||||
|
#ifndef portENTER_CRITICAL
|
||||||
|
#include "portmacro.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if portBYTE_ALIGNMENT == 32
|
||||||
|
#define portBYTE_ALIGNMENT_MASK ( 0x001f )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if portBYTE_ALIGNMENT == 16
|
||||||
|
#define portBYTE_ALIGNMENT_MASK ( 0x000f )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if portBYTE_ALIGNMENT == 8
|
||||||
|
#define portBYTE_ALIGNMENT_MASK ( 0x0007 )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if portBYTE_ALIGNMENT == 4
|
||||||
|
#define portBYTE_ALIGNMENT_MASK ( 0x0003 )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if portBYTE_ALIGNMENT == 2
|
||||||
|
#define portBYTE_ALIGNMENT_MASK ( 0x0001 )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if portBYTE_ALIGNMENT == 1
|
||||||
|
#define portBYTE_ALIGNMENT_MASK ( 0x0000 )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef portBYTE_ALIGNMENT_MASK
|
||||||
|
#error "Invalid portBYTE_ALIGNMENT definition"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef portNUM_CONFIGURABLE_REGIONS
|
||||||
|
#define portNUM_CONFIGURABLE_REGIONS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef portHAS_STACK_OVERFLOW_CHECKING
|
||||||
|
#define portHAS_STACK_OVERFLOW_CHECKING 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef portARCH_NAME
|
||||||
|
#define portARCH_NAME NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "mpu_wrappers.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup the stack of a new task so it is ready to be placed under the
|
||||||
|
* scheduler control. The registers have to be placed on the stack in
|
||||||
|
* the order that the port expects to find them.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#if( portUSING_MPU_WRAPPERS == 1 )
|
||||||
|
#if( portHAS_STACK_OVERFLOW_CHECKING == 1 )
|
||||||
|
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, StackType_t *pxEndOfStack, TaskFunction_t pxCode, void *pvParameters, BaseType_t xRunPrivileged ) PRIVILEGED_FUNCTION;
|
||||||
|
#else
|
||||||
|
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters, BaseType_t xRunPrivileged ) PRIVILEGED_FUNCTION;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#if( portHAS_STACK_OVERFLOW_CHECKING == 1 )
|
||||||
|
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, StackType_t *pxEndOfStack, TaskFunction_t pxCode, void *pvParameters ) PRIVILEGED_FUNCTION;
|
||||||
|
#else
|
||||||
|
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters ) PRIVILEGED_FUNCTION;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Used by heap_5.c to define the start address and size of each memory region
|
||||||
|
that together comprise the total FreeRTOS heap space. */
|
||||||
|
typedef struct HeapRegion
|
||||||
|
{
|
||||||
|
uint8_t *pucStartAddress;
|
||||||
|
size_t xSizeInBytes;
|
||||||
|
} HeapRegion_t;
|
||||||
|
|
||||||
|
/* Used to pass information about the heap out of vPortGetHeapStats(). */
|
||||||
|
typedef struct xHeapStats
|
||||||
|
{
|
||||||
|
size_t xAvailableHeapSpaceInBytes; /* The total heap size currently available - this is the sum of all the free blocks, not the largest block that can be allocated. */
|
||||||
|
size_t xSizeOfLargestFreeBlockInBytes; /* The maximum size, in bytes, of all the free blocks within the heap at the time vPortGetHeapStats() is called. */
|
||||||
|
size_t xSizeOfSmallestFreeBlockInBytes; /* The minimum size, in bytes, of all the free blocks within the heap at the time vPortGetHeapStats() is called. */
|
||||||
|
size_t xNumberOfFreeBlocks; /* The number of free memory blocks within the heap at the time vPortGetHeapStats() is called. */
|
||||||
|
size_t xMinimumEverFreeBytesRemaining; /* The minimum amount of total free memory (sum of all free blocks) there has been in the heap since the system booted. */
|
||||||
|
size_t xNumberOfSuccessfulAllocations; /* The number of calls to pvPortMalloc() that have returned a valid memory block. */
|
||||||
|
size_t xNumberOfSuccessfulFrees; /* The number of calls to vPortFree() that has successfully freed a block of memory. */
|
||||||
|
} HeapStats_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used to define multiple heap regions for use by heap_5.c. This function
|
||||||
|
* must be called before any calls to pvPortMalloc() - not creating a task,
|
||||||
|
* queue, semaphore, mutex, software timer, event group, etc. will result in
|
||||||
|
* pvPortMalloc being called.
|
||||||
|
*
|
||||||
|
* pxHeapRegions passes in an array of HeapRegion_t structures - each of which
|
||||||
|
* defines a region of memory that can be used as the heap. The array is
|
||||||
|
* terminated by a HeapRegions_t structure that has a size of 0. The region
|
||||||
|
* with the lowest start address must appear first in the array.
|
||||||
|
*/
|
||||||
|
void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns a HeapStats_t structure filled with information about the current
|
||||||
|
* heap state.
|
||||||
|
*/
|
||||||
|
void vPortGetHeapStats( HeapStats_t *pxHeapStats );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Map to the memory management routines required for the port.
|
||||||
|
*/
|
||||||
|
void *pvPortMalloc( size_t xSize ) PRIVILEGED_FUNCTION;
|
||||||
|
void vPortFree( void *pv ) PRIVILEGED_FUNCTION;
|
||||||
|
void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION;
|
||||||
|
size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION;
|
||||||
|
size_t xPortGetMinimumEverFreeHeapSize( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup the hardware ready for the scheduler to take control. This generally
|
||||||
|
* sets up a tick interrupt and sets timers for the correct tick frequency.
|
||||||
|
*/
|
||||||
|
BaseType_t xPortStartScheduler( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Undo any hardware/ISR setup that was performed by xPortStartScheduler() so
|
||||||
|
* the hardware is left in its original condition after the scheduler stops
|
||||||
|
* executing.
|
||||||
|
*/
|
||||||
|
void vPortEndScheduler( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The structures and methods of manipulating the MPU are contained within the
|
||||||
|
* port layer.
|
||||||
|
*
|
||||||
|
* Fills the xMPUSettings structure with the memory region information
|
||||||
|
* contained in xRegions.
|
||||||
|
*/
|
||||||
|
#if( portUSING_MPU_WRAPPERS == 1 )
|
||||||
|
struct xMEMORY_REGION;
|
||||||
|
void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, StackType_t *pxBottomOfStack, uint32_t ulStackDepth ) PRIVILEGED_FUNCTION;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* PORTABLE_H */
|
||||||
|
|
||||||
124
Middlewares/Third_Party/FreeRTOS/Source/include/projdefs.h
vendored
Normal file
124
Middlewares/Third_Party/FreeRTOS/Source/include/projdefs.h
vendored
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* FreeRTOS Kernel V10.3.1
|
||||||
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org
|
||||||
|
* http://aws.amazon.com/freertos
|
||||||
|
*
|
||||||
|
* 1 tab == 4 spaces!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PROJDEFS_H
|
||||||
|
#define PROJDEFS_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Defines the prototype to which task functions must conform. Defined in this
|
||||||
|
* file to ensure the type is known before portable.h is included.
|
||||||
|
*/
|
||||||
|
typedef void (*TaskFunction_t)( void * );
|
||||||
|
|
||||||
|
/* Converts a time in milliseconds to a time in ticks. This macro can be
|
||||||
|
overridden by a macro of the same name defined in FreeRTOSConfig.h in case the
|
||||||
|
definition here is not suitable for your application. */
|
||||||
|
#ifndef pdMS_TO_TICKS
|
||||||
|
#define pdMS_TO_TICKS( xTimeInMs ) ( ( TickType_t ) ( ( ( TickType_t ) ( xTimeInMs ) * ( TickType_t ) configTICK_RATE_HZ ) / ( TickType_t ) 1000 ) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define pdFALSE ( ( BaseType_t ) 0 )
|
||||||
|
#define pdTRUE ( ( BaseType_t ) 1 )
|
||||||
|
|
||||||
|
#define pdPASS ( pdTRUE )
|
||||||
|
#define pdFAIL ( pdFALSE )
|
||||||
|
#define errQUEUE_EMPTY ( ( BaseType_t ) 0 )
|
||||||
|
#define errQUEUE_FULL ( ( BaseType_t ) 0 )
|
||||||
|
|
||||||
|
/* FreeRTOS error definitions. */
|
||||||
|
#define errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ( -1 )
|
||||||
|
#define errQUEUE_BLOCKED ( -4 )
|
||||||
|
#define errQUEUE_YIELD ( -5 )
|
||||||
|
|
||||||
|
/* Macros used for basic data corruption checks. */
|
||||||
|
#ifndef configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES
|
||||||
|
#define configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if( configUSE_16_BIT_TICKS == 1 )
|
||||||
|
#define pdINTEGRITY_CHECK_VALUE 0x5a5a
|
||||||
|
#else
|
||||||
|
#define pdINTEGRITY_CHECK_VALUE 0x5a5a5a5aUL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The following errno values are used by FreeRTOS+ components, not FreeRTOS
|
||||||
|
itself. */
|
||||||
|
#define pdFREERTOS_ERRNO_NONE 0 /* No errors */
|
||||||
|
#define pdFREERTOS_ERRNO_ENOENT 2 /* No such file or directory */
|
||||||
|
#define pdFREERTOS_ERRNO_EINTR 4 /* Interrupted system call */
|
||||||
|
#define pdFREERTOS_ERRNO_EIO 5 /* I/O error */
|
||||||
|
#define pdFREERTOS_ERRNO_ENXIO 6 /* No such device or address */
|
||||||
|
#define pdFREERTOS_ERRNO_EBADF 9 /* Bad file number */
|
||||||
|
#define pdFREERTOS_ERRNO_EAGAIN 11 /* No more processes */
|
||||||
|
#define pdFREERTOS_ERRNO_EWOULDBLOCK 11 /* Operation would block */
|
||||||
|
#define pdFREERTOS_ERRNO_ENOMEM 12 /* Not enough memory */
|
||||||
|
#define pdFREERTOS_ERRNO_EACCES 13 /* Permission denied */
|
||||||
|
#define pdFREERTOS_ERRNO_EFAULT 14 /* Bad address */
|
||||||
|
#define pdFREERTOS_ERRNO_EBUSY 16 /* Mount device busy */
|
||||||
|
#define pdFREERTOS_ERRNO_EEXIST 17 /* File exists */
|
||||||
|
#define pdFREERTOS_ERRNO_EXDEV 18 /* Cross-device link */
|
||||||
|
#define pdFREERTOS_ERRNO_ENODEV 19 /* No such device */
|
||||||
|
#define pdFREERTOS_ERRNO_ENOTDIR 20 /* Not a directory */
|
||||||
|
#define pdFREERTOS_ERRNO_EISDIR 21 /* Is a directory */
|
||||||
|
#define pdFREERTOS_ERRNO_EINVAL 22 /* Invalid argument */
|
||||||
|
#define pdFREERTOS_ERRNO_ENOSPC 28 /* No space left on device */
|
||||||
|
#define pdFREERTOS_ERRNO_ESPIPE 29 /* Illegal seek */
|
||||||
|
#define pdFREERTOS_ERRNO_EROFS 30 /* Read only file system */
|
||||||
|
#define pdFREERTOS_ERRNO_EUNATCH 42 /* Protocol driver not attached */
|
||||||
|
#define pdFREERTOS_ERRNO_EBADE 50 /* Invalid exchange */
|
||||||
|
#define pdFREERTOS_ERRNO_EFTYPE 79 /* Inappropriate file type or format */
|
||||||
|
#define pdFREERTOS_ERRNO_ENMFILE 89 /* No more files */
|
||||||
|
#define pdFREERTOS_ERRNO_ENOTEMPTY 90 /* Directory not empty */
|
||||||
|
#define pdFREERTOS_ERRNO_ENAMETOOLONG 91 /* File or path name too long */
|
||||||
|
#define pdFREERTOS_ERRNO_EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
|
||||||
|
#define pdFREERTOS_ERRNO_ENOBUFS 105 /* No buffer space available */
|
||||||
|
#define pdFREERTOS_ERRNO_ENOPROTOOPT 109 /* Protocol not available */
|
||||||
|
#define pdFREERTOS_ERRNO_EADDRINUSE 112 /* Address already in use */
|
||||||
|
#define pdFREERTOS_ERRNO_ETIMEDOUT 116 /* Connection timed out */
|
||||||
|
#define pdFREERTOS_ERRNO_EINPROGRESS 119 /* Connection already in progress */
|
||||||
|
#define pdFREERTOS_ERRNO_EALREADY 120 /* Socket already connected */
|
||||||
|
#define pdFREERTOS_ERRNO_EADDRNOTAVAIL 125 /* Address not available */
|
||||||
|
#define pdFREERTOS_ERRNO_EISCONN 127 /* Socket is already connected */
|
||||||
|
#define pdFREERTOS_ERRNO_ENOTCONN 128 /* Socket is not connected */
|
||||||
|
#define pdFREERTOS_ERRNO_ENOMEDIUM 135 /* No medium inserted */
|
||||||
|
#define pdFREERTOS_ERRNO_EILSEQ 138 /* An invalid UTF-16 sequence was encountered. */
|
||||||
|
#define pdFREERTOS_ERRNO_ECANCELED 140 /* Operation canceled. */
|
||||||
|
|
||||||
|
/* The following endian values are used by FreeRTOS+ components, not FreeRTOS
|
||||||
|
itself. */
|
||||||
|
#define pdFREERTOS_LITTLE_ENDIAN 0
|
||||||
|
#define pdFREERTOS_BIG_ENDIAN 1
|
||||||
|
|
||||||
|
/* Re-defining endian values for generic naming. */
|
||||||
|
#define pdLITTLE_ENDIAN pdFREERTOS_LITTLE_ENDIAN
|
||||||
|
#define pdBIG_ENDIAN pdFREERTOS_BIG_ENDIAN
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* PROJDEFS_H */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
1655
Middlewares/Third_Party/FreeRTOS/Source/include/queue.h
vendored
Normal file
1655
Middlewares/Third_Party/FreeRTOS/Source/include/queue.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1140
Middlewares/Third_Party/FreeRTOS/Source/include/semphr.h
vendored
Normal file
1140
Middlewares/Third_Party/FreeRTOS/Source/include/semphr.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
129
Middlewares/Third_Party/FreeRTOS/Source/include/stack_macros.h
vendored
Normal file
129
Middlewares/Third_Party/FreeRTOS/Source/include/stack_macros.h
vendored
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* FreeRTOS Kernel V10.3.1
|
||||||
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org
|
||||||
|
* http://aws.amazon.com/freertos
|
||||||
|
*
|
||||||
|
* 1 tab == 4 spaces!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STACK_MACROS_H
|
||||||
|
#define STACK_MACROS_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call the stack overflow hook function if the stack of the task being swapped
|
||||||
|
* out is currently overflowed, or looks like it might have overflowed in the
|
||||||
|
* past.
|
||||||
|
*
|
||||||
|
* Setting configCHECK_FOR_STACK_OVERFLOW to 1 will cause the macro to check
|
||||||
|
* the current stack state only - comparing the current top of stack value to
|
||||||
|
* the stack limit. Setting configCHECK_FOR_STACK_OVERFLOW to greater than 1
|
||||||
|
* will also cause the last few stack bytes to be checked to ensure the value
|
||||||
|
* to which the bytes were set when the task was created have not been
|
||||||
|
* overwritten. Note this second test does not guarantee that an overflowed
|
||||||
|
* stack will always be recognised.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH < 0 ) )
|
||||||
|
|
||||||
|
/* Only the current stack state is to be checked. */
|
||||||
|
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||||
|
{ \
|
||||||
|
/* Is the currently saved stack pointer within the stack limit? */ \
|
||||||
|
if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack ) \
|
||||||
|
{ \
|
||||||
|
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH > 0 ) )
|
||||||
|
|
||||||
|
/* Only the current stack state is to be checked. */
|
||||||
|
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||||
|
{ \
|
||||||
|
\
|
||||||
|
/* Is the currently saved stack pointer within the stack limit? */ \
|
||||||
|
if( pxCurrentTCB->pxTopOfStack >= pxCurrentTCB->pxEndOfStack ) \
|
||||||
|
{ \
|
||||||
|
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH < 0 ) )
|
||||||
|
|
||||||
|
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||||
|
{ \
|
||||||
|
const uint32_t * const pulStack = ( uint32_t * ) pxCurrentTCB->pxStack; \
|
||||||
|
const uint32_t ulCheckValue = ( uint32_t ) 0xa5a5a5a5; \
|
||||||
|
\
|
||||||
|
if( ( pulStack[ 0 ] != ulCheckValue ) || \
|
||||||
|
( pulStack[ 1 ] != ulCheckValue ) || \
|
||||||
|
( pulStack[ 2 ] != ulCheckValue ) || \
|
||||||
|
( pulStack[ 3 ] != ulCheckValue ) ) \
|
||||||
|
{ \
|
||||||
|
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH > 0 ) )
|
||||||
|
|
||||||
|
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||||
|
{ \
|
||||||
|
int8_t *pcEndOfStack = ( int8_t * ) pxCurrentTCB->pxEndOfStack; \
|
||||||
|
static const uint8_t ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||||
|
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||||
|
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||||
|
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||||
|
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \
|
||||||
|
\
|
||||||
|
\
|
||||||
|
pcEndOfStack -= sizeof( ucExpectedStackBytes ); \
|
||||||
|
\
|
||||||
|
/* Has the extremity of the task stack ever been written over? */ \
|
||||||
|
if( memcmp( ( void * ) pcEndOfStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \
|
||||||
|
{ \
|
||||||
|
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Remove stack overflow macro if not being used. */
|
||||||
|
#ifndef taskCHECK_FOR_STACK_OVERFLOW
|
||||||
|
#define taskCHECK_FOR_STACK_OVERFLOW()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* STACK_MACROS_H */
|
||||||
|
|
||||||
859
Middlewares/Third_Party/FreeRTOS/Source/include/stream_buffer.h
vendored
Normal file
859
Middlewares/Third_Party/FreeRTOS/Source/include/stream_buffer.h
vendored
Normal file
@@ -0,0 +1,859 @@
|
|||||||
|
/*
|
||||||
|
* FreeRTOS Kernel V10.3.1
|
||||||
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org
|
||||||
|
* http://aws.amazon.com/freertos
|
||||||
|
*
|
||||||
|
* 1 tab == 4 spaces!
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stream buffers are used to send a continuous stream of data from one task or
|
||||||
|
* interrupt to another. Their implementation is light weight, making them
|
||||||
|
* particularly suited for interrupt to task and core to core communication
|
||||||
|
* scenarios.
|
||||||
|
*
|
||||||
|
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
|
||||||
|
* implementation (so also the message buffer implementation, as message buffers
|
||||||
|
* are built on top of stream buffers) assumes there is only one task or
|
||||||
|
* interrupt that will write to the buffer (the writer), and only one task or
|
||||||
|
* interrupt that will read from the buffer (the reader). It is safe for the
|
||||||
|
* writer and reader to be different tasks or interrupts, but, unlike other
|
||||||
|
* FreeRTOS objects, it is not safe to have multiple different writers or
|
||||||
|
* multiple different readers. If there are to be multiple different writers
|
||||||
|
* then the application writer must place each call to a writing API function
|
||||||
|
* (such as xStreamBufferSend()) inside a critical section and set the send
|
||||||
|
* block time to 0. Likewise, if there are to be multiple different readers
|
||||||
|
* then the application writer must place each call to a reading API function
|
||||||
|
* (such as xStreamBufferReceive()) inside a critical section section and set the
|
||||||
|
* receive block time to 0.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STREAM_BUFFER_H
|
||||||
|
#define STREAM_BUFFER_H
|
||||||
|
|
||||||
|
#ifndef INC_FREERTOS_H
|
||||||
|
#error "include FreeRTOS.h must appear in source files before include stream_buffer.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined( __cplusplus )
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type by which stream buffers are referenced. For example, a call to
|
||||||
|
* xStreamBufferCreate() returns an StreamBufferHandle_t variable that can
|
||||||
|
* then be used as a parameter to xStreamBufferSend(), xStreamBufferReceive(),
|
||||||
|
* etc.
|
||||||
|
*/
|
||||||
|
struct StreamBufferDef_t;
|
||||||
|
typedef struct StreamBufferDef_t * StreamBufferHandle_t;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* message_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
StreamBufferHandle_t xStreamBufferCreate( size_t xBufferSizeBytes, size_t xTriggerLevelBytes );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Creates a new stream buffer using dynamically allocated memory. See
|
||||||
|
* xStreamBufferCreateStatic() for a version that uses statically allocated
|
||||||
|
* memory (memory that is allocated at compile time).
|
||||||
|
*
|
||||||
|
* configSUPPORT_DYNAMIC_ALLOCATION must be set to 1 or left undefined in
|
||||||
|
* FreeRTOSConfig.h for xStreamBufferCreate() to be available.
|
||||||
|
*
|
||||||
|
* @param xBufferSizeBytes The total number of bytes the stream buffer will be
|
||||||
|
* able to hold at any one time.
|
||||||
|
*
|
||||||
|
* @param xTriggerLevelBytes The number of bytes that must be in the stream
|
||||||
|
* buffer before a task that is blocked on the stream buffer to wait for data is
|
||||||
|
* moved out of the blocked state. For example, if a task is blocked on a read
|
||||||
|
* of an empty stream buffer that has a trigger level of 1 then the task will be
|
||||||
|
* unblocked when a single byte is written to the buffer or the task's block
|
||||||
|
* time expires. As another example, if a task is blocked on a read of an empty
|
||||||
|
* stream buffer that has a trigger level of 10 then the task will not be
|
||||||
|
* unblocked until the stream buffer contains at least 10 bytes or the task's
|
||||||
|
* block time expires. If a reading task's block time expires before the
|
||||||
|
* trigger level is reached then the task will still receive however many bytes
|
||||||
|
* are actually available. Setting a trigger level of 0 will result in a
|
||||||
|
* trigger level of 1 being used. It is not valid to specify a trigger level
|
||||||
|
* that is greater than the buffer size.
|
||||||
|
*
|
||||||
|
* @return If NULL is returned, then the stream buffer cannot be created
|
||||||
|
* because there is insufficient heap memory available for FreeRTOS to allocate
|
||||||
|
* the stream buffer data structures and storage area. A non-NULL value being
|
||||||
|
* returned indicates that the stream buffer has been created successfully -
|
||||||
|
* the returned value should be stored as the handle to the created stream
|
||||||
|
* buffer.
|
||||||
|
*
|
||||||
|
* Example use:
|
||||||
|
<pre>
|
||||||
|
|
||||||
|
void vAFunction( void )
|
||||||
|
{
|
||||||
|
StreamBufferHandle_t xStreamBuffer;
|
||||||
|
const size_t xStreamBufferSizeBytes = 100, xTriggerLevel = 10;
|
||||||
|
|
||||||
|
// Create a stream buffer that can hold 100 bytes. The memory used to hold
|
||||||
|
// both the stream buffer structure and the data in the stream buffer is
|
||||||
|
// allocated dynamically.
|
||||||
|
xStreamBuffer = xStreamBufferCreate( xStreamBufferSizeBytes, xTriggerLevel );
|
||||||
|
|
||||||
|
if( xStreamBuffer == NULL )
|
||||||
|
{
|
||||||
|
// There was not enough heap memory space available to create the
|
||||||
|
// stream buffer.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The stream buffer was created successfully and can now be used.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xStreamBufferCreate xStreamBufferCreate
|
||||||
|
* \ingroup StreamBufferManagement
|
||||||
|
*/
|
||||||
|
#define xStreamBufferCreate( xBufferSizeBytes, xTriggerLevelBytes ) xStreamBufferGenericCreate( xBufferSizeBytes, xTriggerLevelBytes, pdFALSE )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stream_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
StreamBufferHandle_t xStreamBufferCreateStatic( size_t xBufferSizeBytes,
|
||||||
|
size_t xTriggerLevelBytes,
|
||||||
|
uint8_t *pucStreamBufferStorageArea,
|
||||||
|
StaticStreamBuffer_t *pxStaticStreamBuffer );
|
||||||
|
</pre>
|
||||||
|
* Creates a new stream buffer using statically allocated memory. See
|
||||||
|
* xStreamBufferCreate() for a version that uses dynamically allocated memory.
|
||||||
|
*
|
||||||
|
* configSUPPORT_STATIC_ALLOCATION must be set to 1 in FreeRTOSConfig.h for
|
||||||
|
* xStreamBufferCreateStatic() to be available.
|
||||||
|
*
|
||||||
|
* @param xBufferSizeBytes The size, in bytes, of the buffer pointed to by the
|
||||||
|
* pucStreamBufferStorageArea parameter.
|
||||||
|
*
|
||||||
|
* @param xTriggerLevelBytes The number of bytes that must be in the stream
|
||||||
|
* buffer before a task that is blocked on the stream buffer to wait for data is
|
||||||
|
* moved out of the blocked state. For example, if a task is blocked on a read
|
||||||
|
* of an empty stream buffer that has a trigger level of 1 then the task will be
|
||||||
|
* unblocked when a single byte is written to the buffer or the task's block
|
||||||
|
* time expires. As another example, if a task is blocked on a read of an empty
|
||||||
|
* stream buffer that has a trigger level of 10 then the task will not be
|
||||||
|
* unblocked until the stream buffer contains at least 10 bytes or the task's
|
||||||
|
* block time expires. If a reading task's block time expires before the
|
||||||
|
* trigger level is reached then the task will still receive however many bytes
|
||||||
|
* are actually available. Setting a trigger level of 0 will result in a
|
||||||
|
* trigger level of 1 being used. It is not valid to specify a trigger level
|
||||||
|
* that is greater than the buffer size.
|
||||||
|
*
|
||||||
|
* @param pucStreamBufferStorageArea Must point to a uint8_t array that is at
|
||||||
|
* least xBufferSizeBytes + 1 big. This is the array to which streams are
|
||||||
|
* copied when they are written to the stream buffer.
|
||||||
|
*
|
||||||
|
* @param pxStaticStreamBuffer Must point to a variable of type
|
||||||
|
* StaticStreamBuffer_t, which will be used to hold the stream buffer's data
|
||||||
|
* structure.
|
||||||
|
*
|
||||||
|
* @return If the stream buffer is created successfully then a handle to the
|
||||||
|
* created stream buffer is returned. If either pucStreamBufferStorageArea or
|
||||||
|
* pxStaticstreamBuffer are NULL then NULL is returned.
|
||||||
|
*
|
||||||
|
* Example use:
|
||||||
|
<pre>
|
||||||
|
|
||||||
|
// Used to dimension the array used to hold the streams. The available space
|
||||||
|
// will actually be one less than this, so 999.
|
||||||
|
#define STORAGE_SIZE_BYTES 1000
|
||||||
|
|
||||||
|
// Defines the memory that will actually hold the streams within the stream
|
||||||
|
// buffer.
|
||||||
|
static uint8_t ucStorageBuffer[ STORAGE_SIZE_BYTES ];
|
||||||
|
|
||||||
|
// The variable used to hold the stream buffer structure.
|
||||||
|
StaticStreamBuffer_t xStreamBufferStruct;
|
||||||
|
|
||||||
|
void MyFunction( void )
|
||||||
|
{
|
||||||
|
StreamBufferHandle_t xStreamBuffer;
|
||||||
|
const size_t xTriggerLevel = 1;
|
||||||
|
|
||||||
|
xStreamBuffer = xStreamBufferCreateStatic( sizeof( ucBufferStorage ),
|
||||||
|
xTriggerLevel,
|
||||||
|
ucBufferStorage,
|
||||||
|
&xStreamBufferStruct );
|
||||||
|
|
||||||
|
// As neither the pucStreamBufferStorageArea or pxStaticStreamBuffer
|
||||||
|
// parameters were NULL, xStreamBuffer will not be NULL, and can be used to
|
||||||
|
// reference the created stream buffer in other stream buffer API calls.
|
||||||
|
|
||||||
|
// Other code that uses the stream buffer can go here.
|
||||||
|
}
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
* \defgroup xStreamBufferCreateStatic xStreamBufferCreateStatic
|
||||||
|
* \ingroup StreamBufferManagement
|
||||||
|
*/
|
||||||
|
#define xStreamBufferCreateStatic( xBufferSizeBytes, xTriggerLevelBytes, pucStreamBufferStorageArea, pxStaticStreamBuffer ) xStreamBufferGenericCreateStatic( xBufferSizeBytes, xTriggerLevelBytes, pdFALSE, pucStreamBufferStorageArea, pxStaticStreamBuffer )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stream_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
|
||||||
|
const void *pvTxData,
|
||||||
|
size_t xDataLengthBytes,
|
||||||
|
TickType_t xTicksToWait );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Sends bytes to a stream buffer. The bytes are copied into the stream buffer.
|
||||||
|
*
|
||||||
|
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
|
||||||
|
* implementation (so also the message buffer implementation, as message buffers
|
||||||
|
* are built on top of stream buffers) assumes there is only one task or
|
||||||
|
* interrupt that will write to the buffer (the writer), and only one task or
|
||||||
|
* interrupt that will read from the buffer (the reader). It is safe for the
|
||||||
|
* writer and reader to be different tasks or interrupts, but, unlike other
|
||||||
|
* FreeRTOS objects, it is not safe to have multiple different writers or
|
||||||
|
* multiple different readers. If there are to be multiple different writers
|
||||||
|
* then the application writer must place each call to a writing API function
|
||||||
|
* (such as xStreamBufferSend()) inside a critical section and set the send
|
||||||
|
* block time to 0. Likewise, if there are to be multiple different readers
|
||||||
|
* then the application writer must place each call to a reading API function
|
||||||
|
* (such as xStreamBufferReceive()) inside a critical section and set the receive
|
||||||
|
* block time to 0.
|
||||||
|
*
|
||||||
|
* Use xStreamBufferSend() to write to a stream buffer from a task. Use
|
||||||
|
* xStreamBufferSendFromISR() to write to a stream buffer from an interrupt
|
||||||
|
* service routine (ISR).
|
||||||
|
*
|
||||||
|
* @param xStreamBuffer The handle of the stream buffer to which a stream is
|
||||||
|
* being sent.
|
||||||
|
*
|
||||||
|
* @param pvTxData A pointer to the buffer that holds the bytes to be copied
|
||||||
|
* into the stream buffer.
|
||||||
|
*
|
||||||
|
* @param xDataLengthBytes The maximum number of bytes to copy from pvTxData
|
||||||
|
* into the stream buffer.
|
||||||
|
*
|
||||||
|
* @param xTicksToWait The maximum amount of time the task should remain in the
|
||||||
|
* Blocked state to wait for enough space to become available in the stream
|
||||||
|
* buffer, should the stream buffer contain too little space to hold the
|
||||||
|
* another xDataLengthBytes bytes. The block time is specified in tick periods,
|
||||||
|
* so the absolute time it represents is dependent on the tick frequency. The
|
||||||
|
* macro pdMS_TO_TICKS() can be used to convert a time specified in milliseconds
|
||||||
|
* into a time specified in ticks. Setting xTicksToWait to portMAX_DELAY will
|
||||||
|
* cause the task to wait indefinitely (without timing out), provided
|
||||||
|
* INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h. If a task times out
|
||||||
|
* before it can write all xDataLengthBytes into the buffer it will still write
|
||||||
|
* as many bytes as possible. A task does not use any CPU time when it is in
|
||||||
|
* the blocked state.
|
||||||
|
*
|
||||||
|
* @return The number of bytes written to the stream buffer. If a task times
|
||||||
|
* out before it can write all xDataLengthBytes into the buffer it will still
|
||||||
|
* write as many bytes as possible.
|
||||||
|
*
|
||||||
|
* Example use:
|
||||||
|
<pre>
|
||||||
|
void vAFunction( StreamBufferHandle_t xStreamBuffer )
|
||||||
|
{
|
||||||
|
size_t xBytesSent;
|
||||||
|
uint8_t ucArrayToSend[] = { 0, 1, 2, 3 };
|
||||||
|
char *pcStringToSend = "String to send";
|
||||||
|
const TickType_t x100ms = pdMS_TO_TICKS( 100 );
|
||||||
|
|
||||||
|
// Send an array to the stream buffer, blocking for a maximum of 100ms to
|
||||||
|
// wait for enough space to be available in the stream buffer.
|
||||||
|
xBytesSent = xStreamBufferSend( xStreamBuffer, ( void * ) ucArrayToSend, sizeof( ucArrayToSend ), x100ms );
|
||||||
|
|
||||||
|
if( xBytesSent != sizeof( ucArrayToSend ) )
|
||||||
|
{
|
||||||
|
// The call to xStreamBufferSend() times out before there was enough
|
||||||
|
// space in the buffer for the data to be written, but it did
|
||||||
|
// successfully write xBytesSent bytes.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the string to the stream buffer. Return immediately if there is not
|
||||||
|
// enough space in the buffer.
|
||||||
|
xBytesSent = xStreamBufferSend( xStreamBuffer, ( void * ) pcStringToSend, strlen( pcStringToSend ), 0 );
|
||||||
|
|
||||||
|
if( xBytesSent != strlen( pcStringToSend ) )
|
||||||
|
{
|
||||||
|
// The entire string could not be added to the stream buffer because
|
||||||
|
// there was not enough free space in the buffer, but xBytesSent bytes
|
||||||
|
// were sent. Could try again to send the remaining bytes.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xStreamBufferSend xStreamBufferSend
|
||||||
|
* \ingroup StreamBufferManagement
|
||||||
|
*/
|
||||||
|
size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
|
||||||
|
const void *pvTxData,
|
||||||
|
size_t xDataLengthBytes,
|
||||||
|
TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stream_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer,
|
||||||
|
const void *pvTxData,
|
||||||
|
size_t xDataLengthBytes,
|
||||||
|
BaseType_t *pxHigherPriorityTaskWoken );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Interrupt safe version of the API function that sends a stream of bytes to
|
||||||
|
* the stream buffer.
|
||||||
|
*
|
||||||
|
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
|
||||||
|
* implementation (so also the message buffer implementation, as message buffers
|
||||||
|
* are built on top of stream buffers) assumes there is only one task or
|
||||||
|
* interrupt that will write to the buffer (the writer), and only one task or
|
||||||
|
* interrupt that will read from the buffer (the reader). It is safe for the
|
||||||
|
* writer and reader to be different tasks or interrupts, but, unlike other
|
||||||
|
* FreeRTOS objects, it is not safe to have multiple different writers or
|
||||||
|
* multiple different readers. If there are to be multiple different writers
|
||||||
|
* then the application writer must place each call to a writing API function
|
||||||
|
* (such as xStreamBufferSend()) inside a critical section and set the send
|
||||||
|
* block time to 0. Likewise, if there are to be multiple different readers
|
||||||
|
* then the application writer must place each call to a reading API function
|
||||||
|
* (such as xStreamBufferReceive()) inside a critical section and set the receive
|
||||||
|
* block time to 0.
|
||||||
|
*
|
||||||
|
* Use xStreamBufferSend() to write to a stream buffer from a task. Use
|
||||||
|
* xStreamBufferSendFromISR() to write to a stream buffer from an interrupt
|
||||||
|
* service routine (ISR).
|
||||||
|
*
|
||||||
|
* @param xStreamBuffer The handle of the stream buffer to which a stream is
|
||||||
|
* being sent.
|
||||||
|
*
|
||||||
|
* @param pvTxData A pointer to the data that is to be copied into the stream
|
||||||
|
* buffer.
|
||||||
|
*
|
||||||
|
* @param xDataLengthBytes The maximum number of bytes to copy from pvTxData
|
||||||
|
* into the stream buffer.
|
||||||
|
*
|
||||||
|
* @param pxHigherPriorityTaskWoken It is possible that a stream buffer will
|
||||||
|
* have a task blocked on it waiting for data. Calling
|
||||||
|
* xStreamBufferSendFromISR() can make data available, and so cause a task that
|
||||||
|
* was waiting for data to leave the Blocked state. If calling
|
||||||
|
* xStreamBufferSendFromISR() causes a task to leave the Blocked state, and the
|
||||||
|
* unblocked task has a priority higher than the currently executing task (the
|
||||||
|
* task that was interrupted), then, internally, xStreamBufferSendFromISR()
|
||||||
|
* will set *pxHigherPriorityTaskWoken to pdTRUE. If
|
||||||
|
* xStreamBufferSendFromISR() sets this value to pdTRUE, then normally a
|
||||||
|
* context switch should be performed before the interrupt is exited. This will
|
||||||
|
* ensure that the interrupt returns directly to the highest priority Ready
|
||||||
|
* state task. *pxHigherPriorityTaskWoken should be set to pdFALSE before it
|
||||||
|
* is passed into the function. See the example code below for an example.
|
||||||
|
*
|
||||||
|
* @return The number of bytes actually written to the stream buffer, which will
|
||||||
|
* be less than xDataLengthBytes if the stream buffer didn't have enough free
|
||||||
|
* space for all the bytes to be written.
|
||||||
|
*
|
||||||
|
* Example use:
|
||||||
|
<pre>
|
||||||
|
// A stream buffer that has already been created.
|
||||||
|
StreamBufferHandle_t xStreamBuffer;
|
||||||
|
|
||||||
|
void vAnInterruptServiceRoutine( void )
|
||||||
|
{
|
||||||
|
size_t xBytesSent;
|
||||||
|
char *pcStringToSend = "String to send";
|
||||||
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE; // Initialised to pdFALSE.
|
||||||
|
|
||||||
|
// Attempt to send the string to the stream buffer.
|
||||||
|
xBytesSent = xStreamBufferSendFromISR( xStreamBuffer,
|
||||||
|
( void * ) pcStringToSend,
|
||||||
|
strlen( pcStringToSend ),
|
||||||
|
&xHigherPriorityTaskWoken );
|
||||||
|
|
||||||
|
if( xBytesSent != strlen( pcStringToSend ) )
|
||||||
|
{
|
||||||
|
// There was not enough free space in the stream buffer for the entire
|
||||||
|
// string to be written, ut xBytesSent bytes were written.
|
||||||
|
}
|
||||||
|
|
||||||
|
// If xHigherPriorityTaskWoken was set to pdTRUE inside
|
||||||
|
// xStreamBufferSendFromISR() then a task that has a priority above the
|
||||||
|
// priority of the currently executing task was unblocked and a context
|
||||||
|
// switch should be performed to ensure the ISR returns to the unblocked
|
||||||
|
// task. In most FreeRTOS ports this is done by simply passing
|
||||||
|
// xHigherPriorityTaskWoken into taskYIELD_FROM_ISR(), which will test the
|
||||||
|
// variables value, and perform the context switch if necessary. Check the
|
||||||
|
// documentation for the port in use for port specific instructions.
|
||||||
|
taskYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xStreamBufferSendFromISR xStreamBufferSendFromISR
|
||||||
|
* \ingroup StreamBufferManagement
|
||||||
|
*/
|
||||||
|
size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer,
|
||||||
|
const void *pvTxData,
|
||||||
|
size_t xDataLengthBytes,
|
||||||
|
BaseType_t * const pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stream_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
|
||||||
|
void *pvRxData,
|
||||||
|
size_t xBufferLengthBytes,
|
||||||
|
TickType_t xTicksToWait );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Receives bytes from a stream buffer.
|
||||||
|
*
|
||||||
|
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
|
||||||
|
* implementation (so also the message buffer implementation, as message buffers
|
||||||
|
* are built on top of stream buffers) assumes there is only one task or
|
||||||
|
* interrupt that will write to the buffer (the writer), and only one task or
|
||||||
|
* interrupt that will read from the buffer (the reader). It is safe for the
|
||||||
|
* writer and reader to be different tasks or interrupts, but, unlike other
|
||||||
|
* FreeRTOS objects, it is not safe to have multiple different writers or
|
||||||
|
* multiple different readers. If there are to be multiple different writers
|
||||||
|
* then the application writer must place each call to a writing API function
|
||||||
|
* (such as xStreamBufferSend()) inside a critical section and set the send
|
||||||
|
* block time to 0. Likewise, if there are to be multiple different readers
|
||||||
|
* then the application writer must place each call to a reading API function
|
||||||
|
* (such as xStreamBufferReceive()) inside a critical section and set the receive
|
||||||
|
* block time to 0.
|
||||||
|
*
|
||||||
|
* Use xStreamBufferReceive() to read from a stream buffer from a task. Use
|
||||||
|
* xStreamBufferReceiveFromISR() to read from a stream buffer from an
|
||||||
|
* interrupt service routine (ISR).
|
||||||
|
*
|
||||||
|
* @param xStreamBuffer The handle of the stream buffer from which bytes are to
|
||||||
|
* be received.
|
||||||
|
*
|
||||||
|
* @param pvRxData A pointer to the buffer into which the received bytes will be
|
||||||
|
* copied.
|
||||||
|
*
|
||||||
|
* @param xBufferLengthBytes The length of the buffer pointed to by the
|
||||||
|
* pvRxData parameter. This sets the maximum number of bytes to receive in one
|
||||||
|
* call. xStreamBufferReceive will return as many bytes as possible up to a
|
||||||
|
* maximum set by xBufferLengthBytes.
|
||||||
|
*
|
||||||
|
* @param xTicksToWait The maximum amount of time the task should remain in the
|
||||||
|
* Blocked state to wait for data to become available if the stream buffer is
|
||||||
|
* empty. xStreamBufferReceive() will return immediately if xTicksToWait is
|
||||||
|
* zero. The block time is specified in tick periods, so the absolute time it
|
||||||
|
* represents is dependent on the tick frequency. The macro pdMS_TO_TICKS() can
|
||||||
|
* be used to convert a time specified in milliseconds into a time specified in
|
||||||
|
* ticks. Setting xTicksToWait to portMAX_DELAY will cause the task to wait
|
||||||
|
* indefinitely (without timing out), provided INCLUDE_vTaskSuspend is set to 1
|
||||||
|
* in FreeRTOSConfig.h. A task does not use any CPU time when it is in the
|
||||||
|
* Blocked state.
|
||||||
|
*
|
||||||
|
* @return The number of bytes actually read from the stream buffer, which will
|
||||||
|
* be less than xBufferLengthBytes if the call to xStreamBufferReceive() timed
|
||||||
|
* out before xBufferLengthBytes were available.
|
||||||
|
*
|
||||||
|
* Example use:
|
||||||
|
<pre>
|
||||||
|
void vAFunction( StreamBuffer_t xStreamBuffer )
|
||||||
|
{
|
||||||
|
uint8_t ucRxData[ 20 ];
|
||||||
|
size_t xReceivedBytes;
|
||||||
|
const TickType_t xBlockTime = pdMS_TO_TICKS( 20 );
|
||||||
|
|
||||||
|
// Receive up to another sizeof( ucRxData ) bytes from the stream buffer.
|
||||||
|
// Wait in the Blocked state (so not using any CPU processing time) for a
|
||||||
|
// maximum of 100ms for the full sizeof( ucRxData ) number of bytes to be
|
||||||
|
// available.
|
||||||
|
xReceivedBytes = xStreamBufferReceive( xStreamBuffer,
|
||||||
|
( void * ) ucRxData,
|
||||||
|
sizeof( ucRxData ),
|
||||||
|
xBlockTime );
|
||||||
|
|
||||||
|
if( xReceivedBytes > 0 )
|
||||||
|
{
|
||||||
|
// A ucRxData contains another xRecievedBytes bytes of data, which can
|
||||||
|
// be processed here....
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xStreamBufferReceive xStreamBufferReceive
|
||||||
|
* \ingroup StreamBufferManagement
|
||||||
|
*/
|
||||||
|
size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
|
||||||
|
void *pvRxData,
|
||||||
|
size_t xBufferLengthBytes,
|
||||||
|
TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stream_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
size_t xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer,
|
||||||
|
void *pvRxData,
|
||||||
|
size_t xBufferLengthBytes,
|
||||||
|
BaseType_t *pxHigherPriorityTaskWoken );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* An interrupt safe version of the API function that receives bytes from a
|
||||||
|
* stream buffer.
|
||||||
|
*
|
||||||
|
* Use xStreamBufferReceive() to read bytes from a stream buffer from a task.
|
||||||
|
* Use xStreamBufferReceiveFromISR() to read bytes from a stream buffer from an
|
||||||
|
* interrupt service routine (ISR).
|
||||||
|
*
|
||||||
|
* @param xStreamBuffer The handle of the stream buffer from which a stream
|
||||||
|
* is being received.
|
||||||
|
*
|
||||||
|
* @param pvRxData A pointer to the buffer into which the received bytes are
|
||||||
|
* copied.
|
||||||
|
*
|
||||||
|
* @param xBufferLengthBytes The length of the buffer pointed to by the
|
||||||
|
* pvRxData parameter. This sets the maximum number of bytes to receive in one
|
||||||
|
* call. xStreamBufferReceive will return as many bytes as possible up to a
|
||||||
|
* maximum set by xBufferLengthBytes.
|
||||||
|
*
|
||||||
|
* @param pxHigherPriorityTaskWoken It is possible that a stream buffer will
|
||||||
|
* have a task blocked on it waiting for space to become available. Calling
|
||||||
|
* xStreamBufferReceiveFromISR() can make space available, and so cause a task
|
||||||
|
* that is waiting for space to leave the Blocked state. If calling
|
||||||
|
* xStreamBufferReceiveFromISR() causes a task to leave the Blocked state, and
|
||||||
|
* the unblocked task has a priority higher than the currently executing task
|
||||||
|
* (the task that was interrupted), then, internally,
|
||||||
|
* xStreamBufferReceiveFromISR() will set *pxHigherPriorityTaskWoken to pdTRUE.
|
||||||
|
* If xStreamBufferReceiveFromISR() sets this value to pdTRUE, then normally a
|
||||||
|
* context switch should be performed before the interrupt is exited. That will
|
||||||
|
* ensure the interrupt returns directly to the highest priority Ready state
|
||||||
|
* task. *pxHigherPriorityTaskWoken should be set to pdFALSE before it is
|
||||||
|
* passed into the function. See the code example below for an example.
|
||||||
|
*
|
||||||
|
* @return The number of bytes read from the stream buffer, if any.
|
||||||
|
*
|
||||||
|
* Example use:
|
||||||
|
<pre>
|
||||||
|
// A stream buffer that has already been created.
|
||||||
|
StreamBuffer_t xStreamBuffer;
|
||||||
|
|
||||||
|
void vAnInterruptServiceRoutine( void )
|
||||||
|
{
|
||||||
|
uint8_t ucRxData[ 20 ];
|
||||||
|
size_t xReceivedBytes;
|
||||||
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE; // Initialised to pdFALSE.
|
||||||
|
|
||||||
|
// Receive the next stream from the stream buffer.
|
||||||
|
xReceivedBytes = xStreamBufferReceiveFromISR( xStreamBuffer,
|
||||||
|
( void * ) ucRxData,
|
||||||
|
sizeof( ucRxData ),
|
||||||
|
&xHigherPriorityTaskWoken );
|
||||||
|
|
||||||
|
if( xReceivedBytes > 0 )
|
||||||
|
{
|
||||||
|
// ucRxData contains xReceivedBytes read from the stream buffer.
|
||||||
|
// Process the stream here....
|
||||||
|
}
|
||||||
|
|
||||||
|
// If xHigherPriorityTaskWoken was set to pdTRUE inside
|
||||||
|
// xStreamBufferReceiveFromISR() then a task that has a priority above the
|
||||||
|
// priority of the currently executing task was unblocked and a context
|
||||||
|
// switch should be performed to ensure the ISR returns to the unblocked
|
||||||
|
// task. In most FreeRTOS ports this is done by simply passing
|
||||||
|
// xHigherPriorityTaskWoken into taskYIELD_FROM_ISR(), which will test the
|
||||||
|
// variables value, and perform the context switch if necessary. Check the
|
||||||
|
// documentation for the port in use for port specific instructions.
|
||||||
|
taskYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xStreamBufferReceiveFromISR xStreamBufferReceiveFromISR
|
||||||
|
* \ingroup StreamBufferManagement
|
||||||
|
*/
|
||||||
|
size_t xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer,
|
||||||
|
void *pvRxData,
|
||||||
|
size_t xBufferLengthBytes,
|
||||||
|
BaseType_t * const pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stream_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Deletes a stream buffer that was previously created using a call to
|
||||||
|
* xStreamBufferCreate() or xStreamBufferCreateStatic(). If the stream
|
||||||
|
* buffer was created using dynamic memory (that is, by xStreamBufferCreate()),
|
||||||
|
* then the allocated memory is freed.
|
||||||
|
*
|
||||||
|
* A stream buffer handle must not be used after the stream buffer has been
|
||||||
|
* deleted.
|
||||||
|
*
|
||||||
|
* @param xStreamBuffer The handle of the stream buffer to be deleted.
|
||||||
|
*
|
||||||
|
* \defgroup vStreamBufferDelete vStreamBufferDelete
|
||||||
|
* \ingroup StreamBufferManagement
|
||||||
|
*/
|
||||||
|
void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stream_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
BaseType_t xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Queries a stream buffer to see if it is full. A stream buffer is full if it
|
||||||
|
* does not have any free space, and therefore cannot accept any more data.
|
||||||
|
*
|
||||||
|
* @param xStreamBuffer The handle of the stream buffer being queried.
|
||||||
|
*
|
||||||
|
* @return If the stream buffer is full then pdTRUE is returned. Otherwise
|
||||||
|
* pdFALSE is returned.
|
||||||
|
*
|
||||||
|
* \defgroup xStreamBufferIsFull xStreamBufferIsFull
|
||||||
|
* \ingroup StreamBufferManagement
|
||||||
|
*/
|
||||||
|
BaseType_t xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stream_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
BaseType_t xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Queries a stream buffer to see if it is empty. A stream buffer is empty if
|
||||||
|
* it does not contain any data.
|
||||||
|
*
|
||||||
|
* @param xStreamBuffer The handle of the stream buffer being queried.
|
||||||
|
*
|
||||||
|
* @return If the stream buffer is empty then pdTRUE is returned. Otherwise
|
||||||
|
* pdFALSE is returned.
|
||||||
|
*
|
||||||
|
* \defgroup xStreamBufferIsEmpty xStreamBufferIsEmpty
|
||||||
|
* \ingroup StreamBufferManagement
|
||||||
|
*/
|
||||||
|
BaseType_t xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stream_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Resets a stream buffer to its initial, empty, state. Any data that was in
|
||||||
|
* the stream buffer is discarded. A stream buffer can only be reset if there
|
||||||
|
* are no tasks blocked waiting to either send to or receive from the stream
|
||||||
|
* buffer.
|
||||||
|
*
|
||||||
|
* @param xStreamBuffer The handle of the stream buffer being reset.
|
||||||
|
*
|
||||||
|
* @return If the stream buffer is reset then pdPASS is returned. If there was
|
||||||
|
* a task blocked waiting to send to or read from the stream buffer then the
|
||||||
|
* stream buffer is not reset and pdFAIL is returned.
|
||||||
|
*
|
||||||
|
* \defgroup xStreamBufferReset xStreamBufferReset
|
||||||
|
* \ingroup StreamBufferManagement
|
||||||
|
*/
|
||||||
|
BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stream_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Queries a stream buffer to see how much free space it contains, which is
|
||||||
|
* equal to the amount of data that can be sent to the stream buffer before it
|
||||||
|
* is full.
|
||||||
|
*
|
||||||
|
* @param xStreamBuffer The handle of the stream buffer being queried.
|
||||||
|
*
|
||||||
|
* @return The number of bytes that can be written to the stream buffer before
|
||||||
|
* the stream buffer would be full.
|
||||||
|
*
|
||||||
|
* \defgroup xStreamBufferSpacesAvailable xStreamBufferSpacesAvailable
|
||||||
|
* \ingroup StreamBufferManagement
|
||||||
|
*/
|
||||||
|
size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stream_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* Queries a stream buffer to see how much data it contains, which is equal to
|
||||||
|
* the number of bytes that can be read from the stream buffer before the stream
|
||||||
|
* buffer would be empty.
|
||||||
|
*
|
||||||
|
* @param xStreamBuffer The handle of the stream buffer being queried.
|
||||||
|
*
|
||||||
|
* @return The number of bytes that can be read from the stream buffer before
|
||||||
|
* the stream buffer would be empty.
|
||||||
|
*
|
||||||
|
* \defgroup xStreamBufferBytesAvailable xStreamBufferBytesAvailable
|
||||||
|
* \ingroup StreamBufferManagement
|
||||||
|
*/
|
||||||
|
size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stream_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, size_t xTriggerLevel );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* A stream buffer's trigger level is the number of bytes that must be in the
|
||||||
|
* stream buffer before a task that is blocked on the stream buffer to
|
||||||
|
* wait for data is moved out of the blocked state. For example, if a task is
|
||||||
|
* blocked on a read of an empty stream buffer that has a trigger level of 1
|
||||||
|
* then the task will be unblocked when a single byte is written to the buffer
|
||||||
|
* or the task's block time expires. As another example, if a task is blocked
|
||||||
|
* on a read of an empty stream buffer that has a trigger level of 10 then the
|
||||||
|
* task will not be unblocked until the stream buffer contains at least 10 bytes
|
||||||
|
* or the task's block time expires. If a reading task's block time expires
|
||||||
|
* before the trigger level is reached then the task will still receive however
|
||||||
|
* many bytes are actually available. Setting a trigger level of 0 will result
|
||||||
|
* in a trigger level of 1 being used. It is not valid to specify a trigger
|
||||||
|
* level that is greater than the buffer size.
|
||||||
|
*
|
||||||
|
* A trigger level is set when the stream buffer is created, and can be modified
|
||||||
|
* using xStreamBufferSetTriggerLevel().
|
||||||
|
*
|
||||||
|
* @param xStreamBuffer The handle of the stream buffer being updated.
|
||||||
|
*
|
||||||
|
* @param xTriggerLevel The new trigger level for the stream buffer.
|
||||||
|
*
|
||||||
|
* @return If xTriggerLevel was less than or equal to the stream buffer's length
|
||||||
|
* then the trigger level will be updated and pdTRUE is returned. Otherwise
|
||||||
|
* pdFALSE is returned.
|
||||||
|
*
|
||||||
|
* \defgroup xStreamBufferSetTriggerLevel xStreamBufferSetTriggerLevel
|
||||||
|
* \ingroup StreamBufferManagement
|
||||||
|
*/
|
||||||
|
BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, size_t xTriggerLevel ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stream_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* For advanced users only.
|
||||||
|
*
|
||||||
|
* The sbSEND_COMPLETED() macro is called from within the FreeRTOS APIs when
|
||||||
|
* data is sent to a message buffer or stream buffer. If there was a task that
|
||||||
|
* was blocked on the message or stream buffer waiting for data to arrive then
|
||||||
|
* the sbSEND_COMPLETED() macro sends a notification to the task to remove it
|
||||||
|
* from the Blocked state. xStreamBufferSendCompletedFromISR() does the same
|
||||||
|
* thing. It is provided to enable application writers to implement their own
|
||||||
|
* version of sbSEND_COMPLETED(), and MUST NOT BE USED AT ANY OTHER TIME.
|
||||||
|
*
|
||||||
|
* See the example implemented in FreeRTOS/Demo/Minimal/MessageBufferAMP.c for
|
||||||
|
* additional information.
|
||||||
|
*
|
||||||
|
* @param xStreamBuffer The handle of the stream buffer to which data was
|
||||||
|
* written.
|
||||||
|
*
|
||||||
|
* @param pxHigherPriorityTaskWoken *pxHigherPriorityTaskWoken should be
|
||||||
|
* initialised to pdFALSE before it is passed into
|
||||||
|
* xStreamBufferSendCompletedFromISR(). If calling
|
||||||
|
* xStreamBufferSendCompletedFromISR() removes a task from the Blocked state,
|
||||||
|
* and the task has a priority above the priority of the currently running task,
|
||||||
|
* then *pxHigherPriorityTaskWoken will get set to pdTRUE indicating that a
|
||||||
|
* context switch should be performed before exiting the ISR.
|
||||||
|
*
|
||||||
|
* @return If a task was removed from the Blocked state then pdTRUE is returned.
|
||||||
|
* Otherwise pdFALSE is returned.
|
||||||
|
*
|
||||||
|
* \defgroup xStreamBufferSendCompletedFromISR xStreamBufferSendCompletedFromISR
|
||||||
|
* \ingroup StreamBufferManagement
|
||||||
|
*/
|
||||||
|
BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stream_buffer.h
|
||||||
|
*
|
||||||
|
<pre>
|
||||||
|
BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken );
|
||||||
|
</pre>
|
||||||
|
*
|
||||||
|
* For advanced users only.
|
||||||
|
*
|
||||||
|
* The sbRECEIVE_COMPLETED() macro is called from within the FreeRTOS APIs when
|
||||||
|
* data is read out of a message buffer or stream buffer. If there was a task
|
||||||
|
* that was blocked on the message or stream buffer waiting for data to arrive
|
||||||
|
* then the sbRECEIVE_COMPLETED() macro sends a notification to the task to
|
||||||
|
* remove it from the Blocked state. xStreamBufferReceiveCompletedFromISR()
|
||||||
|
* does the same thing. It is provided to enable application writers to
|
||||||
|
* implement their own version of sbRECEIVE_COMPLETED(), and MUST NOT BE USED AT
|
||||||
|
* ANY OTHER TIME.
|
||||||
|
*
|
||||||
|
* See the example implemented in FreeRTOS/Demo/Minimal/MessageBufferAMP.c for
|
||||||
|
* additional information.
|
||||||
|
*
|
||||||
|
* @param xStreamBuffer The handle of the stream buffer from which data was
|
||||||
|
* read.
|
||||||
|
*
|
||||||
|
* @param pxHigherPriorityTaskWoken *pxHigherPriorityTaskWoken should be
|
||||||
|
* initialised to pdFALSE before it is passed into
|
||||||
|
* xStreamBufferReceiveCompletedFromISR(). If calling
|
||||||
|
* xStreamBufferReceiveCompletedFromISR() removes a task from the Blocked state,
|
||||||
|
* and the task has a priority above the priority of the currently running task,
|
||||||
|
* then *pxHigherPriorityTaskWoken will get set to pdTRUE indicating that a
|
||||||
|
* context switch should be performed before exiting the ISR.
|
||||||
|
*
|
||||||
|
* @return If a task was removed from the Blocked state then pdTRUE is returned.
|
||||||
|
* Otherwise pdFALSE is returned.
|
||||||
|
*
|
||||||
|
* \defgroup xStreamBufferReceiveCompletedFromISR xStreamBufferReceiveCompletedFromISR
|
||||||
|
* \ingroup StreamBufferManagement
|
||||||
|
*/
|
||||||
|
BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/* Functions below here are not part of the public API. */
|
||||||
|
StreamBufferHandle_t xStreamBufferGenericCreate( size_t xBufferSizeBytes,
|
||||||
|
size_t xTriggerLevelBytes,
|
||||||
|
BaseType_t xIsMessageBuffer ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
StreamBufferHandle_t xStreamBufferGenericCreateStatic( size_t xBufferSizeBytes,
|
||||||
|
size_t xTriggerLevelBytes,
|
||||||
|
BaseType_t xIsMessageBuffer,
|
||||||
|
uint8_t * const pucStreamBufferStorageArea,
|
||||||
|
StaticStreamBuffer_t * const pxStaticStreamBuffer ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
size_t xStreamBufferNextMessageLengthBytes( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
#if( configUSE_TRACE_FACILITY == 1 )
|
||||||
|
void vStreamBufferSetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer, UBaseType_t uxStreamBufferNumber ) PRIVILEGED_FUNCTION;
|
||||||
|
UBaseType_t uxStreamBufferGetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
|
||||||
|
uint8_t ucStreamBufferGetStreamBufferType( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined( __cplusplus )
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !defined( STREAM_BUFFER_H ) */
|
||||||
2543
Middlewares/Third_Party/FreeRTOS/Source/include/task.h
vendored
Normal file
2543
Middlewares/Third_Party/FreeRTOS/Source/include/task.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1309
Middlewares/Third_Party/FreeRTOS/Source/include/timers.h
vendored
Normal file
1309
Middlewares/Third_Party/FreeRTOS/Source/include/timers.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
198
Middlewares/Third_Party/FreeRTOS/Source/list.c
vendored
Normal file
198
Middlewares/Third_Party/FreeRTOS/Source/list.c
vendored
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
* FreeRTOS Kernel V10.3.1
|
||||||
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org
|
||||||
|
* http://aws.amazon.com/freertos
|
||||||
|
*
|
||||||
|
* 1 tab == 4 spaces!
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------
|
||||||
|
* PUBLIC LIST API documented in list.h
|
||||||
|
*----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vListInitialise( List_t * const pxList )
|
||||||
|
{
|
||||||
|
/* The list structure contains a list item which is used to mark the
|
||||||
|
end of the list. To initialise the list the list end is inserted
|
||||||
|
as the only list entry. */
|
||||||
|
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */
|
||||||
|
|
||||||
|
/* The list end value is the highest possible value in the list to
|
||||||
|
ensure it remains at the end of the list. */
|
||||||
|
pxList->xListEnd.xItemValue = portMAX_DELAY;
|
||||||
|
|
||||||
|
/* The list end next and previous pointers point to itself so we know
|
||||||
|
when the list is empty. */
|
||||||
|
pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */
|
||||||
|
pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );/*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */
|
||||||
|
|
||||||
|
pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
|
||||||
|
|
||||||
|
/* Write known values into the list if
|
||||||
|
configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||||
|
listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
|
||||||
|
listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vListInitialiseItem( ListItem_t * const pxItem )
|
||||||
|
{
|
||||||
|
/* Make sure the list item is not recorded as being on a list. */
|
||||||
|
pxItem->pxContainer = NULL;
|
||||||
|
|
||||||
|
/* Write known values into the list item if
|
||||||
|
configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||||
|
listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
|
||||||
|
listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
|
||||||
|
{
|
||||||
|
ListItem_t * const pxIndex = pxList->pxIndex;
|
||||||
|
|
||||||
|
/* Only effective when configASSERT() is also defined, these tests may catch
|
||||||
|
the list data structures being overwritten in memory. They will not catch
|
||||||
|
data errors caused by incorrect configuration or use of FreeRTOS. */
|
||||||
|
listTEST_LIST_INTEGRITY( pxList );
|
||||||
|
listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
|
||||||
|
|
||||||
|
/* Insert a new list item into pxList, but rather than sort the list,
|
||||||
|
makes the new list item the last item to be removed by a call to
|
||||||
|
listGET_OWNER_OF_NEXT_ENTRY(). */
|
||||||
|
pxNewListItem->pxNext = pxIndex;
|
||||||
|
pxNewListItem->pxPrevious = pxIndex->pxPrevious;
|
||||||
|
|
||||||
|
/* Only used during decision coverage testing. */
|
||||||
|
mtCOVERAGE_TEST_DELAY();
|
||||||
|
|
||||||
|
pxIndex->pxPrevious->pxNext = pxNewListItem;
|
||||||
|
pxIndex->pxPrevious = pxNewListItem;
|
||||||
|
|
||||||
|
/* Remember which list the item is in. */
|
||||||
|
pxNewListItem->pxContainer = pxList;
|
||||||
|
|
||||||
|
( pxList->uxNumberOfItems )++;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
|
||||||
|
{
|
||||||
|
ListItem_t *pxIterator;
|
||||||
|
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
|
||||||
|
|
||||||
|
/* Only effective when configASSERT() is also defined, these tests may catch
|
||||||
|
the list data structures being overwritten in memory. They will not catch
|
||||||
|
data errors caused by incorrect configuration or use of FreeRTOS. */
|
||||||
|
listTEST_LIST_INTEGRITY( pxList );
|
||||||
|
listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
|
||||||
|
|
||||||
|
/* Insert the new list item into the list, sorted in xItemValue order.
|
||||||
|
|
||||||
|
If the list already contains a list item with the same item value then the
|
||||||
|
new list item should be placed after it. This ensures that TCBs which are
|
||||||
|
stored in ready lists (all of which have the same xItemValue value) get a
|
||||||
|
share of the CPU. However, if the xItemValue is the same as the back marker
|
||||||
|
the iteration loop below will not end. Therefore the value is checked
|
||||||
|
first, and the algorithm slightly modified if necessary. */
|
||||||
|
if( xValueOfInsertion == portMAX_DELAY )
|
||||||
|
{
|
||||||
|
pxIterator = pxList->xListEnd.pxPrevious;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* *** NOTE ***********************************************************
|
||||||
|
If you find your application is crashing here then likely causes are
|
||||||
|
listed below. In addition see https://www.freertos.org/FAQHelp.html for
|
||||||
|
more tips, and ensure configASSERT() is defined!
|
||||||
|
https://www.freertos.org/a00110.html#configASSERT
|
||||||
|
|
||||||
|
1) Stack overflow -
|
||||||
|
see https://www.freertos.org/Stacks-and-stack-overflow-checking.html
|
||||||
|
2) Incorrect interrupt priority assignment, especially on Cortex-M
|
||||||
|
parts where numerically high priority values denote low actual
|
||||||
|
interrupt priorities, which can seem counter intuitive. See
|
||||||
|
https://www.freertos.org/RTOS-Cortex-M3-M4.html and the definition
|
||||||
|
of configMAX_SYSCALL_INTERRUPT_PRIORITY on
|
||||||
|
https://www.freertos.org/a00110.html
|
||||||
|
3) Calling an API function from within a critical section or when
|
||||||
|
the scheduler is suspended, or calling an API function that does
|
||||||
|
not end in "FromISR" from an interrupt.
|
||||||
|
4) Using a queue or semaphore before it has been initialised or
|
||||||
|
before the scheduler has been started (are interrupts firing
|
||||||
|
before vTaskStartScheduler() has been called?).
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. *//*lint !e440 The iterator moves to a different value, not xValueOfInsertion. */
|
||||||
|
{
|
||||||
|
/* There is nothing to do here, just iterating to the wanted
|
||||||
|
insertion position. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pxNewListItem->pxNext = pxIterator->pxNext;
|
||||||
|
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
|
||||||
|
pxNewListItem->pxPrevious = pxIterator;
|
||||||
|
pxIterator->pxNext = pxNewListItem;
|
||||||
|
|
||||||
|
/* Remember which list the item is in. This allows fast removal of the
|
||||||
|
item later. */
|
||||||
|
pxNewListItem->pxContainer = pxList;
|
||||||
|
|
||||||
|
( pxList->uxNumberOfItems )++;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
|
||||||
|
{
|
||||||
|
/* The list item knows which list it is in. Obtain the list from the list
|
||||||
|
item. */
|
||||||
|
List_t * const pxList = pxItemToRemove->pxContainer;
|
||||||
|
|
||||||
|
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
|
||||||
|
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
|
||||||
|
|
||||||
|
/* Only used during decision coverage testing. */
|
||||||
|
mtCOVERAGE_TEST_DELAY();
|
||||||
|
|
||||||
|
/* Make sure the index is left pointing to a valid item. */
|
||||||
|
if( pxList->pxIndex == pxItemToRemove )
|
||||||
|
{
|
||||||
|
pxList->pxIndex = pxItemToRemove->pxPrevious;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
|
||||||
|
pxItemToRemove->pxContainer = NULL;
|
||||||
|
( pxList->uxNumberOfItems )--;
|
||||||
|
|
||||||
|
return pxList->uxNumberOfItems;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
492
Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c
vendored
Normal file
492
Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c
vendored
Normal file
@@ -0,0 +1,492 @@
|
|||||||
|
/*
|
||||||
|
* FreeRTOS Kernel V10.3.1
|
||||||
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org
|
||||||
|
* http://aws.amazon.com/freertos
|
||||||
|
*
|
||||||
|
* 1 tab == 4 spaces!
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A sample implementation of pvPortMalloc() and vPortFree() that combines
|
||||||
|
* (coalescences) adjacent memory blocks as they are freed, and in so doing
|
||||||
|
* limits memory fragmentation.
|
||||||
|
*
|
||||||
|
* See heap_1.c, heap_2.c and heap_3.c for alternative implementations, and the
|
||||||
|
* memory management pages of http://www.FreeRTOS.org for more information.
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
|
||||||
|
all the API functions to use the MPU wrappers. That should only be done when
|
||||||
|
task.h is included from an application file. */
|
||||||
|
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
|
||||||
|
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||||
|
|
||||||
|
#if( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
|
||||||
|
#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Block sizes must not get too small. */
|
||||||
|
#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( xHeapStructSize << 1 ) )
|
||||||
|
|
||||||
|
/* Assumes 8bit bytes! */
|
||||||
|
#define heapBITS_PER_BYTE ( ( size_t ) 8 )
|
||||||
|
|
||||||
|
/* Allocate the memory for the heap. */
|
||||||
|
#if( configAPPLICATION_ALLOCATED_HEAP == 1 )
|
||||||
|
/* The application writer has already defined the array used for the RTOS
|
||||||
|
heap - probably so it can be placed in a special segment or address. */
|
||||||
|
extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
|
||||||
|
#else
|
||||||
|
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
|
||||||
|
#endif /* configAPPLICATION_ALLOCATED_HEAP */
|
||||||
|
|
||||||
|
/* Define the linked list structure. This is used to link free blocks in order
|
||||||
|
of their memory address. */
|
||||||
|
typedef struct A_BLOCK_LINK
|
||||||
|
{
|
||||||
|
struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */
|
||||||
|
size_t xBlockSize; /*<< The size of the free block. */
|
||||||
|
} BlockLink_t;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inserts a block of memory that is being freed into the correct position in
|
||||||
|
* the list of free memory blocks. The block being freed will be merged with
|
||||||
|
* the block in front it and/or the block behind it if the memory blocks are
|
||||||
|
* adjacent to each other.
|
||||||
|
*/
|
||||||
|
static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called automatically to setup the required heap structures the first time
|
||||||
|
* pvPortMalloc() is called.
|
||||||
|
*/
|
||||||
|
static void prvHeapInit( void );
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* The size of the structure placed at the beginning of each allocated memory
|
||||||
|
block must by correctly byte aligned. */
|
||||||
|
static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
|
||||||
|
|
||||||
|
/* Create a couple of list links to mark the start and end of the list. */
|
||||||
|
static BlockLink_t xStart, *pxEnd = NULL;
|
||||||
|
|
||||||
|
/* Keeps track of the number of calls to allocate and free memory as well as the
|
||||||
|
number of free bytes remaining, but says nothing about fragmentation. */
|
||||||
|
static size_t xFreeBytesRemaining = 0U;
|
||||||
|
static size_t xMinimumEverFreeBytesRemaining = 0U;
|
||||||
|
static size_t xNumberOfSuccessfulAllocations = 0;
|
||||||
|
static size_t xNumberOfSuccessfulFrees = 0;
|
||||||
|
|
||||||
|
/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize
|
||||||
|
member of an BlockLink_t structure is set then the block belongs to the
|
||||||
|
application. When the bit is free the block is still part of the free heap
|
||||||
|
space. */
|
||||||
|
static size_t xBlockAllocatedBit = 0;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void *pvPortMalloc( size_t xWantedSize )
|
||||||
|
{
|
||||||
|
BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
|
||||||
|
void *pvReturn = NULL;
|
||||||
|
|
||||||
|
vTaskSuspendAll();
|
||||||
|
{
|
||||||
|
/* If this is the first call to malloc then the heap will require
|
||||||
|
initialisation to setup the list of free blocks. */
|
||||||
|
if( pxEnd == NULL )
|
||||||
|
{
|
||||||
|
prvHeapInit();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the requested block size is not so large that the top bit is
|
||||||
|
set. The top bit of the block size member of the BlockLink_t structure
|
||||||
|
is used to determine who owns the block - the application or the
|
||||||
|
kernel, so it must be free. */
|
||||||
|
if( ( xWantedSize & xBlockAllocatedBit ) == 0 )
|
||||||
|
{
|
||||||
|
/* The wanted size is increased so it can contain a BlockLink_t
|
||||||
|
structure in addition to the requested amount of bytes. */
|
||||||
|
if( xWantedSize > 0 )
|
||||||
|
{
|
||||||
|
xWantedSize += xHeapStructSize;
|
||||||
|
|
||||||
|
/* Ensure that blocks are always aligned to the required number
|
||||||
|
of bytes. */
|
||||||
|
if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
|
||||||
|
{
|
||||||
|
/* Byte alignment required. */
|
||||||
|
xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
|
||||||
|
configASSERT( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) == 0 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
|
||||||
|
{
|
||||||
|
/* Traverse the list from the start (lowest address) block until
|
||||||
|
one of adequate size is found. */
|
||||||
|
pxPreviousBlock = &xStart;
|
||||||
|
pxBlock = xStart.pxNextFreeBlock;
|
||||||
|
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
|
||||||
|
{
|
||||||
|
pxPreviousBlock = pxBlock;
|
||||||
|
pxBlock = pxBlock->pxNextFreeBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the end marker was reached then a block of adequate size
|
||||||
|
was not found. */
|
||||||
|
if( pxBlock != pxEnd )
|
||||||
|
{
|
||||||
|
/* Return the memory space pointed to - jumping over the
|
||||||
|
BlockLink_t structure at its start. */
|
||||||
|
pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );
|
||||||
|
|
||||||
|
/* This block is being returned for use so must be taken out
|
||||||
|
of the list of free blocks. */
|
||||||
|
pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
|
||||||
|
|
||||||
|
/* If the block is larger than required it can be split into
|
||||||
|
two. */
|
||||||
|
if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
|
||||||
|
{
|
||||||
|
/* This block is to be split into two. Create a new
|
||||||
|
block following the number of bytes requested. The void
|
||||||
|
cast is used to prevent byte alignment warnings from the
|
||||||
|
compiler. */
|
||||||
|
pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );
|
||||||
|
configASSERT( ( ( ( size_t ) pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );
|
||||||
|
|
||||||
|
/* Calculate the sizes of two blocks split from the
|
||||||
|
single block. */
|
||||||
|
pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
|
||||||
|
pxBlock->xBlockSize = xWantedSize;
|
||||||
|
|
||||||
|
/* Insert the new block into the list of free blocks. */
|
||||||
|
prvInsertBlockIntoFreeList( pxNewBlockLink );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
|
||||||
|
xFreeBytesRemaining -= pxBlock->xBlockSize;
|
||||||
|
|
||||||
|
if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
|
||||||
|
{
|
||||||
|
xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The block is being returned - it is allocated and owned
|
||||||
|
by the application and has no "next" block. */
|
||||||
|
pxBlock->xBlockSize |= xBlockAllocatedBit;
|
||||||
|
pxBlock->pxNextFreeBlock = NULL;
|
||||||
|
xNumberOfSuccessfulAllocations++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
|
||||||
|
traceMALLOC( pvReturn, xWantedSize );
|
||||||
|
}
|
||||||
|
( void ) xTaskResumeAll();
|
||||||
|
|
||||||
|
#if( configUSE_MALLOC_FAILED_HOOK == 1 )
|
||||||
|
{
|
||||||
|
if( pvReturn == NULL )
|
||||||
|
{
|
||||||
|
extern void vApplicationMallocFailedHook( void );
|
||||||
|
vApplicationMallocFailedHook();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
configASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) portBYTE_ALIGNMENT_MASK ) == 0 );
|
||||||
|
return pvReturn;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortFree( void *pv )
|
||||||
|
{
|
||||||
|
uint8_t *puc = ( uint8_t * ) pv;
|
||||||
|
BlockLink_t *pxLink;
|
||||||
|
|
||||||
|
if( pv != NULL )
|
||||||
|
{
|
||||||
|
/* The memory being freed will have an BlockLink_t structure immediately
|
||||||
|
before it. */
|
||||||
|
puc -= xHeapStructSize;
|
||||||
|
|
||||||
|
/* This casting is to keep the compiler from issuing warnings. */
|
||||||
|
pxLink = ( void * ) puc;
|
||||||
|
|
||||||
|
/* Check the block is actually allocated. */
|
||||||
|
configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );
|
||||||
|
configASSERT( pxLink->pxNextFreeBlock == NULL );
|
||||||
|
|
||||||
|
if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )
|
||||||
|
{
|
||||||
|
if( pxLink->pxNextFreeBlock == NULL )
|
||||||
|
{
|
||||||
|
/* The block is being returned to the heap - it is no longer
|
||||||
|
allocated. */
|
||||||
|
pxLink->xBlockSize &= ~xBlockAllocatedBit;
|
||||||
|
|
||||||
|
vTaskSuspendAll();
|
||||||
|
{
|
||||||
|
/* Add this block to the list of free blocks. */
|
||||||
|
xFreeBytesRemaining += pxLink->xBlockSize;
|
||||||
|
traceFREE( pv, pxLink->xBlockSize );
|
||||||
|
prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
|
||||||
|
xNumberOfSuccessfulFrees++;
|
||||||
|
}
|
||||||
|
( void ) xTaskResumeAll();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
size_t xPortGetFreeHeapSize( void )
|
||||||
|
{
|
||||||
|
return xFreeBytesRemaining;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
size_t xPortGetMinimumEverFreeHeapSize( void )
|
||||||
|
{
|
||||||
|
return xMinimumEverFreeBytesRemaining;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortInitialiseBlocks( void )
|
||||||
|
{
|
||||||
|
/* This just exists to keep the linker quiet. */
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static void prvHeapInit( void )
|
||||||
|
{
|
||||||
|
BlockLink_t *pxFirstFreeBlock;
|
||||||
|
uint8_t *pucAlignedHeap;
|
||||||
|
size_t uxAddress;
|
||||||
|
size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;
|
||||||
|
|
||||||
|
/* Ensure the heap starts on a correctly aligned boundary. */
|
||||||
|
uxAddress = ( size_t ) ucHeap;
|
||||||
|
|
||||||
|
if( ( uxAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
|
||||||
|
{
|
||||||
|
uxAddress += ( portBYTE_ALIGNMENT - 1 );
|
||||||
|
uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
|
||||||
|
xTotalHeapSize -= uxAddress - ( size_t ) ucHeap;
|
||||||
|
}
|
||||||
|
|
||||||
|
pucAlignedHeap = ( uint8_t * ) uxAddress;
|
||||||
|
|
||||||
|
/* xStart is used to hold a pointer to the first item in the list of free
|
||||||
|
blocks. The void cast is used to prevent compiler warnings. */
|
||||||
|
xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap;
|
||||||
|
xStart.xBlockSize = ( size_t ) 0;
|
||||||
|
|
||||||
|
/* pxEnd is used to mark the end of the list of free blocks and is inserted
|
||||||
|
at the end of the heap space. */
|
||||||
|
uxAddress = ( ( size_t ) pucAlignedHeap ) + xTotalHeapSize;
|
||||||
|
uxAddress -= xHeapStructSize;
|
||||||
|
uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
|
||||||
|
pxEnd = ( void * ) uxAddress;
|
||||||
|
pxEnd->xBlockSize = 0;
|
||||||
|
pxEnd->pxNextFreeBlock = NULL;
|
||||||
|
|
||||||
|
/* To start with there is a single free block that is sized to take up the
|
||||||
|
entire heap space, minus the space taken by pxEnd. */
|
||||||
|
pxFirstFreeBlock = ( void * ) pucAlignedHeap;
|
||||||
|
pxFirstFreeBlock->xBlockSize = uxAddress - ( size_t ) pxFirstFreeBlock;
|
||||||
|
pxFirstFreeBlock->pxNextFreeBlock = pxEnd;
|
||||||
|
|
||||||
|
/* Only one block exists - and it covers the entire usable heap space. */
|
||||||
|
xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
|
||||||
|
xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
|
||||||
|
|
||||||
|
/* Work out the position of the top bit in a size_t variable. */
|
||||||
|
xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert )
|
||||||
|
{
|
||||||
|
BlockLink_t *pxIterator;
|
||||||
|
uint8_t *puc;
|
||||||
|
|
||||||
|
/* Iterate through the list until a block is found that has a higher address
|
||||||
|
than the block being inserted. */
|
||||||
|
for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )
|
||||||
|
{
|
||||||
|
/* Nothing to do here, just iterate to the right position. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do the block being inserted, and the block it is being inserted after
|
||||||
|
make a contiguous block of memory? */
|
||||||
|
puc = ( uint8_t * ) pxIterator;
|
||||||
|
if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )
|
||||||
|
{
|
||||||
|
pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
|
||||||
|
pxBlockToInsert = pxIterator;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do the block being inserted, and the block it is being inserted before
|
||||||
|
make a contiguous block of memory? */
|
||||||
|
puc = ( uint8_t * ) pxBlockToInsert;
|
||||||
|
if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )
|
||||||
|
{
|
||||||
|
if( pxIterator->pxNextFreeBlock != pxEnd )
|
||||||
|
{
|
||||||
|
/* Form one big block from the two blocks. */
|
||||||
|
pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
|
||||||
|
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pxBlockToInsert->pxNextFreeBlock = pxEnd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the block being inserted plugged a gab, so was merged with the block
|
||||||
|
before and the block after, then it's pxNextFreeBlock pointer will have
|
||||||
|
already been set, and should not be set here as that would make it point
|
||||||
|
to itself. */
|
||||||
|
if( pxIterator != pxBlockToInsert )
|
||||||
|
{
|
||||||
|
pxIterator->pxNextFreeBlock = pxBlockToInsert;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortGetHeapStats( HeapStats_t *pxHeapStats )
|
||||||
|
{
|
||||||
|
BlockLink_t *pxBlock;
|
||||||
|
size_t xBlocks = 0, xMaxSize = 0, xMinSize = portMAX_DELAY; /* portMAX_DELAY used as a portable way of getting the maximum value. */
|
||||||
|
|
||||||
|
vTaskSuspendAll();
|
||||||
|
{
|
||||||
|
pxBlock = xStart.pxNextFreeBlock;
|
||||||
|
|
||||||
|
/* pxBlock will be NULL if the heap has not been initialised. The heap
|
||||||
|
is initialised automatically when the first allocation is made. */
|
||||||
|
if( pxBlock != NULL )
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* Increment the number of blocks and record the largest block seen
|
||||||
|
so far. */
|
||||||
|
xBlocks++;
|
||||||
|
|
||||||
|
if( pxBlock->xBlockSize > xMaxSize )
|
||||||
|
{
|
||||||
|
xMaxSize = pxBlock->xBlockSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( pxBlock->xBlockSize < xMinSize )
|
||||||
|
{
|
||||||
|
xMinSize = pxBlock->xBlockSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move to the next block in the chain until the last block is
|
||||||
|
reached. */
|
||||||
|
pxBlock = pxBlock->pxNextFreeBlock;
|
||||||
|
} while( pxBlock != pxEnd );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xTaskResumeAll();
|
||||||
|
|
||||||
|
pxHeapStats->xSizeOfLargestFreeBlockInBytes = xMaxSize;
|
||||||
|
pxHeapStats->xSizeOfSmallestFreeBlockInBytes = xMinSize;
|
||||||
|
pxHeapStats->xNumberOfFreeBlocks = xBlocks;
|
||||||
|
|
||||||
|
taskENTER_CRITICAL();
|
||||||
|
{
|
||||||
|
pxHeapStats->xAvailableHeapSpaceInBytes = xFreeBytesRemaining;
|
||||||
|
pxHeapStats->xNumberOfSuccessfulAllocations = xNumberOfSuccessfulAllocations;
|
||||||
|
pxHeapStats->xNumberOfSuccessfulFrees = xNumberOfSuccessfulFrees;
|
||||||
|
pxHeapStats->xMinimumEverFreeBytesRemaining = xMinimumEverFreeBytesRemaining;
|
||||||
|
}
|
||||||
|
taskEXIT_CRITICAL();
|
||||||
|
}
|
||||||
|
|
||||||
788
Middlewares/Third_Party/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c
vendored
Normal file
788
Middlewares/Third_Party/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c
vendored
Normal file
@@ -0,0 +1,788 @@
|
|||||||
|
/*
|
||||||
|
* FreeRTOS Kernel V10.3.1
|
||||||
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org
|
||||||
|
* http://aws.amazon.com/freertos
|
||||||
|
*
|
||||||
|
* 1 tab == 4 spaces!
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------
|
||||||
|
* Implementation of functions defined in portable.h for the ARM CM4F port.
|
||||||
|
*----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Scheduler includes. */
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
|
||||||
|
#ifndef __TARGET_FPU_VFP
|
||||||
|
#error This port can only be used when the project options are configured to enable hardware floating point support.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if configMAX_SYSCALL_INTERRUPT_PRIORITY == 0
|
||||||
|
#error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef configSYSTICK_CLOCK_HZ
|
||||||
|
#define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ
|
||||||
|
/* Ensure the SysTick is clocked at the same frequency as the core. */
|
||||||
|
#define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL )
|
||||||
|
#else
|
||||||
|
/* The way the SysTick is clocked is not modified in case it is not the same
|
||||||
|
as the core. */
|
||||||
|
#define portNVIC_SYSTICK_CLK_BIT ( 0 )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Legacy macro for backward compatibility only. This macro used to be used to
|
||||||
|
replace the function that configures the clock used to generate the tick
|
||||||
|
interrupt (prvSetupTimerInterrupt()), but now the function is declared weak so
|
||||||
|
the application writer can override it by simply defining a function of the
|
||||||
|
same name (vApplicationSetupTickInterrupt()). */
|
||||||
|
#ifndef configOVERRIDE_DEFAULT_TICK_CONFIGURATION
|
||||||
|
#define configOVERRIDE_DEFAULT_TICK_CONFIGURATION 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Constants required to manipulate the core. Registers first... */
|
||||||
|
#define portNVIC_SYSTICK_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000e010 ) )
|
||||||
|
#define portNVIC_SYSTICK_LOAD_REG ( * ( ( volatile uint32_t * ) 0xe000e014 ) )
|
||||||
|
#define portNVIC_SYSTICK_CURRENT_VALUE_REG ( * ( ( volatile uint32_t * ) 0xe000e018 ) )
|
||||||
|
#define portNVIC_SYSPRI2_REG ( * ( ( volatile uint32_t * ) 0xe000ed20 ) )
|
||||||
|
/* ...then bits in the registers. */
|
||||||
|
#define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL )
|
||||||
|
#define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL )
|
||||||
|
#define portNVIC_SYSTICK_COUNT_FLAG_BIT ( 1UL << 16UL )
|
||||||
|
#define portNVIC_PENDSVCLEAR_BIT ( 1UL << 27UL )
|
||||||
|
#define portNVIC_PEND_SYSTICK_CLEAR_BIT ( 1UL << 25UL )
|
||||||
|
|
||||||
|
/* Constants used to detect a Cortex-M7 r0p1 core, which should use the ARM_CM7
|
||||||
|
r0p1 port. */
|
||||||
|
#define portCPUID ( * ( ( volatile uint32_t * ) 0xE000ed00 ) )
|
||||||
|
#define portCORTEX_M7_r0p1_ID ( 0x410FC271UL )
|
||||||
|
#define portCORTEX_M7_r0p0_ID ( 0x410FC270UL )
|
||||||
|
|
||||||
|
#define portNVIC_PENDSV_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )
|
||||||
|
#define portNVIC_SYSTICK_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )
|
||||||
|
|
||||||
|
/* Constants required to check the validity of an interrupt priority. */
|
||||||
|
#define portFIRST_USER_INTERRUPT_NUMBER ( 16 )
|
||||||
|
#define portNVIC_IP_REGISTERS_OFFSET_16 ( 0xE000E3F0 )
|
||||||
|
#define portAIRCR_REG ( * ( ( volatile uint32_t * ) 0xE000ED0C ) )
|
||||||
|
#define portMAX_8_BIT_VALUE ( ( uint8_t ) 0xff )
|
||||||
|
#define portTOP_BIT_OF_BYTE ( ( uint8_t ) 0x80 )
|
||||||
|
#define portMAX_PRIGROUP_BITS ( ( uint8_t ) 7 )
|
||||||
|
#define portPRIORITY_GROUP_MASK ( 0x07UL << 8UL )
|
||||||
|
#define portPRIGROUP_SHIFT ( 8UL )
|
||||||
|
|
||||||
|
/* Masks off all bits but the VECTACTIVE bits in the ICSR register. */
|
||||||
|
#define portVECTACTIVE_MASK ( 0xFFUL )
|
||||||
|
|
||||||
|
/* Constants required to manipulate the VFP. */
|
||||||
|
#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating point context control register. */
|
||||||
|
#define portASPEN_AND_LSPEN_BITS ( 0x3UL << 30UL )
|
||||||
|
|
||||||
|
/* Constants required to set up the initial stack. */
|
||||||
|
#define portINITIAL_XPSR ( 0x01000000 )
|
||||||
|
#define portINITIAL_EXC_RETURN ( 0xfffffffd )
|
||||||
|
|
||||||
|
/* The systick is a 24-bit counter. */
|
||||||
|
#define portMAX_24_BIT_NUMBER ( 0xffffffUL )
|
||||||
|
|
||||||
|
/* A fiddle factor to estimate the number of SysTick counts that would have
|
||||||
|
occurred while the SysTick counter is stopped during tickless idle
|
||||||
|
calculations. */
|
||||||
|
#define portMISSED_COUNTS_FACTOR ( 45UL )
|
||||||
|
|
||||||
|
/* For strict compliance with the Cortex-M spec the task start address should
|
||||||
|
have bit-0 clear, as it is loaded into the PC on exit from an ISR. */
|
||||||
|
#define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup the timer to generate the tick interrupts. The implementation in this
|
||||||
|
* file is weak to allow application writers to change the timer used to
|
||||||
|
* generate the tick interrupt.
|
||||||
|
*/
|
||||||
|
void vPortSetupTimerInterrupt( void );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exception handlers.
|
||||||
|
*/
|
||||||
|
void xPortPendSVHandler( void );
|
||||||
|
void xPortSysTickHandler( void );
|
||||||
|
void vPortSVCHandler( void );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start first task is a separate function so it can be tested in isolation.
|
||||||
|
*/
|
||||||
|
static void prvStartFirstTask( void );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Functions defined in portasm.s to enable the VFP.
|
||||||
|
*/
|
||||||
|
static void prvEnableVFP( void );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used to catch tasks that attempt to return from their implementing function.
|
||||||
|
*/
|
||||||
|
static void prvTaskExitError( void );
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Each task maintains its own interrupt status in the critical nesting
|
||||||
|
variable. */
|
||||||
|
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The number of SysTick increments that make up one tick period.
|
||||||
|
*/
|
||||||
|
#if( configUSE_TICKLESS_IDLE == 1 )
|
||||||
|
static uint32_t ulTimerCountsForOneTick = 0;
|
||||||
|
#endif /* configUSE_TICKLESS_IDLE */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The maximum number of tick periods that can be suppressed is limited by the
|
||||||
|
* 24 bit resolution of the SysTick timer.
|
||||||
|
*/
|
||||||
|
#if( configUSE_TICKLESS_IDLE == 1 )
|
||||||
|
static uint32_t xMaximumPossibleSuppressedTicks = 0;
|
||||||
|
#endif /* configUSE_TICKLESS_IDLE */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compensate for the CPU cycles that pass while the SysTick is stopped (low
|
||||||
|
* power functionality only.
|
||||||
|
*/
|
||||||
|
#if( configUSE_TICKLESS_IDLE == 1 )
|
||||||
|
static uint32_t ulStoppedTimerCompensation = 0;
|
||||||
|
#endif /* configUSE_TICKLESS_IDLE */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure
|
||||||
|
* FreeRTOS API functions are not called from interrupts that have been assigned
|
||||||
|
* a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.
|
||||||
|
*/
|
||||||
|
#if ( configASSERT_DEFINED == 1 )
|
||||||
|
static uint8_t ucMaxSysCallPriority = 0;
|
||||||
|
static uint32_t ulMaxPRIGROUPValue = 0;
|
||||||
|
static const volatile uint8_t * const pcInterruptPriorityRegisters = ( uint8_t * ) portNVIC_IP_REGISTERS_OFFSET_16;
|
||||||
|
#endif /* configASSERT_DEFINED */
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See header file for description.
|
||||||
|
*/
|
||||||
|
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
|
||||||
|
{
|
||||||
|
/* Simulate the stack frame as it would be created by a context switch
|
||||||
|
interrupt. */
|
||||||
|
|
||||||
|
/* Offset added to account for the way the MCU uses the stack on entry/exit
|
||||||
|
of interrupts, and to ensure alignment. */
|
||||||
|
pxTopOfStack--;
|
||||||
|
|
||||||
|
*pxTopOfStack = portINITIAL_XPSR; /* xPSR */
|
||||||
|
pxTopOfStack--;
|
||||||
|
*pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC */
|
||||||
|
pxTopOfStack--;
|
||||||
|
*pxTopOfStack = ( StackType_t ) prvTaskExitError; /* LR */
|
||||||
|
|
||||||
|
/* Save code space by skipping register initialisation. */
|
||||||
|
pxTopOfStack -= 5; /* R12, R3, R2 and R1. */
|
||||||
|
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
|
||||||
|
|
||||||
|
/* A save method is being used that requires each task to maintain its
|
||||||
|
own exec return value. */
|
||||||
|
pxTopOfStack--;
|
||||||
|
*pxTopOfStack = portINITIAL_EXC_RETURN;
|
||||||
|
|
||||||
|
pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */
|
||||||
|
|
||||||
|
return pxTopOfStack;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static void prvTaskExitError( void )
|
||||||
|
{
|
||||||
|
/* A function that implements a task must not exit or attempt to return to
|
||||||
|
its caller as there is nothing to return to. If a task wants to exit it
|
||||||
|
should instead call vTaskDelete( NULL ).
|
||||||
|
|
||||||
|
Artificially force an assert() to be triggered if configASSERT() is
|
||||||
|
defined, then stop here so application writers can catch the error. */
|
||||||
|
configASSERT( uxCriticalNesting == ~0UL );
|
||||||
|
portDISABLE_INTERRUPTS();
|
||||||
|
for( ;; );
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
__asm void vPortSVCHandler( void )
|
||||||
|
{
|
||||||
|
PRESERVE8
|
||||||
|
|
||||||
|
/* Get the location of the current TCB. */
|
||||||
|
ldr r3, =pxCurrentTCB
|
||||||
|
ldr r1, [r3]
|
||||||
|
ldr r0, [r1]
|
||||||
|
/* Pop the core registers. */
|
||||||
|
ldmia r0!, {r4-r11, r14}
|
||||||
|
msr psp, r0
|
||||||
|
isb
|
||||||
|
mov r0, #0
|
||||||
|
msr basepri, r0
|
||||||
|
bx r14
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
__asm void prvStartFirstTask( void )
|
||||||
|
{
|
||||||
|
PRESERVE8
|
||||||
|
|
||||||
|
/* Use the NVIC offset register to locate the stack. */
|
||||||
|
ldr r0, =0xE000ED08
|
||||||
|
ldr r0, [r0]
|
||||||
|
ldr r0, [r0]
|
||||||
|
/* Set the msp back to the start of the stack. */
|
||||||
|
msr msp, r0
|
||||||
|
/* Clear the bit that indicates the FPU is in use in case the FPU was used
|
||||||
|
before the scheduler was started - which would otherwise result in the
|
||||||
|
unnecessary leaving of space in the SVC stack for lazy saving of FPU
|
||||||
|
registers. */
|
||||||
|
mov r0, #0
|
||||||
|
msr control, r0
|
||||||
|
/* Globally enable interrupts. */
|
||||||
|
cpsie i
|
||||||
|
cpsie f
|
||||||
|
dsb
|
||||||
|
isb
|
||||||
|
/* Call SVC to start the first task. */
|
||||||
|
svc 0
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
__asm void prvEnableVFP( void )
|
||||||
|
{
|
||||||
|
PRESERVE8
|
||||||
|
|
||||||
|
/* The FPU enable bits are in the CPACR. */
|
||||||
|
ldr.w r0, =0xE000ED88
|
||||||
|
ldr r1, [r0]
|
||||||
|
|
||||||
|
/* Enable CP10 and CP11 coprocessors, then save back. */
|
||||||
|
orr r1, r1, #( 0xf << 20 )
|
||||||
|
str r1, [r0]
|
||||||
|
bx r14
|
||||||
|
nop
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See header file for description.
|
||||||
|
*/
|
||||||
|
BaseType_t xPortStartScheduler( void )
|
||||||
|
{
|
||||||
|
/* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0.
|
||||||
|
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
|
||||||
|
configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY );
|
||||||
|
|
||||||
|
/* This port can be used on all revisions of the Cortex-M7 core other than
|
||||||
|
the r0p1 parts. r0p1 parts should use the port from the
|
||||||
|
/source/portable/GCC/ARM_CM7/r0p1 directory. */
|
||||||
|
configASSERT( portCPUID != portCORTEX_M7_r0p1_ID );
|
||||||
|
configASSERT( portCPUID != portCORTEX_M7_r0p0_ID );
|
||||||
|
|
||||||
|
#if( configASSERT_DEFINED == 1 )
|
||||||
|
{
|
||||||
|
volatile uint32_t ulOriginalPriority;
|
||||||
|
volatile uint8_t * const pucFirstUserPriorityRegister = ( uint8_t * ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER );
|
||||||
|
volatile uint8_t ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Determine the maximum priority from which ISR safe FreeRTOS API
|
||||||
|
functions can be called. ISR safe functions are those that end in
|
||||||
|
"FromISR". FreeRTOS maintains separate thread and ISR API functions to
|
||||||
|
ensure interrupt entry is as fast and simple as possible.
|
||||||
|
|
||||||
|
Save the interrupt priority value that is about to be clobbered. */
|
||||||
|
ulOriginalPriority = *pucFirstUserPriorityRegister;
|
||||||
|
|
||||||
|
/* Determine the number of priority bits available. First write to all
|
||||||
|
possible bits. */
|
||||||
|
*pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
|
||||||
|
|
||||||
|
/* Read the value back to see how many bits stuck. */
|
||||||
|
ucMaxPriorityValue = *pucFirstUserPriorityRegister;
|
||||||
|
|
||||||
|
/* The kernel interrupt priority should be set to the lowest
|
||||||
|
priority. */
|
||||||
|
configASSERT( ucMaxPriorityValue == ( configKERNEL_INTERRUPT_PRIORITY & ucMaxPriorityValue ) );
|
||||||
|
|
||||||
|
/* Use the same mask on the maximum system call priority. */
|
||||||
|
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
|
||||||
|
|
||||||
|
/* Calculate the maximum acceptable priority group value for the number
|
||||||
|
of bits read back. */
|
||||||
|
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;
|
||||||
|
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
|
||||||
|
{
|
||||||
|
ulMaxPRIGROUPValue--;
|
||||||
|
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __NVIC_PRIO_BITS
|
||||||
|
{
|
||||||
|
/* Check the CMSIS configuration that defines the number of
|
||||||
|
priority bits matches the number of priority bits actually queried
|
||||||
|
from the hardware. */
|
||||||
|
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef configPRIO_BITS
|
||||||
|
{
|
||||||
|
/* Check the FreeRTOS configuration that defines the number of
|
||||||
|
priority bits matches the number of priority bits actually queried
|
||||||
|
from the hardware. */
|
||||||
|
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Shift the priority group value back to its position within the AIRCR
|
||||||
|
register. */
|
||||||
|
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
|
||||||
|
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
|
||||||
|
|
||||||
|
/* Restore the clobbered interrupt priority register to its original
|
||||||
|
value. */
|
||||||
|
*pucFirstUserPriorityRegister = ulOriginalPriority;
|
||||||
|
}
|
||||||
|
#endif /* conifgASSERT_DEFINED */
|
||||||
|
|
||||||
|
/* Make PendSV and SysTick the lowest priority interrupts. */
|
||||||
|
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
|
||||||
|
portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
|
||||||
|
|
||||||
|
/* Start the timer that generates the tick ISR. Interrupts are disabled
|
||||||
|
here already. */
|
||||||
|
vPortSetupTimerInterrupt();
|
||||||
|
|
||||||
|
/* Initialise the critical nesting count ready for the first task. */
|
||||||
|
uxCriticalNesting = 0;
|
||||||
|
|
||||||
|
/* Ensure the VFP is enabled - it should be anyway. */
|
||||||
|
prvEnableVFP();
|
||||||
|
|
||||||
|
/* Lazy save always. */
|
||||||
|
*( portFPCCR ) |= portASPEN_AND_LSPEN_BITS;
|
||||||
|
|
||||||
|
/* Start the first task. */
|
||||||
|
prvStartFirstTask();
|
||||||
|
|
||||||
|
/* Should not get here! */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortEndScheduler( void )
|
||||||
|
{
|
||||||
|
/* Not implemented in ports where there is nothing to return to.
|
||||||
|
Artificially force an assert. */
|
||||||
|
configASSERT( uxCriticalNesting == 1000UL );
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortEnterCritical( void )
|
||||||
|
{
|
||||||
|
portDISABLE_INTERRUPTS();
|
||||||
|
uxCriticalNesting++;
|
||||||
|
|
||||||
|
/* This is not the interrupt safe version of the enter critical function so
|
||||||
|
assert() if it is being called from an interrupt context. Only API
|
||||||
|
functions that end in "FromISR" can be used in an interrupt. Only assert if
|
||||||
|
the critical nesting count is 1 to protect against recursive calls if the
|
||||||
|
assert function also uses a critical section. */
|
||||||
|
if( uxCriticalNesting == 1 )
|
||||||
|
{
|
||||||
|
configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vPortExitCritical( void )
|
||||||
|
{
|
||||||
|
configASSERT( uxCriticalNesting );
|
||||||
|
uxCriticalNesting--;
|
||||||
|
if( uxCriticalNesting == 0 )
|
||||||
|
{
|
||||||
|
portENABLE_INTERRUPTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
__asm void xPortPendSVHandler( void )
|
||||||
|
{
|
||||||
|
extern uxCriticalNesting;
|
||||||
|
extern pxCurrentTCB;
|
||||||
|
extern vTaskSwitchContext;
|
||||||
|
|
||||||
|
PRESERVE8
|
||||||
|
|
||||||
|
mrs r0, psp
|
||||||
|
isb
|
||||||
|
/* Get the location of the current TCB. */
|
||||||
|
ldr r3, =pxCurrentTCB
|
||||||
|
ldr r2, [r3]
|
||||||
|
|
||||||
|
/* Is the task using the FPU context? If so, push high vfp registers. */
|
||||||
|
tst r14, #0x10
|
||||||
|
it eq
|
||||||
|
vstmdbeq r0!, {s16-s31}
|
||||||
|
|
||||||
|
/* Save the core registers. */
|
||||||
|
stmdb r0!, {r4-r11, r14}
|
||||||
|
|
||||||
|
/* Save the new top of stack into the first member of the TCB. */
|
||||||
|
str r0, [r2]
|
||||||
|
|
||||||
|
stmdb sp!, {r0, r3}
|
||||||
|
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
msr basepri, r0
|
||||||
|
dsb
|
||||||
|
isb
|
||||||
|
bl vTaskSwitchContext
|
||||||
|
mov r0, #0
|
||||||
|
msr basepri, r0
|
||||||
|
ldmia sp!, {r0, r3}
|
||||||
|
|
||||||
|
/* The first item in pxCurrentTCB is the task top of stack. */
|
||||||
|
ldr r1, [r3]
|
||||||
|
ldr r0, [r1]
|
||||||
|
|
||||||
|
/* Pop the core registers. */
|
||||||
|
ldmia r0!, {r4-r11, r14}
|
||||||
|
|
||||||
|
/* Is the task using the FPU context? If so, pop the high vfp registers
|
||||||
|
too. */
|
||||||
|
tst r14, #0x10
|
||||||
|
it eq
|
||||||
|
vldmiaeq r0!, {s16-s31}
|
||||||
|
|
||||||
|
msr psp, r0
|
||||||
|
isb
|
||||||
|
#ifdef WORKAROUND_PMU_CM001 /* XMC4000 specific errata */
|
||||||
|
#if WORKAROUND_PMU_CM001 == 1
|
||||||
|
push { r14 }
|
||||||
|
pop { pc }
|
||||||
|
nop
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bx r14
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void xPortSysTickHandler( void )
|
||||||
|
{
|
||||||
|
/* The SysTick runs at the lowest interrupt priority, so when this interrupt
|
||||||
|
executes all interrupts must be unmasked. There is therefore no need to
|
||||||
|
save and then restore the interrupt mask value as its value is already
|
||||||
|
known - therefore the slightly faster vPortRaiseBASEPRI() function is used
|
||||||
|
in place of portSET_INTERRUPT_MASK_FROM_ISR(). */
|
||||||
|
vPortRaiseBASEPRI();
|
||||||
|
{
|
||||||
|
/* Increment the RTOS tick. */
|
||||||
|
if( xTaskIncrementTick() != pdFALSE )
|
||||||
|
{
|
||||||
|
/* A context switch is required. Context switching is performed in
|
||||||
|
the PendSV interrupt. Pend the PendSV interrupt. */
|
||||||
|
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vPortClearBASEPRIFromISR();
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if( configUSE_TICKLESS_IDLE == 1 )
|
||||||
|
|
||||||
|
__weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
|
||||||
|
{
|
||||||
|
uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
|
||||||
|
TickType_t xModifiableIdleTime;
|
||||||
|
|
||||||
|
/* Make sure the SysTick reload value does not overflow the counter. */
|
||||||
|
if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )
|
||||||
|
{
|
||||||
|
xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stop the SysTick momentarily. The time the SysTick is stopped for
|
||||||
|
is accounted for as best it can be, but using the tickless mode will
|
||||||
|
inevitably result in some tiny drift of the time maintained by the
|
||||||
|
kernel with respect to calendar time. */
|
||||||
|
portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;
|
||||||
|
|
||||||
|
/* Calculate the reload value required to wait xExpectedIdleTime
|
||||||
|
tick periods. -1 is used because this code will execute part way
|
||||||
|
through one of the tick periods. */
|
||||||
|
ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
|
||||||
|
if( ulReloadValue > ulStoppedTimerCompensation )
|
||||||
|
{
|
||||||
|
ulReloadValue -= ulStoppedTimerCompensation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enter a critical section but don't use the taskENTER_CRITICAL()
|
||||||
|
method as that will mask interrupts that should exit sleep mode. */
|
||||||
|
__disable_irq();
|
||||||
|
__dsb( portSY_FULL_READ_WRITE );
|
||||||
|
__isb( portSY_FULL_READ_WRITE );
|
||||||
|
|
||||||
|
/* If a context switch is pending or a task is waiting for the scheduler
|
||||||
|
to be unsuspended then abandon the low power entry. */
|
||||||
|
if( eTaskConfirmSleepModeStatus() == eAbortSleep )
|
||||||
|
{
|
||||||
|
/* Restart from whatever is left in the count register to complete
|
||||||
|
this tick period. */
|
||||||
|
portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;
|
||||||
|
|
||||||
|
/* Restart SysTick. */
|
||||||
|
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
|
||||||
|
|
||||||
|
/* Reset the reload register to the value required for normal tick
|
||||||
|
periods. */
|
||||||
|
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
|
||||||
|
|
||||||
|
/* Re-enable interrupts - see comments above __disable_irq() call
|
||||||
|
above. */
|
||||||
|
__enable_irq();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Set the new reload value. */
|
||||||
|
portNVIC_SYSTICK_LOAD_REG = ulReloadValue;
|
||||||
|
|
||||||
|
/* Clear the SysTick count flag and set the count value back to
|
||||||
|
zero. */
|
||||||
|
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
|
||||||
|
|
||||||
|
/* Restart SysTick. */
|
||||||
|
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
|
||||||
|
|
||||||
|
/* Sleep until something happens. configPRE_SLEEP_PROCESSING() can
|
||||||
|
set its parameter to 0 to indicate that its implementation contains
|
||||||
|
its own wait for interrupt or wait for event instruction, and so wfi
|
||||||
|
should not be executed again. However, the original expected idle
|
||||||
|
time variable must remain unmodified, so a copy is taken. */
|
||||||
|
xModifiableIdleTime = xExpectedIdleTime;
|
||||||
|
configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
|
||||||
|
if( xModifiableIdleTime > 0 )
|
||||||
|
{
|
||||||
|
__dsb( portSY_FULL_READ_WRITE );
|
||||||
|
__wfi();
|
||||||
|
__isb( portSY_FULL_READ_WRITE );
|
||||||
|
}
|
||||||
|
configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
|
||||||
|
|
||||||
|
/* Re-enable interrupts to allow the interrupt that brought the MCU
|
||||||
|
out of sleep mode to execute immediately. see comments above
|
||||||
|
__disable_interrupt() call above. */
|
||||||
|
__enable_irq();
|
||||||
|
__dsb( portSY_FULL_READ_WRITE );
|
||||||
|
__isb( portSY_FULL_READ_WRITE );
|
||||||
|
|
||||||
|
/* Disable interrupts again because the clock is about to be stopped
|
||||||
|
and interrupts that execute while the clock is stopped will increase
|
||||||
|
any slippage between the time maintained by the RTOS and calendar
|
||||||
|
time. */
|
||||||
|
__disable_irq();
|
||||||
|
__dsb( portSY_FULL_READ_WRITE );
|
||||||
|
__isb( portSY_FULL_READ_WRITE );
|
||||||
|
|
||||||
|
/* Disable the SysTick clock without reading the
|
||||||
|
portNVIC_SYSTICK_CTRL_REG register to ensure the
|
||||||
|
portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set. Again,
|
||||||
|
the time the SysTick is stopped for is accounted for as best it can
|
||||||
|
be, but using the tickless mode will inevitably result in some tiny
|
||||||
|
drift of the time maintained by the kernel with respect to calendar
|
||||||
|
time*/
|
||||||
|
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
|
||||||
|
|
||||||
|
/* Determine if the SysTick clock has already counted to zero and
|
||||||
|
been set back to the current reload value (the reload back being
|
||||||
|
correct for the entire expected idle time) or if the SysTick is yet
|
||||||
|
to count to zero (in which case an interrupt other than the SysTick
|
||||||
|
must have brought the system out of sleep mode). */
|
||||||
|
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
|
||||||
|
{
|
||||||
|
uint32_t ulCalculatedLoadValue;
|
||||||
|
|
||||||
|
/* The tick interrupt is already pending, and the SysTick count
|
||||||
|
reloaded with ulReloadValue. Reset the
|
||||||
|
portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick
|
||||||
|
period. */
|
||||||
|
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );
|
||||||
|
|
||||||
|
/* Don't allow a tiny value, or values that have somehow
|
||||||
|
underflowed because the post sleep hook did something
|
||||||
|
that took too long. */
|
||||||
|
if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
|
||||||
|
{
|
||||||
|
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );
|
||||||
|
}
|
||||||
|
|
||||||
|
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
|
||||||
|
|
||||||
|
/* As the pending tick will be processed as soon as this
|
||||||
|
function exits, the tick value maintained by the tick is stepped
|
||||||
|
forward by one less than the time spent waiting. */
|
||||||
|
ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Something other than the tick interrupt ended the sleep.
|
||||||
|
Work out how long the sleep lasted rounded to complete tick
|
||||||
|
periods (not the ulReload value which accounted for part
|
||||||
|
ticks). */
|
||||||
|
ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;
|
||||||
|
|
||||||
|
/* How many complete tick periods passed while the processor
|
||||||
|
was waiting? */
|
||||||
|
ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;
|
||||||
|
|
||||||
|
/* The reload value is set to whatever fraction of a single tick
|
||||||
|
period remains. */
|
||||||
|
portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG
|
||||||
|
again, then set portNVIC_SYSTICK_LOAD_REG back to its standard
|
||||||
|
value. */
|
||||||
|
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
|
||||||
|
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
|
||||||
|
vTaskStepTick( ulCompleteTickPeriods );
|
||||||
|
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
|
||||||
|
|
||||||
|
/* Exit with interrupts enabled. */
|
||||||
|
__enable_irq();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* #if configUSE_TICKLESS_IDLE */
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup the SysTick timer to generate the tick interrupts at the required
|
||||||
|
* frequency.
|
||||||
|
*/
|
||||||
|
#if( configOVERRIDE_DEFAULT_TICK_CONFIGURATION == 0 )
|
||||||
|
|
||||||
|
__weak void vPortSetupTimerInterrupt( void )
|
||||||
|
{
|
||||||
|
/* Calculate the constants required to configure the tick interrupt. */
|
||||||
|
#if( configUSE_TICKLESS_IDLE == 1 )
|
||||||
|
{
|
||||||
|
ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
|
||||||
|
xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
|
||||||
|
ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ );
|
||||||
|
}
|
||||||
|
#endif /* configUSE_TICKLESS_IDLE */
|
||||||
|
|
||||||
|
/* Stop and clear the SysTick. */
|
||||||
|
portNVIC_SYSTICK_CTRL_REG = 0UL;
|
||||||
|
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
|
||||||
|
|
||||||
|
/* Configure SysTick to interrupt at the requested rate. */
|
||||||
|
portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
|
||||||
|
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* configOVERRIDE_DEFAULT_TICK_CONFIGURATION */
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
__asm uint32_t vPortGetIPSR( void )
|
||||||
|
{
|
||||||
|
PRESERVE8
|
||||||
|
|
||||||
|
mrs r0, ipsr
|
||||||
|
bx r14
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if( configASSERT_DEFINED == 1 )
|
||||||
|
|
||||||
|
void vPortValidateInterruptPriority( void )
|
||||||
|
{
|
||||||
|
uint32_t ulCurrentInterrupt;
|
||||||
|
uint8_t ucCurrentPriority;
|
||||||
|
|
||||||
|
/* Obtain the number of the currently executing interrupt. */
|
||||||
|
ulCurrentInterrupt = vPortGetIPSR();
|
||||||
|
|
||||||
|
/* Is the interrupt number a user defined interrupt? */
|
||||||
|
if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )
|
||||||
|
{
|
||||||
|
/* Look up the interrupt's priority. */
|
||||||
|
ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
|
||||||
|
|
||||||
|
/* The following assertion will fail if a service routine (ISR) for
|
||||||
|
an interrupt that has been assigned a priority above
|
||||||
|
configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
|
||||||
|
function. ISR safe FreeRTOS API functions must *only* be called
|
||||||
|
from interrupts that have been assigned a priority at or below
|
||||||
|
configMAX_SYSCALL_INTERRUPT_PRIORITY.
|
||||||
|
|
||||||
|
Numerically low interrupt priority numbers represent logically high
|
||||||
|
interrupt priorities, therefore the priority of the interrupt must
|
||||||
|
be set to a value equal to or numerically *higher* than
|
||||||
|
configMAX_SYSCALL_INTERRUPT_PRIORITY.
|
||||||
|
|
||||||
|
Interrupts that use the FreeRTOS API must not be left at their
|
||||||
|
default priority of zero as that is the highest possible priority,
|
||||||
|
which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,
|
||||||
|
and therefore also guaranteed to be invalid.
|
||||||
|
|
||||||
|
FreeRTOS maintains separate thread and ISR API functions to ensure
|
||||||
|
interrupt entry is as fast and simple as possible.
|
||||||
|
|
||||||
|
The following links provide detailed information:
|
||||||
|
http://www.freertos.org/RTOS-Cortex-M3-M4.html
|
||||||
|
http://www.freertos.org/FAQHelp.html */
|
||||||
|
configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Priority grouping: The interrupt controller (NVIC) allows the bits
|
||||||
|
that define each interrupt's priority to be split between bits that
|
||||||
|
define the interrupt's pre-emption priority bits and bits that define
|
||||||
|
the interrupt's sub-priority. For simplicity all bits must be defined
|
||||||
|
to be pre-emption priority bits. The following assertion will fail if
|
||||||
|
this is not the case (if some bits represent a sub-priority).
|
||||||
|
|
||||||
|
If the application only uses CMSIS libraries for interrupt
|
||||||
|
configuration then the correct setting can be achieved on all Cortex-M
|
||||||
|
devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the
|
||||||
|
scheduler. Note however that some vendor specific peripheral libraries
|
||||||
|
assume a non-zero priority group setting, in which cases using a value
|
||||||
|
of zero will result in unpredictable behaviour. */
|
||||||
|
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* configASSERT_DEFINED */
|
||||||
|
|
||||||
|
|
||||||
252
Middlewares/Third_Party/FreeRTOS/Source/portable/RVDS/ARM_CM4F/portmacro.h
vendored
Normal file
252
Middlewares/Third_Party/FreeRTOS/Source/portable/RVDS/ARM_CM4F/portmacro.h
vendored
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
/*
|
||||||
|
* FreeRTOS Kernel V10.3.1
|
||||||
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org
|
||||||
|
* http://aws.amazon.com/freertos
|
||||||
|
*
|
||||||
|
* 1 tab == 4 spaces!
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef PORTMACRO_H
|
||||||
|
#define PORTMACRO_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------
|
||||||
|
* Port specific definitions.
|
||||||
|
*
|
||||||
|
* The settings in this file configure FreeRTOS correctly for the
|
||||||
|
* given hardware and compiler.
|
||||||
|
*
|
||||||
|
* These settings should not be altered.
|
||||||
|
*-----------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Type definitions. */
|
||||||
|
#define portCHAR char
|
||||||
|
#define portFLOAT float
|
||||||
|
#define portDOUBLE double
|
||||||
|
#define portLONG long
|
||||||
|
#define portSHORT short
|
||||||
|
#define portSTACK_TYPE uint32_t
|
||||||
|
#define portBASE_TYPE long
|
||||||
|
|
||||||
|
typedef portSTACK_TYPE StackType_t;
|
||||||
|
typedef long BaseType_t;
|
||||||
|
typedef unsigned long UBaseType_t;
|
||||||
|
|
||||||
|
#if( configUSE_16_BIT_TICKS == 1 )
|
||||||
|
typedef uint16_t TickType_t;
|
||||||
|
#define portMAX_DELAY ( TickType_t ) 0xffff
|
||||||
|
#else
|
||||||
|
typedef uint32_t TickType_t;
|
||||||
|
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
|
||||||
|
|
||||||
|
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
|
||||||
|
not need to be guarded with a critical section. */
|
||||||
|
#define portTICK_TYPE_IS_ATOMIC 1
|
||||||
|
#endif
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Architecture specifics. */
|
||||||
|
#define portSTACK_GROWTH ( -1 )
|
||||||
|
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
|
||||||
|
#define portBYTE_ALIGNMENT 8
|
||||||
|
|
||||||
|
/* Constants used with memory barrier intrinsics. */
|
||||||
|
#define portSY_FULL_READ_WRITE ( 15 )
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Scheduler utilities. */
|
||||||
|
#define portYIELD() \
|
||||||
|
{ \
|
||||||
|
/* Set a PendSV to request a context switch. */ \
|
||||||
|
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
|
||||||
|
\
|
||||||
|
/* Barriers are normally not required but do ensure the code is completely \
|
||||||
|
within the specified behaviour for the architecture. */ \
|
||||||
|
__dsb( portSY_FULL_READ_WRITE ); \
|
||||||
|
__isb( portSY_FULL_READ_WRITE ); \
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) )
|
||||||
|
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
|
||||||
|
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()
|
||||||
|
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Critical section management. */
|
||||||
|
extern void vPortEnterCritical( void );
|
||||||
|
extern void vPortExitCritical( void );
|
||||||
|
|
||||||
|
#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()
|
||||||
|
#define portENABLE_INTERRUPTS() vPortSetBASEPRI( 0 )
|
||||||
|
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||||
|
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||||
|
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x)
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Tickless idle/low power functionality. */
|
||||||
|
#ifndef portSUPPRESS_TICKS_AND_SLEEP
|
||||||
|
extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
|
||||||
|
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
|
||||||
|
#endif
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Port specific optimisations. */
|
||||||
|
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
|
||||||
|
|
||||||
|
/* Check the configuration. */
|
||||||
|
#if( configMAX_PRIORITIES > 32 )
|
||||||
|
#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Store/clear the ready priorities in a bit map. */
|
||||||
|
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
|
||||||
|
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( uint32_t ) __clz( ( uxReadyPriorities ) ) )
|
||||||
|
|
||||||
|
#endif /* taskRECORD_READY_PRIORITY */
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Task function macros as described on the FreeRTOS.org WEB site. These are
|
||||||
|
not necessary for to use this port. They are defined so the common demo files
|
||||||
|
(which build with all the ports) will build. */
|
||||||
|
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
|
||||||
|
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifdef configASSERT
|
||||||
|
void vPortValidateInterruptPriority( void );
|
||||||
|
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* portNOP() is not required by this port. */
|
||||||
|
#define portNOP()
|
||||||
|
|
||||||
|
#define portINLINE __inline
|
||||||
|
|
||||||
|
#ifndef portFORCE_INLINE
|
||||||
|
#define portFORCE_INLINE __forceinline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )
|
||||||
|
{
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
/* Barrier instructions are not used as this function is only used to
|
||||||
|
lower the BASEPRI value. */
|
||||||
|
msr basepri, ulBASEPRI
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static portFORCE_INLINE void vPortRaiseBASEPRI( void )
|
||||||
|
{
|
||||||
|
uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
|
||||||
|
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
/* Set BASEPRI to the max syscall priority to effect a critical
|
||||||
|
section. */
|
||||||
|
msr basepri, ulNewBASEPRI
|
||||||
|
dsb
|
||||||
|
isb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static portFORCE_INLINE void vPortClearBASEPRIFromISR( void )
|
||||||
|
{
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
/* Set BASEPRI to 0 so no interrupts are masked. This function is only
|
||||||
|
used to lower the mask in an interrupt, so memory barriers are not
|
||||||
|
used. */
|
||||||
|
msr basepri, #0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static portFORCE_INLINE uint32_t ulPortRaiseBASEPRI( void )
|
||||||
|
{
|
||||||
|
uint32_t ulReturn, ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
|
||||||
|
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
/* Set BASEPRI to the max syscall priority to effect a critical
|
||||||
|
section. */
|
||||||
|
mrs ulReturn, basepri
|
||||||
|
msr basepri, ulNewBASEPRI
|
||||||
|
dsb
|
||||||
|
isb
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulReturn;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static portFORCE_INLINE BaseType_t xPortIsInsideInterrupt( void )
|
||||||
|
{
|
||||||
|
uint32_t ulCurrentInterrupt;
|
||||||
|
BaseType_t xReturn;
|
||||||
|
|
||||||
|
/* Obtain the number of the currently executing interrupt. */
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
mrs ulCurrentInterrupt, ipsr
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ulCurrentInterrupt == 0 )
|
||||||
|
{
|
||||||
|
xReturn = pdFALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xReturn = pdTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return xReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* PORTMACRO_H */
|
||||||
|
|
||||||
2945
Middlewares/Third_Party/FreeRTOS/Source/queue.c
vendored
Normal file
2945
Middlewares/Third_Party/FreeRTOS/Source/queue.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1263
Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c
vendored
Normal file
1263
Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
5310
Middlewares/Third_Party/FreeRTOS/Source/tasks.c
vendored
Normal file
5310
Middlewares/Third_Party/FreeRTOS/Source/tasks.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1127
Middlewares/Third_Party/FreeRTOS/Source/timers.c
vendored
Normal file
1127
Middlewares/Third_Party/FreeRTOS/Source/timers.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||||
@@ -25,108 +47,125 @@ Dma.USART1_TX.0.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
|
|||||||
Dma.USART1_TX.0.PeriphInc=DMA_PINC_DISABLE
|
Dma.USART1_TX.0.PeriphInc=DMA_PINC_DISABLE
|
||||||
Dma.USART1_TX.0.Priority=DMA_PRIORITY_LOW
|
Dma.USART1_TX.0.Priority=DMA_PRIORITY_LOW
|
||||||
Dma.USART1_TX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
|
Dma.USART1_TX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
|
||||||
|
FREERTOS.FootprintOK=true
|
||||||
|
FREERTOS.IPParameters=Tasks01,configENABLE_FPU,FootprintOK,configTOTAL_HEAP_SIZE
|
||||||
|
FREERTOS.Tasks01=defaultTask,24,512,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL;netTask,24,1024,StartNetTask,Default,NULL,Dynamic,NULL,NULL
|
||||||
|
FREERTOS.configENABLE_FPU=1
|
||||||
|
FREERTOS.configTOTAL_HEAP_SIZE=30720
|
||||||
File.Version=6
|
File.Version=6
|
||||||
GPIO.groupedBy=Group By Peripherals
|
GPIO.groupedBy=Group By Peripherals
|
||||||
KeepUserPlacement=false
|
KeepUserPlacement=false
|
||||||
Mcu.CPN=STM32F407ZGT6
|
Mcu.CPN=STM32F407ZGT6
|
||||||
Mcu.Family=STM32F4
|
Mcu.Family=STM32F4
|
||||||
Mcu.IP0=DMA
|
Mcu.IP0=DMA
|
||||||
Mcu.IP1=I2C1
|
Mcu.IP1=FREERTOS
|
||||||
Mcu.IP10=USART2
|
Mcu.IP10=USART1
|
||||||
Mcu.IP11=USART3
|
Mcu.IP11=USART2
|
||||||
Mcu.IP2=NVIC
|
Mcu.IP12=USART3
|
||||||
Mcu.IP3=RCC
|
Mcu.IP2=I2C1
|
||||||
Mcu.IP4=SPI1
|
Mcu.IP3=NVIC
|
||||||
Mcu.IP5=SPI2
|
Mcu.IP4=RCC
|
||||||
Mcu.IP6=SYS
|
Mcu.IP5=SPI1
|
||||||
Mcu.IP7=UART4
|
Mcu.IP6=SPI2
|
||||||
Mcu.IP8=UART5
|
Mcu.IP7=SYS
|
||||||
Mcu.IP9=USART1
|
Mcu.IP8=UART4
|
||||||
Mcu.IPNb=12
|
Mcu.IP9=UART5
|
||||||
|
Mcu.IPNb=13
|
||||||
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_FREERTOS_VS_CMSIS_V2
|
||||||
Mcu.Pin7=PF12
|
Mcu.Pin58=VP_SYS_VS_tim7
|
||||||
Mcu.Pin8=PF13
|
Mcu.Pin6=PB2
|
||||||
Mcu.Pin9=PF14
|
Mcu.Pin7=PF11
|
||||||
Mcu.PinsNb=57
|
Mcu.Pin8=PF12
|
||||||
|
Mcu.Pin9=PF13
|
||||||
|
Mcu.PinsNb=59
|
||||||
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\:false
|
||||||
NVIC.DMA2_Stream2_IRQn=true\:3\:0\:true\:false\:true\:false\:true\:true
|
NVIC.DMA1_Stream3_IRQn=true\:7\:0\:true\:false\:true\:true\:false\:true\:true
|
||||||
NVIC.DMA2_Stream7_IRQn=true\:3\:0\:true\:false\:true\:false\:true\:true
|
NVIC.DMA1_Stream4_IRQn=true\:7\:0\:true\:false\:true\:true\:false\:true\:true
|
||||||
NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
NVIC.DMA2_Stream2_IRQn=true\:9\:0\:true\:false\:true\:true\:false\:true\:true
|
||||||
NVIC.EXTI9_5_IRQn=true\:2\:0\:true\:false\:true\:true\:true\:true
|
NVIC.DMA2_Stream7_IRQn=true\:9\:0\:true\:false\:true\:true\:false\:true\:true
|
||||||
|
NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false
|
||||||
|
NVIC.EXTI9_5_IRQn=true\:6\:0\:true\:false\:true\:true\:true\:true\:true
|
||||||
NVIC.ForceEnableDMAVector=true
|
NVIC.ForceEnableDMAVector=true
|
||||||
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false
|
||||||
NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\: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\:false
|
||||||
NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
NVIC.PendSV_IRQn=true\:15\:0\:false\:false\:false\:true\:false\:false\:false
|
||||||
NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
|
NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
|
||||||
NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
NVIC.SPI2_IRQn=true\:7\:0\:true\:false\:true\:true\:true\:true\:true
|
||||||
NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false
|
NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:false\:false\:false\:false\:false
|
||||||
NVIC.UART4_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true
|
NVIC.SavedPendsvIrqHandlerGenerated=true
|
||||||
NVIC.UART5_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true
|
NVIC.SavedSvcallIrqHandlerGenerated=true
|
||||||
NVIC.USART1_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true
|
NVIC.SavedSystickIrqHandlerGenerated=true
|
||||||
NVIC.USART2_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true
|
NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:false\:true\:false\:true\:false
|
||||||
NVIC.USART3_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true
|
NVIC.TIM7_IRQn=true\:15\:0\:true\:false\:true\:false\:false\:true\:true
|
||||||
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
NVIC.TimeBase=TIM7_IRQn
|
||||||
|
NVIC.TimeBaseIP=TIM7
|
||||||
|
NVIC.UART4_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true
|
||||||
|
NVIC.UART5_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true
|
||||||
|
NVIC.USART1_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true
|
||||||
|
NVIC.USART2_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true
|
||||||
|
NVIC.USART3_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true
|
||||||
|
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false
|
||||||
PA10.GPIOParameters=GPIO_ModeDefaultPP,GPIO_Speed,GPIO_PuPd
|
PA10.GPIOParameters=GPIO_ModeDefaultPP,GPIO_Speed,GPIO_PuPd
|
||||||
PA10.GPIO_ModeDefaultPP=GPIO_MODE_AF_PP
|
PA10.GPIO_ModeDefaultPP=GPIO_MODE_AF_PP
|
||||||
PA10.GPIO_PuPd=GPIO_NOPULL
|
PA10.GPIO_PuPd=GPIO_NOPULL
|
||||||
@@ -315,6 +354,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 +524,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
|
||||||
@@ -501,6 +546,8 @@ USART2.IPParameters=VirtualMode
|
|||||||
USART2.VirtualMode=VM_ASYNC
|
USART2.VirtualMode=VM_ASYNC
|
||||||
USART3.IPParameters=VirtualMode
|
USART3.IPParameters=VirtualMode
|
||||||
USART3.VirtualMode=VM_ASYNC
|
USART3.VirtualMode=VM_ASYNC
|
||||||
VP_SYS_VS_Systick.Mode=SysTick
|
VP_FREERTOS_VS_CMSIS_V2.Mode=CMSIS_V2
|
||||||
VP_SYS_VS_Systick.Signal=SYS_VS_Systick
|
VP_FREERTOS_VS_CMSIS_V2.Signal=FREERTOS_VS_CMSIS_V2
|
||||||
|
VP_SYS_VS_tim7.Mode=TIM7
|
||||||
|
VP_SYS_VS_tim7.Signal=SYS_VS_tim7
|
||||||
board=custom
|
board=custom
|
||||||
|
|||||||
11
Src/dma.c
11
Src/dma.c
@@ -41,13 +41,20 @@ 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, 7, 0);
|
||||||
|
HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
|
||||||
|
/* DMA1_Stream4_IRQn interrupt configuration */
|
||||||
|
HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 7, 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, 9, 0);
|
||||||
HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
|
HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
|
||||||
/* DMA2_Stream7_IRQn interrupt configuration */
|
/* DMA2_Stream7_IRQn interrupt configuration */
|
||||||
HAL_NVIC_SetPriority(DMA2_Stream7_IRQn, 3, 0);
|
HAL_NVIC_SetPriority(DMA2_Stream7_IRQn, 9, 0);
|
||||||
HAL_NVIC_EnableIRQ(DMA2_Stream7_IRQn);
|
HAL_NVIC_EnableIRQ(DMA2_Stream7_IRQn);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
193
Src/freertos.c
Normal file
193
Src/freertos.c
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
/* USER CODE BEGIN Header */
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* File Name : freertos.c
|
||||||
|
* Description : Code for freertos applications
|
||||||
|
******************************************************************************
|
||||||
|
* @attention
|
||||||
|
*
|
||||||
|
* Copyright (c) 2026 STMicroelectronics.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This software is licensed under terms that can be found in the LICENSE file
|
||||||
|
* in the root directory of this software component.
|
||||||
|
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
/* USER CODE END Header */
|
||||||
|
|
||||||
|
/* Includes ------------------------------------------------------------------*/
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "cmsis_os.h"
|
||||||
|
|
||||||
|
/* Private includes ----------------------------------------------------------*/
|
||||||
|
/* USER CODE BEGIN Includes */
|
||||||
|
#include "net_socket.h"
|
||||||
|
#include "net_select.h"
|
||||||
|
#include "ch395f.h"
|
||||||
|
#include "ch395f_test.h"
|
||||||
|
#include "dbg_log.h"
|
||||||
|
/* USER CODE END Includes */
|
||||||
|
|
||||||
|
/* Private typedef -----------------------------------------------------------*/
|
||||||
|
/* USER CODE BEGIN PTD */
|
||||||
|
|
||||||
|
/* USER CODE END PTD */
|
||||||
|
|
||||||
|
/* Private define ------------------------------------------------------------*/
|
||||||
|
/* USER CODE BEGIN PD */
|
||||||
|
|
||||||
|
/* USER CODE END PD */
|
||||||
|
|
||||||
|
/* Private macro -------------------------------------------------------------*/
|
||||||
|
/* USER CODE BEGIN PM */
|
||||||
|
|
||||||
|
/* USER CODE END PM */
|
||||||
|
|
||||||
|
/* Private variables ---------------------------------------------------------*/
|
||||||
|
/* USER CODE BEGIN Variables */
|
||||||
|
#ifdef ENABLE_PHASE4_TESTS
|
||||||
|
static uint8_t s_net_buf[1500];
|
||||||
|
#endif
|
||||||
|
/* USER CODE END Variables */
|
||||||
|
/* Definitions for defaultTask */
|
||||||
|
osThreadId_t defaultTaskHandle;
|
||||||
|
const osThreadAttr_t defaultTask_attributes = {
|
||||||
|
.name = "defaultTask",
|
||||||
|
.stack_size = 512 * 4,
|
||||||
|
.priority = (osPriority_t) osPriorityNormal,
|
||||||
|
};
|
||||||
|
/* Definitions for netTask */
|
||||||
|
osThreadId_t netTaskHandle;
|
||||||
|
const osThreadAttr_t netTask_attributes = {
|
||||||
|
.name = "netTask",
|
||||||
|
.stack_size = 1024 * 4,
|
||||||
|
.priority = (osPriority_t) osPriorityNormal,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Private function prototypes -----------------------------------------------*/
|
||||||
|
/* USER CODE BEGIN FunctionPrototypes */
|
||||||
|
|
||||||
|
/* USER CODE END FunctionPrototypes */
|
||||||
|
|
||||||
|
void StartDefaultTask(void *argument);
|
||||||
|
void StartNetTask(void *argument);
|
||||||
|
|
||||||
|
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief FreeRTOS initialization
|
||||||
|
* @param None
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
void MX_FREERTOS_Init(void) {
|
||||||
|
/* USER CODE BEGIN Init */
|
||||||
|
|
||||||
|
/* USER CODE END Init */
|
||||||
|
|
||||||
|
/* USER CODE BEGIN RTOS_MUTEX */
|
||||||
|
/* add mutexes, ... */
|
||||||
|
/* USER CODE END RTOS_MUTEX */
|
||||||
|
|
||||||
|
/* USER CODE BEGIN RTOS_SEMAPHORES */
|
||||||
|
/* add semaphores, ... */
|
||||||
|
/* USER CODE END RTOS_SEMAPHORES */
|
||||||
|
|
||||||
|
/* USER CODE BEGIN RTOS_TIMERS */
|
||||||
|
/* start timers, add new ones, ... */
|
||||||
|
/* USER CODE END RTOS_TIMERS */
|
||||||
|
|
||||||
|
/* USER CODE BEGIN RTOS_QUEUES */
|
||||||
|
/* add queues, ... */
|
||||||
|
/* USER CODE END RTOS_QUEUES */
|
||||||
|
|
||||||
|
/* Create the thread(s) */
|
||||||
|
/* creation of defaultTask */
|
||||||
|
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
|
||||||
|
|
||||||
|
/* creation of netTask */
|
||||||
|
netTaskHandle = osThreadNew(StartNetTask, NULL, &netTask_attributes);
|
||||||
|
|
||||||
|
/* USER CODE BEGIN RTOS_THREADS */
|
||||||
|
/* add threads, ... */
|
||||||
|
/* USER CODE END RTOS_THREADS */
|
||||||
|
|
||||||
|
/* USER CODE BEGIN RTOS_EVENTS */
|
||||||
|
/* add events, ... */
|
||||||
|
/* USER CODE END RTOS_EVENTS */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* USER CODE BEGIN Header_StartDefaultTask */
|
||||||
|
/**
|
||||||
|
* @brief Function implementing the defaultTask thread.
|
||||||
|
* @param argument: Not used
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
/* USER CODE END Header_StartDefaultTask */
|
||||||
|
void StartDefaultTask(void *argument)
|
||||||
|
{
|
||||||
|
/* USER CODE BEGIN StartDefaultTask */
|
||||||
|
/* Infinite loop */
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
osDelay(1);
|
||||||
|
}
|
||||||
|
/* USER CODE END StartDefaultTask */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* USER CODE BEGIN Header_StartNetTask */
|
||||||
|
/**
|
||||||
|
* @brief Function implementing the netTask thread.
|
||||||
|
* @param argument: Not used
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
/* USER CODE END Header_StartNetTask */
|
||||||
|
void StartNetTask(void *argument)
|
||||||
|
{
|
||||||
|
/* USER CODE BEGIN StartNetTask */
|
||||||
|
osDelay(2000);
|
||||||
|
|
||||||
|
DBG_INFO("netTask: started");
|
||||||
|
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
net_poll();
|
||||||
|
|
||||||
|
#ifdef ENABLE_PHASE4_TESTS
|
||||||
|
for (int i = 1; i < 8; i++)
|
||||||
|
{
|
||||||
|
net_sock_t *sk = net_get_sock(i);
|
||||||
|
if (sk == NULL || !sk->in_use || sk->state != NET_SOCK_STATE_ESTABLISHED)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int n = net_recv(i, s_net_buf, sizeof(s_net_buf), NET_MSG_DONTWAIT);
|
||||||
|
if (n > 0)
|
||||||
|
{
|
||||||
|
net_send(i, s_net_buf, n, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_PHASE5_TESTS
|
||||||
|
ch395f_phase5_tests();
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_PHASE7_TESTS
|
||||||
|
ch395f_phase7_tests();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
osDelay(10);
|
||||||
|
}
|
||||||
|
/* USER CODE END StartNetTask */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Private application code --------------------------------------------------*/
|
||||||
|
/* USER CODE BEGIN Application */
|
||||||
|
|
||||||
|
/* USER CODE END Application */
|
||||||
|
|
||||||
10
Src/gpio.c
10
Src/gpio.c
@@ -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;
|
||||||
@@ -163,7 +169,7 @@ void MX_GPIO_Init(void)
|
|||||||
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
|
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
|
||||||
|
|
||||||
/* EXTI interrupt init*/
|
/* EXTI interrupt init*/
|
||||||
HAL_NVIC_SetPriority(EXTI9_5_IRQn, 2, 0);
|
HAL_NVIC_SetPriority(EXTI9_5_IRQn, 6, 0);
|
||||||
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
|
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
211
Src/main.c
211
Src/main.c
@@ -18,6 +18,7 @@
|
|||||||
/* USER CODE END Header */
|
/* USER CODE END Header */
|
||||||
/* Includes ------------------------------------------------------------------*/
|
/* Includes ------------------------------------------------------------------*/
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "cmsis_os.h"
|
||||||
#include "dma.h"
|
#include "dma.h"
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include "spi.h"
|
#include "spi.h"
|
||||||
@@ -33,6 +34,9 @@
|
|||||||
#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"
|
||||||
|
#include "ch395f_test.h"
|
||||||
/* USER CODE END Includes */
|
/* USER CODE END Includes */
|
||||||
|
|
||||||
/* Private typedef -----------------------------------------------------------*/
|
/* Private typedef -----------------------------------------------------------*/
|
||||||
@@ -47,7 +51,8 @@
|
|||||||
|
|
||||||
/* Private macro -------------------------------------------------------------*/
|
/* Private macro -------------------------------------------------------------*/
|
||||||
/* USER CODE BEGIN PM */
|
/* USER CODE BEGIN PM */
|
||||||
|
#define DBG_TAG "[MAIN]"
|
||||||
|
#include "dbg_log.h"
|
||||||
/* USER CODE END PM */
|
/* USER CODE END PM */
|
||||||
|
|
||||||
/* Private variables ---------------------------------------------------------*/
|
/* Private variables ---------------------------------------------------------*/
|
||||||
@@ -57,10 +62,13 @@
|
|||||||
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;
|
||||||
/* USER CODE END PV */
|
/* USER CODE END PV */
|
||||||
|
|
||||||
/* Private function prototypes -----------------------------------------------*/
|
/* Private function prototypes -----------------------------------------------*/
|
||||||
void SystemClock_Config(void);
|
void SystemClock_Config(void);
|
||||||
|
void MX_FREERTOS_Init(void);
|
||||||
/* USER CODE BEGIN PFP */
|
/* USER CODE BEGIN PFP */
|
||||||
|
|
||||||
/* USER CODE END PFP */
|
/* USER CODE END PFP */
|
||||||
@@ -110,113 +118,137 @@ 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();
|
DBG_INFO("net init: %s",
|
||||||
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 */
|
||||||
|
uint8_t mac[6];
|
||||||
|
ch395f_get_mac_addr(mac);
|
||||||
|
DBG_INFO("MAC: %02X:%02X:%02X:%02X:%02X:%02X",
|
||||||
|
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||||
|
|
||||||
if (ch395f_ret == CH395F_STATUS_OK) {
|
/* 强制 100M 全双工,建立 PHY 链路 */
|
||||||
/* 1. 复位 */
|
ch395f_set_phy(CH395F_PHY_100M_FULL);
|
||||||
ch395f_reset();
|
HAL_Delay(3000);
|
||||||
|
uint8_t phy = ch395f_get_phy_status();
|
||||||
/* 2. 配置网络参数(必须在 INIT 之前,INIT 会锁定协议栈参数) */
|
DBG_INFO("PHY: %s",
|
||||||
uint8_t ip[4] = {192, 168, 1, 100};
|
(phy == CH395F_PHY_100M_FULL) ? "100M FULL" :
|
||||||
uint8_t gw[4] = {192, 168, 1, 1};
|
(phy == CH395F_PHY_100M_HALF) ? "100M HALF" :
|
||||||
uint8_t mask[4] = {255, 255, 255, 0};
|
(phy == CH395F_PHY_10M_FULL) ? "10M FULL" :
|
||||||
ch395f_set_ip_addr(ip);
|
(phy == CH395F_PHY_10M_HALF) ? "10M HALF" :
|
||||||
ch395f_set_gwip_addr(gw);
|
(phy == CH395F_PHY_DISCONN) ? "DISCONNECT" : "UNKNOWN");
|
||||||
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];
|
|
||||||
ch395f_get_mac_addr(mac);
|
|
||||||
printf("[CH395F] MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n",
|
|
||||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
|
||||||
|
|
||||||
/* 5. 强制 100M 全双工,建立 PHY 链路 */
|
|
||||||
ch395f_set_phy(CH395F_PHY_100M_FULL);
|
|
||||||
HAL_Delay(3000);
|
|
||||||
uint8_t phy = ch395f_get_phy_status();
|
|
||||||
const char *phy_str = "UNKNOWN";
|
|
||||||
switch (phy) {
|
|
||||||
case CH395F_PHY_DISCONN: phy_str = "DISCONNECT"; break;
|
|
||||||
case CH395F_PHY_10M_FULL: phy_str = "10M FULL"; break;
|
|
||||||
case CH395F_PHY_10M_HALF: phy_str = "10M HALF"; break;
|
|
||||||
case CH395F_PHY_100M_FULL: phy_str = "100M FULL"; break;
|
|
||||||
case CH395F_PHY_100M_HALF: phy_str = "100M HALF"; break;
|
|
||||||
}
|
|
||||||
printf("[CH395F] PHY: %s\r\n", phy_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* GD5F 初始化测试 */
|
/* GD5F 初始化测试 */
|
||||||
int ret = gd5f2gq5ue_init();
|
int ret = gd5f2gq5ue_init();
|
||||||
const char *gd5f_str = "UNKNOWN";
|
DBG_INFO("NAND init: %s",
|
||||||
switch (ret) {
|
(ret == GD5F_OK) ? "OK" :
|
||||||
case GD5F_OK: gd5f_str = "OK"; break;
|
(ret == GD5F_ERROR) ? "ERROR" :
|
||||||
case GD5F_ERROR: gd5f_str = "ERROR"; break;
|
(ret == GD5F_BUSY_TIMEOUT) ? "BUSY TIMEOUT" :
|
||||||
case GD5F_BUSY_TIMEOUT: gd5f_str = "BUSY TIMEOUT"; break;
|
(ret == GD5F_ECC_ERROR) ? "ECC ERROR" :
|
||||||
case GD5F_ECC_ERROR: gd5f_str = "ECC ERROR"; break;
|
(ret == GD5F_PROGRAM_FAIL) ? "PROGRAM FAIL" :
|
||||||
case GD5F_PROGRAM_FAIL: gd5f_str = "PROGRAM FAIL"; break;
|
(ret == GD5F_ERASE_FAIL) ? "ERASE FAIL" :
|
||||||
case GD5F_ERASE_FAIL: gd5f_str = "ERASE FAIL"; break;
|
(ret == GD5F_ID_MISMATCH) ? "ID MISMATCH" : "UNKNOWN");
|
||||||
case GD5F_ID_MISMATCH: gd5f_str = "ID MISMATCH"; break;
|
|
||||||
}
|
|
||||||
printf("[GD5F] init: %s\r\n", gd5f_str);
|
|
||||||
|
|
||||||
/* TPAFE5160 ADC 测试 */
|
/* TPAFE5160 ADC 测试 */
|
||||||
int tp_ret = tpafe5160_init();
|
int tp_ret = tpafe5160_init();
|
||||||
printf("[TPAFE5160] init: %s\r\n",
|
DBG_INFO("ADC init: %s",
|
||||||
(tp_ret == TPAFE5160_OK) ? "OK" : "TIMEOUT");
|
(tp_ret == TPAFE5160_OK) ? "OK" : "TIMEOUT");
|
||||||
|
|
||||||
/* SD2506 RTC 初始化测试 */
|
/* SD2506 RTC 初始化测试 */
|
||||||
int sd_ret = sd2506_init();
|
int sd_ret = sd2506_init();
|
||||||
printf("[SD2506] init: %s\r\n",
|
DBG_INFO("SD2506 init: %s",
|
||||||
(sd_ret == SD2506_OK) ? "OK" : "I2C ERROR");
|
(sd_ret == SD2506_OK) ? "OK" : "I2C ERROR");
|
||||||
|
|
||||||
if (sd_ret == SD2506_OK) {
|
if (sd_ret == SD2506_OK) {
|
||||||
/* 读取 ID */
|
/* 读取 ID */
|
||||||
uint8_t sd_id[8];
|
uint8_t sd_id[8];
|
||||||
sd2506_get_id(sd_id);
|
sd2506_get_id(sd_id);
|
||||||
printf("[SD2506] ID: %02X%02X%02X%02X%02X%02X%02X%02X\r\n",
|
DBG_INFO("SD2506 ID: %02X%02X%02X%02X%02X%02X%02X%02X",
|
||||||
sd_id[0], sd_id[1], sd_id[2], sd_id[3],
|
sd_id[0], sd_id[1], sd_id[2], sd_id[3],
|
||||||
sd_id[4], sd_id[5], sd_id[6], sd_id[7]);
|
sd_id[4], sd_id[5], sd_id[6], sd_id[7]);
|
||||||
|
|
||||||
/* 读取当前时间 */
|
/* 读取当前时间 */
|
||||||
sd2506_time_t sd_time;
|
sd2506_time_t sd_time;
|
||||||
sd2506_get_time(&sd_time);
|
sd2506_get_time(&sd_time);
|
||||||
printf("[SD2506] time: %04d-%02d-%02d %02d:%02d:%02d (week %d)\r\n",
|
DBG_INFO("SD2506 time: %04d-%02d-%02d %02d:%02d:%02d (week %d)",
|
||||||
sd_time.year, sd_time.month, sd_time.day,
|
sd_time.year, sd_time.month, sd_time.day,
|
||||||
sd_time.hour, sd_time.minute, sd_time.second,
|
sd_time.hour, sd_time.minute, sd_time.second,
|
||||||
sd_time.week);
|
sd_time.week);
|
||||||
|
|
||||||
/* 读取温度 */
|
/* 读取温度 */
|
||||||
int8_t sd_temp;
|
int8_t sd_temp;
|
||||||
sd2506_get_temperature(&sd_temp);
|
sd2506_get_temperature(&sd_temp);
|
||||||
printf("[SD2506] temp: %d C\r\n", sd_temp);
|
DBG_INFO("SD2506 temp: %d C", sd_temp);
|
||||||
|
|
||||||
/* 读取电池电压 */
|
/* 读取电池电压 */
|
||||||
uint16_t sd_vbat;
|
uint16_t sd_vbat;
|
||||||
sd2506_get_battery_voltage(&sd_vbat);
|
sd2506_get_battery_voltage(&sd_vbat);
|
||||||
printf("[SD2506] battery: %d.%02d V\r\n",
|
DBG_INFO("SD2506 battery: %d.%02d V",
|
||||||
sd_vbat / 1000, (sd_vbat % 1000) / 10);
|
sd_vbat / 1000, (sd_vbat % 1000) / 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RS-485 初始化(UART5 + PD0 方向控制) */
|
/* RS-485 初始化(UART5 + PD0 方向控制) */
|
||||||
rs485_init(&g_rs485, &huart5, ST_DIR4_GPIO_Port, ST_DIR4_Pin);
|
rs485_init(&g_rs485, &huart5, ST_DIR4_GPIO_Port, ST_DIR4_Pin);
|
||||||
printf("[RS485] init: OK (UART5, DE=PD0)\r\n");
|
DBG_INFO("RS485 init: OK (UART5, DE=PD0)");
|
||||||
|
|
||||||
/* 启动第一次 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);
|
||||||
|
DBG_INFO("TCP listen socket: %d", 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) {
|
||||||
|
DBG_INFO("TCP bind: OK (port 8080)");
|
||||||
|
} else {
|
||||||
|
DBG_ERROR("TCP bind: FAIL");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (net_listen(s_listen_sock, NET_TCP_SERVER_MAX_CLIENTS) == 0) {
|
||||||
|
DBG_INFO("TCP listen: OK (max_clients=%d)", NET_TCP_SERVER_MAX_CLIENTS);
|
||||||
|
} else {
|
||||||
|
DBG_ERROR("TCP listen: FAIL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* 启动第一次转换(CubeMX 已配置 BUSY EXTI 中断) */
|
/* 启动第一次转换(CubeMX 已配置 BUSY EXTI 中断) */
|
||||||
tpafe5160_start_conv_irq();
|
tpafe5160_start_conv_irq();
|
||||||
|
|
||||||
|
/* CH395F 驱动测试 — 各阶段独立运行,注释 define 可跳过 */
|
||||||
|
#ifdef ENABLE_PHASE1_TESTS
|
||||||
|
ch395f_phase1_tests();
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_PHASE3_TESTS
|
||||||
|
ch395f_phase3_tests();
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_PHASE2_TESTS
|
||||||
|
ch395f_phase2_tests();
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_PHASE5_TESTS
|
||||||
|
ch395f_phase5_init();
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_PHASE6_TESTS
|
||||||
|
ch395f_phase6_tests();
|
||||||
|
#endif
|
||||||
/* USER CODE END 2 */
|
/* USER CODE END 2 */
|
||||||
|
|
||||||
|
/* Init scheduler */
|
||||||
|
osKernelInitialize(); /* Call init function for freertos objects (in cmsis_os2.c) */
|
||||||
|
MX_FREERTOS_Init();
|
||||||
|
|
||||||
|
/* Start scheduler */
|
||||||
|
osKernelStart();
|
||||||
|
|
||||||
|
/* We should never get here as control is now taken by the scheduler */
|
||||||
|
|
||||||
/* Infinite loop */
|
/* Infinite loop */
|
||||||
/* USER CODE BEGIN WHILE */
|
/* USER CODE BEGIN WHILE */
|
||||||
while (1)
|
while (1)
|
||||||
@@ -224,24 +256,10 @@ int main(void)
|
|||||||
/* USER CODE END WHILE */
|
/* USER CODE END WHILE */
|
||||||
|
|
||||||
/* USER CODE BEGIN 3 */
|
/* USER CODE BEGIN 3 */
|
||||||
/* TPAFE5160 中断模式读取 */
|
/* 网络轮询已移到 FreeRTOS netTask 中 */
|
||||||
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_Delay(500);
|
|
||||||
}
|
|
||||||
/* USER CODE END 3 */
|
/* USER CODE END 3 */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -290,6 +308,7 @@ void SystemClock_Config(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* USER CODE BEGIN 4 */
|
/* USER CODE BEGIN 4 */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HAL UART 扩展接收回调(IDLE 空闲帧中断触发)
|
* HAL UART 扩展接收回调(IDLE 空闲帧中断触发)
|
||||||
* 当 RS-485 总线空闲超过 1 个字符时间后触发
|
* 当 RS-485 总线空闲超过 1 个字符时间后触发
|
||||||
@@ -324,6 +343,28 @@ void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
|
|||||||
}
|
}
|
||||||
/* USER CODE END 4 */
|
/* USER CODE END 4 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Period elapsed callback in non blocking mode
|
||||||
|
* @note This function is called when TIM7 interrupt took place, inside
|
||||||
|
* HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
|
||||||
|
* a global variable "uwTick" used as application time base.
|
||||||
|
* @param htim : TIM handle
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
|
||||||
|
{
|
||||||
|
/* USER CODE BEGIN Callback 0 */
|
||||||
|
|
||||||
|
/* USER CODE END Callback 0 */
|
||||||
|
if (htim->Instance == TIM7)
|
||||||
|
{
|
||||||
|
HAL_IncTick();
|
||||||
|
}
|
||||||
|
/* USER CODE BEGIN Callback 1 */
|
||||||
|
|
||||||
|
/* USER CODE END Callback 1 */
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function is executed in case of error occurrence.
|
* @brief This function is executed in case of error occurrence.
|
||||||
* @retval None
|
* @retval None
|
||||||
|
|||||||
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, 7, 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 */
|
||||||
|
|||||||
@@ -70,6 +70,8 @@ void HAL_MspInit(void)
|
|||||||
__HAL_RCC_PWR_CLK_ENABLE();
|
__HAL_RCC_PWR_CLK_ENABLE();
|
||||||
|
|
||||||
/* System interrupt init*/
|
/* System interrupt init*/
|
||||||
|
/* PendSV_IRQn interrupt configuration */
|
||||||
|
HAL_NVIC_SetPriority(PendSV_IRQn, 15, 0);
|
||||||
|
|
||||||
/* USER CODE BEGIN MspInit 1 */
|
/* USER CODE BEGIN MspInit 1 */
|
||||||
|
|
||||||
|
|||||||
138
Src/stm32f4xx_hal_timebase_tim.c
Normal file
138
Src/stm32f4xx_hal_timebase_tim.c
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
/* USER CODE BEGIN Header */
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @file stm32f4xx_hal_timebase_tim.c
|
||||||
|
* @brief HAL time base based on the hardware TIM.
|
||||||
|
******************************************************************************
|
||||||
|
* @attention
|
||||||
|
*
|
||||||
|
* Copyright (c) 2026 STMicroelectronics.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This software is licensed under terms that can be found in the LICENSE file
|
||||||
|
* in the root directory of this software component.
|
||||||
|
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
/* USER CODE END Header */
|
||||||
|
|
||||||
|
/* Includes ------------------------------------------------------------------*/
|
||||||
|
#include "stm32f4xx_hal.h"
|
||||||
|
#include "stm32f4xx_hal_tim.h"
|
||||||
|
|
||||||
|
/* Private typedef -----------------------------------------------------------*/
|
||||||
|
/* Private define ------------------------------------------------------------*/
|
||||||
|
/* Private macro -------------------------------------------------------------*/
|
||||||
|
/* Private variables ---------------------------------------------------------*/
|
||||||
|
TIM_HandleTypeDef htim7;
|
||||||
|
/* Private function prototypes -----------------------------------------------*/
|
||||||
|
/* Private functions ---------------------------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function configures the TIM7 as a time base source.
|
||||||
|
* The time source is configured to have 1ms time base with a dedicated
|
||||||
|
* Tick interrupt priority.
|
||||||
|
* @note This function is called automatically at the beginning of program after
|
||||||
|
* reset by HAL_Init() or at any time when clock is configured, by HAL_RCC_ClockConfig().
|
||||||
|
* @param TickPriority: Tick interrupt priority.
|
||||||
|
* @retval HAL status
|
||||||
|
*/
|
||||||
|
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
|
||||||
|
{
|
||||||
|
RCC_ClkInitTypeDef clkconfig;
|
||||||
|
uint32_t uwTimclock, uwAPB1Prescaler = 0U;
|
||||||
|
|
||||||
|
uint32_t uwPrescalerValue = 0U;
|
||||||
|
uint32_t pFLatency;
|
||||||
|
|
||||||
|
HAL_StatusTypeDef status;
|
||||||
|
|
||||||
|
/* Enable TIM7 clock */
|
||||||
|
__HAL_RCC_TIM7_CLK_ENABLE();
|
||||||
|
|
||||||
|
/* Get clock configuration */
|
||||||
|
HAL_RCC_GetClockConfig(&clkconfig, &pFLatency);
|
||||||
|
|
||||||
|
/* Get APB1 prescaler */
|
||||||
|
uwAPB1Prescaler = clkconfig.APB1CLKDivider;
|
||||||
|
/* Compute TIM7 clock */
|
||||||
|
if (uwAPB1Prescaler == RCC_HCLK_DIV1)
|
||||||
|
{
|
||||||
|
uwTimclock = HAL_RCC_GetPCLK1Freq();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uwTimclock = 2UL * HAL_RCC_GetPCLK1Freq();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute the prescaler value to have TIM7 counter clock equal to 1MHz */
|
||||||
|
uwPrescalerValue = (uint32_t) ((uwTimclock / 1000000U) - 1U);
|
||||||
|
|
||||||
|
/* Initialize TIM7 */
|
||||||
|
htim7.Instance = TIM7;
|
||||||
|
|
||||||
|
/* Initialize TIMx peripheral as follow:
|
||||||
|
* Period = [(TIM7CLK/1000) - 1]. to have a (1/1000) s time base.
|
||||||
|
* Prescaler = (uwTimclock/1000000 - 1) to have a 1MHz counter clock.
|
||||||
|
* ClockDivision = 0
|
||||||
|
* Counter direction = Up
|
||||||
|
*/
|
||||||
|
htim7.Init.Period = (1000000U / 1000U) - 1U;
|
||||||
|
htim7.Init.Prescaler = uwPrescalerValue;
|
||||||
|
htim7.Init.ClockDivision = 0;
|
||||||
|
htim7.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||||
|
htim7.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
|
||||||
|
|
||||||
|
status = HAL_TIM_Base_Init(&htim7);
|
||||||
|
if (status == HAL_OK)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Start the TIM time Base generation in interrupt mode */
|
||||||
|
status = HAL_TIM_Base_Start_IT(&htim7);
|
||||||
|
if (status == HAL_OK)
|
||||||
|
{
|
||||||
|
/* Enable the TIM7 global Interrupt */
|
||||||
|
HAL_NVIC_EnableIRQ(TIM7_IRQn);
|
||||||
|
/* Configure the SysTick IRQ priority */
|
||||||
|
if (TickPriority < (1UL << __NVIC_PRIO_BITS))
|
||||||
|
{
|
||||||
|
/* Configure the TIM IRQ priority */
|
||||||
|
HAL_NVIC_SetPriority(TIM7_IRQn, TickPriority, 0U);
|
||||||
|
uwTickPrio = TickPriority;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = HAL_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return function status */
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Suspend Tick increment.
|
||||||
|
* @note Disable the tick increment by disabling TIM7 update interrupt.
|
||||||
|
* @param None
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
void HAL_SuspendTick(void)
|
||||||
|
{
|
||||||
|
/* Disable TIM7 update Interrupt */
|
||||||
|
__HAL_TIM_DISABLE_IT(&htim7, TIM_IT_UPDATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Resume Tick increment.
|
||||||
|
* @note Enable the tick increment by Enabling TIM7 update interrupt.
|
||||||
|
* @param None
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
void HAL_ResumeTick(void)
|
||||||
|
{
|
||||||
|
/* Enable TIM7 Update interrupt */
|
||||||
|
__HAL_TIM_ENABLE_IT(&htim7, TIM_IT_UPDATE);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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;
|
||||||
@@ -62,6 +65,8 @@ extern UART_HandleTypeDef huart5;
|
|||||||
extern UART_HandleTypeDef huart1;
|
extern UART_HandleTypeDef huart1;
|
||||||
extern UART_HandleTypeDef huart2;
|
extern UART_HandleTypeDef huart2;
|
||||||
extern UART_HandleTypeDef huart3;
|
extern UART_HandleTypeDef huart3;
|
||||||
|
extern TIM_HandleTypeDef htim7;
|
||||||
|
|
||||||
/* USER CODE BEGIN EV */
|
/* USER CODE BEGIN EV */
|
||||||
|
|
||||||
/* USER CODE END EV */
|
/* USER CODE END EV */
|
||||||
@@ -144,19 +149,6 @@ void UsageFault_Handler(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This function handles System service call via SWI instruction.
|
|
||||||
*/
|
|
||||||
void SVC_Handler(void)
|
|
||||||
{
|
|
||||||
/* USER CODE BEGIN SVCall_IRQn 0 */
|
|
||||||
|
|
||||||
/* USER CODE END SVCall_IRQn 0 */
|
|
||||||
/* USER CODE BEGIN SVCall_IRQn 1 */
|
|
||||||
|
|
||||||
/* USER CODE END SVCall_IRQn 1 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function handles Debug monitor.
|
* @brief This function handles Debug monitor.
|
||||||
*/
|
*/
|
||||||
@@ -170,33 +162,6 @@ void DebugMon_Handler(void)
|
|||||||
/* USER CODE END DebugMonitor_IRQn 1 */
|
/* USER CODE END DebugMonitor_IRQn 1 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This function handles Pendable request for system service.
|
|
||||||
*/
|
|
||||||
void PendSV_Handler(void)
|
|
||||||
{
|
|
||||||
/* USER CODE BEGIN PendSV_IRQn 0 */
|
|
||||||
|
|
||||||
/* USER CODE END PendSV_IRQn 0 */
|
|
||||||
/* USER CODE BEGIN PendSV_IRQn 1 */
|
|
||||||
|
|
||||||
/* USER CODE END PendSV_IRQn 1 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This function handles System tick timer.
|
|
||||||
*/
|
|
||||||
void SysTick_Handler(void)
|
|
||||||
{
|
|
||||||
/* USER CODE BEGIN SysTick_IRQn 0 */
|
|
||||||
|
|
||||||
/* USER CODE END SysTick_IRQn 0 */
|
|
||||||
HAL_IncTick();
|
|
||||||
/* USER CODE BEGIN SysTick_IRQn 1 */
|
|
||||||
|
|
||||||
/* USER CODE END SysTick_IRQn 1 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* STM32F4xx Peripheral Interrupt Handlers */
|
/* STM32F4xx Peripheral Interrupt Handlers */
|
||||||
/* Add here the Interrupt Handlers for the used peripherals. */
|
/* Add here the Interrupt Handlers for the used peripherals. */
|
||||||
@@ -204,6 +169,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 +211,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.
|
||||||
*/
|
*/
|
||||||
@@ -288,6 +295,20 @@ void UART5_IRQHandler(void)
|
|||||||
/* USER CODE END UART5_IRQn 1 */
|
/* USER CODE END UART5_IRQn 1 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function handles TIM7 global interrupt.
|
||||||
|
*/
|
||||||
|
void TIM7_IRQHandler(void)
|
||||||
|
{
|
||||||
|
/* USER CODE BEGIN TIM7_IRQn 0 */
|
||||||
|
|
||||||
|
/* USER CODE END TIM7_IRQn 0 */
|
||||||
|
HAL_TIM_IRQHandler(&htim7);
|
||||||
|
/* USER CODE BEGIN TIM7_IRQn 1 */
|
||||||
|
|
||||||
|
/* USER CODE END TIM7_IRQn 1 */
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function handles DMA2 stream2 global interrupt.
|
* @brief This function handles DMA2 stream2 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
264
docs/CH395F_Test_Guide.md
Normal file
264
docs/CH395F_Test_Guide.md
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
# CH395F 测试使用指南
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
1. [快速开始](#1-快速开始)
|
||||||
|
2. [各阶段测试](#2-各阶段测试)
|
||||||
|
- [Phase 1: 寄存器测试](#phase-1-寄存器测试)
|
||||||
|
- [Phase 2: TCP Client 收发+重连](#phase-2-tcp-client)
|
||||||
|
- [Phase 3: UDP Server Echo](#phase-3-udp-server-echo)
|
||||||
|
- [Phase 4: NET 层 TCP Echo](#phase-4-net-层-tcp-echo)
|
||||||
|
- [Phase 5: NET 层 UDP Echo](#phase-5-net-层-udp-echo)
|
||||||
|
- [Phase 6: DHCP](#phase-6-dhcp)
|
||||||
|
- [Phase 7: Select/Poll](#phase-7-selectpoll)
|
||||||
|
- [Phase 8: 多客户端并发](#phase-8-多客户端并发)
|
||||||
|
3. [Python 脚本参考](#3-python-脚本参考)
|
||||||
|
4. [常见问题](#4-常见问题)
|
||||||
|
5. [陷阱记录](#5-陷阱记录)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 快速开始
|
||||||
|
|
||||||
|
### 启用/禁用测试
|
||||||
|
|
||||||
|
编辑 `Drivers/BSP/CH395F/ch395f_test.h`,取消注释想要测试的阶段:
|
||||||
|
|
||||||
|
```c
|
||||||
|
//#define ENABLE_PHASE1_TESTS /* 取消注释即启用 */
|
||||||
|
//#define ENABLE_PHASE2_TESTS /* 默认关闭 */
|
||||||
|
//#define ENABLE_PHASE3_TESTS /* 默认关闭 */
|
||||||
|
#define ENABLE_PHASE4_TESTS /* 当前默认启用(netTask TCP echo) */
|
||||||
|
//#define ENABLE_PHASE5_TESTS /* 默认关闭 */
|
||||||
|
//#define ENABLE_PHASE6_TESTS /* 默认关闭(会改 IP!) */
|
||||||
|
//#define ENABLE_PHASE7_TESTS /* 默认关闭 */
|
||||||
|
```
|
||||||
|
|
||||||
|
### 测试拓扑
|
||||||
|
|
||||||
|
```
|
||||||
|
PC (192.168.1.2) ──── 交换机 ──── CH395F (192.168.1.100)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 各阶段测试
|
||||||
|
|
||||||
|
### Phase 1: 寄存器测试
|
||||||
|
|
||||||
|
| 项目 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| 类型 | 独立运行,无需 PC 配合 |
|
||||||
|
| 耗时 | ~1 秒 |
|
||||||
|
| 测试项 | 芯片版本、命令状态、IP/网关/掩码、全局中断一致性、Socket 中断、ARP、TTL |
|
||||||
|
|
||||||
|
**操作**:
|
||||||
|
```
|
||||||
|
1. 只启用 ENABLE_PHASE1_TESTS
|
||||||
|
2. 编译烧录
|
||||||
|
3. 看串口输出
|
||||||
|
```
|
||||||
|
|
||||||
|
**通过标准**:串口打印 `=== Phase 1 Tests Complete ===`,中间无 ERROR。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 2: TCP Client
|
||||||
|
|
||||||
|
| 项目 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| 类型 | 需 PC 配合 |
|
||||||
|
| 耗时 | ~60 秒 |
|
||||||
|
| 测试项 | TCP Client 连接、收发 64 字节、关闭重连 ×3 轮 |
|
||||||
|
| 默认端口 | CH395F → PC:8081 |
|
||||||
|
|
||||||
|
**操作**:
|
||||||
|
```
|
||||||
|
终端 1: python test/ch395f_socket_test.py tcp_server --port 8081 --timeout 180
|
||||||
|
终端 2: 编译烧录(只启用 ENABLE_PHASE2_TESTS)
|
||||||
|
```
|
||||||
|
|
||||||
|
**通过标准**:串口显示 3 轮 `closed: sock=0x00`,PC 显示 3 次连接且 PING echo 匹配。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 3: UDP Server Echo
|
||||||
|
|
||||||
|
| 项目 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| 类型 | 需 PC 配合 |
|
||||||
|
| 耗时 | ~30 秒 |
|
||||||
|
| 测试项 | UDP Server 模式、8 字节头解析、30 轮 echo(含 HELLO + PING + 大包) |
|
||||||
|
| 默认端口 | CH395F:60000,PC 发到 60000 |
|
||||||
|
|
||||||
|
**操作**:
|
||||||
|
```
|
||||||
|
终端 1: 编译烧录(只启用 ENABLE_PHASE3_TESTS)
|
||||||
|
终端 2: python test/ch395f_socket_test.py udp_client --ip 192.168.1.100 --port 60000 --timeout 30
|
||||||
|
```
|
||||||
|
|
||||||
|
**通过标准**:PC 显示 30/30 回显匹配(含 HELLO ×1 + PING ×5 + 大包 ×20 + 其他)。
|
||||||
|
|
||||||
|
> **关键发现**:CH395F UDP 分两种模式——DesIP=`255.255.255.255` 是 Server 模式(接受任意来源),否则只能收指定 IP:Port。每次 `write_send_buf` 后必须等 `SINT_STAT_SENDBUF_FREE`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 4: NET 层 TCP Echo
|
||||||
|
|
||||||
|
| 项目 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| 类型 | 需 PC 配合,netTask 中运行 |
|
||||||
|
| 耗时 | 按需 |
|
||||||
|
| 测试项 | `net_recv()` + `net_send()` 非阻塞 echo |
|
||||||
|
| 默认端口 | CH395F TCP Server:8080,PC 连到 8080 |
|
||||||
|
|
||||||
|
> ⚠️ 该测试在 FreeRTOS netTask 中运行,需等调度器启动(`osKernelStart`)后约 2 秒。
|
||||||
|
|
||||||
|
**操作**:
|
||||||
|
```
|
||||||
|
终端 1: 编译烧录(只启用 ENABLE_PHASE4_TESTS),看到 "netTask: started"
|
||||||
|
终端 2: python test/ch395f_socket_test.py tcp_client --ip 192.168.1.100 --port 8080
|
||||||
|
```
|
||||||
|
|
||||||
|
**通过标准**:10/10 回显匹配 + 大数据传输完整。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 5: NET 层 UDP Echo
|
||||||
|
|
||||||
|
| 项目 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| 类型 | 需 PC 配合,netTask 中运行 |
|
||||||
|
| 耗时 | 按需 |
|
||||||
|
| 测试项 | `net_recvfrom()` + `net_sendto()` 非阻塞 echo |
|
||||||
|
| 默认端口 | CH395F UDP:60000 |
|
||||||
|
|
||||||
|
> ⚠️ 该测试在 FreeRTOS netTask 中运行,需等调度器启动后约 2 秒。
|
||||||
|
|
||||||
|
**操作**:
|
||||||
|
```
|
||||||
|
终端 1: 编译烧录(只启用 ENABLE_PHASE5_TESTS),看到 "netTask: started"
|
||||||
|
终端 2: python test/ch395f_socket_test.py udp_client --ip 192.168.1.100 --port 60000 --timeout 30
|
||||||
|
```
|
||||||
|
|
||||||
|
**通过标准**:PING 5/5 + 大包 10/10。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 6: DHCP
|
||||||
|
|
||||||
|
| 项目 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| 类型 | 需 PC 配合 |
|
||||||
|
| 耗时 | ~15 秒 |
|
||||||
|
| 测试项 | DHCP 自动获取 IP、HELLO echo 验证连通性 |
|
||||||
|
|
||||||
|
> ⚠️ **DHCP 会改变 CH395F IP!** 必须独立运行,不能与其他 Phase 同时启用。
|
||||||
|
|
||||||
|
PC 运行内置 DHCP Server,完整 DISCOVER → OFFER → REQUEST → ACK 握手,然后发送 HELLO 验证 UDP 连通性。
|
||||||
|
|
||||||
|
```
|
||||||
|
终端 1: python test/ch395f_socket_test.py dhcp_server --dhcp-iface 192.168.1.2 --ip 192.168.1.100 --dhcp-mask 255.255.255.0 --dhcp-gw 192.168.1.1
|
||||||
|
终端 2: 编译烧录(只启用 ENABLE_PHASE6_TESTS)
|
||||||
|
```
|
||||||
|
|
||||||
|
**通过标准**:PC 显示 `DHCP 分配完成!` + 连通性验证通过。
|
||||||
|
|
||||||
|
> **关键:** 需管理员权限(Windows 绑定端口 67)。xid 偏移为 `data[4:8]`。`--dhcp-iface` 为 PC 网卡 IP(用于区分网卡)。
|
||||||
|
|
||||||
|
**通过标准**:PC 显示 `收到 CH395F 广播宣告` + 3 轮 HELLO echo 成功率 100%。
|
||||||
|
|
||||||
|
> **关键:** CH395F 每次 `write_send_buf` 后必须等 `SENDBUF_FREE` 中断,否则后续接收操作失败。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 7: Select/Poll
|
||||||
|
|
||||||
|
| 项目 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| 类型 | 需 PC 配合,netTask 中运行 |
|
||||||
|
| 耗时 | 按需 |
|
||||||
|
| 测试项 | `net_select()` 多路复用检测可读 socket → echo |
|
||||||
|
| 默认端口 | CH395F TCP Server:8080 |
|
||||||
|
|
||||||
|
> ⚠️ 该测试在 FreeRTOS netTask 中运行,需等调度器启动后约 2 秒。
|
||||||
|
|
||||||
|
**操作**:同 Phase 4(TCP Client 连 8080)。
|
||||||
|
|
||||||
|
**通过标准**:同 Phase 4(10/10 回显匹配)。
|
||||||
|
|
||||||
|
> Phase 4 和 Phase 7 功能相同但实现不同,通常只启用一个。Phase 7 额外验证了 `NET_FD_SET/ISSET` 宏和 `net_select()`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 8: 多客户端并发
|
||||||
|
|
||||||
|
| 项目 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| 类型 | 需 PC 配合,主循环运行 |
|
||||||
|
| 耗时 | ~2 秒 |
|
||||||
|
| 测试项 | 7 个 TCP 客户端并发,每客户端 10 轮 PING echo |
|
||||||
|
| 默认端口 | CH395F TCP Server:8080 |
|
||||||
|
|
||||||
|
**操作**:
|
||||||
|
```
|
||||||
|
终端 1: 编译烧录(启用 ENABLE_PHASE4_TESTS 或 ENABLE_PHASE7_TESTS)
|
||||||
|
终端 2: python test/ch395f_socket_test.py stress --ip 192.168.1.100 --port 8080 --count 10 --timeout 30
|
||||||
|
```
|
||||||
|
|
||||||
|
**通过标准**:7 并发 × 10 轮 = 70/70 成功率 100%。
|
||||||
|
|
||||||
|
> **关键陷阱**:`net_listen()` 中数据 Socket 1~7 的配置必须在监听 Socket 0 的 `OPEN + TCP_LISTEN` **之前**完成。CH395F 在 `TCP_LISTEN` 时刻一次性扫描可用 Socket,若颠倒顺序则 Socket 4~7 不被识别,最多只接受 3 个并发连接。详见 `docs/CH395F_Trap_Records.md → Trap 01`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Python 脚本参考
|
||||||
|
|
||||||
|
| 命令 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `tcp_server --port 8081` | PC 作 TCP Server,测试 CH395F TCP Client |
|
||||||
|
| `tcp_client --ip x.x.x.x --port 8080` | PC 作 TCP Client,测试 CH395F TCP Server echo |
|
||||||
|
| `udp_client --ip x.x.x.x --port 60000 --timeout 30` | PC 发 UDP PING,测试 CH395F UDP echo |
|
||||||
|
| `udp_server --port 8082 --timeout 60` | PC 作 UDP Server,接收 CH395F 数据 |
|
||||||
|
| `stress --ip x.x.x.x --port 8080 --count 10` | 7 并发压力测试 |
|
||||||
|
| `dhcp_server --dhcp-iface IP --dhcp-mask MASK --dhcp-gw GW` | 内置 DHCP Server,完整握手 + 连通性验证(需管理员权限) |
|
||||||
|
|
||||||
|
通用参数:
|
||||||
|
通用参数:
|
||||||
|
- `--ip`:目标 IP(默认 192.168.1.100)
|
||||||
|
- `--port`:端口(各模式默认不同)
|
||||||
|
- `--count`:测试次数(默认 10)
|
||||||
|
- `--timeout`:超时秒数(默认 30)
|
||||||
|
- `--size`:数据包大小(默认 1024)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 常见问题
|
||||||
|
|
||||||
|
| 问题 | 原因 | 解决 |
|
||||||
|
|------|------|------|
|
||||||
|
| Phase 2 `open_socket: 0x20 (FAIL)` | socket 未完全关闭 | 已修复:先 close(RST)不等 disconnect |
|
||||||
|
| Phase 2 收到 `\x00(\x00\x00...` 乱码 | socket 7(`NET_MAX_SOCKETS-1`)默认无发送缓冲 | 在 `open_socket` 前调用 `set_send_buf(sock, 28, 2)` 分配 |
|
||||||
|
| Phase 3 UDP 收不到数据 | DesIP 设为具体 IP 而非 255.255.255.255 | 设 DesIP=`0xFFFFFFFF` 进入 Server 模式 |
|
||||||
|
| Phase 3 HELLO 收到但 PING 收不到 | 没等 `SENDBUF_FREE` 就第二次写 | 每次 `write_send_buf` 后轮询 `SINT_STAT_SENDBUF_FREE` |
|
||||||
|
| Python 报 `WinError 10054` | STM32 还没启动 | 等串口看到阶段启动信息再跑 Python |
|
||||||
|
| Phase 5 UDP 不工作 | NET 层 `net_bind()` 没打开 CH395F Socket | 已修复:`net_bind()` 对 DGRAM 类型自动打开 |
|
||||||
|
| `net_recvfrom()` 源地址错误 | UDP 头解析偏移错了 | 已修复:端口读 `header[2-3]`,IP 读 `header[4-7]` |
|
||||||
|
| Phase 8 Socket 4~7 分配不到 | 数据 Socket 配置在 `TCP_LISTEN` 之后(CH395F 在 listen 时扫描) | 先配数据 Socket 1~7 的缓冲/端口/协议,再配监听 Socket 0 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 陷阱记录
|
||||||
|
|
||||||
|
详细陷阱记录(含根因分析、解决方案、发现时间)见 `docs/CH395F_Trap_Records.md`。
|
||||||
|
|
||||||
|
| # | 陷阱 | 对应文件 |
|
||||||
|
|---|------|----------|
|
||||||
|
| 01 | Socket 4~7 自动分配不到(初始化顺序) | `net_socket.c` → `net_listen()` |
|
||||||
|
| 02 | 数据 Socket 缓冲区重叠 | `net_socket.c` → `net_listen()` |
|
||||||
|
| 03 | DHCP 包 xid 偏移错误 | `test/ch395f_socket_test.py` |
|
||||||
|
| 04 | UDP 发送未等待 SENDBUF_FREE | `ch395f.c` / `ch395f_test.c` |
|
||||||
|
| 05 | CH395F 与 RTL8305NBI 自动协商不兼容 | `ch395f.c` |
|
||||||
|
| 06 | TCP KeepAlive 参数非 500ms 倍数 | `net_socket.c` → `net_init()` |
|
||||||
|
| 07 | TCP 关闭误用 disconnect 导致 FIN_WAIT_2 | `ch395f.c` |
|
||||||
|
| 08 | RECV 中断电平触发无限循环 | `net_socket.c` → `net_poll()` |
|
||||||
221
docs/CH395F_Trap_Records.md
Normal file
221
docs/CH395F_Trap_Records.md
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
# CH395F 驱动陷阱记录
|
||||||
|
|
||||||
|
记录开发过程中遇到的所有坑、根因、解决方案,避免重复踩坑。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Trap 01:Socket 4~7 自动分配不到
|
||||||
|
|
||||||
|
### 现象
|
||||||
|
多连接模式下最多接受 3 个客户端(Socket 1~3),Socket 4~7 的 CONNECT 中断从不触发,新客户端 SYN 被静默丢弃。
|
||||||
|
|
||||||
|
### 根因
|
||||||
|
`net_listen()` 中数据 Socket 的配置顺序错误。CH395F 在 `TCP_LISTEN` 时刻**一次性扫描**当前所有可用 Socket 并建立内部查找表。如果数据 Socket 4~7 在 `TCP_LISTEN` **之后**才配置缓冲区/协议/端口,自动分配逻辑不认识它们。
|
||||||
|
|
||||||
|
### 正确顺序
|
||||||
|
1. 先配置数据 Socket 1~7:`SET_SEND_BUF → SET_RECV_BUF → SET_SOUR_PORT → SET_PROTO_TYPE_TCP`
|
||||||
|
2. 最后配置监听 Socket 0:`SET_SEND_BUF → SET_RECV_BUF → SET_PROTO_TYPE_TCP → SET_SOUR_PORT → OPEN_SOCKET → TCP_LISTEN`
|
||||||
|
|
||||||
|
### 注意事项
|
||||||
|
- 数据 Socket 不调 `OPEN_SOCKET`,由 CH395F 在连接到达时自动打开
|
||||||
|
- DISCONNECT 后 CH395F 自动关闭 Socket,但保留协议/端口/缓冲区配置,可被再次分配
|
||||||
|
- 手册 §9.2.6 要求数据 Socket **先设源端口再设协议类型**(与监听 Socket 顺序相反)
|
||||||
|
|
||||||
|
### 对应文件
|
||||||
|
`Drivers/BSP/NET/net_socket.c` → `net_listen()`
|
||||||
|
|
||||||
|
### 发现时间
|
||||||
|
Phase 8 压力测试,2025-07
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Trap 02:数据 Socket 缓冲区重叠
|
||||||
|
|
||||||
|
### 现象
|
||||||
|
多连接模式下多个 Socket 数据互相覆盖,收到错误数据或客户端挂死。
|
||||||
|
|
||||||
|
### 根因
|
||||||
|
CH395F 默认只为 Socket 0~3 各分配 4 个缓冲区块(共 32 块用完),Socket 4~7 为零块。`net_listen()` 未对 Socket 4~7 显式分配独立缓冲区块,后续代码误用相同块号(如 28~31)导致数据重叠。
|
||||||
|
|
||||||
|
### 解决方案
|
||||||
|
每个数据 Socket 独占 4 个缓冲区块(2 发 + 2 收),按 `ds * 4` 基址分配,确保不重叠:
|
||||||
|
|
||||||
|
| Socket | 发送块 | 接收块 |
|
||||||
|
|--------|--------|--------|
|
||||||
|
| 1 | 4~5 | 6~7 |
|
||||||
|
| 2 | 8~9 | 10~11 |
|
||||||
|
| 3 | 12~13 | 14~15 |
|
||||||
|
| 4 | 16~17 | 18~19 |
|
||||||
|
| 5 | 20~21 | 22~23 |
|
||||||
|
| 6 | 24~25 | 26~27 |
|
||||||
|
| 7 | 28~29 | 30~31 |
|
||||||
|
|
||||||
|
### 对应文件
|
||||||
|
`Drivers/BSP/NET/net_socket.c` → `net_listen()`
|
||||||
|
|
||||||
|
### 发现时间
|
||||||
|
Phase 8 压力测试,2025-07
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Trap 03:DHCP 包 xid 偏移错误
|
||||||
|
|
||||||
|
### 现象
|
||||||
|
Python DHCP Server 收到 DISCOVER 包后无法匹配 Offer/Ack 的 xid,握手失败。
|
||||||
|
|
||||||
|
### 根因
|
||||||
|
错误使用了 `data[232:236]` 作为 xid(Wireshark 某旧版显示误导),实际 DHCP 标准偏移为 `data[4:8]`。
|
||||||
|
|
||||||
|
### 正确偏移
|
||||||
|
- xid:`data[4:8]`
|
||||||
|
- msg_type:`data[242]`
|
||||||
|
- client_mac:`data[28:34]`
|
||||||
|
- magic cookie:`data[236:240]`
|
||||||
|
|
||||||
|
### 对应文件
|
||||||
|
`test/ch395f_socket_test.py` → DHCP server 模式
|
||||||
|
|
||||||
|
### 发现时间
|
||||||
|
Phase 6, 2025-07
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Trap 04:UDP 发送后必须等待 SENDBUF_FREE
|
||||||
|
|
||||||
|
### 现象
|
||||||
|
UDP 发送后立即执行接收操作,接收长度始终为 0 或数据错误。
|
||||||
|
|
||||||
|
### 根因
|
||||||
|
CH395F 手册要求每次 `WRITE_SEND_BUF` 后必须等待 `SINT_STAT_SENBUF_FREE` 中断,否则下次写入或接收操作可能失败。
|
||||||
|
|
||||||
|
### 解决方案
|
||||||
|
每次 `ch395f_write_send_buf()` 后轮询 `ch395f_get_sock_int_status()` 检查 `SINT_STAT_SENBUF_FREE` 标志。
|
||||||
|
|
||||||
|
### 对应文件
|
||||||
|
`Drivers/BSP/CH395F/ch395f.c` / test code in `ch395f_test.c`
|
||||||
|
|
||||||
|
### 发现时间
|
||||||
|
Phase 6 广播宣告模式,2025-07
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Trap 05:CH395F 与 RTL8305NBI 自动协商不兼容
|
||||||
|
|
||||||
|
### 现象
|
||||||
|
`ch395f_get_phy_status()` 始终返回 `PHY_DISCONN`,链路无法建立。
|
||||||
|
|
||||||
|
### 根因
|
||||||
|
CH395F PHY 与 RTL8305NBI-CG 直连时自动协商失败。
|
||||||
|
|
||||||
|
### 解决方案
|
||||||
|
初始化协议栈后强制设为 100M 全双工:
|
||||||
|
```c
|
||||||
|
ch395f_set_phy(CH395F_PHY_100M_FULL);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 对应文件
|
||||||
|
`Drivers/BSP/CH395F/ch395f.c`
|
||||||
|
|
||||||
|
### 发现时间
|
||||||
|
项目初期硬件联调
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Trap 06:TCP KeepAlive 参数必须为 500ms 倍数
|
||||||
|
|
||||||
|
### 现象
|
||||||
|
设置 KeepAlive 后 TCP 连接几秒内 TIMEOUT 断开。
|
||||||
|
|
||||||
|
### 根因
|
||||||
|
CH395F 内部定时器以 500ms 为基准单位,传入非 500ms 倍数的值导致未定义行为。
|
||||||
|
且 `IDLE` 必须 > `INTVL`。
|
||||||
|
|
||||||
|
### 正确值
|
||||||
|
```c
|
||||||
|
ch395f_set_keepalive_idle(60000); // 60s(500 倍数)
|
||||||
|
ch395f_set_keepalive_intvl(5000); // 5s(500 倍数)
|
||||||
|
ch395f_set_keepalive_cnt(3); // 3 次
|
||||||
|
```
|
||||||
|
|
||||||
|
### 对应文件
|
||||||
|
`Drivers/BSP/NET/net_socket.c` → `net_init()`
|
||||||
|
|
||||||
|
### 发现时间
|
||||||
|
Phase 2 测试,2025-07
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Trap 07:TCP 关闭重连直接 close,不要 disconnect
|
||||||
|
|
||||||
|
### 现象
|
||||||
|
`disconnect → close` 后 Socket 卡在 `FIN_WAIT_2` 数分钟,无法重新打开。
|
||||||
|
|
||||||
|
### 根因
|
||||||
|
`disconnect` 发送 FIN 将 Socket 推入 `FIN_WAIT_2`,此后 `close` 不再发 RST,必须等远端发 FIN 才能关闭。
|
||||||
|
|
||||||
|
### 解决方案
|
||||||
|
直接调用 `ch395f_close_socket()`,在 ESTABLISHED 或 CLOSE_WAIT 下会发 RST 立即终止。
|
||||||
|
关闭后轮询 `ch395f_get_socket_status()` 等待 `sock=0x00` 再 `open_socket`。
|
||||||
|
|
||||||
|
### 发现时间
|
||||||
|
Phase 2 TCP Client 测试,2025-07
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Trap 08:RECV 中断电平触发,避免无限循环
|
||||||
|
|
||||||
|
### 现象
|
||||||
|
`net_poll()` 中 RECV 中断无限触发,主循环(echo 等)永远得不到执行。
|
||||||
|
|
||||||
|
### 根因
|
||||||
|
CH395F 的 RECV 中断是电平触发的——只要接收缓冲区有数据就保持 `INT#` 低电平。
|
||||||
|
`do { ... } while(int_status != 0)` 会无限循环。
|
||||||
|
|
||||||
|
### 解决方案
|
||||||
|
`net_poll()` 使用 `do { ... } while(0)` 每次只处理一批中断,由主循环负责读取数据。
|
||||||
|
|
||||||
|
### 对应文件
|
||||||
|
`Drivers/BSP/NET/net_socket.c` → `net_poll()`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 附:CH395F 驱动关键点
|
||||||
|
|
||||||
|
### 初始化顺序
|
||||||
|
- 必须按手册9.2.1节顺序:`SET_MAC → SET_IP/GWIP/MASK → INIT_CH395 → SET_PHY`
|
||||||
|
- **IP/网关/掩码必须在 `INIT_CH395` 之前设置**,INIT 会读取并锁定当前寄存器值到协议栈
|
||||||
|
- **`SET_PHY` 必须在 `INIT_CH395` 之后**,复位 MAC/PHY 建立物理链路,不影响已锁定的协议栈参数
|
||||||
|
- **`CMD_PING_ENABLE` 不需要显式调用**,INIT 后默认可用
|
||||||
|
|
||||||
|
### SPI 通信
|
||||||
|
- 每次 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 参数配置(必须在 INIT_CH395 之前)
|
||||||
|
- **重传参数**:`SET_RETRAN_COUNT`(默认12次,最大20)和 `SET_RETRAN_PERIOD`(默认500ms,最大1000ms),总重传时间 = 次数 × 周期
|
||||||
|
- **KeepAlive 参数必须为 500ms 的倍数**:`IDLE`(默认20000ms)、`INTVL`(默认15000ms),且 IDLE > INTVL;传入非 500 倍数的值导致 CH395F 内部定时器异常
|
||||||
|
- **KeepAlive 默认关闭**:需在 `SINT_STAT_CONNECT` 后调用 `ch395f_set_keepalive_enable(sock, 1)` 启用
|
||||||
|
|
||||||
|
### Socket 4~7 缓冲区
|
||||||
|
- CH395F 默认只给 Socket 0~3 各分配 4 个缓冲区块(共 32 块用完),Socket 4~7 为零块
|
||||||
|
- 多连接模式下使用 Socket 4~7 时,**必须在 `open_socket` 之前**显式分配:
|
||||||
|
- `ch395f_set_send_buf(sock, start_block, count)`
|
||||||
|
- `ch395f_set_recv_buf(sock, start_block, count)`
|
||||||
|
- 不分配会导致发送数据为固定垃圾内容(`0x0028` 填充)、接收缓冲区无法存储数据
|
||||||
|
|
||||||
|
### TCP 关闭重连
|
||||||
|
- **直接调用 `ch395f_close_socket()`,不要先调 `ch395f_tcp_disconnect()`**
|
||||||
|
- ❌ `disconnect → close`:disconnect 发 FIN 推入 FIN_WAIT_2,close 不再发 RST,Socket 卡住数分钟
|
||||||
|
- ✅ `close` 直接:在 ESTABLISHED 或 CLOSE_WAIT 下 close 发 RST 立即终止,瞬间回到 CLOSED
|
||||||
|
- 关闭后需轮询 `ch395f_get_socket_status()` 等待 `sock=0x00` 再 `open_socket`
|
||||||
|
|
||||||
|
### SOCK_TIMEOUT 处理
|
||||||
|
- 长时间无数据时可能触发 `SINT_STAT_SOCK_TIMEOUT`,**不应视为致命错误**——记录日志后继续操作即可,不要因此关闭 Socket
|
||||||
|
|
||||||
|
### UDP 模式区分
|
||||||
|
- **DesIP=0xFFFFFFFF → UDP Server 模式**:接受任意来源数据,接收数据前 8 字节为信息头(`reserved[2] src_port[2] src_ip[4]`),回发前需设置 `SET_DES_IP` 和 `SET_DES_PORT`
|
||||||
|
- **DesIP=具体 IP → UDP Client 模式**:只接收指定 IP:Port 的数据,接收数据无信息头
|
||||||
|
|
||||||
|
### UDP 发送缓冲
|
||||||
|
- 每次 `ch395f_write_send_buf()` 后必须等待 `SINT_STAT_SENBUF_FREE` 中断,否则下次写入会被 CH395F 静默丢弃
|
||||||
BIN
test/__pycache__/ch395f_socket_test.cpython-311.pyc
Normal file
BIN
test/__pycache__/ch395f_socket_test.cpython-311.pyc
Normal file
Binary file not shown.
917
test/ch395f_socket_test.py
Normal file
917
test/ch395f_socket_test.py
Normal file
@@ -0,0 +1,917 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
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(args.timeout)
|
||||||
|
|
||||||
|
try:
|
||||||
|
server_socket.bind(('0.0.0.0', args.port))
|
||||||
|
server_socket.listen(1)
|
||||||
|
log_success(f"服务器启动,监听端口 {args.port}")
|
||||||
|
|
||||||
|
for conn_idx in range(3):
|
||||||
|
try:
|
||||||
|
server_socket.settimeout(args.timeout)
|
||||||
|
log_info(f"等待第 {conn_idx+1} 个连接(超时 {args.timeout}s)...")
|
||||||
|
client_socket, client_addr = server_socket.accept()
|
||||||
|
log_success(f"连接#{conn_idx+1} 来自: {client_addr[0]}:{client_addr[1]}")
|
||||||
|
client_socket.settimeout(5)
|
||||||
|
|
||||||
|
# Test 1: 接收数据
|
||||||
|
log_info("-" * 40)
|
||||||
|
log_info(f"[连接{conn_idx+1}] 测试 1: 接收数据")
|
||||||
|
try:
|
||||||
|
data = client_socket.recv(args.size)
|
||||||
|
if data:
|
||||||
|
log_success(f"收到数据 ({len(data)} bytes): {data[:50]}...")
|
||||||
|
except socket.timeout:
|
||||||
|
log_error("接收超时")
|
||||||
|
|
||||||
|
# Test 2: PING echo
|
||||||
|
log_info(f"[连接{conn_idx+1}] 测试 2: 双向通信 (PING)")
|
||||||
|
ping_ok = 0
|
||||||
|
for i in range(5):
|
||||||
|
try:
|
||||||
|
test_data = f"PING_{i}".encode()
|
||||||
|
client_socket.send(test_data)
|
||||||
|
data = client_socket.recv(args.size)
|
||||||
|
if data and data == test_data:
|
||||||
|
log_success(f"回显匹配: {test_data.decode()}")
|
||||||
|
ping_ok += 1
|
||||||
|
elif data:
|
||||||
|
log_error(f"回显不匹配! 收到: {data[:20]}")
|
||||||
|
break
|
||||||
|
except socket.timeout:
|
||||||
|
log_error("通信超时")
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"通信错误: {e}")
|
||||||
|
break
|
||||||
|
log_info(f"PING 匹配: {ping_ok}/5")
|
||||||
|
|
||||||
|
# Test 3: 大包发送
|
||||||
|
log_info(f"[连接{conn_idx+1}] 测试 3: 大包发送")
|
||||||
|
for i in range(args.count):
|
||||||
|
try:
|
||||||
|
test_data = generate_data(min(100, args.size))
|
||||||
|
client_socket.send(test_data)
|
||||||
|
time.sleep(0.1)
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"发送错误: {e}")
|
||||||
|
break
|
||||||
|
log_success(f"发送 {args.count} 包完成")
|
||||||
|
|
||||||
|
client_socket.close()
|
||||||
|
log_success(f"连接#{conn_idx+1} 测试完成")
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
except socket.timeout:
|
||||||
|
log_error(f"等待连接#{conn_idx+1} 超时")
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"连接#{conn_idx+1} 错误: {e}")
|
||||||
|
break
|
||||||
|
|
||||||
|
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 Echo 测试(测试 CH395F UDP Server)"""
|
||||||
|
log_info("=" * 60)
|
||||||
|
log_info("UDP Echo 测试")
|
||||||
|
log_info("=" * 60)
|
||||||
|
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
dest = (args.ip, args.port)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Phase A: HELLO 探针等待 STM32 就绪
|
||||||
|
log_info(f"Phase A: 等待 CH395F 就绪(超时 {args.timeout}s)")
|
||||||
|
sock.settimeout(2)
|
||||||
|
t0 = time.time()
|
||||||
|
ready = False
|
||||||
|
while time.time() - t0 < args.timeout:
|
||||||
|
try:
|
||||||
|
sock.sendto(b"HELLO", dest)
|
||||||
|
data, addr = sock.recvfrom(64)
|
||||||
|
if data == b"HELLO":
|
||||||
|
log_success(f"就绪 ({time.time()-t0:.1f}s, from {addr[0]}:{addr[1]})")
|
||||||
|
ready = True
|
||||||
|
break
|
||||||
|
except socket.timeout:
|
||||||
|
pass
|
||||||
|
if not ready:
|
||||||
|
log_error(f"未就绪({args.timeout}s 超时)")
|
||||||
|
return
|
||||||
|
|
||||||
|
sock.settimeout(5)
|
||||||
|
|
||||||
|
# Phase B: PING Echo
|
||||||
|
log_info("-" * 40)
|
||||||
|
log_info("Phase B: PING Echo(5 轮)")
|
||||||
|
ok = 0
|
||||||
|
for i in range(5):
|
||||||
|
msg = f"PING_{i}".encode()
|
||||||
|
try:
|
||||||
|
sock.sendto(msg, dest)
|
||||||
|
data, _ = sock.recvfrom(64)
|
||||||
|
if data == msg:
|
||||||
|
ok += 1
|
||||||
|
log_success(f"PING_{i} OK")
|
||||||
|
else:
|
||||||
|
log_error(f"PING_{i} mismatch: {data[:20]}")
|
||||||
|
break
|
||||||
|
except socket.timeout:
|
||||||
|
log_error(f"PING_{i} timeout")
|
||||||
|
break
|
||||||
|
time.sleep(0.02)
|
||||||
|
log_info(f"PING: {ok}/5")
|
||||||
|
|
||||||
|
# Phase C: 大包 Echo
|
||||||
|
log_info("-" * 40)
|
||||||
|
log_info(f"Phase C: 大包 Echo({args.count} 轮)")
|
||||||
|
for i in range(args.count):
|
||||||
|
td = generate_data(min(100, args.size))
|
||||||
|
try:
|
||||||
|
sock.sendto(td, dest)
|
||||||
|
data, _ = sock.recvfrom(args.size)
|
||||||
|
if data == td:
|
||||||
|
log_success(f"#{i+1} OK ({len(data)}B)")
|
||||||
|
else:
|
||||||
|
log_error(f"#{i+1} mismatch")
|
||||||
|
break
|
||||||
|
time.sleep(0.02)
|
||||||
|
except socket.timeout:
|
||||||
|
log_warn(f"#{i+1} timeout")
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"#{i+1}: {e}")
|
||||||
|
break
|
||||||
|
|
||||||
|
log_success("Phase 3 完成")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"错误: {e}")
|
||||||
|
finally:
|
||||||
|
sock.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(args.timeout)
|
||||||
|
|
||||||
|
try:
|
||||||
|
server_socket.bind(('0.0.0.0', args.port))
|
||||||
|
server_socket.listen(1)
|
||||||
|
log_success(f"回显服务器启动,端口 {args.port}")
|
||||||
|
log_info(f"等待连接(超时 {args.timeout}s)...")
|
||||||
|
|
||||||
|
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("压力测试有失败!")
|
||||||
|
|
||||||
|
|
||||||
|
# ==================== DHCP 测试 ====================
|
||||||
|
|
||||||
|
DHCP_SERVER_PORT = 67
|
||||||
|
DHCP_CLIENT_PORT = 68
|
||||||
|
DHCP_DISCOVER = 1
|
||||||
|
DHCP_OFFER = 2
|
||||||
|
DHCP_REQUEST = 3
|
||||||
|
DHCP_ACK = 5
|
||||||
|
OPT_MESSAGE_TYPE = 53
|
||||||
|
OPT_SERVER_ID = 54
|
||||||
|
OPT_SUBNET_MASK = 1
|
||||||
|
OPT_ROUTER = 3
|
||||||
|
OPT_DNS = 6
|
||||||
|
OPT_LEASE_TIME = 51
|
||||||
|
OPT_END = 255
|
||||||
|
|
||||||
|
|
||||||
|
def _ip_to_bytes(ip):
|
||||||
|
return bytes(map(int, ip.split('.')))
|
||||||
|
|
||||||
|
|
||||||
|
def _build_dhcp_pkt(op, xid, client_mac, yiaddr, siaddr, options):
|
||||||
|
op_b = bytes([op])
|
||||||
|
htype = b'\x01'
|
||||||
|
hlen = b'\x06'
|
||||||
|
hops = b'\x00'
|
||||||
|
secs = b'\x00\x00'
|
||||||
|
flags = b'\x00\x00'
|
||||||
|
ciaddr = b'\x00\x00\x00\x00'
|
||||||
|
giaddr = b'\x00\x00\x00\x00'
|
||||||
|
chaddr = client_mac + b'\x00' * 10
|
||||||
|
sname = b'\x00' * 64
|
||||||
|
file = b'\x00' * 128
|
||||||
|
magic = b'\x63\x82\x53\x63'
|
||||||
|
return op_b + htype + hlen + hops + xid + secs + flags + ciaddr + yiaddr + siaddr + giaddr + chaddr + sname + file + magic + options
|
||||||
|
|
||||||
|
|
||||||
|
def dhcp_server_test(args):
|
||||||
|
"""DHCP Server 模式(DISCOVER → OFFER → REQUEST → ACK)"""
|
||||||
|
log_info("=" * 60)
|
||||||
|
log_info("DHCP Server 测试")
|
||||||
|
log_info("=" * 60)
|
||||||
|
|
||||||
|
server_ip = args.dhcp_iface
|
||||||
|
offer_ip = args.ip
|
||||||
|
subnet_mask = args.dhcp_mask
|
||||||
|
router = args.dhcp_gw
|
||||||
|
lease_time = 3600
|
||||||
|
|
||||||
|
log_info(f"DHCP 服务器 IP: {server_ip}")
|
||||||
|
log_info(f"待分配 IP: {offer_ip}")
|
||||||
|
log_info(f"子网掩码: {subnet_mask}")
|
||||||
|
log_info(f"网关: {router}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
||||||
|
sock.bind(('0.0.0.0', DHCP_SERVER_PORT))
|
||||||
|
sock.settimeout(60)
|
||||||
|
|
||||||
|
log_info("DHCP 服务器已启动,等待 CH395F DISCOVER...")
|
||||||
|
log_info("(请确保 MCU 端已启用 ENABLE_PHASE6_TESTS 并复位)")
|
||||||
|
print()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Phase 1: DISCOVER → OFFER
|
||||||
|
data, addr = sock.recvfrom(4096)
|
||||||
|
if len(data) <= 250:
|
||||||
|
log_error("收到无效 DHCP 包")
|
||||||
|
return
|
||||||
|
|
||||||
|
msg_type = data[242]
|
||||||
|
if msg_type != DHCP_DISCOVER:
|
||||||
|
log_error(f"预期 DISCOVER(1),收到 {msg_type}")
|
||||||
|
return
|
||||||
|
|
||||||
|
xid = data[4:8]
|
||||||
|
client_mac = data[28:34]
|
||||||
|
mac_str = ':'.join(f'{b:02X}' for b in client_mac)
|
||||||
|
log_success(f"收到 DHCP DISCOVER from {mac_str} (xid={xid.hex()})")
|
||||||
|
|
||||||
|
# Build OFFER options
|
||||||
|
options = b''
|
||||||
|
options += struct.pack('BBB', OPT_MESSAGE_TYPE, 1, DHCP_OFFER)
|
||||||
|
options += struct.pack('BB', OPT_SUBNET_MASK, 4) + _ip_to_bytes(subnet_mask)
|
||||||
|
options += struct.pack('BB', OPT_ROUTER, 4) + _ip_to_bytes(router)
|
||||||
|
options += struct.pack('BB', OPT_DNS, 4) + _ip_to_bytes(router)
|
||||||
|
options += struct.pack('BB', OPT_SERVER_ID, 4) + _ip_to_bytes(server_ip)
|
||||||
|
options += bytes([OPT_LEASE_TIME, 4]) + struct.pack('!I', lease_time)
|
||||||
|
options += bytes([OPT_END])
|
||||||
|
|
||||||
|
offer = _build_dhcp_pkt(2, xid, client_mac,
|
||||||
|
_ip_to_bytes(offer_ip),
|
||||||
|
_ip_to_bytes(server_ip),
|
||||||
|
options)
|
||||||
|
|
||||||
|
# Try both global broadcast and subnet broadcast
|
||||||
|
for bcast in ['255.255.255.255', '192.168.1.255']:
|
||||||
|
sock.sendto(offer, (bcast, DHCP_CLIENT_PORT))
|
||||||
|
log_success("发送 DHCP OFFER")
|
||||||
|
|
||||||
|
# Phase 2: REQUEST → ACK(最多重试 8 次)
|
||||||
|
sock.settimeout(5)
|
||||||
|
phase2_ok = False
|
||||||
|
for retry in range(8):
|
||||||
|
try:
|
||||||
|
data, addr = sock.recvfrom(4096)
|
||||||
|
if len(data) <= 250:
|
||||||
|
continue
|
||||||
|
msg_type = data[242]
|
||||||
|
if msg_type == DHCP_REQUEST:
|
||||||
|
rx_xid = data[4:8]
|
||||||
|
rx_mac = data[28:34]
|
||||||
|
log_success(f"收到 DHCP REQUEST from {':'.join(f'{b:02X}' for b in rx_mac)}")
|
||||||
|
|
||||||
|
ack_options = b''
|
||||||
|
ack_options += struct.pack('BBB', OPT_MESSAGE_TYPE, 1, DHCP_ACK)
|
||||||
|
ack_options += struct.pack('BB', OPT_SUBNET_MASK, 4) + _ip_to_bytes(subnet_mask)
|
||||||
|
ack_options += struct.pack('BB', OPT_ROUTER, 4) + _ip_to_bytes(router)
|
||||||
|
ack_options += struct.pack('BB', OPT_DNS, 4) + _ip_to_bytes(router)
|
||||||
|
ack_options += struct.pack('BB', OPT_SERVER_ID, 4) + _ip_to_bytes(server_ip)
|
||||||
|
ack_options += bytes([OPT_LEASE_TIME, 4]) + struct.pack('!I', lease_time)
|
||||||
|
ack_options += bytes([OPT_END])
|
||||||
|
|
||||||
|
ack = _build_dhcp_pkt(2, rx_xid, rx_mac,
|
||||||
|
_ip_to_bytes(offer_ip),
|
||||||
|
_ip_to_bytes(server_ip),
|
||||||
|
ack_options)
|
||||||
|
for bcast in ['255.255.255.255', '192.168.1.255']:
|
||||||
|
sock.sendto(ack, (bcast, DHCP_CLIENT_PORT))
|
||||||
|
log_success(f"发送 DHCP ACK → {offer_ip}")
|
||||||
|
log_success("DHCP 分配完成!")
|
||||||
|
phase2_ok = True
|
||||||
|
break
|
||||||
|
elif msg_type == DHCP_DISCOVER:
|
||||||
|
# 重传 DISCOVER,重发 OFFER
|
||||||
|
xid = data[4:8]
|
||||||
|
client_mac = data[28:34]
|
||||||
|
options = b''
|
||||||
|
options += struct.pack('BBB', OPT_MESSAGE_TYPE, 1, DHCP_OFFER)
|
||||||
|
options += struct.pack('BB', OPT_SUBNET_MASK, 4) + _ip_to_bytes(subnet_mask)
|
||||||
|
options += struct.pack('BB', OPT_ROUTER, 4) + _ip_to_bytes(router)
|
||||||
|
options += struct.pack('BB', OPT_DNS, 4) + _ip_to_bytes(router)
|
||||||
|
options += struct.pack('BB', OPT_SERVER_ID, 4) + _ip_to_bytes(server_ip)
|
||||||
|
options += bytes([OPT_LEASE_TIME, 4]) + struct.pack('!I', lease_time)
|
||||||
|
options += bytes([OPT_END])
|
||||||
|
offer = _build_dhcp_pkt(2, xid, client_mac,
|
||||||
|
_ip_to_bytes(offer_ip),
|
||||||
|
_ip_to_bytes(server_ip),
|
||||||
|
options)
|
||||||
|
for bcast in ['255.255.255.255', '192.168.1.255']:
|
||||||
|
sock.sendto(offer, (bcast, DHCP_CLIENT_PORT))
|
||||||
|
log_info(f"重发 DHCP OFFER (retry={retry+1})")
|
||||||
|
except socket.timeout:
|
||||||
|
log_warn(f"Phase 2 等待超时 (retry={retry+1})")
|
||||||
|
if not phase2_ok:
|
||||||
|
log_warn("DHCP REQUEST 未收到")
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Phase 3: 连通性验证(MCU Phase 6 内置 HELLO 端口 = 60000)
|
||||||
|
hello_port = args.port if args.port != 8080 else 60000
|
||||||
|
log_info(f"验证 {offer_ip} 连通性(UDP HELLO → port {hello_port})")
|
||||||
|
sock.close()
|
||||||
|
|
||||||
|
time.sleep(3)
|
||||||
|
verify = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
verify.settimeout(2)
|
||||||
|
phase3_ok = False
|
||||||
|
for retry in range(5):
|
||||||
|
try:
|
||||||
|
verify.sendto(b"HELLO", (offer_ip, hello_port))
|
||||||
|
data, addr = verify.recvfrom(64)
|
||||||
|
if data == b"HELLO":
|
||||||
|
log_success(f"连通性验证通过:{addr[0]}:{addr[1]} 响应正常")
|
||||||
|
phase3_ok = True
|
||||||
|
break
|
||||||
|
time.sleep(1)
|
||||||
|
except (socket.timeout, ConnectionResetError, OSError):
|
||||||
|
log_info(f"等待 UDP 响应... (retry={retry+1})")
|
||||||
|
time.sleep(1)
|
||||||
|
if not phase3_ok:
|
||||||
|
log_warn("连通性验证超时(MCU 的 UDP 服务可能未运行或端口不正确)")
|
||||||
|
log_info("提示:CH395F UDP echo 默认端口为 60000,请使用 --port 60000")
|
||||||
|
|
||||||
|
except socket.timeout:
|
||||||
|
log_error("等待 DHCP DISCOVER 超时(60s)")
|
||||||
|
finally:
|
||||||
|
sock.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ==================== 数据包大小测试 ====================
|
||||||
|
|
||||||
|
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
|
||||||
|
%(prog)s dhcp_server --dhcp-iface 192.168.1.2 --ip 192.168.1.100
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument('mode', choices=['tcp_server', 'tcp_client', 'udp_server', 'udp_client',
|
||||||
|
'tcp_echo', 'udp_echo', 'stress', 'packet_size',
|
||||||
|
'dhcp_server'],
|
||||||
|
help='测试模式')
|
||||||
|
parser.add_argument('--ip', default='192.168.1.100', help='目标 IP 地址 / DHCP 待分配 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='数据包大小')
|
||||||
|
parser.add_argument('--timeout', type=int, default=180, help='接受连接超时(秒,默认180)')
|
||||||
|
parser.add_argument('--dhcp-iface', default='192.168.1.2', help='DHCP 服务器网卡 IP')
|
||||||
|
parser.add_argument('--dhcp-mask', default='255.255.255.0', help='DHCP 分配的子网掩码')
|
||||||
|
parser.add_argument('--dhcp-gw', default='192.168.1.1', help='DHCP 分配的网关')
|
||||||
|
|
||||||
|
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)
|
||||||
|
elif args.mode == 'dhcp_server':
|
||||||
|
dhcp_server_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