Files
STM32F4-Base/Src/freertos.c
T

362 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 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 "test_config.h" /* 套件选择:STORAGE 套件下 defaultTask 让出存储所有权 */
#include <string.h>
#include "net_task.h"
#include "ch395f.h"
#include "dbg_log.h"
#include "net_socket.h"
#include "lftpd.h"
#include "../test/board/ch395f_test_task.h"
#include "../test/board/ch395f_test.h" /* ENABLE_NET_LAYER_TESTS:netTask 条件创建 */
#include "time_sync.h"
#include "sys_events.h"
#include "default_task.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 */
/* 存储测试变量(g_storage_stats / s_perf_buf)已迁至 test/board/storage_test_task.c */
osThreadId_t timeSyncTaskHandle;
const osThreadAttr_t timeSyncTask_attributes = {
.name = "timeSyncTask",
.stack_size = 512 * 4,
.priority = (osPriority_t) osPriorityNormal,
};
/* USER CODE END Variables */
/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
.name = "defaultTask",
.stack_size = 1024 * 4, /* 512→1024: 该任务扛 mount+mkfs+FAT探针+cfg加载+syslog写+
* 配置引擎(全深层 FatFS I/O),2KB 实测峰值溢出——开启
* configCHECK_FOR_STACK_OVERFLOW=2 后被钩子抓到(2026-09-21)。
* 此前静默溢出腐蚀堆相邻块。改 .ioc 前须同步此值防 CubeMX 覆盖 */
.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,
};
/* Definitions for ftpTask */
osThreadId_t ftpTaskHandle;
const osThreadAttr_t ftpTask_attributes = {
.name = "ftpTask",
.stack_size = 1024 * 4,
.priority = (osPriority_t) osPriorityNormal,
};
/* Definitions for testTask */
osThreadId_t testTaskHandle;
const osThreadAttr_t testTask_attributes = {
.name = "testTask",
.stack_size = 2048 * 4, /* 1024→2048: 存储套件 deep call chain + 局部缓冲,4KB 实测溢出(2026-09-20) */
.priority = (osPriority_t) osPriorityBelowNormal,
};
/* Definitions for uiTask */
osThreadId_t uiTaskHandle;
const osThreadAttr_t uiTask_attributes = {
.name = "uiTask",
.stack_size = 4096 * 4,
.priority = (osPriority_t) osPriorityBelowNormal,
};
/* Definitions for netMsgQueue */
osMessageQueueId_t netMsgQueueHandle;
const osMessageQueueAttr_t netMsgQueue_attributes = {
.name = "netMsgQueue"
};
/* Definitions for sys_evt */
osEventFlagsId_t sys_evtHandle;
const osEventFlagsAttr_t sys_evt_attributes = {
.name = "sys_evt"
};
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */
void ui_task_func(void *argument);
/* USER CODE END FunctionPrototypes */
void StartDefaultTask(void *argument);
void StartNetTask(void *argument);
void StartFtpTask(void *argument);
void start_test_task(void *argument);
void StartUiTask(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 */
/* Create the queue(s) */
/* creation of netMsgQueue */
netMsgQueueHandle = osMessageQueueNew (8, sizeof(net_msg_t), &netMsgQueue_attributes);
/* 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);
/* creation of ftpTask */
ftpTaskHandle = osThreadNew(StartFtpTask, NULL, &ftpTask_attributes);
/* creation of testTask */
testTaskHandle = osThreadNew(start_test_task, NULL, &testTask_attributes);
/* creation of uiTask */
uiTaskHandle = osThreadNew(StartUiTask, NULL, &uiTask_attributes);
/* USER CODE BEGIN RTOS_THREADS */
/* netTask = 基础线程:上方生成区的实例是全构建唯一实例(P1-6:旧
* #ifdef ENABLE_NET_LAYER_TESTS 的重复创建已删除)。
* - 产品 / NET 层测试模式:正常运行 bring_up + net_poll
* - CH395F 硬件层测试模式:net_task_func 入口自挂起(testTask 独占 CH395F) */
/* 本地时间同步任务(PC 推送 TCP):依赖 netTask 处理消息队列 */
timeSyncTaskHandle = osThreadNew(time_sync_task, NULL, &timeSyncTask_attributes);
/* USER CODE END RTOS_THREADS */
/* Create the event(s) */
/* creation of sys_evt */
sys_evtHandle = osEventFlagsNew(&sys_evt_attributes);
/* 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 */
/* 任务体已迁出至 App/task/default_task.c(2026-09-25):
* 本文件只保留 CubeMX 接线(任务创建)与崩溃钩子 */
default_task_func(argument);
/* 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 */
net_task_func(argument);
/* USER CODE END StartNetTask */
}
/* USER CODE BEGIN Header_StartFtpTask */
/**
* @brief Function implementing the ftpTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartFtpTask */
__weak void StartFtpTask(void *argument)
{
/* USER CODE BEGIN StartFtpTask */
/* 等网络 + 存储都真正就绪后再 listen,取代拍脑袋的 7s 魔法延时 */
/*
sys_evtHandle:等待哪个事件组
SYS_EVT_NET_READY | SYS_EVT_STORAGE_READY:要等哪几位(1u<<0 网络、1u<<1 存储)
osFlagsWaitAll:请求的位全部置位才唤醒(即"网络且存储都就绪")
osWaitForever:无限期等待,不设超时——任务会挂起(让出 CPU,零占用),直到生产者置位对应位才被唤醒
*/
if (sys_evtHandle != NULL) {
/* osFlagsNoClear 必须带:就绪位是**状态**不是命令,消费型等待会把位清掉,
* 导致后面 WaitAll(两位) 的等待者永远等不到(2026-09-21 实测:netTask 先
* 消费 STORAGE_READY、uiTask/timeSync 再消费 NET_READY → 本任务永不唤醒、
* FTP 21 端口从未监听)。 */
(void)osEventFlagsWait(sys_evtHandle,
SYS_EVT_NET_READY | SYS_EVT_STORAGE_READY,
osFlagsWaitAll | osFlagsNoClear, osWaitForever);
}
lftpd_t ftp;
lftpd_start("/", 21, &ftp);
/* 广播"FTP 服务就绪"(预留给依赖 FTP 的后续功能) */
if (sys_evtHandle != NULL) {
osEventFlagsSet(sys_evtHandle, SYS_EVT_FTP_READY);
}
/* USER CODE END StartFtpTask */
}
/* USER CODE BEGIN Header_start_test_task */
/**
* @brief Function implementing the testTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_start_test_task */
__weak void start_test_task(void *argument)
{
/* USER CODE BEGIN start_test_task */
/* Infinite loop */
for(;;)
{
osDelay(1);
}
/* USER CODE END start_test_task */
}
/* USER CODE BEGIN Header_StartUiTask */
/**
* @brief Function implementing the uiTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartUiTask */
void StartUiTask(void *argument)
{
/* USER CODE BEGIN StartUiTask */
ui_task_func(argument);
/* USER CODE END StartUiTask */
}
/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
/*
* 名称指针合法性校验(栈溢出/越界可能已破坏 TCB,指针不可信):
* 只接受落在 Flash / 主 SRAM / CCM 映射范围内的指针;不校验就直接交给 UART,
* 钩子自身也会以同样方式崩(2026-09-24 实测 HardFault:BFAR=0x10010000 恰为
* CCM 末尾+1,PC 落在 HAL_UART_Transmit 的缓冲读取处)。
*/
static int hook_ptr_ok(const void *p)
{
uint32_t a = (uint32_t)p;
uint32_t win = 32u; /* 将要读取的最大字节数(任务名 ≤ 32) */
if ((a >= 0x08000000u) && (a <= (0x08100000u - win))) {
return 1; /* Flash(RO 区) */
}
if ((a >= 0x20000000u) && (a <= (0x20020000u - win))) {
return 1; /* SRAM1 + SRAM2 */
}
if ((a >= 0x10000000u) && (a <= (0x10010000u - win))) {
return 1; /* CCM(FreeRTOS 堆:TCB/栈所在) */
}
return 0;
}
/*
* 栈溢出钩子(configCHECK_FOR_STACK_OVERFLOW=2,2026-09-20 存储套件死机事故后加):
* 溢出 = 内核状态已不可信,禁止走 printf/内核对象/控制台锁,裸发固定文本后复位。
* 2026-09-24 加固:任务名先经范围校验并拷入本地缓冲(不再把 TCB 指针交给 UART),
* 指针不可信时打印占位文本——避免"上报崩溃的代码自己再崩一次"。
*/
void vApplicationStackOverflowHook(void *xTask, signed char *pcTaskName)
{
static const char msg_head[] = "\r\n[ERR] STACK OVERFLOW task=";
static const char msg_bad[] = "(name unavailable)";
uint16_t len = 0u;
(void)xTask;
dbg_console_write_raw(msg_head, (unsigned)(sizeof(msg_head) - 1u));
if ((pcTaskName != NULL) && (hook_ptr_ok(pcTaskName) != 0)) {
while ((len < 32u) && (pcTaskName[len] != '\0')) {
len++;
}
}
if (len == 0u) {
dbg_console_write_raw(msg_bad, (unsigned)(sizeof(msg_bad) - 1u));
} else {
char name[33]; /* 拷入本地缓冲:UART 永不接触 TCB 指针 */
memcpy(name, pcTaskName, (size_t)len);
name[len] = '\0';
dbg_console_write_raw(name, (unsigned)len);
}
dbg_console_write_raw("\r\n", 2u);
HAL_Delay(200);
NVIC_SystemReset();
}
/*
* 堆分配失败钩子:只告警不复位(NULL 由各调用点自行处理并上报自检)。
* 同样走裸 UART 有界发送——钩子可能在临界区内被调,printf/信号量不可用。
*/
void vApplicationMallocFailedHook(void)
{
static const char msg[] = "\r\n[ERR] MALLOC FAILED (heap exhausted)\r\n";
dbg_console_write_raw(msg, (unsigned)(sizeof(msg) - 1u));
}
/* USER CODE END Application */