]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/logging/iot_logging_task_dynamic_buffers.c
Correct an err in queue.c introduced when previously updating behaviour when queue...
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-IoT-Libraries / c_sdk / standard / common / logging / iot_logging_task_dynamic_buffers.c
1 /*\r
2  * Amazon FreeRTOS Common V1.0.0\r
3  * Copyright (C) 2018 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\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
11  *\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
14  *\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
21  *\r
22  * http://aws.amazon.com/freertos\r
23  * http://www.FreeRTOS.org\r
24  */\r
25 \r
26 /* FreeRTOS includes. */\r
27 #include "FreeRTOS.h"\r
28 #include "task.h"\r
29 #include "queue.h"\r
30 \r
31 /* Logging includes. */\r
32 #include "iot_logging_task.h"\r
33 \r
34 /* Standard includes. */\r
35 #include <stdio.h>\r
36 #include <stdarg.h>\r
37 #include <string.h>\r
38 \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
42 #endif\r
43 \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
46 #endif\r
47 \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
50 #endif\r
51 \r
52 /* A block time of 0 just means don't block. */\r
53 #define loggingDONT_BLOCK    0\r
54 \r
55 /*-----------------------------------------------------------*/\r
56 \r
57 /*\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
62  *\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
68  */\r
69 static void prvLoggingTask( void * pvParameters );\r
70 \r
71 /*-----------------------------------------------------------*/\r
72 \r
73 /*\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
76  */\r
77 static QueueHandle_t xQueue = NULL;\r
78 \r
79 /*-----------------------------------------------------------*/\r
80 \r
81 BaseType_t xLoggingTaskInitialize( uint16_t usStackSize,\r
82                                    UBaseType_t uxPriority,\r
83                                    UBaseType_t uxQueueLength )\r
84 {\r
85     BaseType_t xReturn = pdFAIL;\r
86 \r
87     /* Ensure the logging task has not been created already. */\r
88     if( xQueue == NULL )\r
89     {\r
90         /* Create the queue used to pass pointers to strings to the logging task. */\r
91         xQueue = xQueueCreate( uxQueueLength, sizeof( char ** ) );\r
92 \r
93         if( xQueue != NULL )\r
94         {\r
95             if( xTaskCreate( prvLoggingTask, "Logging", usStackSize, NULL, uxPriority, NULL ) == pdPASS )\r
96             {\r
97                 xReturn = pdPASS;\r
98             }\r
99             else\r
100             {\r
101                 /* Could not create the task, so delete the queue again. */\r
102                 vQueueDelete( xQueue );\r
103             }\r
104         }\r
105     }\r
106 \r
107     return xReturn;\r
108 }\r
109 /*-----------------------------------------------------------*/\r
110 \r
111 static void prvLoggingTask( void * pvParameters )\r
112 {\r
113     char * pcReceivedString = NULL;\r
114 \r
115     for( ; ; )\r
116     {\r
117         /* Block to wait for the next string to print. */\r
118         if( xQueueReceive( xQueue, &pcReceivedString, portMAX_DELAY ) == pdPASS )\r
119         {\r
120             configPRINT_STRING( pcReceivedString );\r
121             vPortFree( ( void * ) pcReceivedString );\r
122         }\r
123     }\r
124 }\r
125 /*-----------------------------------------------------------*/\r
126 \r
127 /*!\r
128  * \brief Formats a string to be printed and sends it\r
129  * to the print queue.\r
130  *\r
131  * Appends the message number, time (in ticks), and task\r
132  * that called vLoggingPrintf to the beginning of each\r
133  * print statement.\r
134  *\r
135  */\r
136 void vLoggingPrintf( const char * pcFormat,\r
137                      ... )\r
138 {\r
139     size_t xLength = 0;\r
140     int32_t xLength2 = 0;\r
141     va_list args;\r
142     char * pcPrintString = NULL;\r
143 \r
144     /* The queue is created by xLoggingTaskInitialize().  Check\r
145      * xLoggingTaskInitialize() has been called. */\r
146     configASSERT( xQueue );\r
147 \r
148     /* Allocate a buffer to hold the log message. */\r
149     pcPrintString = pvPortMalloc( configLOGGING_MAX_MESSAGE_LENGTH );\r
150 \r
151     if( pcPrintString != NULL )\r
152     {\r
153         /* There are a variable number of parameters. */\r
154         va_start( args, pcFormat );\r
155 \r
156         if( strcmp( pcFormat, "\n" ) != 0 )\r
157         {\r
158             #if ( configLOGGING_INCLUDE_TIME_AND_TASK_NAME == 1 )\r
159                 {\r
160                     const char * pcTaskName;\r
161                     const char * pcNoTask = "None";\r
162                     static BaseType_t xMessageNumber = 0;\r
163 \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
167                     {\r
168                         pcTaskName = pcTaskGetName( NULL );\r
169                     }\r
170                     else\r
171                     {\r
172                         pcTaskName = pcNoTask;\r
173                     }\r
174 \r
175                     xLength = snprintf( pcPrintString, configLOGGING_MAX_MESSAGE_LENGTH, "%lu %lu [%s] ",\r
176                                         ( unsigned long ) xMessageNumber++,\r
177                                         ( unsigned long ) xTaskGetTickCount(),\r
178                                         pcTaskName );\r
179                 }\r
180             #else /* if ( configLOGGING_INCLUDE_TIME_AND_TASK_NAME == 1 ) */\r
181                 {\r
182                     xLength = 0;\r
183                 }\r
184             #endif /* if ( configLOGGING_INCLUDE_TIME_AND_TASK_NAME == 1 ) */\r
185         }\r
186 \r
187         xLength2 = vsnprintf( pcPrintString + xLength, configLOGGING_MAX_MESSAGE_LENGTH - xLength, pcFormat, args );\r
188 \r
189         if( xLength2 < 0 )\r
190         {\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
198              */\r
199             xLength2 = 0;\r
200             pcPrintString[ xLength ] = '\0';\r
201         }\r
202 \r
203         xLength += ( size_t ) xLength2;\r
204         va_end( args );\r
205 \r
206         /* Only send the buffer to the logging task if it is\r
207          * not empty. */\r
208         if( xLength > 0 )\r
209         {\r
210             /* Send the string to the logging task for IO. */\r
211             if( xQueueSend( xQueue, &pcPrintString, loggingDONT_BLOCK ) != pdPASS )\r
212             {\r
213                 /* The buffer was not sent so must be freed again. */\r
214                 vPortFree( ( void * ) pcPrintString );\r
215             }\r
216         }\r
217         else\r
218         {\r
219             /* The buffer was not sent, so it must be\r
220              * freed. */\r
221             vPortFree( ( void * ) pcPrintString );\r
222         }\r
223     }\r
224 }\r
225 /*-----------------------------------------------------------*/\r
226 \r
227 void vLoggingPrint( const char * pcMessage )\r
228 {\r
229     char * pcPrintString = NULL;\r
230     size_t xLength = 0;\r
231 \r
232     /* The queue is created by xLoggingTaskInitialize().  Check\r
233      * xLoggingTaskInitialize() has been called. */\r
234     configASSERT( xQueue );\r
235 \r
236     xLength = strlen( pcMessage ) + 1;\r
237     pcPrintString = pvPortMalloc( xLength );\r
238 \r
239     if( pcPrintString != NULL )\r
240     {\r
241         strncpy( pcPrintString, pcMessage, xLength );\r
242 \r
243         /* Send the string to the logging task for IO. */\r
244         if( xQueueSend( xQueue, &pcPrintString, loggingDONT_BLOCK ) != pdPASS )\r
245         {\r
246             /* The buffer was not sent so must be freed again. */\r
247             vPortFree( ( void * ) pcPrintString );\r
248         }\r
249     }\r
250 }\r