2 * Amazon FreeRTOS Common V1.0.0
\r
3 * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
\r
6 * this software and associated documentation files (the "Software"), to deal in
\r
7 * the Software without restriction, including without limitation the rights to
\r
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
\r
9 * the Software, and to permit persons to whom the Software is furnished to do so,
\r
10 * subject to the following conditions:
\r
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\r
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
22 * http://aws.amazon.com/freertos
\r
23 * http://www.FreeRTOS.org
\r
26 /* FreeRTOS includes. */
\r
27 #include "FreeRTOS.h"
\r
31 /* Logging includes. */
\r
32 #include "iot_logging_task.h"
\r
34 /* Standard includes. */
\r
39 /* Sanity check all the definitions required by this file are set. */
\r
40 #ifndef configPRINT_STRING
\r
41 #error configPRINT_STRING( x ) must be defined in FreeRTOSConfig.h to use this logging file. Set configPRINT_STRING( x ) to a function that outputs a string, where X is the string. For example, #define configPRINT_STRING( x ) MyUARTWriteString( X )
\r
44 #ifndef configLOGGING_MAX_MESSAGE_LENGTH
\r
45 #error configLOGGING_MAX_MESSAGE_LENGTH must be defined in FreeRTOSConfig.h to use this logging file. configLOGGING_MAX_MESSAGE_LENGTH sets the size of the buffer into which formatted text is written, so also sets the maximum log message length.
\r
48 #ifndef configLOGGING_INCLUDE_TIME_AND_TASK_NAME
\r
49 #error configLOGGING_INCLUDE_TIME_AND_TASK_NAME must be defined in FreeRTOSConfig.h to use this logging file. Set configLOGGING_INCLUDE_TIME_AND_TASK_NAME to 1 to prepend a time stamp, message number and the name of the calling task to each logged message. Otherwise set to 0.
\r
52 /* A block time of 0 just means don't block. */
\r
53 #define loggingDONT_BLOCK 0
\r
55 /*-----------------------------------------------------------*/
\r
58 * The task that actually performs the print output. Using a separate task
\r
59 * enables the use of slow output, such as as a UART, without the task that is
\r
60 * outputting the log message having to wait for the message to be completely
\r
61 * written. Using a separate task also serializes access to the output port.
\r
63 * The structure of this task is very simple; it blocks on a queue to wait for
\r
64 * a pointer to a string, sending any received strings to a macro that performs
\r
65 * the actual output. The macro is port specific, so implemented outside of
\r
66 * this file. This version uses dynamic memory, so the buffer that contained
\r
67 * the log message is freed after it has been output.
\r
69 static void prvLoggingTask( void * pvParameters );
\r
71 /*-----------------------------------------------------------*/
\r
74 * The queue used to pass pointers to log messages from the task that created
\r
75 * the message to the task that will performs the output.
\r
77 static QueueHandle_t xQueue = NULL;
\r
79 /*-----------------------------------------------------------*/
\r
81 BaseType_t xLoggingTaskInitialize( uint16_t usStackSize,
\r
82 UBaseType_t uxPriority,
\r
83 UBaseType_t uxQueueLength )
\r
85 BaseType_t xReturn = pdFAIL;
\r
87 /* Ensure the logging task has not been created already. */
\r
88 if( xQueue == NULL )
\r
90 /* Create the queue used to pass pointers to strings to the logging task. */
\r
91 xQueue = xQueueCreate( uxQueueLength, sizeof( char ** ) );
\r
93 if( xQueue != NULL )
\r
95 if( xTaskCreate( prvLoggingTask, "Logging", usStackSize, NULL, uxPriority, NULL ) == pdPASS )
\r
101 /* Could not create the task, so delete the queue again. */
\r
102 vQueueDelete( xQueue );
\r
109 /*-----------------------------------------------------------*/
\r
111 static void prvLoggingTask( void * pvParameters )
\r
113 char * pcReceivedString = NULL;
\r
117 /* Block to wait for the next string to print. */
\r
118 if( xQueueReceive( xQueue, &pcReceivedString, portMAX_DELAY ) == pdPASS )
\r
120 configPRINT_STRING( pcReceivedString );
\r
121 vPortFree( ( void * ) pcReceivedString );
\r
125 /*-----------------------------------------------------------*/
\r
128 * \brief Formats a string to be printed and sends it
\r
129 * to the print queue.
\r
131 * Appends the message number, time (in ticks), and task
\r
132 * that called vLoggingPrintf to the beginning of each
\r
136 void vLoggingPrintf( const char * pcFormat,
\r
139 size_t xLength = 0;
\r
140 int32_t xLength2 = 0;
\r
142 char * pcPrintString = NULL;
\r
144 /* The queue is created by xLoggingTaskInitialize(). Check
\r
145 * xLoggingTaskInitialize() has been called. */
\r
146 configASSERT( xQueue );
\r
148 /* Allocate a buffer to hold the log message. */
\r
149 pcPrintString = pvPortMalloc( configLOGGING_MAX_MESSAGE_LENGTH );
\r
151 if( pcPrintString != NULL )
\r
153 /* There are a variable number of parameters. */
\r
154 va_start( args, pcFormat );
\r
156 if( strcmp( pcFormat, "\n" ) != 0 )
\r
158 #if ( configLOGGING_INCLUDE_TIME_AND_TASK_NAME == 1 )
\r
160 const char * pcTaskName;
\r
161 const char * pcNoTask = "None";
\r
162 static BaseType_t xMessageNumber = 0;
\r
164 /* Add a time stamp and the name of the calling task to the
\r
165 * start of the log. */
\r
166 if( xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED )
\r
168 pcTaskName = pcTaskGetName( NULL );
\r
172 pcTaskName = pcNoTask;
\r
175 xLength = snprintf( pcPrintString, configLOGGING_MAX_MESSAGE_LENGTH, "%lu %lu [%s] ",
\r
176 ( unsigned long ) xMessageNumber++,
\r
177 ( unsigned long ) xTaskGetTickCount(),
\r
180 #else /* if ( configLOGGING_INCLUDE_TIME_AND_TASK_NAME == 1 ) */
\r
184 #endif /* if ( configLOGGING_INCLUDE_TIME_AND_TASK_NAME == 1 ) */
\r
187 xLength2 = vsnprintf( pcPrintString + xLength, configLOGGING_MAX_MESSAGE_LENGTH - xLength, pcFormat, args );
\r
191 /* vsnprintf() failed. Restore the terminating NULL
\r
192 * character of the first part. Note that the first
\r
193 * part of the buffer may be empty if the value of
\r
194 * configLOGGING_INCLUDE_TIME_AND_TASK_NAME is not
\r
195 * 1 and as a result, the whole buffer may be empty.
\r
196 * That's the reason we have a check for xLength > 0
\r
197 * before sending the buffer to the logging task.
\r
200 pcPrintString[ xLength ] = '\0';
\r
203 xLength += ( size_t ) xLength2;
\r
206 /* Only send the buffer to the logging task if it is
\r
210 /* Send the string to the logging task for IO. */
\r
211 if( xQueueSend( xQueue, &pcPrintString, loggingDONT_BLOCK ) != pdPASS )
\r
213 /* The buffer was not sent so must be freed again. */
\r
214 vPortFree( ( void * ) pcPrintString );
\r
219 /* The buffer was not sent, so it must be
\r
221 vPortFree( ( void * ) pcPrintString );
\r
225 /*-----------------------------------------------------------*/
\r
227 void vLoggingPrint( const char * pcMessage )
\r
229 char * pcPrintString = NULL;
\r
230 size_t xLength = 0;
\r
232 /* The queue is created by xLoggingTaskInitialize(). Check
\r
233 * xLoggingTaskInitialize() has been called. */
\r
234 configASSERT( xQueue );
\r
236 xLength = strlen( pcMessage ) + 1;
\r
237 pcPrintString = pvPortMalloc( xLength );
\r
239 if( pcPrintString != NULL )
\r
241 strncpy( pcPrintString, pcMessage, xLength );
\r
243 /* Send the string to the logging task for IO. */
\r
244 if( xQueueSend( xQueue, &pcPrintString, loggingDONT_BLOCK ) != pdPASS )
\r
246 /* The buffer was not sent so must be freed again. */
\r
247 vPortFree( ( void * ) pcPrintString );
\r