| /* |
| * Copyright 2017 NXP |
| * All rights reserved. |
| * |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| * |
| */ |
| #include "fsl_log.h" |
| #include "fsl_debug_console_conf.h" |
| #include "fsl_io.h" |
| #ifdef FSL_RTOS_FREE_RTOS |
| #include "FreeRTOS.h" |
| #include "task.h" |
| #include "semphr.h" |
| #endif |
| /******************************************************************************* |
| * Definitions |
| ******************************************************************************/ |
| #ifndef BACKSPACE |
| /*! @brief character backspace ASCII value */ |
| #define BACKSPACE 127 |
| #endif |
| |
| #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING |
| /*! @brief increase pop member */ |
| #define LOG_CHECK_BUFFER_INDEX_OVERFLOW(index) \ |
| { \ |
| if (index >= DEBUG_CONSOLE_TRANSMIT_BUFFER_LEN) \ |
| { \ |
| index -= DEBUG_CONSOLE_TRANSMIT_BUFFER_LEN; \ |
| } \ |
| \ |
| \ |
| } |
| |
| /*! @brief get current runing environment is ISR or not */ |
| #ifdef __CA7_REV |
| #define IS_RUNNING_IN_ISR() SystemGetIRQNestingLevel() |
| #else |
| #define IS_RUNNING_IN_ISR() __get_IPSR() |
| #endif /* __CA7_REV */ |
| |
| #else |
| #define IS_RUNNING_IN_ISR() (0U) |
| #endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */ |
| |
| /* define for rtos */ |
| #if (DEBUG_CONSOLE_SYNCHRONIZATION_MODE == DEBUG_CONSOLE_SYNCHRONIZATION_FREERTOS) |
| /* metex semaphore */ |
| #define LOG_CREATE_MUTEX_SEMAPHORE(mutex) (mutex = xSemaphoreCreateMutex()) |
| |
| #define LOG_GIVE_MUTEX_SEMAPHORE(mutex) \ |
| \ |
| { \ |
| if (IS_RUNNING_IN_ISR() == 0U) \ |
| { \ |
| xSemaphoreGive(mutex); \ |
| } \ |
| \ |
| } |
| |
| #define LOG_TAKE_MUTEX_SEMAPHORE_BLOCKING(mutex) \ |
| \ |
| { \ |
| if (IS_RUNNING_IN_ISR() == 0U) \ |
| { \ |
| xSemaphoreTake(mutex, portMAX_DELAY); \ |
| } \ |
| \ |
| } |
| |
| #define LOG_TAKE_MUTEX_SEMAPHORE_NONBLOCKING(mutex, result) \ |
| \ |
| { \ |
| if (IS_RUNNING_IN_ISR() == 0U) \ |
| { \ |
| result = xSemaphoreTake(mutex, 0U); \ |
| } \ |
| else \ |
| { \ |
| result = 1U; \ |
| } \ |
| \ |
| } |
| |
| /* Binary semaphore */ |
| #define LOG_CREATE_BINARY_SEMAPHORE(binary) (binary = xSemaphoreCreateBinary()) |
| #define LOG_TAKE_BINARY_SEMAPHORE_BLOCKING(binary) (xSemaphoreTake(binary, portMAX_DELAY)) |
| #define LOG_GIVE_BINARY_SEMAPHORE_FROM_ISR(binary) (xSemaphoreGiveFromISR(binary, NULL)) |
| |
| #elif(DEBUG_CONSOLE_SYNCHRONIZATION_MODE == DEBUG_CONSOLE_SYNCHRONIZATION_BM) |
| |
| #define LOG_CREATE_MUTEX_SEMAPHORE(mutex) |
| #define LOG_TAKE_MUTEX_SEMAPHORE_BLOCKING(mutex) |
| #define LOG_GIVE_MUTEX_SEMAPHORE(mutex) |
| #define LOG_CREATE_BINARY_SEMAPHORE(binary) |
| #define LOG_TAKE_MUTEX_SEMAPHORE_NONBLOCKING(mutex, result) (result = 1U) |
| #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING |
| #define LOG_TAKE_BINARY_SEMAPHORE_BLOCKING(binary) \ |
| \ |
| { \ |
| while (!binary) \ |
| ; \ |
| binary = false; \ |
| \ |
| \ |
| } |
| #define LOG_GIVE_BINARY_SEMAPHORE_FROM_ISR(binary) (binary = true) |
| #else |
| #define LOG_TAKE_BINARY_SEMAPHORE_BLOCKING(binary) |
| #define LOG_GIVE_BINARY_SEMAPHORE_FROM_ISR(binary) |
| #endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */ |
| |
| /* add other implementation here |
| *such as : |
| * #elif(DEBUG_CONSOLE_SYNCHRONIZATION_MODE == DEBUG_CONSOLE_SYNCHRONIZATION_xxx) |
| */ |
| |
| #else |
| |
| #define LOG_CREATE_MUTEX_SEMAPHORE(mutex) |
| #define LOG_TAKE_MUTEX_SEMAPHORE_BLOCKING(mutex) |
| #define LOG_TAKE_MUTEX_SEMAPHORE_NONBLOCKING(mutex, result) (result = 1U) |
| #define LOG_GIVE_MUTEX_SEMAPHORE(mutex) |
| #define LOG_CREATE_BINARY_SEMAPHORE(binary) |
| #define LOG_TAKE_BINARY_SEMAPHORE_BLOCKING(binary) |
| #define LOG_GIVE_BINARY_SEMAPHORE(binary) |
| #endif /* DEBUG_CONSOLE_SYNCHRONIZATION_MODE == DEBUG_CONSOLE_SYNCHRONIZATION_FREERTOS */ |
| |
| #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING |
| /*! @brief Define the buffer |
| * The total buffer size should be calucate as (BUFFER_SUPPORT_LOG_LENGTH + 1) * BUFFER_SUPPORT_LOG_NUM * 4 |
| */ |
| typedef struct _log_buffer |
| { |
| volatile uint16_t totalIndex; /*!< indicate the total usage of the buffer */ |
| volatile uint16_t pushIndex; /*!< indicate the next push index */ |
| volatile uint16_t popIndex; /*!< indicate the pop index */ |
| uint8_t txBuf[DEBUG_CONSOLE_TRANSMIT_BUFFER_LEN]; /*!< buffer to store printf log */ |
| |
| uint8_t rxBuf[DEBUG_CONSOLE_RECEIVE_BUFFER_LEN]; /*!< buffer to store scanf log */ |
| } log_buffer_t; |
| #endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */ |
| |
| /******************************************************************************* |
| * Variables |
| ******************************************************************************/ |
| #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING |
| /* A global log buffer */ |
| static log_buffer_t s_log_buffer; |
| #endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */ |
| |
| /* lock definition */ |
| #if (DEBUG_CONSOLE_SYNCHRONIZATION_MODE == DEBUG_CONSOLE_SYNCHRONIZATION_FREERTOS) |
| #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING |
| static SemaphoreHandle_t s_logPushSemaphore = NULL; |
| #endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */ |
| static SemaphoreHandle_t s_logPopSemaphore = NULL; |
| static SemaphoreHandle_t s_logReadSemaphore = NULL; |
| |
| #elif(DEBUG_CONSOLE_SYNCHRONIZATION_MODE == DEBUG_CONSOLE_SYNCHRONIZATION_BM) |
| |
| #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING |
| |
| static volatile bool s_logReadSemaphore = false; /* transferred event from ISR for bare-metal + interrupt */ |
| |
| #endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */ |
| |
| #else |
| #endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */ |
| |
| /******************************************************************************* |
| * Prototypes |
| ******************************************************************************/ |
| #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING |
| /*! |
| * @brief callback function for IO layer to notify LOG |
| * |
| * @param size last transfer data size |
| * @param receive indicate a RX transfer |
| * @param transmit indicate a TX transfer |
| * |
| */ |
| static void LOG_Transferred(size_t *size, bool receive, bool transmit); |
| |
| /*! |
| * @brief log push function |
| * |
| * @param buf target buffer |
| * @param size log size |
| * |
| */ |
| static int LOG_BufPush(uint8_t *buf, size_t size); |
| |
| /*! |
| * @brief Get next avaliable log |
| * |
| * @param next avaliable size |
| * @return next avaliable address |
| */ |
| static uint8_t *LOG_BufGetNextAvaliableLog(size_t *size); |
| |
| /*! |
| * @brief buf pop |
| * |
| * @param size log size popped and next available log size |
| * @return next avaliable address |
| */ |
| static uint8_t *LOG_BufPop(size_t *size); |
| |
| #endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */ |
| |
| /*! |
| * @brief read one character |
| * |
| * @param ch character address |
| * @return indicate the read status |
| * |
| */ |
| static status_t LOG_ReadOneCharacter(uint8_t *ch); |
| |
| #if DEBUG_CONSOLE_ENABLE_ECHO_FUNCTION |
| /*! |
| * @brief echo one character |
| * |
| * @param ch character address |
| * @param isGetchar flag to distinguish getchar from scanf |
| * @param index special for scanf to support backspace |
| * @return indicate the read status |
| * |
| */ |
| static status_t LOG_EchoCharacter(uint8_t *ch, bool isGetChar, int *index); |
| #endif |
| |
| /******************************************************************************* |
| * Code |
| ******************************************************************************/ |
| status_t LOG_Init(uint32_t baseAddr, uint8_t device, uint32_t baudRate, uint32_t clkSrcFreq) |
| { |
| io_state_t io; |
| /* init io */ |
| io.ioBase = (void *)baseAddr; |
| io.ioType = device; |
| |
| #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING |
| /* memset the global queue */ |
| memset(&s_log_buffer, 0U, sizeof(s_log_buffer)); |
| /* init callback for NON-BLOCKING */ |
| io.callBack = LOG_Transferred; |
| /* io init function */ |
| IO_Init(&io, baudRate, clkSrcFreq, s_log_buffer.rxBuf); |
| /* Debug console buffer push lock create */ |
| LOG_CREATE_MUTEX_SEMAPHORE(s_logPushSemaphore); |
| #else |
| IO_Init(&io, baudRate, clkSrcFreq, NULL); |
| #endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */ |
| |
| /* Debug console lock create */ |
| LOG_CREATE_MUTEX_SEMAPHORE(s_logPopSemaphore); |
| LOG_CREATE_BINARY_SEMAPHORE(s_logReadSemaphore); |
| |
| return kStatus_Success; |
| } |
| |
| void LOG_Deinit(void) |
| { |
| #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING |
| /* memset the global queue */ |
| memset(&s_log_buffer, 0U, sizeof(s_log_buffer)); |
| #endif /*DEBUG_CONSOLE_TRANSFER_NON_BLOCKING*/ |
| /* Deinit IO */ |
| IO_Deinit(); |
| } |
| |
| status_t LOG_WaitIdle(void) |
| { |
| #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING |
| /* wait buffer empty */ |
| while (!(s_log_buffer.totalIndex == 0U)) |
| ; |
| #endif /*DEBUG_CONSOLE_TRANSFER_NON_BLOCKING*/ |
| /* wait IO idle */ |
| IO_WaitIdle(); |
| |
| return kStatus_Success; |
| } |
| |
| int LOG_Push(uint8_t *buf, size_t size) |
| { |
| assert(buf != NULL); |
| |
| #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING |
| /* push to buffer */ |
| LOG_BufPush(buf, size); |
| buf = LOG_BufGetNextAvaliableLog(&size); |
| #endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */ |
| /* pop log */ |
| return LOG_Pop(buf, size); |
| } |
| |
| int LOG_Pop(uint8_t *buf, size_t size) |
| { |
| uint8_t getLock = 0U; |
| |
| if ((0 != size) && (NULL != buf)) |
| { |
| /* take POP lock, should be non-blocking */ |
| LOG_TAKE_MUTEX_SEMAPHORE_NONBLOCKING(s_logPopSemaphore, getLock); |
| |
| if (getLock) |
| { |
| /* call IO transfer function */ |
| if (IO_Transfer(buf, size, true) != kStatus_Success) |
| { |
| size = 0U; |
| } |
| /* release POP lock */ |
| LOG_GIVE_MUTEX_SEMAPHORE(s_logPopSemaphore); |
| } |
| } |
| |
| return size; |
| } |
| |
| int LOG_ReadLine(uint8_t *buf, size_t size) |
| { |
| assert(buf != NULL); |
| |
| int i = 0; |
| |
| /* take mutex lock function */ |
| LOG_TAKE_MUTEX_SEMAPHORE_BLOCKING(s_logPushSemaphore); |
| |
| for (i = 0; i < size; i++) |
| { |
| /* recieve one char every time */ |
| if (LOG_ReadOneCharacter(&buf[i]) != kStatus_Success) |
| { |
| return -1; |
| } |
| #if DEBUG_CONSOLE_ENABLE_ECHO_FUNCTION |
| LOG_EchoCharacter(&buf[i], false, &i); |
| #endif |
| /* analysis data */ |
| if ((buf[i] == '\r') || (buf[i] == '\n')) |
| { |
| /* End of Line. */ |
| if (i == 0) |
| { |
| buf[i] = '\0'; |
| i = -1; |
| } |
| else |
| { |
| break; |
| } |
| } |
| } |
| /* get char should not add '\0'*/ |
| if (i == size) |
| { |
| buf[i] = '\0'; |
| } |
| else |
| { |
| buf[i + 1] = '\0'; |
| } |
| |
| /* release mutex lock function */ |
| LOG_GIVE_MUTEX_SEMAPHORE(s_logPushSemaphore); |
| |
| return i; |
| } |
| |
| int LOG_ReadCharacter(uint8_t *ch) |
| { |
| assert(ch != NULL); |
| int ret = 0; |
| |
| /* take mutex lock function */ |
| LOG_TAKE_MUTEX_SEMAPHORE_BLOCKING(s_logPushSemaphore); |
| /* read one character */ |
| if (LOG_ReadOneCharacter(ch) == kStatus_Success) |
| { |
| ret = 1; |
| #if DEBUG_CONSOLE_ENABLE_ECHO_FUNCTION |
| LOG_EchoCharacter(ch, true, NULL); |
| #endif |
| } |
| else |
| { |
| ret = -1; |
| } |
| /* release mutex lock function */ |
| LOG_GIVE_MUTEX_SEMAPHORE(s_logPushSemaphore); |
| |
| return ret; |
| } |
| |
| static status_t LOG_ReadOneCharacter(uint8_t *ch) |
| { |
| /* recieve one char every time */ |
| if (IO_Transfer(ch, 1U, false) != kStatus_Success) |
| { |
| return kStatus_Fail; |
| } |
| |
| /* wait release from ISR */ |
| LOG_TAKE_BINARY_SEMAPHORE_BLOCKING(s_logReadSemaphore); |
| |
| return kStatus_Success; |
| } |
| |
| #if DEBUG_CONSOLE_ENABLE_ECHO_FUNCTION |
| static status_t LOG_EchoCharacter(uint8_t *ch, bool isGetChar, int *index) |
| { |
| /* Due to scanf take \n and \r as end of string,should not echo */ |
| if (((*ch != '\r') && (*ch != '\n')) || (isGetChar)) |
| { |
| /* recieve one char every time */ |
| if (IO_Transfer(ch, 1U, true) != kStatus_Success) |
| { |
| return kStatus_Fail; |
| } |
| } |
| |
| if (!isGetChar) |
| { |
| if ((*index > 0) && (*ch == BACKSPACE)) |
| { |
| *index -= 2; |
| } |
| } |
| |
| return kStatus_Success; |
| } |
| #endif |
| |
| #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING |
| static int LOG_BufPush(uint8_t *buf, size_t size) |
| { |
| uint32_t pushIndex = 0U, i = 0U; |
| bool pushAvaliable = false; |
| |
| /* take mutex lock function */ |
| LOG_TAKE_MUTEX_SEMAPHORE_BLOCKING(s_logPushSemaphore); |
| if (size <= (DEBUG_CONSOLE_TRANSMIT_BUFFER_LEN - s_log_buffer.totalIndex)) |
| { |
| /* get push index */ |
| pushIndex = s_log_buffer.pushIndex; |
| s_log_buffer.pushIndex += size; |
| /* check index overflow */ |
| LOG_CHECK_BUFFER_INDEX_OVERFLOW(s_log_buffer.pushIndex); |
| /* update push/total index value */ |
| s_log_buffer.totalIndex += size; |
| pushAvaliable = true; |
| } |
| /* release mutex lock function */ |
| LOG_GIVE_MUTEX_SEMAPHORE(s_logPushSemaphore); |
| |
| /* check the buffer if have enough space to store the log */ |
| if (pushAvaliable) |
| { |
| for (i = size; i > 0; i--) |
| { |
| /* copy log to buffer, the buffer only support a fixed length argument, if the log argument |
| is longer than the fixed length, the left argument will be losed */ |
| s_log_buffer.txBuf[pushIndex] = *buf++; |
| /* increase index */ |
| pushIndex++; |
| /* check index overflow */ |
| LOG_CHECK_BUFFER_INDEX_OVERFLOW(pushIndex); |
| } |
| } |
| else |
| { |
| size = 0U; |
| } |
| |
| return size; |
| } |
| |
| static uint8_t *LOG_BufGetNextAvaliableLog(size_t *size) |
| { |
| uint16_t popIndex = s_log_buffer.popIndex; |
| |
| /* get avaliable size */ |
| if (s_log_buffer.totalIndex > (DEBUG_CONSOLE_TRANSMIT_BUFFER_LEN - popIndex)) |
| { |
| *size = (DEBUG_CONSOLE_TRANSMIT_BUFFER_LEN - popIndex); |
| } |
| else |
| { |
| *size = s_log_buffer.totalIndex; |
| } |
| |
| /* return address */ |
| return (&(s_log_buffer.txBuf[popIndex])); |
| } |
| |
| static uint8_t *LOG_BufPop(size_t *size) |
| { |
| if (s_log_buffer.totalIndex >= *size) |
| { |
| /* decrease the log total member */ |
| s_log_buffer.totalIndex -= *size; |
| /* there is more log in the queue to be pushed */ |
| if (s_log_buffer.totalIndex > 0U) |
| { |
| /* update the pop index */ |
| s_log_buffer.popIndex += *size; |
| /* check index overflow */ |
| LOG_CHECK_BUFFER_INDEX_OVERFLOW(s_log_buffer.popIndex); |
| |
| return LOG_BufGetNextAvaliableLog(size); |
| } |
| else |
| { |
| /* reset push and pop */ |
| s_log_buffer.popIndex = 0U; |
| s_log_buffer.pushIndex = 0U; |
| *size = 0U; |
| } |
| } |
| |
| return NULL; |
| } |
| |
| static void LOG_Transferred(size_t *size, bool receive, bool transmit) |
| { |
| uint8_t *addr = NULL; |
| |
| if (transmit) |
| { |
| addr = LOG_BufPop(size); |
| /* continue pop log from buffer */ |
| LOG_Pop(addr, *size); |
| } |
| |
| if (receive) |
| { |
| /* release from ISR */ |
| LOG_GIVE_BINARY_SEMAPHORE_FROM_ISR(s_logReadSemaphore); |
| } |
| } |
| #endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */ |