You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
338 lines
13 KiB
C
338 lines
13 KiB
C
/*
|
|
FreeRTOS V7.0.2 - Copyright (C) 2011 Real Time Engineers Ltd.
|
|
|
|
|
|
***************************************************************************
|
|
* *
|
|
* FreeRTOS tutorial books are available in pdf and paperback. *
|
|
* Complete, revised, and edited pdf reference manuals are also *
|
|
* available. *
|
|
* *
|
|
* Purchasing FreeRTOS documentation will not only help you, by *
|
|
* ensuring you get running as quickly as possible and with an *
|
|
* in-depth knowledge of how to use FreeRTOS, it will also help *
|
|
* the FreeRTOS project to continue with its mission of providing *
|
|
* professional grade, cross platform, de facto standard solutions *
|
|
* for microcontrollers - completely free of charge! *
|
|
* *
|
|
* >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
|
|
* *
|
|
* Thank you for using FreeRTOS, and thank you for your support! *
|
|
* *
|
|
***************************************************************************
|
|
|
|
|
|
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. See the GNU General Public License for
|
|
more details. You should have received a copy of the GNU General Public
|
|
License and the FreeRTOS license exception along with FreeRTOS; if not it
|
|
can be viewed here: http://www.freertos.org/a00114.html and also obtained
|
|
by writing to Richard Barry, contact details for whom are available on the
|
|
FreeRTOS WEB site.
|
|
|
|
1 tab == 4 spaces!
|
|
|
|
http://www.FreeRTOS.org - Documentation, latest information, license and
|
|
contact details.
|
|
|
|
http://www.SafeRTOS.com - A version that is certified for use in safety
|
|
critical systems.
|
|
|
|
http://www.OpenRTOS.com - Commercial support, development, porting,
|
|
licensing and training services.
|
|
*/
|
|
|
|
|
|
/*
|
|
* Creates a task and a timer that operate on an interrupt driven serial port.
|
|
* This demo assumes that the characters transmitted on a port will also be
|
|
* received on the same port. Therefore, the UART must either be connected to
|
|
* an echo server, or the uart connector must have a loopback connector fitted.
|
|
* See http://www.serialporttool.com/CommEcho.htm for a suitable echo server
|
|
* for Windows hosts.
|
|
*
|
|
* The timer sends a string to the UART, toggles an LED, then resets itself by
|
|
* changing its own period. The period is calculated as a pseudo random number
|
|
* between comTX_MAX_BLOCK_TIME and comTX_MIN_BLOCK_TIME.
|
|
*
|
|
* The task blocks on an Rx queue waiting for a character to become available.
|
|
* Received characters are checked to ensure they match those transmitted by the
|
|
* Tx timer. An error is latched if characters are missing, incorrect, or
|
|
* arrive too slowly.
|
|
*
|
|
* How characters are actually transmitted and received is port specific. Demos
|
|
* that include this test/demo file will provide example drivers. The Tx timer
|
|
* executes in the context of the timer service (daemon) task, and must
|
|
* therefore never attempt to block.
|
|
*
|
|
*/
|
|
|
|
/* Scheduler include files. */
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "FreeRTOS.h"
|
|
#include "task.h"
|
|
#include "timers.h"
|
|
|
|
#ifndef configUSE_TIMERS
|
|
#error This demo uses timers. configUSE_TIMERS must be set to 1 in FreeRTOSConfig.h.
|
|
#endif
|
|
|
|
#if configUSE_TIMERS != 1
|
|
#error This demo uses timers. configUSE_TIMERS must be set to 1 in FreeRTOSConfig.h.
|
|
#endif
|
|
|
|
|
|
/* Demo program include files. */
|
|
#include "serial.h"
|
|
#include "comtest_strings.h"
|
|
#include "partest.h"
|
|
|
|
/* The size of the stack given to the Rx task. */
|
|
#define comSTACK_SIZE configMINIMAL_STACK_SIZE
|
|
|
|
/* See the comment above the declaraction of the uxBaseLED variable. */
|
|
#define comTX_LED_OFFSET ( 0 )
|
|
#define comRX_LED_OFFSET ( 1 )
|
|
|
|
/* The Tx timer transmits the sequence of characters at a pseudo random
|
|
interval that is capped between comTX_MAX_BLOCK_TIME and
|
|
comTX_MIN_BLOCK_TIME. */
|
|
#define comTX_MAX_BLOCK_TIME ( ( portTickType ) 0x96 )
|
|
#define comTX_MIN_BLOCK_TIME ( ( portTickType ) 0x32 )
|
|
#define comOFFSET_TIME ( ( portTickType ) 3 )
|
|
|
|
/* States for the simple state machine implemented in the Rx task. */
|
|
#define comtstWAITING_START_OF_STRING 0
|
|
#define comtstWAITING_END_OF_STRING 1
|
|
|
|
/* A short delay in ticks - this delay is used to allow the Rx queue to fill up
|
|
a bit so more than one character can be processed at a time. This is relative
|
|
to comTX_MIN_BLOCK_TIME to ensure it is never longer than the shortest gap
|
|
between transmissions. It could be worked out more scientifically from the
|
|
baud rate being used. */
|
|
#define comSHORT_DELAY ( comTX_MIN_BLOCK_TIME >> ( portTickType ) 2 )
|
|
|
|
/* The string that is transmitted and received. */
|
|
#define comTRANSACTED_STRING "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
|
|
|
|
/* A block time of 0 simply means "don't block". */
|
|
#define comtstDONT_BLOCK ( portTickType ) 0
|
|
|
|
/* Handle to the com port used by both tasks. */
|
|
static xComPortHandle xPort = NULL;
|
|
|
|
/* The callback function allocated to the transmit timer, as described in the
|
|
comments at the top of this file. */
|
|
static void prvComTxTimerCallback( xTimerHandle xTimer );
|
|
|
|
/* The receive task as described in the comments at the top of this file. */
|
|
static void vComRxTask( void *pvParameters );
|
|
|
|
/* The Rx task will toggle LED ( uxBaseLED + comRX_LED_OFFSET). The Tx task
|
|
will toggle LED ( uxBaseLED + comTX_LED_OFFSET ). */
|
|
static unsigned portBASE_TYPE uxBaseLED = 0;
|
|
|
|
/* The Rx task toggles uxRxLoops on each successful iteration of its defined
|
|
function - provided no errors have ever been latched. If this variable stops
|
|
incrementing, then an error has occurred. */
|
|
static volatile unsigned portBASE_TYPE uxRxLoops = 0UL;
|
|
|
|
/* The timer used to periodically transmit the string. This is the timer that
|
|
has prvComTxTimerCallback allocated to it as its callback function. */
|
|
static xTimerHandle xTxTimer = NULL;
|
|
|
|
/* The string length is held at file scope so the Tx timer does not need to
|
|
calculate it each time it executes. */
|
|
static size_t xStringLength = 0U;
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
void vStartComTestStringsTasks( unsigned portBASE_TYPE uxPriority, unsigned long ulBaudRate, unsigned portBASE_TYPE uxLED )
|
|
{
|
|
/* Store values that are used at run time. */
|
|
uxBaseLED = uxLED;
|
|
|
|
/* Calculate the string length here, rather than each time the Tx timer
|
|
executes. */
|
|
xStringLength = strlen( comTRANSACTED_STRING );
|
|
|
|
/* Include the null terminator in the string length as this is used to
|
|
detect the end of the string in the Rx task. */
|
|
xStringLength++;
|
|
|
|
/* Initialise the com port, then spawn the Rx task and create the Tx
|
|
timer. */
|
|
xSerialPortInitMinimal( ulBaudRate, ( xStringLength * 2U ) );
|
|
|
|
/* Create the Rx task and the Tx timer. The timer is started from the
|
|
Rx task. */
|
|
xTaskCreate( vComRxTask, ( signed char * ) "COMRx", comSTACK_SIZE, NULL, uxPriority, ( xTaskHandle * ) NULL );
|
|
xTxTimer = xTimerCreate( ( const signed char * ) "TxTimer", comTX_MIN_BLOCK_TIME, pdFALSE, NULL, prvComTxTimerCallback );
|
|
configASSERT( xTxTimer );
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static void prvComTxTimerCallback( xTimerHandle xTimer )
|
|
{
|
|
portTickType xTimeToWait;
|
|
|
|
/* The parameter is not used in this case. */
|
|
( void ) xTimer;
|
|
|
|
/* Send the string. How this is actually performed depends on the
|
|
sample driver provided with this demo. However - as this is a timer,
|
|
it executes in the context of the timer task and therefore must not
|
|
block. */
|
|
vSerialPutString( xPort, ( const signed char * const ) comTRANSACTED_STRING, xStringLength );
|
|
|
|
/* Toggle an LED to give a visible indication that another transmission
|
|
has been performed. */
|
|
vParTestToggleLED( uxBaseLED + comTX_LED_OFFSET );
|
|
|
|
/* Wait a pseudo random time before sending the string again. */
|
|
xTimeToWait = xTaskGetTickCount() + comOFFSET_TIME;
|
|
|
|
/* Ensure the time to wait is not greater than comTX_MAX_BLOCK_TIME. */
|
|
xTimeToWait %= comTX_MAX_BLOCK_TIME;
|
|
|
|
/* Ensure the time to wait is not less than comTX_MIN_BLOCK_TIME. */
|
|
if( xTimeToWait < comTX_MIN_BLOCK_TIME )
|
|
{
|
|
xTimeToWait = comTX_MIN_BLOCK_TIME;
|
|
}
|
|
|
|
/* Reset the timer to run again xTimeToWait ticks from now. This function
|
|
is called from the context of the timer task, so the block time must not
|
|
be anything other than zero. */
|
|
xTimerChangePeriod( xTxTimer, xTimeToWait, comtstDONT_BLOCK );
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static void vComRxTask( void *pvParameters )
|
|
{
|
|
portBASE_TYPE xState = comtstWAITING_START_OF_STRING, xErrorOccurred = pdFALSE;
|
|
signed char *pcExpectedByte, cRxedChar;
|
|
const xComPortHandle xPort = NULL;
|
|
|
|
/* The parameter is not used in this example. */
|
|
( void ) pvParameters;
|
|
|
|
/* Start the Tx timer. This only needs to be started once, as it will
|
|
reset itself thereafter. */
|
|
xTimerStart( xTxTimer, portMAX_DELAY );
|
|
|
|
/* The first expected Rx character is the first in the string that is
|
|
transmitted. */
|
|
pcExpectedByte = ( signed char * ) comTRANSACTED_STRING;
|
|
|
|
for( ;; )
|
|
{
|
|
/* Wait for the next character. */
|
|
if( xSerialGetChar( xPort, &cRxedChar, ( comTX_MAX_BLOCK_TIME * 2 ) ) == pdFALSE )
|
|
{
|
|
/* A character definitely should have been received by now. As a
|
|
character was not received an error must have occurred (which might
|
|
just be that the loopback connector is not fitted). */
|
|
xErrorOccurred = pdTRUE;
|
|
}
|
|
|
|
switch( xState )
|
|
{
|
|
case comtstWAITING_START_OF_STRING:
|
|
if( cRxedChar == *pcExpectedByte )
|
|
{
|
|
/* The received character was the first character of the
|
|
string. Move to the next state to check each character
|
|
as it comes in until the entire string has been received. */
|
|
xState = comtstWAITING_END_OF_STRING;
|
|
pcExpectedByte++;
|
|
|
|
/* Block for a short period. This just allows the Rx queue
|
|
to contain more than one character, and therefore prevent
|
|
thrashing reads to the queue, and repetitive context
|
|
switches as each character is received. */
|
|
vTaskDelay( comSHORT_DELAY );
|
|
}
|
|
break;
|
|
|
|
case comtstWAITING_END_OF_STRING:
|
|
if( cRxedChar == *pcExpectedByte )
|
|
{
|
|
/* The received character was the expected character. Was
|
|
it the last character in the string - i.e. the null
|
|
terminator? */
|
|
if( cRxedChar == 0x00 )
|
|
{
|
|
/* The entire string has been received. If no errors
|
|
have been latched, then increment the loop counter to
|
|
show this task is still healthy. */
|
|
if( xErrorOccurred == pdFALSE )
|
|
{
|
|
uxRxLoops++;
|
|
|
|
/* Toggle an LED to give a visible sign that a
|
|
complete string has been received. */
|
|
vParTestToggleLED( uxBaseLED + comRX_LED_OFFSET );
|
|
}
|
|
|
|
/* Go back to wait for the start of the next string. */
|
|
pcExpectedByte = ( signed char * ) comTRANSACTED_STRING;
|
|
xState = comtstWAITING_START_OF_STRING;
|
|
}
|
|
else
|
|
{
|
|
/* Wait for the next character in the string. */
|
|
pcExpectedByte++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* The character received was not that expected. */
|
|
xErrorOccurred = pdTRUE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
/* Should not get here. Stop the Rx loop counter from
|
|
incrementing to latch the error. */
|
|
xErrorOccurred = pdTRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
portBASE_TYPE xAreComTestTasksStillRunning( void )
|
|
{
|
|
portBASE_TYPE xReturn;
|
|
|
|
/* If the count of successful reception loops has not changed than at
|
|
some time an error occurred (i.e. a character was received out of sequence)
|
|
and false is returned. */
|
|
if( uxRxLoops == 0UL )
|
|
{
|
|
xReturn = pdFALSE;
|
|
}
|
|
else
|
|
{
|
|
xReturn = pdTRUE;
|
|
}
|
|
|
|
/* Reset the count of successful Rx loops. When this function is called
|
|
again it should have been incremented again. */
|
|
uxRxLoops = 0UL;
|
|
|
|
return xReturn;
|
|
}
|
|
|