Files

283 lines
9.6 KiB
C
Raw Permalink 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.
/**
* @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 <string.h>
#include <stdio.h>
#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