fsl_log.c 17 KB

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