1 /*
2  * Copyright 2017 NXP
3  * All rights reserved.
4  *
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  *
8  */
9 #include "fsl_log.h"
10 #include "fsl_debug_console_conf.h"
11 #include "fsl_io.h"
12 #ifdef FSL_RTOS_FREE_RTOS
13 #include "FreeRTOS.h"
14 #include "task.h"
15 #include "semphr.h"
16 #endif
17 /*******************************************************************************
18  * Definitions
19  ******************************************************************************/
20 #ifndef BACKSPACE
21 /*! @brief character backspace ASCII value */
22 #define BACKSPACE 127
23 #endif
24 
25 #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING
26 /*! @brief increase pop member */
27 #define LOG_CHECK_BUFFER_INDEX_OVERFLOW(index)          \
28     {                                                   \
29         if (index >= DEBUG_CONSOLE_TRANSMIT_BUFFER_LEN) \
30         {                                               \
31             index -= DEBUG_CONSOLE_TRANSMIT_BUFFER_LEN; \
32         }                                               \
33     \
34 \
35 }
36 
37 /*! @brief get current runing environment is ISR or not */
38 #ifdef __CA7_REV
39 #define IS_RUNNING_IN_ISR() SystemGetIRQNestingLevel()
40 #else
41 #define IS_RUNNING_IN_ISR() __get_IPSR()
42 #endif /* __CA7_REV */
43 
44 #else
45 #define IS_RUNNING_IN_ISR() (0U)
46 #endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */
47 
48 /* define for rtos */
49 #if (DEBUG_CONSOLE_SYNCHRONIZATION_MODE == DEBUG_CONSOLE_SYNCHRONIZATION_FREERTOS)
50 /* metex semaphore */
51 #define LOG_CREATE_MUTEX_SEMAPHORE(mutex) (mutex = xSemaphoreCreateMutex())
52 
53 #define LOG_GIVE_MUTEX_SEMAPHORE(mutex) \
54     \
55 {                                \
56         if (IS_RUNNING_IN_ISR() == 0U)  \
57         {                               \
58             xSemaphoreGive(mutex);      \
59         }                               \
60     \
61 }
62 
63 #define LOG_TAKE_MUTEX_SEMAPHORE_BLOCKING(mutex)  \
64     \
65 {                                          \
66         if (IS_RUNNING_IN_ISR() == 0U)            \
67         {                                         \
68             xSemaphoreTake(mutex, portMAX_DELAY); \
69         }                                         \
70     \
71 }
72 
73 #define LOG_TAKE_MUTEX_SEMAPHORE_NONBLOCKING(mutex, result) \
74     \
75 {                                                    \
76         if (IS_RUNNING_IN_ISR() == 0U)                      \
77         {                                                   \
78             result = xSemaphoreTake(mutex, 0U);             \
79         }                                                   \
80         else                                                \
81         {                                                   \
82             result = 1U;                                    \
83         }                                                   \
84     \
85 }
86 
87 /* Binary semaphore */
88 #define LOG_CREATE_BINARY_SEMAPHORE(binary) (binary = xSemaphoreCreateBinary())
89 #define LOG_TAKE_BINARY_SEMAPHORE_BLOCKING(binary) (xSemaphoreTake(binary, portMAX_DELAY))
90 #define LOG_GIVE_BINARY_SEMAPHORE_FROM_ISR(binary) (xSemaphoreGiveFromISR(binary, NULL))
91 
92 #elif(DEBUG_CONSOLE_SYNCHRONIZATION_MODE == DEBUG_CONSOLE_SYNCHRONIZATION_BM)
93 
94 #define LOG_CREATE_MUTEX_SEMAPHORE(mutex)
95 #define LOG_TAKE_MUTEX_SEMAPHORE_BLOCKING(mutex)
96 #define LOG_GIVE_MUTEX_SEMAPHORE(mutex)
97 #define LOG_CREATE_BINARY_SEMAPHORE(binary)
98 #define LOG_TAKE_MUTEX_SEMAPHORE_NONBLOCKING(mutex, result) (result = 1U)
99 #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING
100 #define LOG_TAKE_BINARY_SEMAPHORE_BLOCKING(binary) \
101     \
102 {                                           \
103         while (!binary)                            \
104             ;                                      \
105         binary = false;                            \
106     \
107 \
108 }
109 #define LOG_GIVE_BINARY_SEMAPHORE_FROM_ISR(binary) (binary = true)
110 #else
111 #define LOG_TAKE_BINARY_SEMAPHORE_BLOCKING(binary)
112 #define LOG_GIVE_BINARY_SEMAPHORE_FROM_ISR(binary)
113 #endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */
114 
115 /* add other implementation here
116 *such as :
117 * #elif(DEBUG_CONSOLE_SYNCHRONIZATION_MODE == DEBUG_CONSOLE_SYNCHRONIZATION_xxx)
118 */
119 
120 #else
121 
122 #define LOG_CREATE_MUTEX_SEMAPHORE(mutex)
123 #define LOG_TAKE_MUTEX_SEMAPHORE_BLOCKING(mutex)
124 #define LOG_TAKE_MUTEX_SEMAPHORE_NONBLOCKING(mutex, result) (result = 1U)
125 #define LOG_GIVE_MUTEX_SEMAPHORE(mutex)
126 #define LOG_CREATE_BINARY_SEMAPHORE(binary)
127 #define LOG_TAKE_BINARY_SEMAPHORE_BLOCKING(binary)
128 #define LOG_GIVE_BINARY_SEMAPHORE(binary)
129 #endif /* DEBUG_CONSOLE_SYNCHRONIZATION_MODE == DEBUG_CONSOLE_SYNCHRONIZATION_FREERTOS */
130 
131 #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING
132 /*! @brief Define the buffer
133 * The total buffer size should be calucate as (BUFFER_SUPPORT_LOG_LENGTH + 1) * BUFFER_SUPPORT_LOG_NUM * 4
134 */
135 typedef struct _log_buffer
136 {
137     volatile uint16_t totalIndex;                     /*!< indicate the total usage of the buffer */
138     volatile uint16_t pushIndex;                      /*!< indicate the next push index */
139     volatile uint16_t popIndex;                       /*!< indicate the pop index */
140     uint8_t txBuf[DEBUG_CONSOLE_TRANSMIT_BUFFER_LEN]; /*!< buffer to store printf log */
141 
142     uint8_t rxBuf[DEBUG_CONSOLE_RECEIVE_BUFFER_LEN]; /*!< buffer to store scanf log */
143 } log_buffer_t;
144 #endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */
145 
146 /*******************************************************************************
147  * Variables
148  ******************************************************************************/
149 #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING
150 /* A global log buffer */
151 static log_buffer_t s_log_buffer;
152 #endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */
153 
154 /* lock definition */
155 #if (DEBUG_CONSOLE_SYNCHRONIZATION_MODE == DEBUG_CONSOLE_SYNCHRONIZATION_FREERTOS)
156 #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING
157 static SemaphoreHandle_t s_logPushSemaphore = NULL;
158 #endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */
159 static SemaphoreHandle_t s_logPopSemaphore = NULL;
160 static SemaphoreHandle_t s_logReadSemaphore = NULL;
161 
162 #elif(DEBUG_CONSOLE_SYNCHRONIZATION_MODE == DEBUG_CONSOLE_SYNCHRONIZATION_BM)
163 
164 #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING
165 
166 static volatile bool s_logReadSemaphore = false; /* transferred event from ISR for bare-metal + interrupt */
167 
168 #endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */
169 
170 #else
171 #endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */
172 
173 /*******************************************************************************
174 * Prototypes
175 ******************************************************************************/
176 #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING
177 /*!
178  * @brief callback function for IO layer to notify LOG
179  *
180  * @param size last transfer data size
181  * @param receive indicate a RX transfer
182  * @param transmit indicate a TX transfer
183  *
184  */
185 static void LOG_Transferred(size_t *size, bool receive, bool transmit);
186 
187 /*!
188  * @brief log push function
189  *
190  * @param buf target buffer
191  * @param size log size
192  *
193  */
194 static int LOG_BufPush(uint8_t *buf, size_t size);
195 
196 /*!
197  * @brief Get next avaliable log
198  *
199  * @param next avaliable size
200  * @return next avaliable address
201  */
202 static uint8_t *LOG_BufGetNextAvaliableLog(size_t *size);
203 
204 /*!
205  * @brief buf pop
206  *
207  * @param size log size popped and next available log size
208  * @return next avaliable address
209  */
210 static uint8_t *LOG_BufPop(size_t *size);
211 
212 #endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */
213 
214 /*!
215  * @brief read one character
216  *
217  * @param ch character address
218  * @return indicate the read status
219  *
220  */
221 static status_t LOG_ReadOneCharacter(uint8_t *ch);
222 
223 #if DEBUG_CONSOLE_ENABLE_ECHO_FUNCTION
224 /*!
225  * @brief echo one character
226  *
227  * @param ch character address
228  * @param isGetchar flag to distinguish getchar from scanf
229  * @param index special for scanf to support backspace
230  * @return indicate the read status
231  *
232  */
233 static status_t LOG_EchoCharacter(uint8_t *ch, bool isGetChar, int *index);
234 #endif
235 
236 /*******************************************************************************
237  * Code
238  ******************************************************************************/
LOG_Init(uint32_t baseAddr,uint8_t device,uint32_t baudRate,uint32_t clkSrcFreq)239 status_t LOG_Init(uint32_t baseAddr, uint8_t device, uint32_t baudRate, uint32_t clkSrcFreq)
240 {
241     io_state_t io;
242     /* init io */
243     io.ioBase = (void *)baseAddr;
244     io.ioType = device;
245 
246 #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING
247     /* memset the global queue */
248     memset(&s_log_buffer, 0U, sizeof(s_log_buffer));
249     /* init callback for NON-BLOCKING */
250     io.callBack = LOG_Transferred;
251     /* io init function */
252     IO_Init(&io, baudRate, clkSrcFreq, s_log_buffer.rxBuf);
253     /* Debug console buffer push lock create */
254     LOG_CREATE_MUTEX_SEMAPHORE(s_logPushSemaphore);
255 #else
256     IO_Init(&io, baudRate, clkSrcFreq, NULL);
257 #endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */
258 
259     /* Debug console lock create */
260     LOG_CREATE_MUTEX_SEMAPHORE(s_logPopSemaphore);
261     LOG_CREATE_BINARY_SEMAPHORE(s_logReadSemaphore);
262 
263     return kStatus_Success;
264 }
265 
LOG_Deinit(void)266 void LOG_Deinit(void)
267 {
268 #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING
269     /* memset the global queue */
270     memset(&s_log_buffer, 0U, sizeof(s_log_buffer));
271 #endif /*DEBUG_CONSOLE_TRANSFER_NON_BLOCKING*/
272     /* Deinit IO */
273     IO_Deinit();
274 }
275 
LOG_WaitIdle(void)276 status_t LOG_WaitIdle(void)
277 {
278 #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING
279     /* wait buffer empty */
280     while (!(s_log_buffer.totalIndex == 0U))
281         ;
282 #endif /*DEBUG_CONSOLE_TRANSFER_NON_BLOCKING*/
283     /* wait IO idle */
284     IO_WaitIdle();
285 
286     return kStatus_Success;
287 }
288 
LOG_Push(uint8_t * buf,size_t size)289 int LOG_Push(uint8_t *buf, size_t size)
290 {
291     assert(buf != NULL);
292 
293 #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING
294     /* push to buffer */
295     LOG_BufPush(buf, size);
296     buf = LOG_BufGetNextAvaliableLog(&size);
297 #endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */
298     /* pop log */
299     return LOG_Pop(buf, size);
300 }
301 
LOG_Pop(uint8_t * buf,size_t size)302 int LOG_Pop(uint8_t *buf, size_t size)
303 {
304     uint8_t getLock = 0U;
305 
306     if ((0 != size) && (NULL != buf))
307     {
308         /* take POP lock, should be non-blocking */
309         LOG_TAKE_MUTEX_SEMAPHORE_NONBLOCKING(s_logPopSemaphore, getLock);
310 
311         if (getLock)
312         {
313             /* call IO transfer function */
314             if (IO_Transfer(buf, size, true) != kStatus_Success)
315             {
316                 size = 0U;
317             }
318             /* release POP lock */
319             LOG_GIVE_MUTEX_SEMAPHORE(s_logPopSemaphore);
320         }
321     }
322 
323     return size;
324 }
325 
LOG_ReadLine(uint8_t * buf,size_t size)326 int LOG_ReadLine(uint8_t *buf, size_t size)
327 {
328     assert(buf != NULL);
329 
330     int i = 0;
331 
332     /* take mutex lock function */
333     LOG_TAKE_MUTEX_SEMAPHORE_BLOCKING(s_logPushSemaphore);
334 
335     for (i = 0; i < size; i++)
336     {
337         /* recieve one char every time */
338         if (LOG_ReadOneCharacter(&buf[i]) != kStatus_Success)
339         {
340             return -1;
341         }
342 #if DEBUG_CONSOLE_ENABLE_ECHO_FUNCTION
343         LOG_EchoCharacter(&buf[i], false, &i);
344 #endif
345         /* analysis data */
346         if ((buf[i] == '\r') || (buf[i] == '\n'))
347         {
348             /* End of Line. */
349             if (i == 0)
350             {
351                 buf[i] = '\0';
352                 i = -1;
353             }
354             else
355             {
356                 break;
357             }
358         }
359     }
360     /* get char should not add '\0'*/
361     if (i == size)
362     {
363         buf[i] = '\0';
364     }
365     else
366     {
367         buf[i + 1] = '\0';
368     }
369 
370     /* release mutex lock function */
371     LOG_GIVE_MUTEX_SEMAPHORE(s_logPushSemaphore);
372 
373     return i;
374 }
375 
LOG_ReadCharacter(uint8_t * ch)376 int LOG_ReadCharacter(uint8_t *ch)
377 {
378     assert(ch != NULL);
379     int ret = 0;
380 
381     /* take mutex lock function */
382     LOG_TAKE_MUTEX_SEMAPHORE_BLOCKING(s_logPushSemaphore);
383     /* read one character */
384     if (LOG_ReadOneCharacter(ch) == kStatus_Success)
385     {
386         ret = 1;
387 #if DEBUG_CONSOLE_ENABLE_ECHO_FUNCTION
388         LOG_EchoCharacter(ch, true, NULL);
389 #endif
390     }
391     else
392     {
393         ret = -1;
394     }
395     /* release mutex lock function */
396     LOG_GIVE_MUTEX_SEMAPHORE(s_logPushSemaphore);
397 
398     return ret;
399 }
400 
LOG_ReadOneCharacter(uint8_t * ch)401 static status_t LOG_ReadOneCharacter(uint8_t *ch)
402 {
403     /* recieve one char every time */
404     if (IO_Transfer(ch, 1U, false) != kStatus_Success)
405     {
406         return kStatus_Fail;
407     }
408 
409     /* wait release from ISR */
410     LOG_TAKE_BINARY_SEMAPHORE_BLOCKING(s_logReadSemaphore);
411 
412     return kStatus_Success;
413 }
414 
415 #if DEBUG_CONSOLE_ENABLE_ECHO_FUNCTION
LOG_EchoCharacter(uint8_t * ch,bool isGetChar,int * index)416 static status_t LOG_EchoCharacter(uint8_t *ch, bool isGetChar, int *index)
417 {
418     /* Due to scanf take \n and \r as end of string,should not echo */
419     if (((*ch != '\r') && (*ch != '\n')) || (isGetChar))
420     {
421         /* recieve one char every time */
422         if (IO_Transfer(ch, 1U, true) != kStatus_Success)
423         {
424             return kStatus_Fail;
425         }
426     }
427 
428     if (!isGetChar)
429     {
430         if ((*index > 0) && (*ch == BACKSPACE))
431         {
432             *index -= 2;
433         }
434     }
435 
436     return kStatus_Success;
437 }
438 #endif
439 
440 #ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING
LOG_BufPush(uint8_t * buf,size_t size)441 static int LOG_BufPush(uint8_t *buf, size_t size)
442 {
443     uint32_t pushIndex = 0U, i = 0U;
444     bool pushAvaliable = false;
445 
446     /* take mutex lock function */
447     LOG_TAKE_MUTEX_SEMAPHORE_BLOCKING(s_logPushSemaphore);
448     if (size <= (DEBUG_CONSOLE_TRANSMIT_BUFFER_LEN - s_log_buffer.totalIndex))
449     {
450         /* get push index */
451         pushIndex = s_log_buffer.pushIndex;
452         s_log_buffer.pushIndex += size;
453         /* check index overflow */
454         LOG_CHECK_BUFFER_INDEX_OVERFLOW(s_log_buffer.pushIndex);
455         /* update push/total index value */
456         s_log_buffer.totalIndex += size;
457         pushAvaliable = true;
458     }
459     /* release mutex lock function */
460     LOG_GIVE_MUTEX_SEMAPHORE(s_logPushSemaphore);
461 
462     /* check the buffer if have enough space to store the log */
463     if (pushAvaliable)
464     {
465         for (i = size; i > 0; i--)
466         {
467             /* copy log to buffer, the buffer only support a fixed length argument, if the log argument
468             is longer than the fixed length, the left argument will be losed */
469             s_log_buffer.txBuf[pushIndex] = *buf++;
470             /* increase index */
471             pushIndex++;
472             /* check index overflow */
473             LOG_CHECK_BUFFER_INDEX_OVERFLOW(pushIndex);
474         }
475     }
476     else
477     {
478         size = 0U;
479     }
480 
481     return size;
482 }
483 
LOG_BufGetNextAvaliableLog(size_t * size)484 static uint8_t *LOG_BufGetNextAvaliableLog(size_t *size)
485 {
486     uint16_t popIndex = s_log_buffer.popIndex;
487 
488     /* get avaliable size */
489     if (s_log_buffer.totalIndex > (DEBUG_CONSOLE_TRANSMIT_BUFFER_LEN - popIndex))
490     {
491         *size = (DEBUG_CONSOLE_TRANSMIT_BUFFER_LEN - popIndex);
492     }
493     else
494     {
495         *size = s_log_buffer.totalIndex;
496     }
497 
498     /* return address */
499     return (&(s_log_buffer.txBuf[popIndex]));
500 }
501 
LOG_BufPop(size_t * size)502 static uint8_t *LOG_BufPop(size_t *size)
503 {
504     if (s_log_buffer.totalIndex >= *size)
505     {
506         /* decrease the log total member */
507         s_log_buffer.totalIndex -= *size;
508         /* there is more log in the queue to be pushed */
509         if (s_log_buffer.totalIndex > 0U)
510         {
511             /* update the pop index */
512             s_log_buffer.popIndex += *size;
513             /* check index overflow */
514             LOG_CHECK_BUFFER_INDEX_OVERFLOW(s_log_buffer.popIndex);
515 
516             return LOG_BufGetNextAvaliableLog(size);
517         }
518         else
519         {
520             /* reset push and pop */
521             s_log_buffer.popIndex = 0U;
522             s_log_buffer.pushIndex = 0U;
523             *size = 0U;
524         }
525     }
526 
527     return NULL;
528 }
529 
LOG_Transferred(size_t * size,bool receive,bool transmit)530 static void LOG_Transferred(size_t *size, bool receive, bool transmit)
531 {
532     uint8_t *addr = NULL;
533 
534     if (transmit)
535     {
536         addr = LOG_BufPop(size);
537         /* continue pop log from buffer */
538         LOG_Pop(addr, *size);
539     }
540 
541     if (receive)
542     {
543         /* release from ISR */
544         LOG_GIVE_BINARY_SEMAPHORE_FROM_ISR(s_logReadSemaphore);
545     }
546 }
547 #endif /* DEBUG_CONSOLE_TRANSFER_NON_BLOCKING */
548