summaryrefslogtreecommitdiffhomepage
path: root/utilities/fsl_log.c
diff options
context:
space:
mode:
Diffstat (limited to 'utilities/fsl_log.c')
-rw-r--r--utilities/fsl_log.c587
1 files changed, 587 insertions, 0 deletions
diff --git a/utilities/fsl_log.c b/utilities/fsl_log.c
new file mode 100644
index 0000000..e36832d
--- /dev/null
+++ b/utilities/fsl_log.c
@@ -0,0 +1,587 @@
+/*
+ * The Clear BSD License
+ * Copyright 2017 NXP
+ * All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted (subject to the limitations in the disclaimer below) provided
+ * that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form 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.
+ *
+ * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EEMPLARY, 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 "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)
+#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;
+static SemaphoreHandle_t s_logReadSemaphore = NULL;
+#endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */
+static SemaphoreHandle_t s_logPopSemaphore = NULL;
+static SemaphoreHandle_t s_logReadWaitSemaphore = NULL;
+
+#elif(DEBUG_CONSOLE_SYNCHRONIZATION_MODE == DEBUG_CONSOLE_SYNCHRONIZATION_BM)
+
+#ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING
+
+static volatile bool s_logReadWaitSemaphore = 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);
+ /* Debug console get/scanf mutex lock create */
+ LOG_CREATE_MUTEX_SEMAPHORE(s_logReadSemaphore);
+#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_logReadWaitSemaphore);
+
+ 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_logReadSemaphore);
+
+ 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_logReadSemaphore);
+
+ return i;
+}
+
+int LOG_ReadCharacter(uint8_t *ch)
+{
+ assert(ch != NULL);
+ int ret = 0;
+
+ /* take mutex lock function */
+ LOG_TAKE_MUTEX_SEMAPHORE_BLOCKING(s_logReadSemaphore);
+ /* 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_logReadSemaphore);
+
+ 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_logReadWaitSemaphore);
+
+ 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_logReadWaitSemaphore);
+ }
+}
+#endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */
+
+#ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING
+status_t LOG_TryReadCharacter(uint8_t *ch)
+{
+ if (NULL != ch)
+ {
+ return IO_TryReceiveCharacter(ch);
+ }
+ return kStatus_Fail;
+}
+#endif

Highly Recommended Verilog Books