362 lines
12 KiB
C
362 lines
12 KiB
C
/* 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 */
|