mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2026-02-21 17:45:30 -05:00
Add the Labs projects provided in the V10.2.1_191129 zip file.
This commit is contained in:
parent
46e5937529
commit
e5708b38e9
801 changed files with 356576 additions and 0 deletions
502
FreeRTOS-Labs/Demo/Common/Utilities/UDPLoggingPrintf.c
Normal file
502
FreeRTOS-Labs/Demo/Common/Utilities/UDPLoggingPrintf.c
Normal file
|
|
@ -0,0 +1,502 @@
|
|||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/*
|
||||
* Logging utility that allows FreeRTOS tasks to log to a UDP port.
|
||||
*
|
||||
* Logging print calls generate messages that are buffered in a stream buffer.
|
||||
* A background task then retrieves messages from the stream buffer and sends
|
||||
* them to a UDP port.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* FreeRTOS+TCP includes. */
|
||||
#include "FreeRTOS_IP.h"
|
||||
#include "FreeRTOS_Sockets.h"
|
||||
#include "FreeRTOS_tcp_server.h"
|
||||
#include "FreeRTOS_Stream_Buffer.h"
|
||||
#include "FreeRTOS_DHCP.h"
|
||||
#include "NetworkInterface.h"
|
||||
|
||||
/* Demo includes. */
|
||||
#include "hr_gettime.h"
|
||||
#include "UDPLoggingPrintf.h"
|
||||
|
||||
/* Set to 1 to end each line with \r\n, or 0 for just \n. */
|
||||
#ifndef configUDP_LOGGING_NEEDS_CR_LF
|
||||
#define configUDP_LOGGING_NEEDS_CR_LF ( 0 )
|
||||
#endif
|
||||
|
||||
/* The maximum string length for each logged message. */
|
||||
#ifndef configUDP_LOGGING_STRING_LENGTH
|
||||
#define configUDP_LOGGING_STRING_LENGTH ( 200 )
|
||||
#endif
|
||||
|
||||
/* The maximum number of messages that can be buffered at any one time. */
|
||||
#ifndef configUDP_LOGGING_MAX_MESSAGES_IN_BUFFER
|
||||
#define configUDP_LOGGING_MAX_MESSAGES_IN_BUFFER ( 30 )
|
||||
#endif
|
||||
|
||||
#ifndef configUDP_LOGGING_TASK_STACK_SIZE
|
||||
#define configUDP_LOGGING_TASK_STACK_SIZE ( 512 )
|
||||
#endif
|
||||
|
||||
#ifndef configUDP_LOGGING_TASK_PRIORITY
|
||||
#define configUDP_LOGGING_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 )
|
||||
#endif
|
||||
|
||||
/* configUDP_LOGGING_PORT_REMOTE is the port number to which the logging
|
||||
will be sent. */
|
||||
#ifndef configUDP_LOGGING_PORT_REMOTE
|
||||
#error configUDP_LOGGING_PORT_REMOTE must be defined in FreeRTOSconfig.h to use UDP logging
|
||||
#endif
|
||||
|
||||
/* configUDP_LOGGING_PORT_LOCAL is the port number to which the
|
||||
socket will be bound. It is possible to send messages to
|
||||
this socket. */
|
||||
#ifndef configUDP_LOGGING_PORT_LOCAL
|
||||
/* If not defined, the UDP socket will be bound to a random port number.
|
||||
If you want to use a specific port number, please define so in FreeRTOSconfig.h */
|
||||
#define configUDP_LOGGING_PORT_LOCAL 0
|
||||
#endif
|
||||
|
||||
/* The logging task's block time. This is used as the UDP socket's send block
|
||||
time, and the maximum time the logging task will spend in the Blocked state
|
||||
waiting to be notified of a new message to send before manually looking for a
|
||||
message. */
|
||||
#ifndef logUDP_LOGGING_BLOCK_TIME_MS
|
||||
#define logUDP_LOGGING_BLOCK_TIME_MS ( 1000ul )
|
||||
#endif
|
||||
|
||||
/* Log messages are cached in a stream buffer. The stream buffer's storage
|
||||
area is dimensioned to contain the maximum number of strings of the maximum
|
||||
string length. */
|
||||
#define logMESSAGE_BUFFER_SIZE_BYTES ( ( configUDP_LOGGING_STRING_LENGTH ) * ( configUDP_LOGGING_MAX_MESSAGES_IN_BUFFER ) )
|
||||
|
||||
/* Ascii characters used in this file. */
|
||||
#define logASCII_CR ( 13 )
|
||||
#define logASCII_NL ( 10 )
|
||||
|
||||
#ifndef iptraceUDP_LOGGING_TASK_STARTING
|
||||
/* This macro will be called once when the UDP logging task is starting up. */
|
||||
#define iptraceUDP_LOGGING_TASK_STARTING() do { } while( 0 )
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Called automatically to create the stream buffer.
|
||||
*/
|
||||
static BaseType_t prvInitialiseLogging( void );
|
||||
|
||||
/*
|
||||
* The task that reads messages from the stream buffer and sends them to the
|
||||
* UDP port.
|
||||
*/
|
||||
static void prvLoggingTask( void *pvParameters );
|
||||
|
||||
/*
|
||||
* Obtain a message from the stream buffer.
|
||||
*/
|
||||
static size_t prvGetMessageFromStreamBuffer( char *pcBuffer, size_t xBufferLength );
|
||||
|
||||
/*
|
||||
* Generate a formatted string and add it to the stream buffer ready for the
|
||||
* logging task to transmit.
|
||||
*/
|
||||
static size_t prvBufferFormattedString( const char *pcFormatString, va_list xArgs );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Is this structure used anywhere? */
|
||||
typedef struct LogStruct
|
||||
{
|
||||
size_t xLength;
|
||||
|
||||
#if LOGBUF_SHOW_US
|
||||
uint64_t ullLogTime;
|
||||
#else
|
||||
uint32_t ulLogTime;
|
||||
#endif
|
||||
uint32_t ulPriority;
|
||||
|
||||
} LogStruct_t;
|
||||
|
||||
typedef struct LogUnit_t
|
||||
{
|
||||
LogStruct_t xHeader;
|
||||
char cMessage[ configUDP_LOGGING_STRING_LENGTH ];
|
||||
|
||||
} LogUnit_t;
|
||||
|
||||
static LogUnit_t xLogEntry;
|
||||
static StreamBuffer_t *pxStreamBuffer = NULL;
|
||||
static TaskHandle_t xLoggingTask = NULL;
|
||||
static xSocket_t xUDPLoggingSocket = FREERTOS_INVALID_SOCKET;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static BaseType_t prvInitialiseLogging( void )
|
||||
{
|
||||
size_t xSize;
|
||||
static BaseType_t xLoggingInitialised = pdFALSE;
|
||||
|
||||
if( xLoggingInitialised == pdFALSE )
|
||||
{
|
||||
/* Don't attempt to log unless the scheduler is running. */
|
||||
if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )
|
||||
{
|
||||
/* Create a stream buffer large enough for the maximum number of
|
||||
bytes + 1. */ /*_RB_ Why is the size of pxStreamBuffer->ucArray
|
||||
subtracted here? */
|
||||
xSize = sizeof( StreamBuffer_t ) - sizeof( pxStreamBuffer->ucArray ) + logMESSAGE_BUFFER_SIZE_BYTES + 1;
|
||||
pxStreamBuffer = pvPortMalloc( xSize );
|
||||
|
||||
if( pxStreamBuffer != NULL )
|
||||
{
|
||||
memset( pxStreamBuffer, '\0', xSize );
|
||||
pxStreamBuffer->LENGTH = logMESSAGE_BUFFER_SIZE_BYTES + 1;
|
||||
|
||||
xLoggingInitialised = pdTRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return xLoggingInitialised;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static size_t prvGetMessageFromStreamBuffer( char* pcBuffer, size_t xBufferLength )
|
||||
{
|
||||
size_t uxLength;
|
||||
size_t xMessageLength = 0;
|
||||
|
||||
if( pxStreamBuffer != NULL )
|
||||
{
|
||||
/* Is there data in the stream buffer? */
|
||||
uxLength = uxStreamBufferGetSize( pxStreamBuffer );
|
||||
if( uxLength > sizeof( size_t ) )
|
||||
{
|
||||
/* Avoid concurrent access to the buffer. */
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
/* Every message is stored as a length followed by the string.
|
||||
Obtain the length of the data first. */
|
||||
uxStreamBufferGet( pxStreamBuffer, 0, ( uint8_t * ) &xMessageLength, sizeof( xMessageLength ), pdFALSE );
|
||||
|
||||
if( xBufferLength < xMessageLength )
|
||||
{
|
||||
/* The 'pcBuffer' provided by the caller is too small. Load
|
||||
the message first into 'xLogEntry.message', and then copy
|
||||
as much as possible to 'pcBuffer'. */
|
||||
uxStreamBufferGet( pxStreamBuffer, 0, ( uint8_t * ) xLogEntry.cMessage, xMessageLength, pdFALSE );
|
||||
memcpy( pcBuffer, xLogEntry.cMessage, xBufferLength );
|
||||
xMessageLength = xBufferLength;
|
||||
|
||||
/* Terminate the string at the very end of the buffer. */
|
||||
pcBuffer[ xBufferLength - 1 ] = 0x00;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The 'pcBuffer' provided by the caller is big enough. */
|
||||
uxStreamBufferGet( pxStreamBuffer, 0, ( uint8_t * ) pcBuffer, xMessageLength, pdFALSE );
|
||||
|
||||
/* Terminate the string after the string's last character. */
|
||||
pcBuffer[ xMessageLength ] = 0x00;
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
}
|
||||
}
|
||||
|
||||
return xMessageLength;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static size_t prvBufferFormattedString( const char *pcFormatString, va_list xArgs )
|
||||
{
|
||||
size_t xLength, xSpace;
|
||||
uint64_t ullCurrentTime;
|
||||
uint32_t ulSeconds, ulMilliSeconds, ulMicroSeconds;
|
||||
|
||||
/* Sanity check. */
|
||||
configASSERT( pxStreamBuffer );
|
||||
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
ullCurrentTime = ullGetHighResolutionTime();
|
||||
ulSeconds = ( uint32_t ) ( ullCurrentTime / 1000000ull );
|
||||
ullCurrentTime = ullCurrentTime % 1000000ull;
|
||||
ulMilliSeconds = ( uint32_t ) ( ullCurrentTime / 1000ull );
|
||||
ulMicroSeconds = ( uint32_t ) ( ullCurrentTime % 1000ull );
|
||||
|
||||
xLength = ( size_t ) snprintf( xLogEntry.cMessage, sizeof( xLogEntry.cMessage ), "%4u.%03u.%03u [%-10s] ",
|
||||
( unsigned int ) ulSeconds, ( unsigned int ) ulMilliSeconds, ( unsigned int ) ulMicroSeconds, pcTaskGetTaskName( NULL ) );
|
||||
xLength += ( size_t ) vsnprintf( xLogEntry.cMessage + xLength, sizeof( xLogEntry.cMessage ) - xLength, pcFormatString, xArgs );
|
||||
|
||||
xSpace = uxStreamBufferGetSpace( pxStreamBuffer );
|
||||
|
||||
if( xSpace > ( xLength + sizeof( BaseType_t ) ) )
|
||||
{
|
||||
uxStreamBufferAdd( pxStreamBuffer, 0, ( const uint8_t * ) &xLength, sizeof( xLength ) );
|
||||
uxStreamBufferAdd( pxStreamBuffer, 0, ( const uint8_t * ) ( xLogEntry.cMessage ), xLength );
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
|
||||
if( xLoggingTask != NULL )
|
||||
{
|
||||
/* Unblock the logging task so it can output the message. */
|
||||
xTaskNotifyGive( xLoggingTask );
|
||||
}
|
||||
|
||||
return xLength;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
int lUDPLoggingPrintf( const char *pcFormatString, ... )
|
||||
{
|
||||
size_t xLength;
|
||||
|
||||
if( prvInitialiseLogging() != pdFALSE )
|
||||
{
|
||||
va_list args;
|
||||
va_start (args, pcFormatString);
|
||||
xLength = prvBufferFormattedString (pcFormatString, args);
|
||||
va_end (args);
|
||||
}
|
||||
else
|
||||
{
|
||||
xLength = 0;
|
||||
}
|
||||
|
||||
return ( int ) xLength;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vUDPLoggingTaskCreate( void )
|
||||
{
|
||||
/* Start a task which will send out the logging lines to a UDP address. */
|
||||
xTaskCreate( prvLoggingTask, "LogTask", configUDP_LOGGING_TASK_STACK_SIZE, NULL, configUDP_LOGGING_TASK_PRIORITY, &xLoggingTask );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
xSocket_t xLoggingGetSocket( void )
|
||||
{
|
||||
xSocket_t xReturn;
|
||||
|
||||
if( ( xUDPLoggingSocket != NULL ) && ( xUDPLoggingSocket != FREERTOS_INVALID_SOCKET ) )
|
||||
{
|
||||
xReturn = xUDPLoggingSocket;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = NULL;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void prvLoggingTask( void *pvParameters )
|
||||
{
|
||||
TickType_t xBlockingTime = pdMS_TO_TICKS( logUDP_LOGGING_BLOCK_TIME_MS );
|
||||
struct freertos_sockaddr xLocalAddress, xRemoteAddress;
|
||||
BaseType_t xSendTimeOut;
|
||||
int32_t lLines;
|
||||
size_t xCount;
|
||||
static char cLoggingLine[ configUDP_LOGGING_STRING_LENGTH ];
|
||||
const TickType_t xResolveDelay = pdMS_TO_TICKS( ( TickType_t ) 250 );
|
||||
|
||||
/* Prevent compiler warnings about unused parameters. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* A possibility to set some additional task properties. */
|
||||
iptraceUDP_LOGGING_TASK_STARTING();
|
||||
|
||||
xRemoteAddress.sin_port = FreeRTOS_htons( configUDP_LOGGING_PORT_REMOTE );
|
||||
#if defined( configUDP_LOGGING_ADDR0 )
|
||||
{
|
||||
/* Use a fixed address to where the logging will be sent. */
|
||||
xRemoteAddress.sin_addr = FreeRTOS_inet_addr_quick( configUDP_LOGGING_ADDR0,
|
||||
configUDP_LOGGING_ADDR1,
|
||||
configUDP_LOGGING_ADDR2,
|
||||
configUDP_LOGGING_ADDR3 );
|
||||
}
|
||||
#else
|
||||
{
|
||||
/* The logging will be broadcasted on the local broadcasting
|
||||
address, such as 192.168.0.255 */
|
||||
xRemoteAddress.sin_addr = FreeRTOS_GetIPAddress() | ~( FreeRTOS_GetNetmask() );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Loop until a socket is created. */
|
||||
do
|
||||
{
|
||||
vTaskDelay( xBlockingTime );
|
||||
xUDPLoggingSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
|
||||
} while( xUDPLoggingSocket == FREERTOS_INVALID_SOCKET );
|
||||
|
||||
xLocalAddress.sin_port = FreeRTOS_htons( configUDP_LOGGING_PORT_LOCAL );
|
||||
xLocalAddress.sin_addr = FreeRTOS_GetIPAddress();
|
||||
|
||||
FreeRTOS_bind( xUDPLoggingSocket, &xLocalAddress, sizeof( xLocalAddress ) );
|
||||
|
||||
xSendTimeOut = xBlockingTime;
|
||||
FreeRTOS_setsockopt( xUDPLoggingSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) );
|
||||
|
||||
/* Send a dummy message to resolve the IP address before sending the logging
|
||||
messages. */
|
||||
snprintf( cLoggingLine, configUDP_LOGGING_STRING_LENGTH, "Logging Probe\n" );
|
||||
FreeRTOS_sendto( xUDPLoggingSocket, ( void * ) cLoggingLine, strlen( cLoggingLine ), 0, &xRemoteAddress, sizeof( xRemoteAddress ) );
|
||||
vTaskDelay( xResolveDelay );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Wait for another message to be placed into the stream buffer. */
|
||||
ulTaskNotifyTake( pdTRUE, xBlockingTime );
|
||||
|
||||
if( xGetPhyLinkStatus() != pdFALSE )
|
||||
{
|
||||
/* Check for messages in the buffer. */
|
||||
for( lLines = 0; lLines < configUDP_LOGGING_MAX_MESSAGES_IN_BUFFER; lLines++ )
|
||||
{
|
||||
xCount = prvGetMessageFromStreamBuffer ( cLoggingLine, sizeof( cLoggingLine ) );
|
||||
|
||||
if( xCount <= 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
#if( configUDP_LOGGING_NEEDS_CR_LF != 0 )
|
||||
{
|
||||
char *pcTarget;
|
||||
const char *pcSource;
|
||||
|
||||
/* Within the code, a single "\n" is used to denote a
|
||||
newline. If 'configUDP_LOGGING_NEEDS_CR_LF' is defined as non-zero,
|
||||
every "\n" will be translated into a "\r\n". */
|
||||
pcTarget = cLoggingLine;
|
||||
pcSource = cLoggingLine;
|
||||
|
||||
while( ( *pcSource != 0x00 ) && ( pcSource < ( cLoggingLine + xCount ) ) )
|
||||
{
|
||||
*pcTarget = *pcSource;
|
||||
|
||||
if( ( ( pcSource == cLoggingLine ) || ( pcSource[ -1 ] != logASCII_CR ) ) && ( pcSource[ 0 ] == logASCII_NL ) )
|
||||
{
|
||||
pcTarget[ 0 ] = logASCII_CR;
|
||||
pcTarget[ 1 ] = logASCII_NL;
|
||||
|
||||
if( xCount < ( sizeof( cLoggingLine ) - 1 ) )
|
||||
{
|
||||
xCount++;
|
||||
pcTarget++;
|
||||
}
|
||||
}
|
||||
|
||||
pcTarget++;
|
||||
pcSource++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
FreeRTOS_sendto( xUDPLoggingSocket, ( void * ) cLoggingLine, xCount, 0, &xRemoteAddress, sizeof( xRemoteAddress ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vUDPLoggingFlush( void )
|
||||
{
|
||||
const TickType_t xDelay = pdMS_TO_TICKS( 20UL );
|
||||
|
||||
/* In some situations a lot of logging is produced deliberately in which
|
||||
case vUDPLoggingFlush() can be called to prevent the buffer overflowing. */
|
||||
if( xLoggingTask != NULL )
|
||||
{
|
||||
/* Unblock the logging task so it can output the message. */
|
||||
xTaskNotifyGive( xLoggingTask );
|
||||
}
|
||||
|
||||
/* Allow the low priority logging task a chance to clear the buffer. */
|
||||
vTaskDelay( pdMS_TO_TICKS( xDelay ) );
|
||||
}
|
||||
|
||||
176
FreeRTOS-Labs/Demo/Common/Utilities/date_and_time.c
Normal file
176
FreeRTOS-Labs/Demo/Common/Utilities/date_and_time.c
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#include "date_and_time.h"
|
||||
|
||||
int iTimeZone;
|
||||
|
||||
uint32_t ulSeconds, ulMsec;
|
||||
|
||||
/*
|
||||
* You can add the following code to you FreeRTOSConfig file:
|
||||
*
|
||||
extern TickType_t ulSeconds, ulMsec;
|
||||
|
||||
#define traceINCREASE_TICK_COUNT( xTicksToJump ) \
|
||||
{ \
|
||||
ulMsec += xTicksToJump; \
|
||||
if( ulMsec >= 1000 ) \
|
||||
{ \
|
||||
ulSeconds += ( ulMsec / 1000ul ); \
|
||||
ulMsec = ( ulMsec % 1000ul ); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
#define traceTASK_INCREMENT_TICK( xTickCount ) \
|
||||
if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) \
|
||||
{ \
|
||||
if( ++ulMsec >= 1000 ) \
|
||||
{ \
|
||||
ulMsec = 0; \
|
||||
ulSeconds++; \
|
||||
} \
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
time_t FreeRTOS_time( time_t *pxTime )
|
||||
{
|
||||
time_t uxTime;
|
||||
|
||||
/* Critical section required if running on a 16 bit processor. */
|
||||
portTICK_TYPE_ENTER_CRITICAL();
|
||||
{
|
||||
uxTime = ( time_t ) ulSeconds;
|
||||
}
|
||||
portTICK_TYPE_EXIT_CRITICAL();
|
||||
if( pxTime != NULL )
|
||||
{
|
||||
*pxTime = uxTime;
|
||||
}
|
||||
return uxTime;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void FreeRTOS_settime( time_t *pxTime )
|
||||
{
|
||||
/* Critical section required if running on a 16 bit processor. */
|
||||
portTICK_TYPE_ENTER_CRITICAL();
|
||||
{
|
||||
ulSeconds = ( uint32_t ) *pxTime;
|
||||
ulMsec = ( uint32_t ) 0;
|
||||
}
|
||||
portTICK_TYPE_EXIT_CRITICAL();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
time_t FreeRTOS_get_secs_msec( time_t *pulMsec )
|
||||
{
|
||||
time_t uxReturn;
|
||||
|
||||
/* Critical section required if running on a 16 bit processor. */
|
||||
portTICK_TYPE_ENTER_CRITICAL();
|
||||
{
|
||||
uxReturn = ( time_t ) ulSeconds;
|
||||
if( pulMsec != NULL )
|
||||
{
|
||||
*pulMsec = ulMsec;
|
||||
}
|
||||
}
|
||||
portTICK_TYPE_EXIT_CRITICAL();
|
||||
|
||||
return uxReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
|
||||
void FreeRTOS_set_secs_msec( time_t *pulSeconds, time_t *pulMsec )
|
||||
{
|
||||
|
||||
/* Critical section required if running on a 16 bit processor. */
|
||||
portTICK_TYPE_ENTER_CRITICAL();
|
||||
{
|
||||
ulSeconds= *pulSeconds;
|
||||
if( pulMsec != NULL )
|
||||
{
|
||||
ulMsec = *pulMsec;
|
||||
}
|
||||
}
|
||||
portTICK_TYPE_EXIT_CRITICAL();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
100
FreeRTOS-Labs/Demo/Common/Utilities/include/UDPLoggingPrintf.h
Normal file
100
FreeRTOS-Labs/Demo/Common/Utilities/include/UDPLoggingPrintf.h
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
#ifndef DEMO_LOGGING_H
|
||||
#define DEMO_LOGGING_H
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
/*
|
||||
* Add a formatted string along with a time-stamp to the buffer of logging messages.
|
||||
*/
|
||||
int lUDPLoggingPrintf( const char *pcFormatString, ... );
|
||||
|
||||
/*
|
||||
* Start a task which will send out the logging lines to a UDP address.
|
||||
* Only start this task once the TCP/IP stack is up and running.
|
||||
*/
|
||||
void vUDPLoggingTaskCreate( void );
|
||||
|
||||
/*
|
||||
* vUDPLoggingFlush() can be called in cases where a lot of logging is being
|
||||
* generated to try to avoid the logging buffer overflowing. WARNING - this
|
||||
* function will place the calling task into the Blocked state for 20ms.
|
||||
*/
|
||||
void vUDPLoggingFlush( void );
|
||||
|
||||
/* FreeRTOS+TCP includes. */
|
||||
#include "FreeRTOS_IP.h"
|
||||
#include "FreeRTOS_Sockets.h"
|
||||
|
||||
Socket_t xLoggingGetSocket( void );
|
||||
|
||||
#endif /* DEMO_LOGGING_H */
|
||||
|
||||
93
FreeRTOS-Labs/Demo/Common/Utilities/include/date_and_time.h
Normal file
93
FreeRTOS-Labs/Demo/Common/Utilities/include/date_and_time.h
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
#ifndef DATE_AND_TIME_H
|
||||
#define DATE_AND_TIME_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
|
||||
extern uint32_t ulSeconds, ulMsec;
|
||||
extern int iTimeZone;
|
||||
|
||||
extern time_t FreeRTOS_get_secs_msec( time_t *pulMsec );
|
||||
extern void FreeRTOS_set_secs_msec( time_t *pulSeconds, time_t *pulMsec );
|
||||
|
||||
extern time_t FreeRTOS_time( time_t *pxTime );
|
||||
extern void FreeRTOS_settime( time_t *pxTime );
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* DATE_AND_TIME_H */
|
||||
675
FreeRTOS-Labs/Demo/Common/Utilities/printf-stdarg.c
Normal file
675
FreeRTOS-Labs/Demo/Common/Utilities/printf-stdarg.c
Normal file
|
|
@ -0,0 +1,675 @@
|
|||
/*
|
||||
Copyright 2001, 2002 Georges Menie (www.menie.org)
|
||||
stdarg version contributed by Christian Ettinger
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Changes for the FreeRTOS ports:
|
||||
|
||||
- The dot in "%-8.8s"
|
||||
- The specifiers 'l' (long) and 'L' (long long)
|
||||
- The specifier 'u' for unsigned
|
||||
- Dot notation for IP addresses:
|
||||
sprintf("IP = %xip\n", 0xC0A80164);
|
||||
will produce "IP = 192.168.1.100\n"
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
#define PAD_RIGHT 1
|
||||
#define PAD_ZERO 2
|
||||
|
||||
/*
|
||||
* Return 1 for readable, 2 for writeable, 3 for both.
|
||||
* Function must be provided by the application.
|
||||
*/
|
||||
extern BaseType_t xApplicationMemoryPermissions( uint32_t aAddress );
|
||||
|
||||
extern void vOutputChar( const char cChar, const TickType_t xTicksToWait );
|
||||
static const TickType_t xTicksToWait = pdMS_TO_TICKS( 20 );
|
||||
|
||||
struct xPrintFlags
|
||||
{
|
||||
int base;
|
||||
int width;
|
||||
int printLimit;
|
||||
unsigned
|
||||
pad : 8,
|
||||
letBase : 8,
|
||||
isSigned : 1,
|
||||
isNumber : 1,
|
||||
long32 : 1,
|
||||
long64 : 1;
|
||||
};
|
||||
|
||||
struct SStringBuf
|
||||
{
|
||||
char *str;
|
||||
const char *orgStr;
|
||||
const char *nulPos;
|
||||
int curLen;
|
||||
struct xPrintFlags flags;
|
||||
};
|
||||
|
||||
static void strbuf_init( struct SStringBuf *apStr, char *apBuf, const char *apMaxStr )
|
||||
{
|
||||
apStr->str = apBuf;
|
||||
apStr->orgStr = apBuf;
|
||||
apStr->nulPos = apMaxStr-1;
|
||||
apStr->curLen = 0;
|
||||
|
||||
memset( &apStr->flags, '\0', sizeof( apStr->flags ) );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static BaseType_t strbuf_printchar( struct SStringBuf *apStr, int c )
|
||||
{
|
||||
if( apStr->str == NULL )
|
||||
{
|
||||
vOutputChar( ( char ) c, xTicksToWait );
|
||||
apStr->curLen++;
|
||||
return pdTRUE;
|
||||
}
|
||||
if( apStr->str < apStr->nulPos )
|
||||
{
|
||||
*( apStr->str++ ) = c;
|
||||
apStr->curLen++;
|
||||
return pdTRUE;
|
||||
}
|
||||
if( apStr->str == apStr->nulPos )
|
||||
{
|
||||
*( apStr->str++ ) = '\0';
|
||||
}
|
||||
return pdFALSE;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portINLINE BaseType_t strbuf_printchar_inline( struct SStringBuf *apStr, int c )
|
||||
{
|
||||
if( apStr->str == NULL )
|
||||
{
|
||||
vOutputChar( ( char ) c, xTicksToWait );
|
||||
if( c == 0 )
|
||||
{
|
||||
return pdFALSE;
|
||||
}
|
||||
apStr->curLen++;
|
||||
return pdTRUE;
|
||||
}
|
||||
if( apStr->str < apStr->nulPos )
|
||||
{
|
||||
*(apStr->str++) = c;
|
||||
if( c == 0 )
|
||||
{
|
||||
return pdFALSE;
|
||||
}
|
||||
apStr->curLen++;
|
||||
return pdTRUE;
|
||||
}
|
||||
if( apStr->str == apStr->nulPos )
|
||||
{
|
||||
*( apStr->str++ ) = '\0';
|
||||
}
|
||||
return pdFALSE;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portINLINE int i2hex( int aCh )
|
||||
{
|
||||
int iResult;
|
||||
|
||||
if( aCh < 10 )
|
||||
{
|
||||
iResult = '0' + aCh;
|
||||
}
|
||||
else
|
||||
{
|
||||
iResult = 'A' + aCh - 10;
|
||||
}
|
||||
|
||||
return iResult;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static BaseType_t prints(struct SStringBuf *apBuf, const char *apString )
|
||||
{
|
||||
register int padchar = ' ';
|
||||
int i,len;
|
||||
|
||||
if( apBuf->flags.width > 0 )
|
||||
{
|
||||
register int len = 0;
|
||||
register const char *ptr;
|
||||
for( ptr = apString; *ptr; ++ptr )
|
||||
{
|
||||
++len;
|
||||
}
|
||||
|
||||
if( len >= apBuf->flags.width )
|
||||
{
|
||||
apBuf->flags.width = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
apBuf->flags.width -= len;
|
||||
}
|
||||
|
||||
if( apBuf->flags.pad & PAD_ZERO )
|
||||
{
|
||||
padchar = '0';
|
||||
}
|
||||
}
|
||||
if( ( apBuf->flags.pad & PAD_RIGHT ) == 0 )
|
||||
{
|
||||
for( ; apBuf->flags.width > 0; --apBuf->flags.width )
|
||||
{
|
||||
if( strbuf_printchar( apBuf, padchar ) == 0 )
|
||||
{
|
||||
return pdFALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( ( apBuf->flags.isNumber == pdTRUE ) && ( apBuf->flags.pad == pdTRUE ) )
|
||||
{
|
||||
/* The string to print represents an integer number.
|
||||
* In this case, printLimit is the min number of digits to print
|
||||
* If the length of the number to print is less than the min nb of i
|
||||
* digits to display, we add 0 before printing the number
|
||||
*/
|
||||
len = strlen( apString );
|
||||
|
||||
if( len < apBuf->flags.printLimit )
|
||||
{
|
||||
i = apBuf->flags.printLimit - len;
|
||||
for( ; i; i-- )
|
||||
{
|
||||
if( strbuf_printchar( apBuf, '0' ) == 0 )
|
||||
{
|
||||
return pdFALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* The string to print is not the result of a number conversion to ascii.
|
||||
* For a string, printLimit is the max number of characters to display
|
||||
*/
|
||||
for( ; apBuf->flags.printLimit && *apString ; ++apString, --apBuf->flags.printLimit )
|
||||
{
|
||||
if( !strbuf_printchar( apBuf, *apString ) )
|
||||
{
|
||||
return pdFALSE;
|
||||
}
|
||||
}
|
||||
|
||||
for( ; apBuf->flags.width > 0; --apBuf->flags.width )
|
||||
{
|
||||
if( !strbuf_printchar( apBuf, padchar ) )
|
||||
{
|
||||
return pdFALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return pdTRUE;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* the following should be enough for 32 bit int */
|
||||
#define PRINT_BUF_LEN 12 /* to print 4294967296 */
|
||||
|
||||
#if SPRINTF_LONG_LONG
|
||||
#warning 64-bit libraries will be included as well
|
||||
static BaseType_t printll( struct SStringBuf *apBuf, long long i )
|
||||
{
|
||||
char print_buf[ 2 * PRINT_BUF_LEN ];
|
||||
register char *s;
|
||||
register int t, neg = 0;
|
||||
register unsigned long long u = i;
|
||||
lldiv_t lldiv_result;
|
||||
|
||||
/* typedef struct
|
||||
* {
|
||||
* long long int quot; // quotient
|
||||
* long long int rem; // remainder
|
||||
* } lldiv_t;
|
||||
*/
|
||||
|
||||
apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */
|
||||
if( i == 0LL )
|
||||
{
|
||||
print_buf[ 0 ] = '0';
|
||||
print_buf[ 1 ] = '\0';
|
||||
return prints( apBuf, print_buf );
|
||||
}
|
||||
|
||||
if( ( apBuf->flags.isSigned == pdTRUE ) && ( apBuf->flags.base == 10 ) && ( i < 0LL ) )
|
||||
{
|
||||
neg = 1;
|
||||
u = -i;
|
||||
}
|
||||
|
||||
s = print_buf + sizeof( print_buf ) - 1;
|
||||
|
||||
*s = '\0';
|
||||
/* 18446744073709551616 */
|
||||
while( u != 0 )
|
||||
{
|
||||
lldiv_result = lldiv( u, ( unsigned long long ) apBuf->flags.base );
|
||||
t = lldiv_result.rem;
|
||||
if( t >= 10 )
|
||||
{
|
||||
t += apBuf->flags.letBase - '0' - 10;
|
||||
}
|
||||
*( --s ) = t + '0';
|
||||
u = lldiv_result.quot;
|
||||
}
|
||||
|
||||
if( neg != 0 )
|
||||
{
|
||||
if( ( apBuf->flags.width != 0 ) && ( apBuf->flags.pad & PAD_ZERO ) )
|
||||
{
|
||||
if( !strbuf_printchar( apBuf, '-' ) )
|
||||
{
|
||||
return pdFALSE;
|
||||
}
|
||||
--apBuf->flags.width;
|
||||
}
|
||||
else
|
||||
{
|
||||
*( --s ) = '-';
|
||||
}
|
||||
}
|
||||
|
||||
return prints( apBuf, s );
|
||||
}
|
||||
#endif /* SPRINTF_LONG_LONG */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static BaseType_t printi( struct SStringBuf *apBuf, int i )
|
||||
{
|
||||
char print_buf[ PRINT_BUF_LEN ];
|
||||
register char *s;
|
||||
register int t, neg = 0;
|
||||
register unsigned int u = i;
|
||||
register unsigned base = apBuf->flags.base;
|
||||
|
||||
apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */
|
||||
|
||||
if( i == 0 )
|
||||
{
|
||||
print_buf[ 0 ] = '0';
|
||||
print_buf[ 1 ] = '\0';
|
||||
return prints( apBuf, print_buf );
|
||||
}
|
||||
|
||||
if( ( apBuf->flags.isSigned == pdTRUE ) && ( base == 10 ) && ( i < 0 ) )
|
||||
{
|
||||
neg = 1;
|
||||
u = -i;
|
||||
}
|
||||
|
||||
s = print_buf + sizeof( print_buf ) - 1;
|
||||
|
||||
*s = '\0';
|
||||
switch( base )
|
||||
{
|
||||
case 16:
|
||||
while( u != 0 )
|
||||
{
|
||||
t = u & 0xF;
|
||||
if( t >= 10 )
|
||||
{
|
||||
t += apBuf->flags.letBase - '0' - 10;
|
||||
}
|
||||
*( --s ) = t + '0';
|
||||
u >>= 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case 8:
|
||||
case 10:
|
||||
/* GCC compiles very efficient */
|
||||
while( u )
|
||||
{
|
||||
t = u % base;
|
||||
*( --s ) = t + '0';
|
||||
u /= base;
|
||||
}
|
||||
break;
|
||||
/*
|
||||
// The generic case, not yet in use
|
||||
default:
|
||||
while( u )
|
||||
{
|
||||
t = u % base;
|
||||
if( t >= 10)
|
||||
{
|
||||
t += apBuf->flags.letBase - '0' - 10;
|
||||
}
|
||||
*( --s ) = t + '0';
|
||||
u /= base;
|
||||
}
|
||||
break;
|
||||
*/
|
||||
}
|
||||
|
||||
if( neg != 0 )
|
||||
{
|
||||
if( apBuf->flags.width && (apBuf->flags.pad & PAD_ZERO ) )
|
||||
{
|
||||
if( strbuf_printchar( apBuf, '-' ) == 0 )
|
||||
{
|
||||
return pdFALSE;
|
||||
}
|
||||
--apBuf->flags.width;
|
||||
}
|
||||
else
|
||||
{
|
||||
*( --s ) = '-';
|
||||
}
|
||||
}
|
||||
|
||||
return prints( apBuf, s );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static BaseType_t printIp(struct SStringBuf *apBuf, unsigned i )
|
||||
{
|
||||
char print_buf[16];
|
||||
|
||||
sprintf( print_buf, "%u.%u.%u.%u",
|
||||
i >> 24,
|
||||
( i >> 16 ) & 0xff,
|
||||
( i >> 8 ) & 0xff,
|
||||
i & 0xff );
|
||||
apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */
|
||||
prints( apBuf, print_buf );
|
||||
|
||||
return pdTRUE;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void tiny_print( struct SStringBuf *apBuf, const char *format, va_list args )
|
||||
{
|
||||
char scr[2];
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
int ch = *( format++ );
|
||||
|
||||
if( ch != '%' )
|
||||
{
|
||||
do
|
||||
{
|
||||
/* Put the most like flow in a small loop */
|
||||
if( strbuf_printchar_inline( apBuf, ch ) == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
ch = *( format++ );
|
||||
} while( ch != '%' );
|
||||
}
|
||||
ch = *( format++ );
|
||||
/* Now ch has character after '%', format pointing to next */
|
||||
|
||||
if( ch == '\0' )
|
||||
{
|
||||
break;
|
||||
}
|
||||
if( ch == '%' )
|
||||
{
|
||||
if( strbuf_printchar( apBuf, ch ) == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
memset( &apBuf->flags, '\0', sizeof( apBuf->flags ) );
|
||||
|
||||
if( ch == '-' )
|
||||
{
|
||||
ch = *( format++ );
|
||||
apBuf->flags.pad = PAD_RIGHT;
|
||||
}
|
||||
while( ch == '0' )
|
||||
{
|
||||
ch = *( format++ );
|
||||
apBuf->flags.pad |= PAD_ZERO;
|
||||
}
|
||||
if( ch == '*' )
|
||||
{
|
||||
ch = *( format++ );
|
||||
apBuf->flags.width = va_arg( args, int );
|
||||
}
|
||||
else
|
||||
{
|
||||
while( ch >= '0' && ch <= '9' )
|
||||
{
|
||||
apBuf->flags.width *= 10;
|
||||
apBuf->flags.width += ch - '0';
|
||||
ch = *( format++ );
|
||||
}
|
||||
}
|
||||
if( ch == '.' )
|
||||
{
|
||||
ch = *( format++ );
|
||||
if( ch == '*' )
|
||||
{
|
||||
apBuf->flags.printLimit = va_arg( args, int );
|
||||
ch = *( format++ );
|
||||
}
|
||||
else
|
||||
{
|
||||
while( ch >= '0' && ch <= '9' )
|
||||
{
|
||||
apBuf->flags.printLimit *= 10;
|
||||
apBuf->flags.printLimit += ch - '0';
|
||||
ch = *( format++ );
|
||||
}
|
||||
}
|
||||
}
|
||||
if( apBuf->flags.printLimit == 0 )
|
||||
{
|
||||
apBuf->flags.printLimit--; /* -1: make it unlimited */
|
||||
}
|
||||
if( ch == 's' )
|
||||
{
|
||||
register char *s = ( char * )va_arg( args, int );
|
||||
if( prints( apBuf, s ? s : "(null)" ) == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if( ch == 'c' )
|
||||
{
|
||||
/* char are converted to int then pushed on the stack */
|
||||
scr[0] = ( char ) va_arg( args, int );
|
||||
|
||||
if( strbuf_printchar( apBuf, scr[0] ) == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
if( ch == 'l' )
|
||||
{
|
||||
ch = *( format++ );
|
||||
apBuf->flags.long32 = 1;
|
||||
/* Makes not difference as u32 == long */
|
||||
}
|
||||
if( ch == 'L' )
|
||||
{
|
||||
ch = *( format++ );
|
||||
apBuf->flags.long64 = 1;
|
||||
/* Does make a difference */
|
||||
}
|
||||
apBuf->flags.base = 10;
|
||||
apBuf->flags.letBase = 'a';
|
||||
|
||||
if( ch == 'd' || ch == 'u' )
|
||||
{
|
||||
apBuf->flags.isSigned = ( ch == 'd' );
|
||||
#if SPRINTF_LONG_LONG
|
||||
if( apBuf->flags.long64 != pdFALSE )
|
||||
{
|
||||
if( printll( apBuf, va_arg( args, long long ) ) == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
} else
|
||||
#endif /* SPRINTF_LONG_LONG */
|
||||
if( printi( apBuf, va_arg( args, int ) ) == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
apBuf->flags.base = 16; /* From here all hexadecimal */
|
||||
|
||||
if( ch == 'x' && format[0] == 'i' && format[1] == 'p' )
|
||||
{
|
||||
format += 2; /* eat the "xi" of "xip" */
|
||||
/* Will use base 10 again */
|
||||
if( printIp( apBuf, va_arg( args, int ) ) == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if( ch == 'x' || ch == 'X' || ch == 'p' || ch == 'o' )
|
||||
{
|
||||
if( ch == 'X' )
|
||||
{
|
||||
apBuf->flags.letBase = 'A';
|
||||
}
|
||||
else if( ch == 'o' )
|
||||
{
|
||||
apBuf->flags.base = 8;
|
||||
}
|
||||
#if SPRINTF_LONG_LONG
|
||||
if( apBuf->flags.long64 != pdFALSE )
|
||||
{
|
||||
if( printll( apBuf, va_arg( args, long long ) ) == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
} else
|
||||
#endif /* SPRINTF_LONG_LONG */
|
||||
if( printi( apBuf, va_arg( args, int ) ) == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
strbuf_printchar( apBuf, '\0' );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
int tiny_printf( const char *format, ... )
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start( args, format );
|
||||
struct SStringBuf strBuf;
|
||||
strbuf_init( &strBuf, NULL, ( const char* )NULL );
|
||||
tiny_print( &strBuf, format, args );
|
||||
va_end( args );
|
||||
|
||||
return strBuf.curLen;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
int vsnprintf( char *apBuf, size_t aMaxLen, const char *apFmt, va_list args )
|
||||
{
|
||||
struct SStringBuf strBuf;
|
||||
strbuf_init( &strBuf, apBuf, ( const char* )apBuf + aMaxLen );
|
||||
tiny_print( &strBuf, apFmt, args );
|
||||
|
||||
return strBuf.curLen;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
int snprintf( char *apBuf, size_t aMaxLen, const char *apFmt, ... )
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start( args, apFmt );
|
||||
struct SStringBuf strBuf;
|
||||
strbuf_init( &strBuf, apBuf, ( const char* )apBuf + aMaxLen );
|
||||
tiny_print( &strBuf, apFmt, args );
|
||||
va_end( args );
|
||||
|
||||
return strBuf.curLen;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
int sprintf( char *apBuf, const char *apFmt, ... )
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start( args, apFmt );
|
||||
struct SStringBuf strBuf;
|
||||
strbuf_init( &strBuf, apBuf, ( const char * )apBuf + 1024 );
|
||||
tiny_print( &strBuf, apFmt, args );
|
||||
va_end( args );
|
||||
|
||||
return strBuf.curLen;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
int vsprintf( char *apBuf, const char *apFmt, va_list args )
|
||||
{
|
||||
struct SStringBuf strBuf;
|
||||
strbuf_init( &strBuf, apBuf, ( const char* ) apBuf + 1024 );
|
||||
tiny_print( &strBuf, apFmt, args );
|
||||
|
||||
return strBuf.curLen;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
const char *mkSize (unsigned long long aSize, char *apBuf, int aLen)
|
||||
{
|
||||
static char retString[33];
|
||||
size_t gb, mb, kb, sb;
|
||||
|
||||
if (apBuf == NULL) {
|
||||
apBuf = retString;
|
||||
aLen = sizeof( retString );
|
||||
}
|
||||
gb = aSize / (1024*1024*1024);
|
||||
aSize -= gb * (1024*1024*1024);
|
||||
mb = aSize / (1024*1024);
|
||||
aSize -= mb * (1024*1024);
|
||||
kb = aSize / (1024);
|
||||
aSize -= kb * (1024);
|
||||
sb = aSize;
|
||||
if( gb )
|
||||
{
|
||||
snprintf (apBuf, aLen, "%u.%02u GB", ( unsigned ) gb, ( unsigned ) ( ( 100 * mb ) / 1024ul ) );
|
||||
}
|
||||
else if( mb )
|
||||
{
|
||||
snprintf (apBuf, aLen, "%u.%02u MB", ( unsigned ) mb, ( unsigned ) ( ( 100 * kb) / 1024ul ) );
|
||||
}
|
||||
else if( kb != 0ul )
|
||||
{
|
||||
snprintf (apBuf, aLen, "%u.%02u KB", ( unsigned ) kb, ( unsigned ) ( ( 100 * sb) / 1024ul ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf (apBuf, aLen, "%u bytes", ( unsigned ) sb);
|
||||
}
|
||||
return apBuf;
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue