595 lines
14 KiB
C
595 lines
14 KiB
C
|
|
|
|
#include "HDLog.h"
|
|
#include "HBit.h"
|
|
#include "HShellLex.h"
|
|
#include <stdarg.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#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
|
|
}
|