| /* |
| * FreeRTOS Common V1.1.1 |
| * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a copy of |
| * this software and associated documentation files (the "Software"), to deal in |
| * the Software without restriction, including without limitation the rights to |
| * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of |
| * the Software, and to permit persons to whom the Software is furnished to do so, |
| * subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included in all |
| * copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS |
| * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
| * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
| * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| * |
| * http://aws.amazon.com/freertos |
| * http://www.FreeRTOS.org |
| */ |
| |
| /* FreeRTOS includes. */ |
| #include "FreeRTOS.h" |
| #include "task.h" |
| #include "queue.h" |
| |
| /* Logging includes. */ |
| #include "iot_logging_task.h" |
| |
| /* Standard includes. */ |
| #include <stdio.h> |
| #include <stdarg.h> |
| #include <string.h> |
| |
| /* Sanity check all the definitions required by this file are set. */ |
| #ifndef configPRINT_STRING |
| #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 ) |
| #endif |
| |
| #ifndef configLOGGING_MAX_MESSAGE_LENGTH |
| #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. |
| #endif |
| |
| #ifndef configLOGGING_INCLUDE_TIME_AND_TASK_NAME |
| #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. |
| #endif |
| |
| /* A block time of 0 just means don't block. */ |
| #define loggingDONT_BLOCK 0 |
| |
| /*-----------------------------------------------------------*/ |
| |
| /* |
| * The task that actually performs the print output. Using a separate task |
| * enables the use of slow output, such as as a UART, without the task that is |
| * outputting the log message having to wait for the message to be completely |
| * written. Using a separate task also serializes access to the output port. |
| * |
| * The structure of this task is very simple; it blocks on a queue to wait for |
| * a pointer to a string, sending any received strings to a macro that performs |
| * the actual output. The macro is port specific, so implemented outside of |
| * this file. This version uses dynamic memory, so the buffer that contained |
| * the log message is freed after it has been output. |
| */ |
| static void prvLoggingTask( void * pvParameters ); |
| |
| /*-----------------------------------------------------------*/ |
| |
| /* |
| * The queue used to pass pointers to log messages from the task that created |
| * the message to the task that will performs the output. |
| */ |
| static QueueHandle_t xQueue = NULL; |
| |
| /*-----------------------------------------------------------*/ |
| |
| BaseType_t xLoggingTaskInitialize( uint16_t usStackSize, |
| UBaseType_t uxPriority, |
| UBaseType_t uxQueueLength ) |
| { |
| BaseType_t xReturn = pdFAIL; |
| |
| /* Ensure the logging task has not been created already. */ |
| if( xQueue == NULL ) |
| { |
| /* Create the queue used to pass pointers to strings to the logging task. */ |
| xQueue = xQueueCreate( uxQueueLength, sizeof( char ** ) ); |
| |
| if( xQueue != NULL ) |
| { |
| if( xTaskCreate( prvLoggingTask, "Logging", usStackSize, NULL, uxPriority, NULL ) == pdPASS ) |
| { |
| xReturn = pdPASS; |
| } |
| else |
| { |
| /* Could not create the task, so delete the queue again. */ |
| vQueueDelete( xQueue ); |
| } |
| } |
| } |
| |
| return xReturn; |
| } |
| /*-----------------------------------------------------------*/ |
| |
| static void prvLoggingTask( void * pvParameters ) |
| { |
| char * pcReceivedString = NULL; |
| |
| for( ; ; ) |
| { |
| /* Block to wait for the next string to print. */ |
| if( xQueueReceive( xQueue, &pcReceivedString, portMAX_DELAY ) == pdPASS ) |
| { |
| configPRINT_STRING( pcReceivedString ); |
| vPortFree( ( void * ) pcReceivedString ); |
| } |
| } |
| } |
| /*-----------------------------------------------------------*/ |
| |
| /*! |
| * \brief Formats a string to be printed and sends it |
| * to the print queue. |
| * |
| * Appends the message number, time (in ticks), and task |
| * that called vLoggingPrintf to the beginning of each |
| * print statement. |
| * |
| */ |
| void vLoggingPrintf( const char * pcFormat, |
| ... ) |
| { |
| size_t xLength = 0; |
| int32_t xLength2 = 0; |
| va_list args; |
| char * pcPrintString = NULL; |
| |
| /* The queue is created by xLoggingTaskInitialize(). Check |
| * xLoggingTaskInitialize() has been called. */ |
| configASSERT( xQueue ); |
| |
| /* Allocate a buffer to hold the log message. */ |
| pcPrintString = pvPortMalloc( configLOGGING_MAX_MESSAGE_LENGTH ); |
| |
| if( pcPrintString != NULL ) |
| { |
| /* There are a variable number of parameters. */ |
| va_start( args, pcFormat ); |
| |
| if( strcmp( pcFormat, "\n" ) != 0 ) |
| { |
| #if ( configLOGGING_INCLUDE_TIME_AND_TASK_NAME == 1 ) |
| { |
| const char * pcTaskName; |
| const char * pcNoTask = "None"; |
| static BaseType_t xMessageNumber = 0; |
| |
| /* Add a time stamp and the name of the calling task to the |
| * start of the log. */ |
| if( xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED ) |
| { |
| pcTaskName = pcTaskGetName( NULL ); |
| } |
| else |
| { |
| pcTaskName = pcNoTask; |
| } |
| |
| xLength = snprintf( pcPrintString, configLOGGING_MAX_MESSAGE_LENGTH, "%lu %lu [%s] ", |
| ( unsigned long ) xMessageNumber++, |
| ( unsigned long ) xTaskGetTickCount(), |
| pcTaskName ); |
| } |
| #else /* if ( configLOGGING_INCLUDE_TIME_AND_TASK_NAME == 1 ) */ |
| { |
| xLength = 0; |
| } |
| #endif /* if ( configLOGGING_INCLUDE_TIME_AND_TASK_NAME == 1 ) */ |
| } |
| |
| xLength2 = vsnprintf( pcPrintString + xLength, configLOGGING_MAX_MESSAGE_LENGTH - xLength, pcFormat, args ); |
| |
| if( xLength2 < 0 ) |
| { |
| /* vsnprintf() failed. Restore the terminating NULL |
| * character of the first part. Note that the first |
| * part of the buffer may be empty if the value of |
| * configLOGGING_INCLUDE_TIME_AND_TASK_NAME is not |
| * 1 and as a result, the whole buffer may be empty. |
| * That's the reason we have a check for xLength > 0 |
| * before sending the buffer to the logging task. |
| */ |
| xLength2 = 0; |
| pcPrintString[ xLength ] = '\0'; |
| } |
| |
| xLength += ( size_t ) xLength2; |
| va_end( args ); |
| |
| /* Only send the buffer to the logging task if it is |
| * not empty. */ |
| if( xLength > 0 ) |
| { |
| /* Send the string to the logging task for IO. */ |
| if( xQueueSend( xQueue, &pcPrintString, loggingDONT_BLOCK ) != pdPASS ) |
| { |
| /* The buffer was not sent so must be freed again. */ |
| vPortFree( ( void * ) pcPrintString ); |
| } |
| } |
| else |
| { |
| /* The buffer was not sent, so it must be |
| * freed. */ |
| vPortFree( ( void * ) pcPrintString ); |
| } |
| } |
| } |
| /*-----------------------------------------------------------*/ |
| |
| void vLoggingPrint( const char * pcMessage ) |
| { |
| char * pcPrintString = NULL; |
| size_t xLength = 0; |
| |
| /* The queue is created by xLoggingTaskInitialize(). Check |
| * xLoggingTaskInitialize() has been called. */ |
| configASSERT( xQueue ); |
| |
| xLength = strlen( pcMessage ) + 1; |
| pcPrintString = pvPortMalloc( xLength ); |
| |
| if( pcPrintString != NULL ) |
| { |
| strncpy( pcPrintString, pcMessage, xLength ); |
| |
| /* Send the string to the logging task for IO. */ |
| if( xQueueSend( xQueue, &pcPrintString, loggingDONT_BLOCK ) != pdPASS ) |
| { |
| /* The buffer was not sent so must be freed again. */ |
| vPortFree( ( void * ) pcPrintString ); |
| } |
| } |
| } |