From cc432b761c884a0bd8e9d83db0a4e26109fc08b1 Mon Sep 17 00:00:00 2001
From: chen <15335560115@163.com>
Date: 星期五, 08 十一月 2024 15:35:38 +0800
Subject: [PATCH] 安邦手环GPS删除部分无用数据和修改4G波特率9600出厂测试固件

---
 keil/include/drivers/mk_trace.c | 1857 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 1,857 insertions(+), 0 deletions(-)

diff --git a/keil/include/drivers/mk_trace.c b/keil/include/drivers/mk_trace.c
new file mode 100644
index 0000000..19f5965
--- /dev/null
+++ b/keil/include/drivers/mk_trace.c
@@ -0,0 +1,1857 @@
+/*
+ * Copyright (c) 2019-2023 Beijing Hanwei Innovation Technology Ltd. Co. and
+ * its subsidiaries and affiliates (collectly called MKSEMI).
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into an MKSEMI
+ *    integrated circuit in a product or a software update for such product,
+ *    must reproduce the above copyright notice, this list of conditions and
+ *    the following disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * 3. Neither the name of MKSEMI nor the names of its contributors may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ *    MKSEMI integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be
+ *    reverse engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MKSEMI "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL MKSEMI OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "mk_trace.h"
+#include "mk_reset.h"
+#include "mk_io.h"
+#include "mk_misc.h"
+
+#include "stdio.h"
+#include "string.h"
+#include "stdlib.h"
+
+#if TRACE_EN
+
+#ifndef BACKTRACE_EN
+#define BACKTRACE_EN (1)
+#endif
+
+#ifndef TRACE_BUF_SIZE
+#define TRACE_BUF_SIZE 2048
+#endif
+
+#if UART_CONSOLE_EN
+/*
+|-------|---------|----------| ---------- | -------------------------------------- |
+|       | Header  | Preamble | 1B         | CMD = 0xF1, ACK = 0xF2                 |
+|       |         | -------- | ---------- | -------------------------------------- |
+|       |         | Length   | 2B         | The length of the payload              |
+|       | ------- | -------- | ---------- | -------------------------------------- |
+| Frame |         | ID       | 2B         | Payload - Identification of the frame  |
+|       |         | -------- | ---------- | -------------------------------------- |
+|       | Payload | Data     | Length - 4 | Payload - Data of the frame            |
+|       |         | -------- | ---------- | -------------------------------------- |
+|       |         | CRC      | 2B         | Payload - CRC16 of the whole frame     |
+| ----- | ------- | -------- | ---------- | -------------------------------------- |
+*/
+#include "crc.h"
+#include "mk_uwb.h"
+#include "uwb_api.h"
+#define CONSOLE_BUF_SIZE 1024
+
+#define CONSOLE_RX_HEADER 0
+#define CONSOLE_RX_PAYLOAD 1
+
+#define CONSOLE_CMD 0xF1
+
+#define POS_PREAMBLE 0
+#define POS_LENGTH 1
+#define POS_ID 3
+#define POS_DATA 5
+
+#define LEN_HEADER 3
+#define LEN_ID 2
+#define LEN_CRC 2
+
+enum ID_TYPE_T
+{
+    // F1 04 00 - 00 00 F6 5F
+    ID_RANGING_STOP = 0x0000,
+    // F1 04 00 - 01 00 C7 6C
+    ID_RANGING_START = 0x0001,
+    // F1 07 00 - 02 00 28 00 08 F6 F9
+    ID_PHY_PARAMS_SET = 0x0002,
+
+    ID_TYPE_MAX,
+};
+
+static void console_receive_callback(void *dev, uint32_t err_code);
+
+typedef uint8_t (*console_cmd_function_t)(void const *param, uint16_t const len);
+
+#ifndef UWB_UCI_TEST_EN
+extern void app_ranging_report_callback(void *report);
+#endif
+
+// Element of a cmd handler table.
+struct console_cmd_handler
+{
+    // ID of the cmd.
+    uint16_t id;
+    // Pointer to the handler function for the cmd id above.
+    console_cmd_function_t function;
+};
+
+static uint8_t console_ranging_stop(void const *param, uint16_t const len)
+{
+    uwbapi_session_stop(uwb_app_config.session_id);
+    return 1;
+}
+
+static uint8_t console_ranging_start(void const *param, uint16_t const len)
+{
+#ifndef UWB_UCI_TEST_EN
+    uwbapi_session_start(uwb_app_config.session_id, app_ranging_report_callback);
+#else
+    uwbapi_session_start(uwb_app_config.session_id, NULL);
+#endif
+    return 1;
+}
+
+static uint8_t console_phy_params_set(void const *param, uint16_t const len)
+{
+    uint8_t ret = 0;
+    if (len == sizeof(struct PHY_USER_CONFIG_T))
+    {
+        phy_loop_params_configure((const struct PHY_USER_CONFIG_T *)param, (uint8_t)len, 1);
+        ret = 1;
+    }
+    else
+    {
+        LOG_ERROR(TRACE_MODULE_DRIVER, "PHY params length is wrong\r\n");
+    }
+
+    return ret;
+}
+
+static const struct console_cmd_handler console_cmd_handler_list[ID_TYPE_MAX] = {
+    {ID_RANGING_STOP, (console_cmd_function_t)console_ranging_stop},
+    {ID_RANGING_START, (console_cmd_function_t)console_ranging_start},
+    {ID_PHY_PARAMS_SET, (console_cmd_function_t)console_phy_params_set},
+};
+#endif
+
+extern uint32_t __INITIAL_SP;
+#if BACKTRACE_EN
+void HardFault_Handler(void) __attribute__((naked));
+#else
+__NO_RETURN void HardFault_Handler(void);
+#endif
+__NO_RETURN void trace_exception_handler(void *regs);
+__NO_RETURN void trace_end(void);
+
+#ifndef TRACE_LVL_CONFIG_0
+#define TRACE_LVL_CONFIG_0 (0x44444444)
+#endif
+
+#ifndef TRACE_LVL_CONFIG_1
+#define TRACE_LVL_CONFIG_1 (0x00044444)
+#endif
+
+const static uint8_t trace_level_cfg[TRACE_MODULE_NUM] = {
+    // MAC
+    (TRACE_LVL_CONFIG_0 >> (4 * TRACE_MODULE_MAC)) & 0xf,
+    // PHY
+    (TRACE_LVL_CONFIG_0 >> (4 * TRACE_MODULE_PHY)) & 0xf,
+    // DRIVER
+    (TRACE_LVL_CONFIG_0 >> (4 * TRACE_MODULE_DRIVER)) & 0xf,
+    // APP
+    (TRACE_LVL_CONFIG_0 >> (4 * TRACE_MODULE_APP)) & 0xf,
+    // UWB
+    (TRACE_LVL_CONFIG_0 >> (4 * TRACE_MODULE_UWB)) & 0xf,
+    // UCI
+    (TRACE_LVL_CONFIG_0 >> (4 * TRACE_MODULE_UCI)) & 0xf,
+    // TEST
+    (TRACE_LVL_CONFIG_0 >> (4 * TRACE_MODULE_TEST)) & 0xf,
+    // BOOT
+    (TRACE_LVL_CONFIG_0 >> (4 * TRACE_MODULE_BOOT)) & 0xf,
+    // OS
+    (TRACE_LVL_CONFIG_1 >> (4 * (TRACE_MODULE_OS - 8))) & 0xf,
+    // FIRA
+    (TRACE_LVL_CONFIG_1 >> (4 * (TRACE_MODULE_FIRA - 8))) & 0xf,
+    // CCC
+    (TRACE_LVL_CONFIG_1 >> (4 * (TRACE_MODULE_CCC - 8))) & 0xf,
+    // SE
+    (TRACE_LVL_CONFIG_1 >> (4 * (TRACE_MODULE_SE - 8))) & 0xf,
+    // SCP03
+    (TRACE_LVL_CONFIG_1 >> (4 * (TRACE_MODULE_SCP03 - 8))) & 0xf,
+};
+
+const static char *module_name[TRACE_MODULE_NUM] = {"[MAC]",  "[PHY]", "[DRV]",  "[APP]", "[UWB]", "[UCI]",  "[TEST]",
+        "[BOOT]", "[OS]",  "[FIRA]", "[CCC]", "[SE]",  "[SCP03]"
+                                                   };
+
+const static char *level_tag[TRACE_LEVEL_NUM] = {
+    "[ERROR]",
+    "[WARN]",
+    "[INFO]",
+    "[VERBOSE]",
+};
+
+struct TRACE_HANDLE_T
+{
+    enum TRACE_PORT_T port;
+    char tx_buf[TRACE_BUF_SIZE];
+#if UART_CONSOLE_EN
+    uint8_t rx_buf[CONSOLE_BUF_SIZE];
+#endif
+    uint32_t guard;
+    uint16_t wptr;
+    uint16_t rptr;
+    uint16_t send;
+    uint8_t busy;
+    uint8_t sending;
+    uint8_t enabled;
+#if UART_CONSOLE_EN
+    uint8_t console_fsm;
+    uint8_t reserved[2];
+#else
+    uint8_t reserved[3];
+#endif
+};
+
+struct TRACE_ASSERT_INF_T
+{
+    const char *FILE;
+    const char *FUNC;
+    uint32_t LINE;
+    uint32_t SP;
+    uint32_t LR;
+    uint32_t xPSR;
+    uint32_t PRIMASK;
+    uint32_t CONTROL;
+    uint32_t MSP;
+    uint32_t PSP;
+    uint32_t ID;
+};
+
+struct TRACE_EXCEPTION_INF_T
+{
+    uint32_t REGS[13];
+    uint32_t SP;
+    uint32_t LR;
+    uint32_t PC;
+    uint32_t xPSR;
+    uint32_t PRIMASK;
+    uint32_t CONTROL;
+    uint32_t ICSR;
+    uint32_t AIRCR;
+    uint32_t SCR;
+    uint32_t CCR;
+    uint32_t MSP;
+    uint32_t PSP;
+    uint32_t EXC_RETURN;
+    uint32_t ID;
+};
+
+static struct TRACE_HANDLE_T trace_handle;
+static TRACE_CRASH_DUMP_CB_T trace_crash_dump_cb_list[1];
+
+static void trace_sending(void);
+
+int trace_open(enum TRACE_PORT_T port, enum UART_BAUD_T baud_rate)
+{
+    int ret = 0;
+    if (port >= TRACE_PORT_NUM)
+    {
+        return -1;
+    }
+
+    trace_handle.guard = 0xc0ffc0ff;
+    trace_handle.wptr = 0;
+    trace_handle.rptr = 0;
+    trace_handle.busy = false;
+    trace_handle.sending = false;
+    trace_handle.send = 0;
+    trace_handle.port = port;
+    trace_handle.enabled = 1;
+
+    if ((trace_handle.port == TRACE_PORT_UART0) || (trace_handle.port == TRACE_PORT_UART1))
+    {
+        enum UART_DEV_T trace_uart = (trace_handle.port == TRACE_PORT_UART0) ? UART_ID0 : UART_ID1;
+        struct UART_CFG_T trace_uart_cfg = {.parity = UART_PARITY_NONE,
+            .stop = UART_STOP_BITS_1,
+             .data = UART_DATA_BITS_8,
+              .flow = UART_FLOW_CONTROL_NONE,
+               .rx_level = UART_RXFIFO_CHAR_1,
+                .tx_level = UART_TXFIFO_EMPTY,
+                 .baud = baud_rate,
+#ifdef TRACE_BLOCKING
+                  .dma_en = false,
+#else
+                  .dma_en = true,
+#endif
+                   .int_rx = false,
+                    .int_tx = false
+        };
+
+        ret = uart_open(trace_uart, &trace_uart_cfg);
+
+#if UART_CONSOLE_EN
+        // 1. Header
+        trace_handle.console_fsm = CONSOLE_RX_HEADER;
+        uart_receive(trace_uart, &trace_handle.rx_buf[0], LEN_HEADER, console_receive_callback);
+#endif
+    }
+    else if (trace_handle.port == TRACE_PORT_SPI0)
+    {
+    }
+
+    return ret;
+}
+
+int trace_close(void)
+{
+    int ret = 0;
+    trace_handle.enabled = 0;
+    if ((trace_handle.port == TRACE_PORT_UART0) || (trace_handle.port == TRACE_PORT_UART1))
+    {
+        enum UART_DEV_T trace_uart = (trace_handle.port == TRACE_PORT_UART0) ? UART_ID0 : UART_ID1;
+        ret = uart_close(trace_uart);
+    }
+    else if (trace_handle.port == TRACE_PORT_SPI0)
+    {
+    }
+    return ret;
+}
+
+int trace_crash_dump_cb_register(TRACE_CRASH_DUMP_CB_T cb)
+{
+    for (uint32_t i = 0; i < ARRAY_SIZE(trace_crash_dump_cb_list); i++)
+    {
+        if (trace_crash_dump_cb_list[i] == NULL)
+        {
+            trace_crash_dump_cb_list[i] = cb;
+            return 0;
+        }
+    }
+
+    return -1;
+}
+
+static void trace_sending_continue(void *dev, uint32_t err_code)
+{
+    uint32_t lock = int_lock();
+    if (err_code & (UART_ERR_MODEM | UART_ERR_LINE))
+    {
+        // uart error
+        LOG_ERROR(TRACE_MODULE_DRIVER, "UART Error %x\r\n", err_code);
+    }
+    else
+    {
+        trace_handle.rptr += trace_handle.send;
+        if (trace_handle.rptr >= TRACE_BUF_SIZE)
+        {
+            trace_handle.rptr -= TRACE_BUF_SIZE;
+        }
+
+        // sent done
+        trace_handle.sending = false;
+
+        // continue to send rest
+        trace_sending();
+    }
+
+    int_unlock(lock);
+}
+
+static void trace_sending(void)
+{
+    uint32_t lock = int_lock();
+
+    if (trace_handle.wptr != trace_handle.rptr)
+    {
+        trace_handle.sending = true;
+
+        if (trace_handle.wptr > trace_handle.rptr)
+        {
+            trace_handle.send = trace_handle.wptr - trace_handle.rptr;
+        }
+        else
+        {
+            trace_handle.send = TRACE_BUF_SIZE - trace_handle.rptr;
+        }
+
+        if (trace_handle.send > (TRACE_BUF_SIZE >> 1))
+        {
+            trace_handle.send = (TRACE_BUF_SIZE >> 1);
+        }
+
+        uint8_t *tx_buf = (uint8_t *)&trace_handle.tx_buf[trace_handle.rptr];
+        uint32_t tx_len = trace_handle.send;
+
+        if ((trace_handle.port == TRACE_PORT_UART0) || (trace_handle.port == TRACE_PORT_UART1))
+        {
+            enum UART_DEV_T trace_uart = (trace_handle.port == TRACE_PORT_UART0) ? UART_ID0 : UART_ID1;
+
+            if (DRV_OK != uart_send(trace_uart, tx_buf, tx_len, trace_sending_continue))
+            {
+                // uart busy or error
+                trace_handle.sending = false;
+            }
+        }
+        else if (trace_handle.port == TRACE_PORT_SPI0)
+        {
+        }
+    }
+    else
+    {
+        trace_handle.send = 0;
+    }
+    int_unlock(lock);
+}
+
+int trace_buf_is_empty(void)
+{
+    uint32_t lock = int_lock();
+    int ret = (trace_handle.wptr == trace_handle.rptr ? 1 : 0);
+    int_unlock(lock);
+    return ret;
+}
+
+int trace_output(const char *buf, int len)
+{
+    int ret = 0;
+    int free_len;
+    int size;
+
+    if (len <= 0)
+    {
+        return -1;
+    }
+
+    uint32_t lock = int_lock();
+
+    if (trace_handle.busy == false)
+    {
+        trace_handle.busy = true;
+
+        if (trace_handle.wptr >= trace_handle.rptr)
+        {
+            free_len = TRACE_BUF_SIZE - trace_handle.wptr + trace_handle.rptr;
+        }
+        else
+        {
+            free_len = trace_handle.rptr - trace_handle.wptr;
+        }
+
+        if (free_len < len)
+        {
+            ret = -1;
+            // ASSERT(0, "TRACE buffer is not enough free %d need %d", free_len, len);
+
+            uint16_t target;
+            if (trace_handle.sending)
+            {
+                target = trace_handle.rptr + trace_handle.send;
+                if (target >= TRACE_BUF_SIZE)
+                {
+                    target -= TRACE_BUF_SIZE;
+                }
+            }
+            else
+            {
+                target = trace_handle.rptr;
+            }
+
+            uint16_t discard;
+            if (trace_handle.wptr >= target)
+            {
+                discard = trace_handle.wptr - target;
+            }
+            else
+            {
+                discard = TRACE_BUF_SIZE - target + trace_handle.wptr;
+            }
+            trace_handle.wptr = target;
+            trace_handle.busy = false;
+            LOG_ERROR(TRACE_MODULE_DRIVER | TRACE_NO_OPTION, "\r\nTrace buffer is full, discards %u bytes\r\n", discard);
+        }
+        else
+        {
+            // copy data to trace buffer
+            size = TRACE_BUF_SIZE - trace_handle.wptr;
+            if (size >= len)
+            {
+                size = len;
+            }
+            memcpy(&trace_handle.tx_buf[trace_handle.wptr], &buf[0], (uint32_t)size);
+            if (size < len)
+            {
+                memcpy(&trace_handle.tx_buf[0], &buf[size], (uint32_t)(len - size));
+            }
+            trace_handle.wptr += len;
+            if (trace_handle.wptr >= TRACE_BUF_SIZE)
+            {
+                trace_handle.wptr -= TRACE_BUF_SIZE;
+            }
+
+            if (trace_handle.sending == false)
+            {
+                // sending right away
+                trace_sending();
+            }
+
+            ret = len;
+            trace_handle.busy = false;
+        }
+    }
+    else
+    {
+        ASSERT(0, "TRACE BUSY");
+    }
+
+    int_unlock(lock);
+
+    return ret;
+}
+
+static int trace_output_blocking(const char *buf, int len)
+{
+    if ((trace_handle.port == TRACE_PORT_UART0) || (trace_handle.port == TRACE_PORT_UART1))
+    {
+        UART_TypeDef *trace_uart = (trace_handle.port == TRACE_PORT_UART0) ? UART0 : UART1;
+
+        // polling
+        while (len)
+        {
+            if (trace_uart->STATUS & UART_STATUS_TFNF_MSK)
+            {
+                trace_uart->TX_DATA = *buf++;
+                len--;
+            }
+        }
+    }
+    else if (trace_handle.port == TRACE_PORT_SPI0)
+    {
+    }
+
+    return 0;
+}
+
+#if UART_CONSOLE_EN
+static void console_receive_callback(void *dev, uint32_t err_code)
+{
+    if (err_code & (UART_ERR_MODEM | UART_ERR_LINE))
+    {
+        // uart error
+        LOG_ERROR(TRACE_MODULE_DRIVER, "Console Error %x\r\n", err_code);
+    }
+    else
+    {
+        uint16_t payload_len = 0;
+        enum UART_DEV_T trace_uart = (trace_handle.port == TRACE_PORT_UART0) ? UART_ID0 : UART_ID1;
+        switch (trace_handle.console_fsm)
+        {
+        case CONSOLE_RX_HEADER:
+        {
+            if (trace_handle.rx_buf[POS_PREAMBLE] == CONSOLE_CMD)
+            {
+                payload_len = (uint16_t)(trace_handle.rx_buf[POS_LENGTH + 1] << 8) + trace_handle.rx_buf[POS_LENGTH];
+                trace_handle.console_fsm = CONSOLE_RX_PAYLOAD;
+                uart_receive(trace_uart, &trace_handle.rx_buf[POS_ID], payload_len, console_receive_callback);
+            }
+            else if (trace_handle.rx_buf[1] == CONSOLE_CMD)
+            {
+                trace_handle.rx_buf[POS_PREAMBLE] = CONSOLE_CMD;
+                trace_handle.rx_buf[1] = trace_handle.rx_buf[2];
+                uart_receive(trace_uart, &trace_handle.rx_buf[2], 1, console_receive_callback);
+            }
+            else if (trace_handle.rx_buf[2] == CONSOLE_CMD)
+            {
+                trace_handle.rx_buf[POS_PREAMBLE] = CONSOLE_CMD;
+                uart_receive(trace_uart, &trace_handle.rx_buf[1], 2, console_receive_callback);
+            }
+            else
+            {
+                uart_receive(trace_uart, &trace_handle.rx_buf[POS_PREAMBLE], LEN_HEADER, console_receive_callback);
+            }
+            break;
+        }
+
+        case CONSOLE_RX_PAYLOAD:
+        {
+            // check crc
+            payload_len = (uint16_t)(trace_handle.rx_buf[POS_LENGTH + 1] << 8) + trace_handle.rx_buf[POS_LENGTH];
+            uint16_t crc_frame =
+                (uint16_t)(trace_handle.rx_buf[payload_len + LEN_HEADER - LEN_CRC + 1] << 8) + trace_handle.rx_buf[payload_len + LEN_HEADER - LEN_CRC];
+            uint16_t crc_cal = crc16(&trace_handle.rx_buf[0], payload_len + LEN_HEADER - LEN_CRC);
+
+            if (crc_frame == crc_cal)
+            {
+                uint16_t id = (uint16_t)(trace_handle.rx_buf[POS_ID + 1] << 8) + trace_handle.rx_buf[POS_ID];
+
+                // packet process
+                if (console_cmd_handler_list[id].function)
+                {
+                    console_cmd_handler_list[id].function(&trace_handle.rx_buf[POS_DATA], payload_len - LEN_CRC - LEN_ID);
+                }
+                else
+                {
+                    LOG_ERROR(TRACE_MODULE_DRIVER, "Console CMD ID %04x Function is Null\r\n", id);
+                }
+            }
+            else
+            {
+                LOG_ERROR(TRACE_MODULE_DRIVER, "Console CRC Error %04x %04x\r\n", crc_cal, crc_frame);
+            }
+            trace_handle.console_fsm = CONSOLE_RX_HEADER;
+            uart_receive(trace_uart, &trace_handle.rx_buf[0], LEN_HEADER, console_receive_callback);
+            break;
+        }
+
+        default:
+            break;
+        }
+    }
+}
+#endif
+
+#if TRACE_STD_LIB_EN == 0
+
+#define FORMAT_FLAG_LEFT_JUSTIFY (1u << 0)
+#define FORMAT_FLAG_PAD_ZERO (1u << 1)
+#define FORMAT_FLAG_PRINT_SIGN (1u << 2)
+#define FORMAT_FLAG_ALTERNATE (1u << 3)
+
+typedef struct
+{
+    char *pBuffer;
+    unsigned BufferSize;
+    unsigned Cnt;
+
+    int ReturnValue;
+
+} MK_PRINTF_DESC_T;
+
+static void _StoreChar(MK_PRINTF_DESC_T *p, char c)
+{
+    unsigned Cnt;
+
+    Cnt = p->Cnt;
+    if ((Cnt + 1u) <= p->BufferSize)
+    {
+        *(p->pBuffer + Cnt) = c;
+        p->Cnt = Cnt + 1u;
+        p->ReturnValue++;
+    }
+    //
+    // Write part of string, when the buffer is full
+    //
+}
+
+static void _PrintUnsigned(MK_PRINTF_DESC_T *pBufferDesc, unsigned v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags)
+{
+    static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+    unsigned Div;
+    unsigned Digit;
+    unsigned Number;
+    unsigned Width;
+    char c;
+
+    Number = v;
+    Digit = 1u;
+    //
+    // Get actual field width
+    //
+    Width = 1u;
+    while (Number >= Base)
+    {
+        Number = (Number / Base);
+        Width++;
+    }
+    if (NumDigits > Width)
+    {
+        Width = NumDigits;
+    }
+    //
+    // Print leading chars if necessary
+    //
+    if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u)
+    {
+        if (FieldWidth != 0u)
+        {
+            if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && (NumDigits == 0u))
+            {
+                c = '0';
+            }
+            else
+            {
+                c = ' ';
+            }
+            while ((FieldWidth != 0u) && (Width < FieldWidth))
+            {
+                FieldWidth--;
+                _StoreChar(pBufferDesc, c);
+                if (pBufferDesc->ReturnValue < 0)
+                {
+                    break;
+                }
+            }
+        }
+    }
+    if (pBufferDesc->ReturnValue >= 0)
+    {
+        //
+        // Compute Digit.
+        // Loop until Digit has the value of the highest digit required.
+        // Example: If the output is 345 (Base 10), loop 2 times until Digit is 100.
+        //
+        while (1)
+        {
+            if (NumDigits > 1u)
+            {   // User specified a min number of digits to print? => Make sure we loop at least that often, before
+                // checking anything else (> 1 check avoids problems with NumDigits being signed / unsigned)
+                NumDigits--;
+            }
+            else
+            {
+                Div = v / Digit;
+                if (Div < Base)
+                {   // Is our divider big enough to extract the highest digit from value? => Done
+                    break;
+                }
+            }
+            Digit *= Base;
+        }
+        //
+        // Output digits
+        //
+        do
+        {
+            Div = v / Digit;
+            v -= Div * Digit;
+            _StoreChar(pBufferDesc, _aV2C[Div]);
+            if (pBufferDesc->ReturnValue < 0)
+            {
+                break;
+            }
+            Digit /= Base;
+        } while (Digit);
+        //
+        // Print trailing spaces if necessary
+        //
+        if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == FORMAT_FLAG_LEFT_JUSTIFY)
+        {
+            if (FieldWidth != 0u)
+            {
+                while ((FieldWidth != 0u) && (Width < FieldWidth))
+                {
+                    FieldWidth--;
+                    _StoreChar(pBufferDesc, ' ');
+                    if (pBufferDesc->ReturnValue < 0)
+                    {
+                        break;
+                    }
+                }
+            }
+        }
+    }
+}
+
+static void _PrintInt(MK_PRINTF_DESC_T *pBufferDesc, int v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags)
+{
+    unsigned Width;
+    int Number;
+
+    Number = (v < 0) ? -v : v;
+
+    //
+    // Get actual field width
+    //
+    Width = 1u;
+    while (Number >= (int)Base)
+    {
+        Number = (Number / (int)Base);
+        Width++;
+    }
+    if (NumDigits > Width)
+    {
+        Width = NumDigits;
+    }
+    if ((FieldWidth > 0u) && ((v < 0) || ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN)))
+    {
+        FieldWidth--;
+    }
+
+    //
+    // Print leading spaces if necessary
+    //
+    if ((((FormatFlags & FORMAT_FLAG_PAD_ZERO) == 0u) || (NumDigits != 0u)) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u))
+    {
+        if (FieldWidth != 0u)
+        {
+            while ((FieldWidth != 0u) && (Width < FieldWidth))
+            {
+                FieldWidth--;
+                _StoreChar(pBufferDesc, ' ');
+                if (pBufferDesc->ReturnValue < 0)
+                {
+                    break;
+                }
+            }
+        }
+    }
+    //
+    // Print sign if necessary
+    //
+    if (pBufferDesc->ReturnValue >= 0)
+    {
+        if (v < 0)
+        {
+            v = -v;
+            _StoreChar(pBufferDesc, '-');
+        }
+        else if ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN)
+        {
+            _StoreChar(pBufferDesc, '+');
+        }
+        else
+        {
+        }
+        if (pBufferDesc->ReturnValue >= 0)
+        {
+            //
+            // Print leading zeros if necessary
+            //
+            if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) && (NumDigits == 0u))
+            {
+                if (FieldWidth != 0u)
+                {
+                    while ((FieldWidth != 0u) && (Width < FieldWidth))
+                    {
+                        FieldWidth--;
+                        _StoreChar(pBufferDesc, '0');
+                        if (pBufferDesc->ReturnValue < 0)
+                        {
+                            break;
+                        }
+                    }
+                }
+            }
+            if (pBufferDesc->ReturnValue >= 0)
+            {
+                //
+                // Print number without sign
+                //
+                _PrintUnsigned(pBufferDesc, (unsigned)v, Base, NumDigits, FieldWidth, FormatFlags);
+            }
+        }
+    }
+}
+
+int trace_format(char *buf, unsigned int size, const char *fmt, va_list args)
+{
+    char c;
+    int v;
+    unsigned NumDigits;
+    unsigned FormatFlags;
+    unsigned FieldWidth;
+
+    MK_PRINTF_DESC_T BufferDesc;
+    BufferDesc.pBuffer = buf;
+    BufferDesc.BufferSize = size;
+    BufferDesc.Cnt = 0u;
+    BufferDesc.ReturnValue = 0;
+
+    do
+    {
+        c = *fmt;
+        fmt++;
+        if (c == 0u)
+        {
+            break;
+        }
+        if (c == '%')
+        {
+            //
+            // Filter out flags
+            //
+            FormatFlags = 0u;
+            v = 1;
+            do
+            {
+                c = *fmt;
+                switch (c)
+                {
+                case '-':
+                    FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY;
+                    fmt++;
+                    break;
+                case '0':
+                    FormatFlags |= FORMAT_FLAG_PAD_ZERO;
+                    fmt++;
+                    break;
+                case '+':
+                    FormatFlags |= FORMAT_FLAG_PRINT_SIGN;
+                    fmt++;
+                    break;
+                case '#':
+                    FormatFlags |= FORMAT_FLAG_ALTERNATE;
+                    fmt++;
+                    break;
+                default:
+                    v = 0;
+                    break;
+                }
+            } while (v);
+            //
+            // filter out field with
+            //
+            FieldWidth = 0u;
+            do
+            {
+                c = *fmt;
+                if ((c < '0') || (c > '9'))
+                {
+                    break;
+                }
+                fmt++;
+                FieldWidth = (FieldWidth * 10u) + ((unsigned)c - '0');
+            } while (1);
+
+            //
+            // Filter out precision (number of digits to display)
+            //
+            NumDigits = 0u;
+            c = *fmt;
+            if (c == '.')
+            {
+                fmt++;
+                do
+                {
+                    c = *fmt;
+                    if ((c < '0') || (c > '9'))
+                    {
+                        break;
+                    }
+                    fmt++;
+                    NumDigits = NumDigits * 10u + ((unsigned)c - '0');
+                } while (1);
+            }
+            //
+            // Filter out length modifier
+            //
+            c = *fmt;
+            do
+            {
+                if ((c == 'l') || (c == 'h'))
+                {
+                    fmt++;
+                    c = *fmt;
+                }
+                else
+                {
+                    break;
+                }
+            } while (1);
+            //
+            // Handle specifiers
+            //
+            switch (c)
+            {
+            case 'c':
+            {
+                char c0;
+                v = va_arg(args, int);
+                c0 = (char)v;
+                _StoreChar(&BufferDesc, c0);
+                break;
+            }
+            case 'd':
+                v = va_arg(args, int);
+                _PrintInt(&BufferDesc, v, 10u, NumDigits, FieldWidth, FormatFlags);
+                break;
+            case 'u':
+                v = va_arg(args, int);
+                _PrintUnsigned(&BufferDesc, (unsigned)v, 10u, NumDigits, FieldWidth, FormatFlags);
+                break;
+            case 'x':
+            case 'X':
+                v = va_arg(args, int);
+                _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, NumDigits, FieldWidth, FormatFlags);
+                break;
+            case 's':
+            {
+                const char *s = va_arg(args, const char *);
+                do
+                {
+                    c = *s;
+                    s++;
+                    if (c == '\0')
+                    {
+                        break;
+                    }
+                    _StoreChar(&BufferDesc, c);
+                } while (BufferDesc.ReturnValue >= 0);
+            }
+            break;
+            case 'f':
+            case 'F':
+            {
+                float fv = (float)va_arg(args, double);
+                if (fv < 0)
+                    _StoreChar(&BufferDesc, '-');
+                v = abs((int)fv);
+                _PrintInt(&BufferDesc, v, 10u, NumDigits, FieldWidth, FormatFlags);
+                _StoreChar(&BufferDesc, '.');
+                v = abs((int)(fv * 1000000));
+                v = v % 1000000;
+                _PrintInt(&BufferDesc, v, 10u, 6, FieldWidth, FormatFlags);
+            }
+            break;
+            case 'p':
+                v = va_arg(args, int);
+                _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, 8u, 8u, 0u);
+                break;
+            case '%':
+                _StoreChar(&BufferDesc, '%');
+                break;
+            default:
+                break;
+            }
+            fmt++;
+        }
+        else
+        {
+            _StoreChar(&BufferDesc, c);
+        }
+    } while (BufferDesc.ReturnValue >= 0);
+
+    if (BufferDesc.ReturnValue > 0)
+    {
+        //
+        // Write remaining data, if any
+        //
+    }
+    return BufferDesc.ReturnValue;
+}
+
+#else
+
+__attribute__((__format__(__printf__, 3, 0))) int trace_format(char *buf, unsigned int size, const char *fmt, va_list args)
+{
+    return vsnprintf(buf, size, fmt, args);
+}
+
+#endif
+
+int trace_printf(uint16_t module, uint8_t level, const char *fmt, ...)
+{
+    if (trace_handle.enabled == 0)
+    {
+        return 0;
+    }
+    char buf[256] = {0};
+    uint32_t pre_len = 0;
+    int len = 0;
+    uint8_t mod_idx = (module & 0xff);
+
+    if (mod_idx >= TRACE_MODULE_NUM)
+    {
+        return -1;
+    }
+    if ((level >= TRACE_LEVEL_NUM) || (level == 0))
+    {
+        return -1;
+    }
+    if (level > trace_level_cfg[mod_idx])
+    {
+        return 0;
+    }
+
+    // uint32_t lock = int_lock();
+    if ((module & TRACE_NO_TIMESTAMP) == 0)
+    {
+        mk_snprintf(&buf[pre_len], sizeof(buf) - pre_len, "%10u | ", sys_tick_us());
+        pre_len = strlen(buf);
+    }
+    if ((module & TRACE_NO_MODULE_NAME) == 0)
+    {
+        mk_snprintf(&buf[pre_len], sizeof(buf) - pre_len, "%s", module_name[mod_idx]);
+        pre_len = strlen(buf);
+    }
+    if ((module & TRACE_NO_LEVEL_TAG) == 0)
+    {
+        mk_snprintf(&buf[pre_len], sizeof(buf) - pre_len, "%s", level_tag[level - 1]);
+        pre_len = strlen(buf);
+    }
+
+    va_list argp;
+    va_start(argp, fmt);
+    len = trace_format(&buf[pre_len], sizeof(buf) - pre_len, fmt, argp);
+    va_end(argp);
+
+    // int_unlock(lock);
+    return trace_output(buf, (int)pre_len + len);
+}
+
+#if TRACE_OVER_UCI_EN
+int uci_print_enable = 0;
+
+static unsigned short checksum_string(const char *addr, int count)
+{
+    long sum = 0;
+
+    // Take original data as 16 digits, add it with 32 digits, so can carry save
+    while (count > 1)
+    {
+        sum += (*addr) | *(addr + 1) << 8;
+        addr += 2;
+        count -= 2;
+    }
+
+    /* Add left-over byte, if any */
+    if (count > 0)
+    {
+        sum += *(unsigned const char *)addr;
+    }
+    /* Fold 32-bit sum to 16 bits */
+    while (sum >> 16)
+    {
+        sum = (sum & 0xffff) + (sum >> 16);
+    }
+    return (unsigned short)~sum;
+}
+
+extern void uci_vendor_log_upload(uint16_t len, const uint8_t *data);
+
+void trace_upto_host(uint16_t module, uint8_t level, const char *fmt, ...)
+{
+    if (uci_print_enable == 0)
+    {
+        // TRACE(TRACE_MODULE_APP, TRACE_LEVEL_INFO, "uci proxy not start.\r\n");
+        return;
+    }
+
+    uint8_t mod_idx = (module & 0xff);
+
+    if (mod_idx >= TRACE_MODULE_NUM)
+    {
+        return;
+    }
+    if ((level >= TRACE_LEVEL_NUM) || (level == 0))
+    {
+        return;
+    }
+    if (level > trace_level_cfg[mod_idx])
+    {
+        return;
+    }
+
+    if ((module & TRACE_NO_OPTION) || (module & TRACE_NO_REPORT_HOST))
+    {
+        return;
+    }
+
+    int it = 0;
+    double dd = 0;
+    char const *p;
+    // checksum
+    unsigned short stringCsum;
+    va_list aq;
+    va_start(aq, fmt);
+    p = fmt;
+
+    char var_count = 0; // To control the length of data sent, only support up to 4 input variables, can be expanded
+    char dataBits = 0;  // Two bits represent a input variable's length, so the max is 4 bytes, can be expanded[0-0,1-1,2-2,3-4]
+    uint8_t j = 0;
+    uint8_t recdBuf[256];
+
+    stringCsum = checksum_string(fmt, (int)strlen(fmt));
+
+    // TRACE(TRACE_MODULE_FIRA, TRACE_LEVEL_ERROR, "%s cksum=%x len=%d\r\n", fmt, stringCsum, strlen(fmt));
+
+    for (j = 0; j < sizeof(unsigned short); j++)
+    {
+        *(recdBuf + j) = (stringCsum >> (8 * j) & 0xff);
+    }
+
+    *(recdBuf + 2) = 0;
+    j = 3;
+
+    while (*p != '\0')
+    {   // fill begin at recdBuf[3]
+        if (*p != '%')
+        {
+            p++;
+            continue;
+        }
+
+        if ((*(p + 1) == '0') && ((*(p + 2) > '0') && (*(p + 2) < '9'))) /* skip %0* */
+        {
+            p += 2;
+        }
+
+        switch (*++p)
+        {
+        case 's':
+        {
+            recdBuf[j++] = 0;
+            dataBits |= 1 << 2 * var_count++;
+        }
+        break;
+        case 'c':
+        case 'd':
+        {
+            it = va_arg(aq, int);
+            if (it > 0x7FFF)
+            {
+                *(recdBuf + j++) = 0xff;
+                *(recdBuf + j++) = 0x7f;
+                dataBits |= 2 << 2 * var_count++;
+            }
+
+            if (it < 256)
+            {   // 1byte
+                recdBuf[j++] = (char)it;
+                dataBits |= 1 << 2 * var_count++;
+            }
+            else
+            {   // 2byte
+                *(recdBuf + j++) = it & 0xff;
+                *(recdBuf + j++) = it >> 8 & 0xff;
+                dataBits |= 2 << 2 * var_count++;
+            }
+        }
+        break;
+        case 'x':
+        case 'X':
+        case 'u':
+        {
+            it = va_arg(aq, int);
+            if (it > 0xFFFF)
+            {
+                *(recdBuf + j++) = 0xff;
+                *(recdBuf + j++) = 0xff;
+                dataBits |= 2 << 2 * var_count++;
+            }
+
+            if (it < 0x100) //<0xFF
+            {   // 1byte
+                recdBuf[j++] = (char)it;
+                dataBits |= 1 << 2 * var_count++;
+            }
+            else
+            {   // 2byte
+                *(recdBuf + j++) = it & 0xff;
+                *(recdBuf + j++) = it >> 8 & 0xff;
+                dataBits |= 2 << 2 * var_count++;
+            }
+        }
+        break;
+        case 'f':
+        {
+            dd = va_arg(aq, double);
+            if (dd > 3.4e38)
+            {
+                *(recdBuf + j++) = 0xff;
+                *(recdBuf + j++) = 0xff;
+                *(recdBuf + j++) = 0xff;
+                *(recdBuf + j++) = 0xff;
+                dataBits |= 3 << 2 * var_count++;
+            }
+            else
+            {
+                *(recdBuf + j++) = (unsigned int)dd & 0xff;
+                *(recdBuf + j++) = (unsigned int)dd >> 8 & 0xff;
+                *(recdBuf + j++) = (unsigned int)dd >> 16 & 0xff;
+                *(recdBuf + j++) = (unsigned int)dd >> 24 & 0xff;
+                dataBits |= 3 << 2 * var_count++;
+            }
+        }
+        break;
+        }
+        p++;
+    }
+    va_end(aq);
+
+    if (var_count > 4)
+    {
+        // TRACE(TRACE_MODULE_APP, TRACE_LEVEL_INFO, "We only support for 4 var input.\r\n");
+        return;
+    }
+
+    *(recdBuf + 2) = dataBits;
+    uci_vendor_log_upload((uint16_t)j, (uint8_t *)recdBuf);
+}
+#endif
+
+__attribute__((__format__(__printf__, 3, 0))) int mk_snprintf(char *buf, unsigned int size, const char *fmt, ...)
+{
+    va_list argp;
+    int i = 0;
+    va_start(argp, fmt);
+    i = trace_format(buf, size, fmt, argp);
+    va_end(argp);
+
+    return i;
+}
+
+__attribute__((__format__(__printf__, 3, 0))) int trace_dump(uint16_t module, uint8_t level, const char *fmt, uint32_t size, const void *data, uint32_t count)
+{
+    if (trace_handle.enabled == 0)
+    {
+        return 0;
+    }
+    char buf[256] = {0};
+    int len = 0;
+
+    if (module >= TRACE_MODULE_NUM)
+    {
+        return -1;
+    }
+    if ((level >= TRACE_LEVEL_NUM) || (level == 0))
+    {
+        return -1;
+    }
+    if (level > trace_level_cfg[module])
+    {
+        return 0;
+    }
+
+    if (size == sizeof(uint32_t))
+    {
+        for (uint32_t i = 0; i < count && (uint32_t)len < sizeof(buf); i++)
+        {
+            len += mk_snprintf(&buf[len], sizeof(buf) - (uint32_t)len, fmt, *(const uint32_t *)((const uint32_t *)data + i));
+        }
+    }
+    else if (size == sizeof(uint16_t))
+    {
+        for (uint32_t i = 0; i < count && (uint32_t)len < sizeof(buf); i++)
+        {
+            len += mk_snprintf(&buf[len], sizeof(buf) - (uint32_t)len, fmt, *(const uint16_t *)((const uint16_t *)data + i));
+        }
+    }
+    else if (size == sizeof(uint8_t))
+    {
+        for (uint32_t i = 0; i < count && (uint32_t)len < sizeof(buf); i++)
+        {
+            len += mk_snprintf(&buf[len], sizeof(buf) - (uint32_t)len, fmt, *(const uint8_t *)((const uint8_t *)data + i));
+        }
+    }
+
+    ASSERT((uint32_t)len <= sizeof(buf), "len %d", len);
+
+    return trace_output(buf, len);
+}
+
+#if BACKTRACE_EN
+static int trace_address_executable(uint32_t addr)
+{
+    // check thumb flag
+    if ((addr & 0x01) == 0)
+    {
+        return 0;
+    }
+
+    // check location
+    if (CODE_BASE < addr && addr < CODE_BASE + SRAM_SIZE)
+    {
+        return 1;
+    }
+    if (ROM_BASE < addr && addr < ROM_BASE + ROM_SIZE)
+    {
+        return 1;
+    }
+
+    return 0;
+}
+
+static void trace_print_backtrace(uint32_t addr, uint32_t depth, uint32_t count)
+{
+    uint32_t *stack = (uint32_t *)addr;
+    char buf[20] = {0};
+    int len;
+
+    if (addr & 0x03)
+    {
+        return;
+    }
+
+    len = mk_snprintf(buf, sizeof(buf), TRACE_NEW_LINE "Backtrace: " TRACE_NEW_LINE);
+    trace_output_blocking(buf, len);
+
+    for (uint32_t i = 0, j = 0; i < depth && j < count; i++)
+    {
+        if (trace_address_executable(stack[i]))
+        {
+            len = mk_snprintf(buf, sizeof(buf), "%08X" TRACE_NEW_LINE, stack[i]);
+            trace_output_blocking(buf, len);
+            j++;
+        }
+    }
+}
+
+static void trace_crash_dump_callback(void)
+{
+    for (uint32_t i = 0; i < ARRAY_SIZE(trace_crash_dump_cb_list); i++)
+    {
+        if (trace_crash_dump_cb_list[i])
+        {
+            trace_crash_dump_cb_list[i]();
+        }
+    }
+}
+#endif
+
+__NO_RETURN void trace_end(void)
+{
+    trace_output_blocking("Crashed!!!\r\n", 12);
+#if TRACE_REBOOT_EN
+    // reboot
+    reset_module(RESET_MODULE_REBOOT);
+#endif
+    // open SWD
+    // io_pin_mux_set(IO_PIN_15, IO_FUNC0);
+    // io_pin_mux_set(IO_PIN_16, IO_FUNC0);
+    // trace_output_blocking("SWD open\r\n", 10);
+
+    do
+    {
+        __NOP();
+        __NOP();
+        __NOP();
+        __NOP();
+    } while (1);
+}
+
+#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wuninitialized"
+#endif
+
+#if BACKTRACE_EN
+void trace_flush(void)
+{
+    if ((trace_handle.port == TRACE_PORT_UART0) || (trace_handle.port == TRACE_PORT_UART1))
+    {
+        enum UART_DEV_T trace_uart = (trace_handle.port == TRACE_PORT_UART0) ? UART_ID0 : UART_ID1;
+        while (uart_tx_in_progress(trace_uart))
+        {
+        }
+    }
+    else if (trace_handle.port == TRACE_PORT_SPI0)
+    {
+    }
+
+    uint32_t lock = int_lock();
+
+			while (trace_handle.wptr != trace_handle.rptr)
+    {
+        if (trace_handle.wptr > trace_handle.rptr)
+        {
+            trace_handle.send = trace_handle.wptr - trace_handle.rptr;
+        }
+        else
+        {
+            trace_handle.send = TRACE_BUF_SIZE - trace_handle.rptr;
+        }
+
+        uint8_t *tx_buf = (uint8_t *)&trace_handle.tx_buf[trace_handle.rptr];
+        uint32_t tx_len = trace_handle.send;
+        trace_output_blocking((const char *)tx_buf, (int)tx_len);
+
+        trace_handle.rptr += trace_handle.send;
+        if (trace_handle.rptr >= TRACE_BUF_SIZE)
+        {
+            trace_handle.rptr -= TRACE_BUF_SIZE;
+        }
+    }
+
+    // sent done
+    trace_handle.sending = false;
+    int_unlock(lock);
+}
+
+static const char trace_new_line[] = TRACE_NEW_LINE;
+
+static void _trace_assert_dump(uint32_t primask, uint32_t sp, uint32_t lr, const char *file, const char *func, uint32_t line, const char *fmt)
+{
+    struct TRACE_ASSERT_INF_T assert_inf;
+
+    assert_inf.SP = sp;
+    assert_inf.LR = lr;
+
+    assert_inf.ID = TRACE_ASSERT_ID;
+    assert_inf.FILE = file;
+    assert_inf.FUNC = func;
+    assert_inf.LINE = line;
+    assert_inf.xPSR = __get_xPSR();
+    assert_inf.MSP = __get_MSP();
+    assert_inf.PSP = __get_PSP();
+    assert_inf.PRIMASK = primask;
+    assert_inf.CONTROL = __get_CONTROL();
+
+    // Store assert_inf in memory (optional)
+    //*(volatile uint32_t *)SRAM_BASE = (uint32_t)&assert_inf;
+    trace_flush();
+
+    static const char desc_file[] = "FILE    : ";
+    static const char desc_func[] = "FUNCTION: ";
+    static const char desc_line[] = "LINE    : ";
+
+    int len = 0;
+
+    static const char separate_line[] = "----------------------------------------" TRACE_NEW_LINE;
+    trace_output_blocking(separate_line, sizeof(separate_line) - 1);
+    // format output string
+    trace_output_blocking(fmt, (int)strlen(fmt));
+    trace_output_blocking(trace_new_line, sizeof(trace_new_line) - 1);
+    trace_output_blocking(separate_line, sizeof(separate_line) - 1);
+
+    // Timestamp
+    len += mk_snprintf(&trace_handle.tx_buf[len], sizeof(trace_handle.tx_buf) - (uint32_t)len, "%10d | " TRACE_NEW_LINE, sys_tick_us());
+
+    // Title and PC
+    len += mk_snprintf(&trace_handle.tx_buf[len], sizeof(trace_handle.tx_buf) - (uint32_t)len, TRACE_NEW_LINE "### ASSERT @ 0x%08X ###" TRACE_NEW_LINE,
+                       (assert_inf.LR & ~1U) - 4);
+    trace_output_blocking(trace_handle.tx_buf, len);
+
+    // File
+    trace_output_blocking(desc_file, sizeof(desc_file) - 1);
+    trace_output_blocking(file, (int)strlen(file));
+    trace_output_blocking(trace_new_line, sizeof(trace_new_line) - 1);
+    // Func
+    trace_output_blocking(desc_func, sizeof(desc_func) - 1);
+    trace_output_blocking(func, (int)strlen(func));
+    trace_output_blocking(trace_new_line, sizeof(trace_new_line) - 1);
+    // Line
+    trace_output_blocking(desc_line, sizeof(desc_func) - 1);
+    len = mk_snprintf(trace_handle.tx_buf, sizeof(trace_handle.tx_buf), "%d", line);
+    trace_output_blocking(trace_handle.tx_buf, len);
+    trace_output_blocking(trace_new_line, sizeof(trace_new_line) - 1);
+
+    // SP, LR
+    len = mk_snprintf(trace_handle.tx_buf, sizeof(trace_handle.tx_buf), TRACE_NEW_LINE "SP=%08X" TRACE_NEW_LINE, assert_inf.SP);
+    len += mk_snprintf(&trace_handle.tx_buf[len], sizeof(trace_handle.tx_buf) - (uint32_t)len, "LR=%08X" TRACE_NEW_LINE, assert_inf.LR);
+    trace_output_blocking(trace_handle.tx_buf, len);
+
+    // xPSR
+    len = mk_snprintf(trace_handle.tx_buf, sizeof(trace_handle.tx_buf), "xPSR=%08X" TRACE_NEW_LINE, assert_inf.xPSR);
+    len += mk_snprintf(&trace_handle.tx_buf[len], sizeof(trace_handle.tx_buf) - (uint32_t)len, "N=%d, Z=%d, C=%d, V=%d" TRACE_NEW_LINE,
+                       ((assert_inf.xPSR >> 31) & 0x1), ((assert_inf.xPSR >> 30) & 0x1), ((assert_inf.xPSR >> 29) & 0x1), ((assert_inf.xPSR >> 28) & 0x1));
+    len += mk_snprintf(&trace_handle.tx_buf[len], sizeof(trace_handle.tx_buf) - (uint32_t)len, "IPSR=%08X" TRACE_NEW_LINE, assert_inf.xPSR & 0x3F);
+    trace_output_blocking(trace_handle.tx_buf, len);
+
+    // PRIMASK, CONTROL
+    len = mk_snprintf(trace_handle.tx_buf, sizeof(trace_handle.tx_buf), "PRIMASK=%08X" TRACE_NEW_LINE, assert_inf.PRIMASK);
+    len += mk_snprintf(&trace_handle.tx_buf[len], sizeof(trace_handle.tx_buf) - (uint32_t)len, "CONTROL=%08X" TRACE_NEW_LINE, assert_inf.CONTROL);
+    trace_output_blocking(trace_handle.tx_buf, len);
+
+    // MSP, PSP
+    len = mk_snprintf(trace_handle.tx_buf, sizeof(trace_handle.tx_buf), "MSP=%08X" TRACE_NEW_LINE, assert_inf.MSP);
+    len += mk_snprintf(&trace_handle.tx_buf[len], sizeof(trace_handle.tx_buf) - (uint32_t)len, "PSP=%08X" TRACE_NEW_LINE, assert_inf.PSP);
+    trace_output_blocking(trace_handle.tx_buf, len);
+
+    // Backtrace
+    uint32_t stack_base = (uint32_t)(&__INITIAL_SP);
+    trace_print_backtrace(assert_inf.SP, MIN(TRACE_BACKTRACE_DEPTH, stack_base - assert_inf.SP) >> 2, TRACE_BACKTRACE_COUNT);
+}
+#endif
+
+void __NO_RETURN trace_assert_dump(const char *file, const char *func, uint32_t line, const char *fmt, ...)
+{
+    int_lock();
+#if BACKTRACE_EN
+    uint32_t primask = __get_PRIMASK();
+    register uint32_t sp;
+    register uint32_t lr;
+
+#if defined(__CC_ARM)
+
+#else
+__ASM volatile("mov %0, sp" : "=r"(sp));
+__ASM volatile("mov %0, lr" : "=r"(lr));
+#endif
+
+    // Parameters
+    va_list argp;
+    va_start(argp, fmt);
+    int len = trace_format(&trace_handle.tx_buf[0], sizeof(trace_handle.tx_buf), fmt, argp);
+    va_end(argp);
+    trace_handle.tx_buf[len] = 0;
+
+    _trace_assert_dump(primask, sp, lr, file, func, line, &trace_handle.tx_buf[0]);
+
+    // User registered callback
+    trace_crash_dump_callback();
+#endif
+    // Delay for printing
+    trace_end();
+    // while(1);
+}
+
+#if BACKTRACE_EN
+__NO_RETURN void trace_exception_handler(void *regs)
+{
+    struct TRACE_EXCEPTION_INF_T *inf = regs;
+
+    inf->ID = TRACE_EXCEPTION_ID;
+
+    // Store inf in memory (optional)
+    //*(volatile uint32_t *)SRAM_BASE = (uint32_t)&inf;
+    trace_flush();
+
+    int len = 0;
+    uint32_t value;
+    uint32_t *stack;
+
+    // Timestamp
+    len += mk_snprintf(&trace_handle.tx_buf[len], sizeof(trace_handle.tx_buf) - (uint32_t)len, "%10d | " TRACE_NEW_LINE, sys_tick_us());
+
+    // Title
+    len += mk_snprintf(&trace_handle.tx_buf[len], sizeof(trace_handle.tx_buf) - (uint32_t)len,
+                       TRACE_NEW_LINE TRACE_NEW_LINE "### EXCEPTION %d ###" TRACE_NEW_LINE, inf->ICSR & 0x3F);
+    trace_output_blocking(trace_handle.tx_buf, len);
+    // PC
+    len = mk_snprintf(trace_handle.tx_buf, sizeof(trace_handle.tx_buf), "PC=%08X", inf->PC);
+    // Exception number
+    value = inf->xPSR & 0x3F;
+    if (value == 0)
+    {
+        len += mk_snprintf(&trace_handle.tx_buf[len], sizeof(trace_handle.tx_buf) - (uint32_t)len, ", ThreadMode" TRACE_NEW_LINE);
+    }
+    else
+    {
+        len += mk_snprintf(&trace_handle.tx_buf[len], sizeof(trace_handle.tx_buf) - (uint32_t)len, ", ExceptionNumber=%d" TRACE_NEW_LINE, value);
+    }
+    trace_output_blocking(trace_handle.tx_buf, len);
+
+    // R0 ~ R12
+    for (int i = 0; i < 13; i++)
+    {
+        len = mk_snprintf(trace_handle.tx_buf, sizeof(trace_handle.tx_buf), "R%-2d=%08X" TRACE_NEW_LINE, i, inf->REGS[i]);
+        trace_output_blocking(trace_handle.tx_buf, len);
+    }
+    // SP, LR
+    len = mk_snprintf(trace_handle.tx_buf, sizeof(trace_handle.tx_buf), "SP=%08X" TRACE_NEW_LINE, inf->SP);
+    len += mk_snprintf(&trace_handle.tx_buf[len], sizeof(trace_handle.tx_buf) - (uint32_t)len, "LR=%08X" TRACE_NEW_LINE, inf->LR);
+    trace_output_blocking(trace_handle.tx_buf, len);
+
+    // xPSR
+    len = mk_snprintf(trace_handle.tx_buf, sizeof(trace_handle.tx_buf), "xPSR=%08X" TRACE_NEW_LINE, inf->xPSR);
+    len += mk_snprintf(&trace_handle.tx_buf[len], sizeof(trace_handle.tx_buf) - (uint32_t)len, "N=%d, Z=%d, C=%d, V=%d" TRACE_NEW_LINE,
+                       ((inf->xPSR >> 31) & 0x1), ((inf->xPSR >> 30) & 0x1), ((inf->xPSR >> 29) & 0x1), ((inf->xPSR >> 28) & 0x1));
+    len += mk_snprintf(&trace_handle.tx_buf[len], sizeof(trace_handle.tx_buf) - (uint32_t)len, "IPSR=%08X" TRACE_NEW_LINE, inf->xPSR & 0x3F);
+    trace_output_blocking(trace_handle.tx_buf, len);
+
+    // PRIMASK, CONTROL
+    len = mk_snprintf(trace_handle.tx_buf, sizeof(trace_handle.tx_buf), "PRIMASK=%08X" TRACE_NEW_LINE, inf->PRIMASK);
+    len += mk_snprintf(&trace_handle.tx_buf[len], sizeof(trace_handle.tx_buf) - (uint32_t)len, "CONTROL=%08X" TRACE_NEW_LINE, inf->CONTROL);
+    trace_output_blocking(trace_handle.tx_buf, len);
+
+    // MSP, PSP, EXC_RETURN
+    if (inf->EXC_RETURN & 0x04)
+    {
+        len = mk_snprintf(trace_handle.tx_buf, sizeof(trace_handle.tx_buf), "MSP=%08X" TRACE_NEW_LINE, inf->PSP);
+        len += mk_snprintf(&trace_handle.tx_buf[len], sizeof(trace_handle.tx_buf) - (uint32_t)len, "PSP=%08X" TRACE_NEW_LINE, inf->MSP);
+    }
+    else
+    {
+        len = mk_snprintf(trace_handle.tx_buf, sizeof(trace_handle.tx_buf), "MSP=%08X" TRACE_NEW_LINE, inf->MSP);
+        len += mk_snprintf(&trace_handle.tx_buf[len], sizeof(trace_handle.tx_buf) - (uint32_t)len, "PSP=%08X" TRACE_NEW_LINE, inf->PSP);
+    }
+    len += mk_snprintf(&trace_handle.tx_buf[len], sizeof(trace_handle.tx_buf) - (uint32_t)len, "EXC_RETURN=%08X" TRACE_NEW_LINE, inf->EXC_RETURN);
+    trace_output_blocking(trace_handle.tx_buf, len);
+
+    // ICSR, AIRCR, SCR, CCR
+    len = mk_snprintf(trace_handle.tx_buf, sizeof(trace_handle.tx_buf), "ICSR=%08X" TRACE_NEW_LINE, inf->ICSR);
+    len += mk_snprintf(&trace_handle.tx_buf[len], sizeof(trace_handle.tx_buf) - (uint32_t)len, "AIRCR=%08X" TRACE_NEW_LINE, inf->AIRCR);
+    len += mk_snprintf(&trace_handle.tx_buf[len], sizeof(trace_handle.tx_buf) - (uint32_t)len, "SCR=%08X" TRACE_NEW_LINE, inf->SCR);
+    len += mk_snprintf(&trace_handle.tx_buf[len], sizeof(trace_handle.tx_buf) - (uint32_t)len, "CCR=%08X" TRACE_NEW_LINE TRACE_NEW_LINE, inf->CCR);
+    trace_output_blocking(trace_handle.tx_buf, len);
+
+    stack = (uint32_t *)(inf->SP & ~0x3U);
+    uint32_t stack_base = (uint32_t)(&__INITIAL_SP);
+    for (uint32_t i = 0; (i < TRACE_STACK_DUMP_LEN) && ((i * 4 + inf->SP) < stack_base); i += 4)
+    {
+        len = mk_snprintf(trace_handle.tx_buf, sizeof(trace_handle.tx_buf), "%08X: %08X %08X %08X %08X" TRACE_NEW_LINE, (uint32_t)&stack[i], stack[i],
+                          stack[i + 1], stack[i + 2], stack[i + 3]);
+        trace_output_blocking(trace_handle.tx_buf, len);
+    }
+
+    // Backtrace
+    trace_print_backtrace(inf->SP, MIN(TRACE_BACKTRACE_DEPTH, (stack_base - inf->SP)) >> 2, TRACE_BACKTRACE_COUNT);
+
+    // User registered callback
+    trace_crash_dump_callback();
+
+    // Delay for printing
+
+    trace_end();
+}
+#endif
+
+/*----------------------------------------------------------------------------
+  Default Handler for Exceptions / Interrupts
+ *----------------------------------------------------------------------------*/
+void HardFault_Handler(void)
+{
+#if BACKTRACE_EN
+    __ASM volatile(
+        "movs r1, #0x04 \n"
+        "mov r0, lr \n"
+        "tst r0, r1 \n"
+        "beq label_1 \n"
+
+        // Using PSP
+        "mrs r3, psp \n"
+        "mrs r2, msp \n"
+        "b label_2 \n"
+
+        "label_1: \n"
+        // Using MSP
+        "mrs r3, msp \n"
+        "mrs r2, psp \n"
+
+        "label_2: \n"
+        // Allocate space for r0-r15,psr...
+        "sub sp, #27*4 \n"
+
+        // Save r4-r7
+        "add r0, sp, #4*4 \n"
+        "stm r0!, {r4-r7} \n"
+
+        // Save r8 - r11
+        "mov r4, r8 \n"
+        "mov r5, r9 \n"
+        "mov r6, r10 \n"
+        "mov r7, r11 \n"
+        "add r0, sp, #8*4 \n"
+        "stm r0!, {r4-r7} \n"
+
+        // Save r0-r3
+        "mov r0, r3 \n"
+        "ldm r0!, {r4-r7} \n"
+        "mov r0, sp \n"
+        "stm r0!, {r4-r7} \n"
+
+        // Save r12
+        "ldr r0, [r3, #4*4] \n"
+        "str r0, [sp, #12*4] \n"
+        // Save sp
+        "movs r0, #8*4 \n"
+        "add r0, r0, r3 \n"
+        "str r0, [sp, #13*4] \n"
+        // Save lr
+        "ldr r0, [r3, #5*4] \n"
+        "str r0, [sp, #14*4] \n"
+        // Save pc
+        "ldr r0, [r3, #6*4] \n"
+        "str r0, [sp, #15*4] \n"
+        // Save PSR
+        "ldr r0, [r3, #7*4] \n"
+        "str r0, [sp, #16*4] \n"
+        // Save primask
+        "mrs r0, primask \n"
+        "str r0, [sp, #17*4] \n"
+        // Save control
+        "mrs r0, control \n"
+        "str r0, [sp, #18*4] \n"
+        // Save ICSR
+        "ldr r1, =0xE000ED04 \n"
+        "ldr r0, [r1] \n"
+        "str r0, [sp, #19*4] \n"
+        // Save AIRCR
+        "ldr r1, =0xE000ED0C \n"
+        "ldr r0, [r1] \n"
+        "str r0, [sp, #20*4] \n"
+        // Save SCR
+        "ldr r1, =0xE000ED10 \n"
+        "ldr r0, [r1] \n"
+        "str r0, [sp, #21*4] \n"
+        // Save CCR
+        "ldr r1, =0xE000ED14 \n"
+        "ldr r0, [r1] \n"
+        "str r0, [sp, #22*4] \n"
+        // Save msp, psp
+        "str r3, [sp, #23*4] \n"
+        "str r2, [sp, #24*4] \n"
+        // Save exc_return
+        "mov r0, lr \n"
+        "str r0, [sp, #25*4] \n"
+
+        // Invoke the fault handler
+        "mov r0, sp \n"
+        "bl trace_exception_handler \n");
+#else
+    trace_end();
+    // while(1);
+#endif
+}
+
+#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
+#pragma clang diagnostic pop
+#endif
+
+#else
+__NO_RETURN void HardFault_Handler(void);
+
+void HardFault_Handler(void)
+{
+#if TRACE_REBOOT_EN
+    // reboot
+    reset_module(RESET_MODULE_REBOOT);
+#endif
+    // open SWD
+    // io_pin_mux_set(IO_PIN_15, IO_FUNC0);
+    // io_pin_mux_set(IO_PIN_16, IO_FUNC0);
+
+    do
+    {
+        __NOP();
+        __NOP();
+        __NOP();
+        __NOP();
+    } while (1);
+}
+
+int trace_printf(uint16_t module, uint8_t level, const char *fmt, ...)
+{
+    return 0;
+}
+
+int trace_dump(uint16_t module, uint8_t level, const char *fmt, uint32_t size, const void *data, uint32_t count)
+{
+    return 0;
+}
+
+void __NO_RETURN trace_assert_dump(const char *file, const char *func, uint32_t line, const char *fmt, ...)
+{
+    HardFault_Handler();
+}
+
+void trace_flush(void)
+{
+}
+
+#endif

--
Gitblit v1.9.3