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