/** * @file app_freertos.c * @brief FreeRTOS 运行信息查看(任务/堆/CPU占用) * * 参考实现:`CCU601E_RUN/BSP/freertos/app_freertos.c` * * 本工程适配说明: * - 任务“栈大小/周期”从 `app_init/app_init.c` 的任务表 `my_task_data[]` 获取 * - 看门狗计数 `wdtCount` 通过 `u16_get_wdt_cnt()` 获取实时值 * - 通过 letter_shell 导出 `ps` 命令打印任务信息 */ #include "freertos/app_freertos.h" #include #include #include "FreeRTOS.h" #include "task.h" #include "app_init/app_init.h" #include "wdt_task/wdt_task.h" #include "publicdata/public_define.h" #if (MY_SHELL_EN) #include "letter_shell/shell_port.h" #define APP_RTOS_OUTPUT(str_) shell_send_String((str_)) #else static void app_rtos_output(const char *str) { (void)str; } #define APP_RTOS_OUTPUT(str_) app_rtos_output((str_)) #endif /* 按任务名查表:type=0 栈大小(字节);type=1 周期(ms) */ static uint32_t get_task_cfg_by_name(const char *name, uint8_t type) { if (name == NULL) { return 0U; } for (uint32_t i = 0U; i < (uint32_t)MY_TASK_NUM; i++) { if (strcmp(name, my_task_data[i].task_name) == 0) { return (type == 0U) ? (uint32_t)my_task_data[i].task_size : (uint32_t)my_task_data[i].task_timer; } } return 0U; } /* 按任务名查任务ID:成功返回1,并通过 task_id 输出;失败返回0 */ static uint8_t get_task_id_by_name(const char *name, TASK_ID *task_id) { if ((name == NULL) || (task_id == NULL)) { return 0U; } for (uint32_t i = 0U; i < (uint32_t)MY_TASK_NUM; i++) { if (strcmp(name, my_task_data[i].task_name) == 0) { *task_id = (TASK_ID)i; return 1U; } } return 0U; } /** * @brief 按优先级对任务状态数组进行排序,返回排序后的原始数组下标 * @param pxTaskStatusArray 任务状态数组指针 * @param uxArraySize 数组长度 * @param rtos_pri_index 输出缓冲区(最大30个元素),存储排序后的原始数组下标 * @return 实际存储数量(≤uxArraySize) */ static UBaseType_t SortTasksByPriorityIndex(const TaskStatus_t *pxTaskStatusArray, UBaseType_t uxArraySize, UBaseType_t rtos_pri_index[30]) { if (pxTaskStatusArray == NULL || rtos_pri_index == NULL) { return 0U; } UBaseType_t valid_size = (uxArraySize > 30U) ? 30U : uxArraySize; UBaseType_t indexes[30]; for (UBaseType_t i = 0U; i < valid_size; i++) { indexes[i] = i; } for (UBaseType_t i = 0U; i + 1U < valid_size; i++) { for (UBaseType_t j = 0U; j + 1U < (valid_size - i); j++) { if (pxTaskStatusArray[indexes[j]].uxCurrentPriority <= pxTaskStatusArray[indexes[j + 1U]].uxCurrentPriority) { UBaseType_t tmp = indexes[j]; indexes[j] = indexes[j + 1U]; indexes[j + 1U] = tmp; } } } for (UBaseType_t i = 0U; i < valid_size; i++) { rtos_pri_index[i] = indexes[i]; } return valid_size; } SystemInfo_t *getSystemInfo(void) { TaskStatus_t *pxTaskStatusArray = NULL; UBaseType_t uxArraySize; UBaseType_t rtos_pri[30] = {0}; const char states[] = {'X', 'R', 'B', 'S', 'D'}; uint32_t ulTotalTime = 0U; uxArraySize = uxTaskGetNumberOfTasks(); pxTaskStatusArray = (TaskStatus_t *)pvPortMalloc(uxArraySize * sizeof(TaskStatus_t)); if (pxTaskStatusArray == NULL) { return NULL; } uxArraySize = uxTaskGetSystemState(pxTaskStatusArray, uxArraySize, &ulTotalTime); UBaseType_t sorted_count = SortTasksByPriorityIndex(pxTaskStatusArray, uxArraySize, rtos_pri); SystemInfo_t *sysInfo = (SystemInfo_t *)pvPortMalloc(sizeof(SystemInfo_t)); if (sysInfo == NULL) { vPortFree(pxTaskStatusArray); return NULL; } memset(sysInfo, 0, sizeof(SystemInfo_t)); sysInfo->tasks = (TaskInfo_t *)pvPortMalloc(sorted_count * sizeof(TaskInfo_t)); if (sysInfo->tasks == NULL) { vPortFree(pxTaskStatusArray); vPortFree(sysInfo); return NULL; } memset(sysInfo->tasks, 0, sorted_count * sizeof(TaskInfo_t)); sysInfo->taskCount = (unsigned int)sorted_count; for (UBaseType_t i = 0U; i < sorted_count; i++) { UBaseType_t x = rtos_pri[i]; if (x >= uxArraySize) { break; } TaskInfo_t *task = &sysInfo->tasks[i]; strncpy(task->taskName, pxTaskStatusArray[x].pcTaskName, sizeof(task->taskName) - 1U); task->taskName[sizeof(task->taskName) - 1U] = '\0'; if (pxTaskStatusArray[x].eCurrentState <= eDeleted) { task->state = states[pxTaskStatusArray[x].eCurrentState]; } else { task->state = '?'; } task->id = (unsigned int)i; task->priority = (unsigned int)pxTaskStatusArray[x].uxCurrentPriority; task->allocatedStack = (unsigned int)get_task_cfg_by_name(pxTaskStatusArray[x].pcTaskName, 0U); task->cycle = (unsigned int)get_task_cfg_by_name(pxTaskStatusArray[x].pcTaskName, 1U); { TASK_ID task_id; task->wdtCount = (get_task_id_by_name(pxTaskStatusArray[x].pcTaskName, &task_id) == 1U) ? (unsigned int)u16_get_wdt_cnt((uint8_t)task_id) : 0U; } task->minFreeStack = (unsigned int)pxTaskStatusArray[x].usStackHighWaterMark * 4U; sysInfo->totalAllocatedStack += task->allocatedStack; if (task->allocatedStack > 0U) { unsigned int freePct = (task->minFreeStack * 100U) / task->allocatedStack; task->stackUsagePercentage = (freePct == 0U) ? 0U : (100U - freePct); } else { task->stackUsagePercentage = 0U; } task->cpuUsagePercentage = (ulTotalTime > 0U) ? (unsigned int)((pxTaskStatusArray[x].ulRunTimeCounter * 100UL) / ulTotalTime) : 0U; } sysInfo->freeHeapSize = (unsigned int)xPortGetFreeHeapSize(); sysInfo->minEverFreeHeapSize = (unsigned int)xPortGetMinimumEverFreeHeapSize(); sysInfo->totalHeapSize = (unsigned int)configTOTAL_HEAP_SIZE; vPortFree(pxTaskStatusArray); return sysInfo; } void freeSystemInfo(SystemInfo_t *sysInfo) { if (sysInfo != NULL) { if (sysInfo->tasks != NULL) { vPortFree(sysInfo->tasks); } vPortFree(sysInfo); } } void printSystemInfo(void) { SystemInfo_t *sysInfo = getSystemInfo(); if (sysInfo == NULL) { APP_RTOS_OUTPUT("Error: Failed to get system information!\r\n"); return; } char buffer[256]; (void)snprintf(buffer, sizeof(buffer), "%-3s %-12s %-2s %-4s %-6s %-6s %-6s %-6s %-5s %-5s\r\n", "ID", "TaskName", "St", "Pri", "Cycle", "Stack", "Wdt", "Free", "Use%", "CPU%"); APP_RTOS_OUTPUT(buffer); for (unsigned int i = 0U; i < sysInfo->taskCount; i++) { TaskInfo_t *task = &sysInfo->tasks[i]; const char *cpuStr = (task->cpuUsagePercentage > 0U) ? "" : "<1"; if (task->cpuUsagePercentage > 0U) { (void)snprintf(buffer, sizeof(buffer), "%-3u %-12.12s %-2c %-4u %-6u %-6u %-6u %-6u %-5u %-5u%%\r\n", task->id, task->taskName, task->state, task->priority, task->cycle, task->allocatedStack, task->wdtCount, task->minFreeStack, task->stackUsagePercentage, task->cpuUsagePercentage); } else { (void)snprintf(buffer, sizeof(buffer), "%-3u %-12.12s %-2c %-4u %-6u %-6u %-6u %-6u %-5u %-5s%%\r\n", task->id, task->taskName, task->state, task->priority, task->cycle, task->allocatedStack, task->wdtCount, task->minFreeStack, task->stackUsagePercentage, cpuStr); } APP_RTOS_OUTPUT(buffer); } float free_percent = (sysInfo->totalHeapSize > 0U) ? ((float)sysInfo->freeHeapSize * 100.0f) / (float)sysInfo->totalHeapSize : 0.0f; float min_percent = (sysInfo->totalHeapSize > 0U) ? ((float)sysInfo->minEverFreeHeapSize * 100.0f) / (float)sysInfo->totalHeapSize : 0.0f; (void)snprintf(buffer, sizeof(buffer), "\r\nHeap:\r\n" "Free: %u bytes (%.1f%%)\r\n" "Min: %u bytes (%.1f%%)\r\n" "Stacks: %u bytes\r\n" "Total: %u bytes\r\n" "----------------------------------------\r\n", sysInfo->freeHeapSize, free_percent, sysInfo->minEverFreeHeapSize, min_percent, sysInfo->totalAllocatedStack, sysInfo->totalHeapSize); APP_RTOS_OUTPUT(buffer); freeSystemInfo(sysInfo); } #if (MY_SHELL_EN) /* 兼容入口:对齐参考工程函数名 */ static void printTaskStackUsage(void) { printSystemInfo(); } /* Shell 命令:ps */ static void v_task_show(void) { printTaskStackUsage(); } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC), ps, v_task_show, myshlle-- task runing state show); #endif