#include "HDLog.h" #include "HBit.h" #include "HShellLex.h" #include #include #include #include #if USE_RTOS_LOG_LOCK #include "FreeRTOS.h" #include "semphr.h" #endif typedef struct HDLogStackCheckInfo { uint32_t enable : 1; ///< 是否使用 uint32_t stackSize : 31; ///< 栈大小 unsigned long stackAddr; ///< 栈开始地址, 可能误差多字节 unsigned long taskID; ///< 任务ID } HDLogStackCheckInfo; #if USE_HD_FPGA_CHECK enum eFpgaSendType { kFpgaSendTypeControl = 0x01, ///< 控制段 kFpgaSendTypeSend = 0x02, ///< 发送段 kFpgaSendTypeFeedBack = 0x03, ///< 反馈段 }; typedef struct HDLogFpgaCheckInfo { uint32_t sendCount; ///< 发送次数 uint32_t recvCount; ///< 接收次数 uint32_t sendError; ///< 发送错误次数 uint32_t recvError; ///< 接收错误次数 uint32_t sendTypeCount[3]; ///< 发送类型次数 uint32_t readTypeCount[3]; ///< 接收类型次数 } HDLogFpgaCheckInfo; #define CHECK_FPGA_INFO_ID (100) #endif static HShellMatch sLogMatch[] = { HSHELL_MATCH_ITEM(kLogLevelSwitch, "log"), HSHELL_MATCH_ITEM(kLogLevelColor, "logColor"), HSHELL_MATCH_ITEM(kLogLevelDebug, "logDebug"), HSHELL_MATCH_ITEM(kLogLevelError, "logError"), HSHELL_MATCH_ITEM(kLogLevelHex, "logHex"), HSHELL_MATCH_ITEM(kLogLevelStack, "logStack"), HSHELL_MATCH_ITEM(kLogLevelHeap, "logHeap"), #if USE_HD_FPGA_CHECK HSHELL_MATCH_ITEM(CHECK_FPGA_INFO_ID, "checkFpga"), HSHELL_MATCH_ITEM(CHECK_FPGA_INFO_ID + 1, "clearCheckFpga"), #endif }; static HBIT_DEFINE(sLogItem, kLogLevelMax); static uint32_t (*sGetTime)() = NULL; static HDLogGetTaskType_t sGetCurrTask = NULL; static HDLogGetStackSizeType_t sGetCurrStackSize = NULL; static HDLogFlashOpt_t sFlashCall = NULL; #if USE_SYS_CHECK_HEAP static HDLogGetStackSizeType_t sGetCurrHeapSize = NULL; #endif static HDLogStackCheckInfo sStackCheckInfo[USE_CHECK_STACK_NUM]; #if USE_RTOS_LOG_LOCK static SemaphoreHandle_t sLogMutex = NULL; #define LOG_LOCK() do { if (sLogMutex && xSemaphoreTake(sLogMutex, pdMS_TO_TICKS(2000)) != pdTRUE) { printf("log mutex timeout\r\n"); } } while (0) #define LOG_UNLOCK() do { if (sLogMutex) { xSemaphoreGive(sLogMutex); } } while (0) #else #define LOG_LOCK() #define LOG_UNLOCK() #endif #if USE_HD_FPGA_CHECK static HDLogFpgaCheckInfo sFpgaCheckInfo; #define FPGA_TYPE_INDEX(index, maxValue) ((index) > (maxValue) ? (maxValue) : (index)) static uint32_t *GetFpgaType(uint8_t type, uint8_t isWrite) { if (isWrite) { // 异常段返回最后一个记录 if (type != kFpgaSendTypeControl && type != kFpgaSendTypeSend) { return &sFpgaCheckInfo.sendTypeCount[2]; } return &sFpgaCheckInfo.sendTypeCount[type - 1]; } switch (type) { case kFpgaSendTypeControl: return &sFpgaCheckInfo.readTypeCount[0]; case kFpgaSendTypeFeedBack: return &sFpgaCheckInfo.readTypeCount[1]; default: break; } return &sFpgaCheckInfo.readTypeCount[2]; } #endif static void LogHex(const uint8_t *data, int len, uint8_t checkPrint, uint32_t *offset, uint8_t lock) { if (checkPrint && HBitGet(sLogItem, kLogLevelHex) == 0) { return; } if (len <= 0) { return; } if (lock) { LOG_LOCK(); } #define PRINT_HEX(...) printf(__VA_ARGS__); if (offset == NULL || *offset == 0) { PRINT_HEX(" "); // 16进制打印, 打印15个换行, 开头打印0A-0F 开头样式, 数据列每行00-FF for (int i = 0; i < 16; ++i) { PRINT_HEX("0%X ", i); } PRINT_HEX("\r\n"); for (int i = 0; i < 17; ++i) { PRINT_HEX("---"); ; } PRINT_HEX("\r\n"); } int index = offset ? *offset : 0; for (int i = 0; i < len; ++i, ++index) { if (index % 16 == 0) { PRINT_HEX("%X%X| ", index / 256, index / 16 % 16); } PRINT_HEX("%02X ", data[i]); if (index % 16 == 15) { PRINT_HEX("\r\n"); } } if (offset) { *offset = index; } else { PRINT_HEX("\r\n"); } #undef PRINT_HEX if (lock) { LOG_UNLOCK(); } } static void LogShell(HSHELL_FUNC_ARGS) { uint32_t arg1 = 0; // 可以不用检查参数, 如果未输入就默认关闭 HSHellToUint32(tokens, tokensLen, 1, &arg1); #if USE_HD_FPGA_CHECK switch (key) { case CHECK_FPGA_INFO_ID: HSHELL_PRINTFL("sendCount[%u], recvCount[%u], sendError[%u], recvError[%u]", sFpgaCheckInfo.sendCount, sFpgaCheckInfo.recvCount, sFpgaCheckInfo.sendError, sFpgaCheckInfo.recvError); HSHELL_PRINTFL("Send Control Type[%u], Send Type[%u], error Type[%u]", *GetFpgaType(kFpgaSendTypeControl, 1), *GetFpgaType(kFpgaSendTypeSend, 1), *GetFpgaType(100, 1)); HSHELL_PRINTFL("Read Control Type[%u], FeedBack Type[%u], error Type[%u]", *GetFpgaType(kFpgaSendTypeControl, 0), *GetFpgaType(kFpgaSendTypeFeedBack, 0), *GetFpgaType(100, 0)); return ; case (CHECK_FPGA_INFO_ID + 1): memset(&sFpgaCheckInfo, 0, sizeof(sFpgaCheckInfo)); return ; } #endif uint8_t lastStatus = HBitGet(sLogItem, key); HBitSet(sLogItem, key, arg1); HSHELL_PRINTFL("logStatus[%d]->[%d]", lastStatus, HBitGet(sLogItem, key)); if (sFlashCall != NULL) { sFlashCall(1, key, arg1); } } void HDLogSetOptFlashCall(HDLogFlashOpt_t call) { sFlashCall = call; } void HDLogOptFlashInit() { if (sFlashCall == NULL) { return ; } for (int i = 0; i < kLogLevelMax; ++i) { uint8_t enable = sFlashCall(0, i, 0); HBitSet(sLogItem, i, enable); } } void HDLogInit(uint32_t (*getTime)()) { sGetTime = getTime; HSHellRegister(sLogMatch, sizeof(sLogMatch) / sizeof(HShellMatch), LogShell, 1); if (sFlashCall == NULL) { HBitSet(sLogItem, kLogLevelSwitch, 1); HBitSet(sLogItem, kLogLevelDebug, 1); HBitSet(sLogItem, kLogLevelError, 1); HBitSet(sLogItem, kLogLevelHex, 0); HBitSet(sLogItem, kLogLevelStack, 1); #ifdef USE_RTOS HBitSet(sLogItem, kLogLevelHeap, 1); #endif } else { // 如果配置了flash调用, 全部打开, 延后读取, 避免flash未初始化 for (int i = 0; i < kLogLevelMax; ++i) { HBitSet(sLogItem, i, 1); } HBitSet(sLogItem, kLogLevelColor, 0); } #if USE_RTOS_LOG_LOCK if (sLogMutex == NULL) { sLogMutex = xSemaphoreCreateMutex(); } #endif } uint32_t HDLogGetTime() { if (sGetTime) { return sGetTime(); } return 0; } void HDLogOut(uint8_t ext, uint8_t level, const char *fileName, const char *funcName, int line, const char *format, ...) { if (HBitGet(sLogItem, kLogLevelSwitch) == 0) { return; } if (HBitGet(sLogItem, level) == 0) { return; } { const char *name = strrchr(fileName, '/'); if (name) { fileName = name + 1; } } // 日志颜色 #define _LOG_COLOR_RED "\033[1;31m" #define _LOG_COLOR_GREEN "\033[1;32m" #define _LOG_COLOR_YELLOW "\033[1;33m" #define _LOG_COLOR_BLUE "\033[1;34m" #define _LOG_COLOR_PURPLE "\033[1;35m" #define _LOG_COLOR_CYAN "\033[1;36m" #define _LOG_COLOR_END "\033[0m" // 日志前缀基础信息, 文件名, 函数名, 行号 #define _LOG_BASE_ARGS _BASENAME(__FILE__), __func__, __LINE__ #define _LOG_BASE_INFO "[%s:%s:%d]" #define _LOG_BASE_INFO_COLOR "[" _LOG_COLOR_BLUE \ "%s:%s:" _LOG_COLOR_PURPLE \ "%d" _LOG_COLOR_END \ "]" #define _LOG_USE_COLOR(outColor) if (color) { printf(outColor); } uint8_t color = HBitGet(sLogItem, kLogLevelColor); LOG_LOCK(); if (ext == 0) { if (sGetTime) { uint32_t ms = sGetTime(); printf("[%d:%02d:%02d.%03d]", ms / 1000 / 60 / 60, ms / 1000 / 60 % 60, ms / 1000 % 60, ms % 1000); } if (color) { printf(_LOG_BASE_INFO_COLOR, fileName, funcName, line); } else { printf(_LOG_BASE_INFO, fileName, funcName, line); } if (HBitGet(sLogItem, kLogLevelStack)) { _LOG_USE_COLOR(_LOG_COLOR_YELLOW); printf("[0x%04X]", HDLogDebugGetCurrStackSize()); } #if USE_SYS_CHECK_HEAP if (HBitGet(sLogItem, kLogLevelHeap) && sGetCurrHeapSize) { _LOG_USE_COLOR(_LOG_COLOR_GREEN); printf("[0x%04X]", sGetCurrHeapSize(0)); } #endif } _LOG_USE_COLOR(_LOG_COLOR_CYAN); va_list args; va_start(args, format); vprintf(format, args); va_end(args); _LOG_USE_COLOR(_LOG_COLOR_END); if (ext == 0) { printf("\r\n"); } LOG_UNLOCK(); } static void HDLogFpgaError(const uint8_t *data, int len, uint8_t isWrite, uint8_t checkFpga) { if (checkFpga == 0) { return ; } #if USE_HD_FPGA_CHECK if (isWrite) { ++sFpgaCheckInfo.sendError; } else { ++sFpgaCheckInfo.recvError; } #endif if (HBitGet(sLogItem, kLogLevelHex) == 0) { return ; } const char *opt = isWrite ? "write" : "read"; printf("%s fpga error, len[%d]\r\n", opt, len); HDLogHex((const uint8_t *)(data), len, 1, NULL); return ; } uint8_t HDLogCheckFpgaHeader(const uint8_t *data, int len) { if (len <= 21) { return 0; } for (uint8_t i = 0; i < 7; ++i) { if (0x55 != data[i]) { return 0; } } const uint16_t effectLen = (uint16_t)((data[15] << 8) | data[16]); if (effectLen < 16) { return 0; } if (len < 21 + effectLen) { return 0; } return 1; } uint8_t HDLogPrintFpga(const uint8_t *data, int len, uint8_t isWrite, uint8_t checkFpga) { const HBitType isPrint = HBitGet(sLogItem, kLogLevelHex); LOG_LOCK(); // 记录打印时间 if (isPrint && sGetTime) { uint32_t ms = sGetTime(); printf("[%d:%02d:%02d.%03d]\r\n", ms / 1000 / 60 / 60, ms / 1000 / 60 % 60, ms / 1000 % 60, ms % 1000); } if (HDLogCheckFpgaHeader(data, len) == 0) { HDLogFpgaError(data, len, isWrite, checkFpga); LOG_UNLOCK(); return 0; } const uint8_t type = data[8]; const uint8_t sendCard = (data[9] >> 3) & 0x1F; const uint8_t port = data[9]; const uint8_t recvCardNumber = data[10]; const uint16_t subFunc = (uint16_t)((data[11] << 8) | data[12]); const uint16_t group = (uint16_t)((data[13] << 8) | data[14]); const uint16_t effectLen = (uint16_t)((data[15] << 8) | data[16]); uint32_t count = 0; uint32_t typeCount = 0; #if USE_HD_FPGA_CHECK ++(*GetFpgaType(type, isWrite)); if (isWrite) { ++sFpgaCheckInfo.sendCount; count = sFpgaCheckInfo.sendCount; } else { ++sFpgaCheckInfo.recvCount; count = sFpgaCheckInfo.recvCount; } typeCount = *GetFpgaType(type, isWrite); #endif if (isPrint == 0) { LOG_UNLOCK(); return 0; } const char *opt = isWrite ? "write" : "read"; printf("%s[%u], typeCount[%u] - type[%02X], sendCard[%d], netPort[%d], cardNumber[%d], subFunc[%04X], group[%04X], effectLen[%d]\r\n", opt, count, typeCount, type, sendCard, port, recvCardNumber, subFunc, group, effectLen); LogHex((const uint8_t *)(data) + 17, (len) - 21, 1, NULL, 0); LOG_UNLOCK(); return 1; } void HDLogHex(const uint8_t *data, int len, uint8_t checkPrint, uint32_t *offset) { LogHex(data, len, checkPrint, offset, 1); } void HDLogData(const uint8_t *data, int len, uint8_t checkPrint) { if (checkPrint && HBitGet(sLogItem, kLogLevelHex) == 0) { return; } LOG_LOCK(); for (int i = 0; i < len; ++i) { printf("%02X ", data[i]); if (i % 16 == 15) { printf("\r\n"); } } LOG_UNLOCK(); } static int16_t HDLogGetIndex(unsigned long id) { unsigned taskId = id; if (taskId == 0 && sGetCurrTask) { taskId = sGetCurrTask(); } int16_t index = -1; for (int16_t i = 0; i < USE_CHECK_STACK_NUM; ++i) { if (index == -1 && sStackCheckInfo[i].enable) { index = i; } if (sStackCheckInfo[i].enable && sStackCheckInfo[i].taskID == taskId) { return i; } } return index; } void HDLogDebugSetGetTask(HDLogGetTaskType_t getTask) { sGetCurrTask = getTask; } void HDLogDebugInitStackAddr(unsigned long currTask, uint32_t size) { void *start = 0; for (int i = 0; i < USE_CHECK_STACK_NUM; ++i) { if (sStackCheckInfo[i].enable) { continue; } sStackCheckInfo[i].enable = 1; sStackCheckInfo[i].stackAddr = (unsigned long)&start - sizeof(void *); sStackCheckInfo[i].stackSize = size; sStackCheckInfo[i].taskID = currTask; break; } } void HDLogDebugDeleteStackAddr(unsigned long currTask) { int16_t index = HDLogGetIndex(currTask); if (index != -1) { memset(&sStackCheckInfo[index], 0, sizeof(HDLogStackCheckInfo)); } } uint32_t HDLogDebugGetCurrStackSize() { uint32_t currSize = 0; #if USE_SYS_CHECK_STACK if (sGetCurrStackSize) { currSize = sGetCurrStackSize(0); } #else void *curr = NULL; int16_t index = HDLogGetIndex(0); if (index == -1) { return 0; } currSize = sStackCheckInfo[index].stackAddr - (unsigned long)&curr; if (sGetCurrStackSize) { currSize = sGetCurrStackSize(sStackCheckInfo[index].taskID); } if (sStackCheckInfo[index].stackSize < currSize + 0x100) { printf("The current stack[%d] is insufficient, size[%d], taskId[%lx]\r\n", currSize, sStackCheckInfo[index].stackSize, sStackCheckInfo[index].taskID); } #endif return currSize; } void HDLogSetGetCurrStackSizeCall(HDLogGetStackSizeType_t getStackSize) { sGetCurrStackSize = getStackSize; } void HDLogSetGetCurrHeapSizeCall(HDLogGetStackSizeType_t getHeapSize) { #if USE_SYS_CHECK_HEAP sGetCurrHeapSize = getHeapSize; #else (void)getHeapSize; #endif }