/* 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 #include "net_task.h" #include "ch395f.h" #include "dbg_log.h" #include "net_socket.h" #include "lftpd.h" #include "../test/ch395f_test_task.h" #include "../test/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/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 */