Add uncrustify github workflow (#659)

* Add uncrustify github workflow

* Fix exclusion pattern

* fix find expression

* exclude uncrustify files

* Uncrustify common demo and test files

* exlude white space checking files

* Fix EOL whitespace checker

* Remove whitespaces from EOL

* Fix space at EOL

* Fix find spaces at EOL

Co-authored-by: Archit Aggarwal <architag@amazon.com>
This commit is contained in:
alfred gedeon 2021-07-22 14:23:48 -07:00 committed by GitHub
parent dd80d615b5
commit ae92d8c6ee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
191 changed files with 17540 additions and 17102 deletions

View file

@ -17,7 +17,7 @@ If you discover a potential security issue in this project we ask that you notif
## Submitting a bugs/feature request ## Submitting a bugs/feature request
Have a bug to report or feature to request? Follow these steps: Have a bug to report or feature to request? Follow these steps:
1. Search on the [FreeRTOS Community Support Forums](https://forums.freertos.org/) and [GitHub issue tracker](https://github.com/FreeRTOS/FreeRTOS/issues?utf8=%E2%9C%93&q=is%3Aissue) to be sure this hasn't been already reported or discussed. 1. Search on the [FreeRTOS Community Support Forums](https://forums.freertos.org/) and [GitHub issue tracker](https://github.com/FreeRTOS/FreeRTOS/issues?utf8=%E2%9C%93&q=is%3Aissue) to be sure this hasn't been already reported or discussed.
2. If your search turns up empty, create a new topic in the [forums](https://forums.freertos.org/) and work with the community to help clarify issues or refine the idea. Include as many of the details listed below. 2. If your search turns up empty, create a new topic in the [forums](https://forums.freertos.org/) and work with the community to help clarify issues or refine the idea. Include as many of the details listed below.
3. Once the community has had time to discuss and digest, we welcome you to create an [issue](https://github.com/FreeRTOS/FreeRTOS/issues) to report bugs or suggest features. 3. Once the community has had time to discuss and digest, we welcome you to create an [issue](https://github.com/FreeRTOS/FreeRTOS/issues) to report bugs or suggest features.
@ -43,8 +43,8 @@ To send us a pull request, please:
2. Modify the source; focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 2. Modify the source; focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change.
3. Follow the [coding style guide](https://www.freertos.org/FreeRTOS-Coding-Standard-and-Style-Guide.html). 3. Follow the [coding style guide](https://www.freertos.org/FreeRTOS-Coding-Standard-and-Style-Guide.html).
4. Commit to your fork using clear commit messages. 4. Commit to your fork using clear commit messages.
5. Send us a pull request, answering any default questions in the pull request interface. 5. Send us a pull request, answering any default questions in the pull request interface.
NOTE: Please make sure the default option (Allow edits from maintainers) is left checked. NOTE: Please make sure the default option (Allow edits from maintainers) is left checked.
6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation.
GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and

View file

@ -24,7 +24,7 @@ A concise description of what the bug is.
**To Reproduce** **To Reproduce**
- Use project ... and configure with ... - Use project ... and configure with ...
- Run on ... and could observe ... - Run on ... and could observe ...
**Expected behavior** **Expected behavior**
A concise description of what you expected to happen. A concise description of what you expected to happen.

View file

@ -11,7 +11,7 @@ assignees: ''
Please describe the issue and expected clarification in concise language. Please describe the issue and expected clarification in concise language.
**Reference** **Reference**
Please attach the URL at which you are experiencing the issue. Please attach the URL at which you are experiencing the issue.
**Screenshot** **Screenshot**
If applicable, please attach screenshot. If applicable, please attach screenshot.

4
.github/SECURITY.md vendored
View file

@ -1,5 +1,5 @@
## Reporting a Vulnerability ## Reporting a Vulnerability
If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security
via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/) or directly via email to aws-security@amazon.com. via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/) or directly via email to aws-security@amazon.com.
Please do **not** create a public github issue. Please do **not** create a public github issue.

View file

@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# python >= 3.4 # python >= 3.4
import os import os
from common.header_checker import HeaderChecker from common.header_checker import HeaderChecker

View file

@ -211,7 +211,7 @@ def configure_argparser():
type = str, type = str,
default = 'HEAD', default = 'HEAD',
help = 'Commit ID of FreeRTOS repo to package') help = 'Commit ID of FreeRTOS repo to package')
return parser return parser
def sanitize_cmd_args(args): def sanitize_cmd_args(args):
@ -254,13 +254,13 @@ def main():
FREERTOS_GIT_LINK, FREERTOS_GIT_LINK,
core_package_name, core_package_name,
commit_id=args.freertos_commit) commit_id=args.freertos_commit)
if path_core_out_tree == None: if path_core_out_tree == None:
print('Failed to prepare repo for zipping') print('Failed to prepare repo for zipping')
exit(1); exit(1);
core_outzip = create_package(path_core_out_tree, core_package_name, RELATIVE_FILE_EXCLUDES) core_outzip = create_package(path_core_out_tree, core_package_name, RELATIVE_FILE_EXCLUDES)
# Create FreeRTOS-Labs package # Create FreeRTOS-Labs package
labs_package_name = 'FreeRTOS-Labs' labs_package_name = 'FreeRTOS-Labs'
(path_labs_in_tree, path_labs_out_tree) = create_file_trees(DIR_INPUT_TREES, (path_labs_in_tree, path_labs_out_tree) = create_file_trees(DIR_INPUT_TREES,
@ -271,7 +271,7 @@ def main():
if path_labs_out_tree == None: if path_labs_out_tree == None:
print('Failed to prepare repo for zipping') print('Failed to prepare repo for zipping')
exit(1); exit(1);
labs_outzip = create_package(path_labs_out_tree, labs_package_name, LABS_RELATIVE_EXCLUDE_FILES) labs_outzip = create_package(path_labs_out_tree, labs_package_name, LABS_RELATIVE_EXCLUDE_FILES)
# Package summaries # Package summaries

View file

@ -10,7 +10,7 @@ from argparse import ArgumentParser
REPO_PATH='' REPO_PATH=''
# List of submodules excluded from manifest.yml file # List of submodules excluded from manifest.yml file
IGNORE_SUBMODULES_LIST = [ IGNORE_SUBMODULES_LIST = [
'FreeRTOS-Plus/Test/CMock', 'FreeRTOS-Plus/Test/CMock',
'FreeRTOS/Test/CMock/CMock', 'FreeRTOS/Test/CMock/CMock',
'FreeRTOS/Test/litani' 'FreeRTOS/Test/litani'
@ -19,7 +19,7 @@ IGNORE_SUBMODULES_LIST = [
# Obtain submodule path of all entries in manifest.yml file. # Obtain submodule path of all entries in manifest.yml file.
def read_manifest(): def read_manifest():
path_list = [] path_list = []
# Read YML file # Read YML file
path_manifest = os.path.join(REPO_PATH, 'manifest.yml') path_manifest = os.path.join(REPO_PATH, 'manifest.yml')
assert os.path.exists(path_manifest), 'Missing manifest.yml' assert os.path.exists(path_manifest), 'Missing manifest.yml'
@ -53,7 +53,7 @@ def get_all_submodules():
path = submodule.abspath.replace(REPO_PATH+'/', '') path = submodule.abspath.replace(REPO_PATH+'/', '')
if path not in IGNORE_SUBMODULES_LIST: if path not in IGNORE_SUBMODULES_LIST:
path_list.append(path) path_list.append(path)
return sorted(path_list) return sorted(path_list)
if __name__ == '__main__': if __name__ == '__main__':
@ -69,13 +69,13 @@ if __name__ == '__main__':
# Convert any relative path (like './') in passed argument to absolute path. # Convert any relative path (like './') in passed argument to absolute path.
REPO_PATH = os.path.abspath(args.repo_root_path) REPO_PATH = os.path.abspath(args.repo_root_path)
libraries_in_manifest_file = read_manifest() libraries_in_manifest_file = read_manifest()
git_submodules_list = get_all_submodules() git_submodules_list = get_all_submodules()
print(REPO_PATH) print(REPO_PATH)
print(git_submodules_list) print(git_submodules_list)
# Check that manifest.yml contains entries for all submodules # Check that manifest.yml contains entries for all submodules
# present in repository. # present in repository.
if libraries_in_manifest_file == git_submodules_list: if libraries_in_manifest_file == git_submodules_list:
print('Manifest.yml is verified!') print('Manifest.yml is verified!')

View file

@ -24,6 +24,38 @@ jobs:
run: | run: |
git-secrets --register-aws git-secrets --register-aws
git-secrets --scan git-secrets --scan
formatting:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Uncrustify
run: sudo apt-get install uncrustify
- name: Run Uncrustify
run: |
uncrustify --version
find FreeRTOS/Demo/Common FreeRTOS/Test \( -name ethernet -o -name drivers -o -path 'FreeRTOS/Test/CMock/CMock' \) -prune -false -o -name "*.[hc]" -exec uncrustify --check -c tools/uncrustify.cfg {} +
- name: Check For Trailing Whitespace
run: |
set +e
ERROR=0
find . \( -name '.git' -o -path "./FreeRTOS/Test/CBMC/patches" -o -path "./FreeRTOS-Plus" -o -path "./FreeRTOS/Source" -o -path "./FreeRTOS/Test/CMock/CMock" -o -path "./FreeRTOS/Demo" \) -prune -false -o -type f -a -name "*" -exec grep -In -e "[[:blank:]]$" {} +
if [ "$?" = "0" ]; then
echo "Files have trailing whitespace."
ERROR=1
fi
find FreeRTOS/Demo/Common \( -name "ethernet" \) -prune -o -false -o -type f -a -name "*" -exec grep --color=yes -In -e "[[:blank:]]$" {} +
if [ "$?" = "0" ]; then
echo "Files have trailing whitespace."
exit 1
else
if [ "$ERROR" -eq "1" ]; then
exit 1
fi
exit 0
fi
doxygen: doxygen:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
steps: steps:
@ -53,7 +85,7 @@ jobs:
- name: Upload doxygen artifact if main branch - name: Upload doxygen artifact if main branch
if: success() && ( github.ref == 'refs/heads/main' || github.ref == 'refs/heads/release-candidate' ) if: success() && ( github.ref == 'refs/heads/main' || github.ref == 'refs/heads/release-candidate' )
env: env:
GIT_SHA: GIT_SHA:
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
with: with:
name: doxygen.zip-${{ github.sha }} name: doxygen.zip-${{ github.sha }}

2
.gitignore vendored
View file

@ -1,4 +1,4 @@
# Ignore MacOS file system related. # Ignore MacOS file system related.
**/*.DS_Store* **/*.DS_Store*
# Ignore build results # Ignore build results

View file

@ -68,6 +68,7 @@ int main()
#error "Invalid Selection...\nPlease Select a Demo application from the main command" #error "Invalid Selection...\nPlease Select a Demo application from the main command"
} }
#endif /* if ( mainCREATE_SIMPLE_BLINKY_DEMO_ONLY == 1 ) */ #endif /* if ( mainCREATE_SIMPLE_BLINKY_DEMO_ONLY == 1 ) */
snprint
return 0; return 0;
} }

View file

@ -32,7 +32,7 @@
/** /**
* @brief Size of the shared memory region. * @brief Size of the shared memory region.
*/ */
#define SHARED_MEMORY_SIZE 32 #define SHARED_MEMORY_SIZE 32
/** /**
* @brief Memory region shared between two tasks. * @brief Memory region shared between two tasks.
@ -74,153 +74,155 @@ static void prvRWAccessTask( void * pvParameters );
static void prvROAccessTask( void * pvParameters ) static void prvROAccessTask( void * pvParameters )
{ {
uint8_t ucVal; uint8_t ucVal;
/* Unused parameters. */ /* Unused parameters. */
( void ) pvParameters; ( void ) pvParameters;
for( ; ; ) for( ; ; )
{ {
/* This task has RO access to ucSharedMemory and therefore it can read /* This task has RO access to ucSharedMemory and therefore it can read
* it but cannot modify it. */ * it but cannot modify it. */
ucVal = ucSharedMemory[ 0 ]; ucVal = ucSharedMemory[ 0 ];
/* Silent compiler warnings about unused variables. */ /* Silent compiler warnings about unused variables. */
( void ) ucVal; ( void ) ucVal;
/* Since this task has Read Only access to the ucSharedMemory region, /* Since this task has Read Only access to the ucSharedMemory region,
* writing to it results in Memory Fault. Set ucROTaskFaultTracker[ 0 ] * writing to it results in Memory Fault. Set ucROTaskFaultTracker[ 0 ]
* to 1 to tell the Memory Fault Handler that this is an expected fault. * to 1 to tell the Memory Fault Handler that this is an expected fault.
* The handler will recover from this fault gracefully by jumping to the * The handler will recover from this fault gracefully by jumping to the
* next instruction. */ * next instruction. */
ucROTaskFaultTracker[ 0 ] = 1; ucROTaskFaultTracker[ 0 ] = 1;
/* Illegal access to generate Memory Fault. */ /* Illegal access to generate Memory Fault. */
ucSharedMemory[ 0 ] = 0; ucSharedMemory[ 0 ] = 0;
/* Wait for a second. */ /* Wait for a second. */
vTaskDelay( pdMS_TO_TICKS( 1000 ) ); vTaskDelay( pdMS_TO_TICKS( 1000 ) );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvRWAccessTask( void * pvParameters ) static void prvRWAccessTask( void * pvParameters )
{ {
/* Unused parameters. */ /* Unused parameters. */
( void ) pvParameters; ( void ) pvParameters;
for( ; ; ) for( ; ; )
{ {
/* This task has RW access to ucSharedMemory and therefore can write to /* This task has RW access to ucSharedMemory and therefore can write to
* it. */ * it. */
ucSharedMemory[ 0 ] = 0; ucSharedMemory[ 0 ] = 0;
/* Wait for a second. */ /* Wait for a second. */
vTaskDelay( pdMS_TO_TICKS( 1000 ) ); vTaskDelay( pdMS_TO_TICKS( 1000 ) );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vStartMPUDemo( void ) void vStartMPUDemo( void )
{ {
static StackType_t xROAccessTaskStack[ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned( 32 ) ) ); static StackType_t xROAccessTaskStack[ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned( 32 ) ) );
static StackType_t xRWAccessTaskStack[ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned( 32 ) ) ); static StackType_t xRWAccessTaskStack[ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned( 32 ) ) );
TaskParameters_t xROAccessTaskParameters = TaskParameters_t xROAccessTaskParameters =
{ {
.pvTaskCode = prvROAccessTask, .pvTaskCode = prvROAccessTask,
.pcName = "ROAccess", .pcName = "ROAccess",
.usStackDepth = configMINIMAL_STACK_SIZE, .usStackDepth = configMINIMAL_STACK_SIZE,
.pvParameters = NULL, .pvParameters = NULL,
.uxPriority = tskIDLE_PRIORITY, .uxPriority = tskIDLE_PRIORITY,
.puxStackBuffer = xROAccessTaskStack, .puxStackBuffer = xROAccessTaskStack,
.xRegions = { .xRegions =
{ ucSharedMemory, 32, tskMPU_REGION_READ_ONLY | tskMPU_REGION_EXECUTE_NEVER }, {
{ ucROTaskFaultTracker, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER }, { ucSharedMemory, 32, tskMPU_REGION_READ_ONLY | tskMPU_REGION_EXECUTE_NEVER },
{ 0, 0, 0 }, { ucROTaskFaultTracker, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
} { 0, 0, 0 },
}; }
TaskParameters_t xRWAccessTaskParameters = };
{ TaskParameters_t xRWAccessTaskParameters =
.pvTaskCode = prvRWAccessTask, {
.pcName = "RWAccess", .pvTaskCode = prvRWAccessTask,
.usStackDepth = configMINIMAL_STACK_SIZE, .pcName = "RWAccess",
.pvParameters = NULL, .usStackDepth = configMINIMAL_STACK_SIZE,
.uxPriority = tskIDLE_PRIORITY, .pvParameters = NULL,
.puxStackBuffer = xRWAccessTaskStack, .uxPriority = tskIDLE_PRIORITY,
.xRegions = { .puxStackBuffer = xRWAccessTaskStack,
{ ucSharedMemory, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER }, .xRegions =
{ 0, 0, 0 }, {
{ 0, 0, 0 }, { ucSharedMemory, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
} { 0, 0, 0 },
}; { 0, 0, 0 },
}
};
/* Create an unprivileged task with RO access to ucSharedMemory. */ /* Create an unprivileged task with RO access to ucSharedMemory. */
xTaskCreateRestricted( &( xROAccessTaskParameters ), NULL ); xTaskCreateRestricted( &( xROAccessTaskParameters ), NULL );
/* Create an unprivileged task with RW access to ucSharedMemory. */ /* Create an unprivileged task with RW access to ucSharedMemory. */
xTaskCreateRestricted( &( xRWAccessTaskParameters ), NULL ); xTaskCreateRestricted( &( xRWAccessTaskParameters ), NULL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
portDONT_DISCARD void vHandleMemoryFault( uint32_t * pulFaultStackAddress ) portDONT_DISCARD void vHandleMemoryFault( uint32_t * pulFaultStackAddress )
{ {
uint32_t ulPC; uint32_t ulPC;
uint16_t usOffendingInstruction; uint16_t usOffendingInstruction;
/* Is this an expected fault? */ /* Is this an expected fault? */
if( ucROTaskFaultTracker[ 0 ] == 1 ) if( ucROTaskFaultTracker[ 0 ] == 1 )
{ {
/* Read program counter. */ /* Read program counter. */
ulPC = pulFaultStackAddress[ 6 ]; ulPC = pulFaultStackAddress[ 6 ];
/* Read the offending instruction. */ /* Read the offending instruction. */
usOffendingInstruction = *( uint16_t * )ulPC; usOffendingInstruction = *( uint16_t * ) ulPC;
/* From ARM docs: /* From ARM docs:
* If the value of bits[15:11] of the halfword being decoded is one of * If the value of bits[15:11] of the halfword being decoded is one of
* the following, the halfword is the first halfword of a 32-bit * the following, the halfword is the first halfword of a 32-bit
* instruction: * instruction:
* - 0b11101. * - 0b11101.
* - 0b11110. * - 0b11110.
* - 0b11111. * - 0b11111.
* Otherwise, the halfword is a 16-bit instruction. * Otherwise, the halfword is a 16-bit instruction.
*/ */
/* Extract bits[15:11] of the offending instruction. */ /* Extract bits[15:11] of the offending instruction. */
usOffendingInstruction = usOffendingInstruction & 0xF800; usOffendingInstruction = usOffendingInstruction & 0xF800;
usOffendingInstruction = ( usOffendingInstruction >> 11 ); usOffendingInstruction = ( usOffendingInstruction >> 11 );
/* Determine if the offending instruction is a 32-bit instruction or /* Determine if the offending instruction is a 32-bit instruction or
* a 16-bit instruction. */ * a 16-bit instruction. */
if( usOffendingInstruction == 0x001F || if( ( usOffendingInstruction == 0x001F ) ||
usOffendingInstruction == 0x001E || ( usOffendingInstruction == 0x001E ) ||
usOffendingInstruction == 0x001D ) ( usOffendingInstruction == 0x001D ) )
{ {
/* Since the offending instruction is a 32-bit instruction, /* Since the offending instruction is a 32-bit instruction,
* increment the program counter by 4 to move to the next * increment the program counter by 4 to move to the next
* instruction. */ * instruction. */
ulPC += 4; ulPC += 4;
} }
else else
{ {
/* Since the offending instruction is a 16-bit instruction, /* Since the offending instruction is a 16-bit instruction,
* increment the program counter by 2 to move to the next * increment the program counter by 2 to move to the next
* instruction. */ * instruction. */
ulPC += 2; ulPC += 2;
} }
/* Save the new program counter on the stack. */ /* Save the new program counter on the stack. */
pulFaultStackAddress[ 6 ] = ulPC; pulFaultStackAddress[ 6 ] = ulPC;
/* Mark the fault as handled. */ /* Mark the fault as handled. */
ucROTaskFaultTracker[ 0 ] = 0; ucROTaskFaultTracker[ 0 ] = 0;
} }
else else
{ {
/* This is an unexpected fault - loop forever. */ /* This is an unexpected fault - loop forever. */
for( ; ; ) for( ; ; )
{ {
} }
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -37,23 +37,23 @@ static uint32_t ulSecureCounter = 0;
/** /**
* @brief typedef for non-secure callback. * @brief typedef for non-secure callback.
*/ */
typedef void ( *NonSecureCallback_t ) ( void ) __attribute__( ( cmse_nonsecure_call ) ); typedef void ( *NonSecureCallback_t )( void ) __attribute__( ( cmse_nonsecure_call ) );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
secureportNON_SECURE_CALLABLE uint32_t NSCFunction( Callback_t pxCallback ) secureportNON_SECURE_CALLABLE uint32_t NSCFunction( Callback_t pxCallback )
{ {
NonSecureCallback_t pxNonSecureCallback; NonSecureCallback_t pxNonSecureCallback;
/* Return function pointer with cleared LSB. */ /* Return function pointer with cleared LSB. */
pxNonSecureCallback = ( NonSecureCallback_t ) cmse_nsfptr_create( pxCallback ); pxNonSecureCallback = ( NonSecureCallback_t ) cmse_nsfptr_create( pxCallback );
/* Invoke the supplied callback. */ /* Invoke the supplied callback. */
pxNonSecureCallback(); pxNonSecureCallback();
/* Increment the secure side counter. */ /* Increment the secure side counter. */
ulSecureCounter += 1; ulSecureCounter += 1;
/* Return the secure side counter. */ /* Return the secure side counter. */
return ulSecureCounter; return ulSecureCounter;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -33,7 +33,7 @@
/** /**
* @brief Callback function pointer definition. * @brief Callback function pointer definition.
*/ */
typedef void ( *Callback_t ) ( void ); typedef void ( * Callback_t ) ( void );
/** /**
* @brief Invokes the supplied callback which is on the non-secure side. * @brief Invokes the supplied callback which is on the non-secure side.

View file

@ -42,7 +42,7 @@
* 4 bytes and upto 32 bytes will also fall in the same MPU region and the task * 4 bytes and upto 32 bytes will also fall in the same MPU region and the task
* having access to ulNonSecureCounter will also have access to all those items. * having access to ulNonSecureCounter will also have access to all those items.
*/ */
static uint32_t ulNonSecureCounter[8] __attribute__( ( aligned( 32 ) ) ) = { 0 }; static uint32_t ulNonSecureCounter[ 8 ] __attribute__( ( aligned( 32 ) ) ) = { 0 };
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/** /**
@ -68,66 +68,67 @@ static void prvSecureCallingTask( void * pvParameters );
void vStartTZDemo( void ) void vStartTZDemo( void )
{ {
static StackType_t xSecureCallingTaskStack[ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned( 32 ) ) ); static StackType_t xSecureCallingTaskStack[ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned( 32 ) ) );
TaskParameters_t xSecureCallingTaskParameters = TaskParameters_t xSecureCallingTaskParameters =
{ {
.pvTaskCode = prvSecureCallingTask, .pvTaskCode = prvSecureCallingTask,
.pcName = "SecCalling", .pcName = "SecCalling",
.usStackDepth = configMINIMAL_STACK_SIZE, .usStackDepth = configMINIMAL_STACK_SIZE,
.pvParameters = NULL, .pvParameters = NULL,
.uxPriority = tskIDLE_PRIORITY, .uxPriority = tskIDLE_PRIORITY,
.puxStackBuffer = xSecureCallingTaskStack, .puxStackBuffer = xSecureCallingTaskStack,
.xRegions = { .xRegions =
{ ulNonSecureCounter, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER }, {
{ 0, 0, 0 }, { ulNonSecureCounter, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
{ 0, 0, 0 }, { 0, 0, 0 },
} { 0, 0, 0 },
}; }
};
/* Create an unprivileged task which calls secure functions. */ /* Create an unprivileged task which calls secure functions. */
xTaskCreateRestricted( &( xSecureCallingTaskParameters ), NULL ); xTaskCreateRestricted( &( xSecureCallingTaskParameters ), NULL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvCallback( void ) static void prvCallback( void )
{ {
/* This function is called from the secure side. Just increment the counter /* This function is called from the secure side. Just increment the counter
* here. The check that this counter keeps incrementing is performed in the * here. The check that this counter keeps incrementing is performed in the
* prvSecureCallingTask. */ * prvSecureCallingTask. */
ulNonSecureCounter[ 0 ] += 1; ulNonSecureCounter[ 0 ] += 1;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvSecureCallingTask( void * pvParameters ) static void prvSecureCallingTask( void * pvParameters )
{ {
uint32_t ulLastSecureCounter = 0, ulLastNonSecureCounter = 0; uint32_t ulLastSecureCounter = 0, ulLastNonSecureCounter = 0;
uint32_t ulCurrentSecureCounter = 0; uint32_t ulCurrentSecureCounter = 0;
/* This task calls secure side functions. So allocate a secure context for /* This task calls secure side functions. So allocate a secure context for
* it. */ * it. */
portALLOCATE_SECURE_CONTEXT( configMINIMAL_SECURE_STACK_SIZE ); portALLOCATE_SECURE_CONTEXT( configMINIMAL_SECURE_STACK_SIZE );
for( ; ; ) for( ; ; )
{ {
/* Call the secure side function. It does two things: /* Call the secure side function. It does two things:
* - It calls the supplied function (prvCallback) which in turn * - It calls the supplied function (prvCallback) which in turn
* increments the non-secure counter. * increments the non-secure counter.
* - It increments the secure counter and returns the incremented value. * - It increments the secure counter and returns the incremented value.
* Therefore at the end of this function call both the secure and * Therefore at the end of this function call both the secure and
* non-secure counters must have been incremented. * non-secure counters must have been incremented.
*/ */
ulCurrentSecureCounter = NSCFunction( prvCallback ); ulCurrentSecureCounter = NSCFunction( prvCallback );
/* Make sure that both the counters are incremented. */ /* Make sure that both the counters are incremented. */
configASSERT( ulCurrentSecureCounter == ulLastSecureCounter + 1 ); configASSERT( ulCurrentSecureCounter == ulLastSecureCounter + 1 );
configASSERT( ulNonSecureCounter[ 0 ] == ulLastNonSecureCounter + 1 ); configASSERT( ulNonSecureCounter[ 0 ] == ulLastNonSecureCounter + 1 );
/* Update the last values for both the counters. */ /* Update the last values for both the counters. */
ulLastSecureCounter = ulCurrentSecureCounter; ulLastSecureCounter = ulCurrentSecureCounter;
ulLastNonSecureCounter = ulNonSecureCounter[ 0 ]; ulLastNonSecureCounter = ulNonSecureCounter[ 0 ];
/* Wait for a second. */ /* Wait for a second. */
vTaskDelay( pdMS_TO_TICKS( 1000 ) ); vTaskDelay( pdMS_TO_TICKS( 1000 ) );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -28,23 +28,23 @@
/** /**
* Creates six tasks that operate on three queues as follows: * Creates six tasks that operate on three queues as follows:
* *
* The first two tasks send and receive an incrementing number to/from a queue. * The first two tasks send and receive an incrementing number to/from a queue.
* One task acts as a producer and the other as the consumer. The consumer is a * One task acts as a producer and the other as the consumer. The consumer is a
* higher priority than the producer and is set to block on queue reads. The queue * higher priority than the producer and is set to block on queue reads. The queue
* only has space for one item - as soon as the producer posts a message on the * only has space for one item - as soon as the producer posts a message on the
* queue the consumer will unblock, pre-empt the producer, and remove the item. * queue the consumer will unblock, pre-empt the producer, and remove the item.
* *
* The second two tasks work the other way around. Again the queue used only has * The second two tasks work the other way around. Again the queue used only has
* enough space for one item. This time the consumer has a lower priority than the * enough space for one item. This time the consumer has a lower priority than the
* producer. The producer will try to post on the queue blocking when the queue is * producer. The producer will try to post on the queue blocking when the queue is
* full. When the consumer wakes it will remove the item from the queue, causing * full. When the consumer wakes it will remove the item from the queue, causing
* the producer to unblock, pre-empt the consumer, and immediately re-fill the * the producer to unblock, pre-empt the consumer, and immediately re-fill the
* queue. * queue.
* *
* The last two tasks use the same queue producer and consumer functions. This time the queue has * The last two tasks use the same queue producer and consumer functions. This time the queue has
* enough space for lots of items and the tasks operate at the same priority. The * enough space for lots of items and the tasks operate at the same priority. The
* producer will execute, placing items into the queue. The consumer will start * producer will execute, placing items into the queue. The consumer will start
* executing when either the queue becomes full (causing the producer to block) or * executing when either the queue becomes full (causing the producer to block) or
* a context switch occurs (tasks of the same priority will time slice). * a context switch occurs (tasks of the same priority will time slice).
* *
* \page BlockQC blockQ.c * \page BlockQC blockQ.c
@ -53,21 +53,21 @@
*/ */
/* /*
Changes from V1.00: * Changes from V1.00:
*
+ Reversed the priority and block times of the second two demo tasks so + Reversed the priority and block times of the second two demo tasks so
they operate as per the description above. + they operate as per the description above.
+
Changes from V2.0.0 + Changes from V2.0.0
+
+ Delay periods are now specified using variables and constants of + Delay periods are now specified using variables and constants of
TickType_t rather than unsigned long. + TickType_t rather than unsigned long.
+
Changes from V4.0.2 + Changes from V4.0.2
+
+ The second set of tasks were created the wrong way around. This has been + The second set of tasks were created the wrong way around. This has been
corrected. + corrected.
*/ */
#include <stdlib.h> #include <stdlib.h>
@ -81,228 +81,228 @@ Changes from V4.0.2
#include "BlockQ.h" #include "BlockQ.h"
#include "print.h" #include "print.h"
#define blckqSTACK_SIZE ( ( unsigned short ) configMINIMAL_STACK_SIZE ) #define blckqSTACK_SIZE ( ( unsigned short ) configMINIMAL_STACK_SIZE )
#define blckqNUM_TASK_SETS ( 3 ) #define blckqNUM_TASK_SETS ( 3 )
/* Structure used to pass parameters to the blocking queue tasks. */ /* Structure used to pass parameters to the blocking queue tasks. */
typedef struct BLOCKING_QUEUE_PARAMETERS typedef struct BLOCKING_QUEUE_PARAMETERS
{ {
QueueHandle_t xQueue; /*< The queue to be used by the task. */ QueueHandle_t xQueue; /*< The queue to be used by the task. */
TickType_t xBlockTime; /*< The block time to use on queue reads/writes. */ TickType_t xBlockTime; /*< The block time to use on queue reads/writes. */
volatile short *psCheckVariable; /*< Incremented on each successful cycle to check the task is still running. */ volatile short * psCheckVariable; /*< Incremented on each successful cycle to check the task is still running. */
} xBlockingQueueParameters; } xBlockingQueueParameters;
/* Task function that creates an incrementing number and posts it on a queue. */ /* Task function that creates an incrementing number and posts it on a queue. */
static void vBlockingQueueProducer( void *pvParameters ); static void vBlockingQueueProducer( void * pvParameters );
/* Task function that removes the incrementing number from a queue and checks that /* Task function that removes the incrementing number from a queue and checks that
it is the expected number. */ * it is the expected number. */
static void vBlockingQueueConsumer( void *pvParameters ); static void vBlockingQueueConsumer( void * pvParameters );
/* Variables which are incremented each time an item is removed from a queue, and /* Variables which are incremented each time an item is removed from a queue, and
found to be the expected value. * found to be the expected value.
These are used to check that the tasks are still running. */ * These are used to check that the tasks are still running. */
static volatile short sBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 }; static volatile short sBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 };
/* Variable which are incremented each time an item is posted on a queue. These /* Variable which are incremented each time an item is posted on a queue. These
are used to check that the tasks are still running. */ * are used to check that the tasks are still running. */
static volatile short sBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 }; static volatile short sBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 };
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vStartBlockingQueueTasks( unsigned portBASE_TYPE uxPriority ) void vStartBlockingQueueTasks( unsigned portBASE_TYPE uxPriority )
{ {
xBlockingQueueParameters *pxQueueParameters1, *pxQueueParameters2; xBlockingQueueParameters * pxQueueParameters1, * pxQueueParameters2;
xBlockingQueueParameters *pxQueueParameters3, *pxQueueParameters4; xBlockingQueueParameters * pxQueueParameters3, * pxQueueParameters4;
xBlockingQueueParameters *pxQueueParameters5, *pxQueueParameters6; xBlockingQueueParameters * pxQueueParameters5, * pxQueueParameters6;
const unsigned portBASE_TYPE uxQueueSize1 = 1, uxQueueSize5 = 5; const unsigned portBASE_TYPE uxQueueSize1 = 1, uxQueueSize5 = 5;
const TickType_t xBlockTime = ( TickType_t ) 1000 / portTICK_PERIOD_MS; const TickType_t xBlockTime = ( TickType_t ) 1000 / portTICK_PERIOD_MS;
const TickType_t xDontBlock = ( TickType_t ) 0; const TickType_t xDontBlock = ( TickType_t ) 0;
/* Create the first two tasks as described at the top of the file. */ /* Create the first two tasks as described at the top of the file. */
/* First create the structure used to pass parameters to the consumer tasks. */
pxQueueParameters1 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
/* Create the queue used by the first two tasks to pass the incrementing number. /* First create the structure used to pass parameters to the consumer tasks. */
Pass a pointer to the queue in the parameter structure. */ pxQueueParameters1 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters1->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
/* The consumer is created first so gets a block time as described above. */ /* Create the queue used by the first two tasks to pass the incrementing number.
pxQueueParameters1->xBlockTime = xBlockTime; * Pass a pointer to the queue in the parameter structure. */
pxQueueParameters1->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
/* Pass in the variable that this task is going to increment so we can check it /* The consumer is created first so gets a block time as described above. */
is still running. */ pxQueueParameters1->xBlockTime = xBlockTime;
pxQueueParameters1->psCheckVariable = &( sBlockingConsumerCount[ 0 ] );
/* Create the structure used to pass parameters to the producer task. */
pxQueueParameters2 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
/* Pass the queue to this task also, using the parameter structure. */ /* Pass in the variable that this task is going to increment so we can check it
pxQueueParameters2->xQueue = pxQueueParameters1->xQueue; * is still running. */
pxQueueParameters1->psCheckVariable = &( sBlockingConsumerCount[ 0 ] );
/* The producer is not going to block - as soon as it posts the consumer will /* Create the structure used to pass parameters to the producer task. */
wake and remove the item so the producer should always have room to post. */ pxQueueParameters2 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters2->xBlockTime = xDontBlock;
/* Pass in the variable that this task is going to increment so we can check /* Pass the queue to this task also, using the parameter structure. */
it is still running. */ pxQueueParameters2->xQueue = pxQueueParameters1->xQueue;
pxQueueParameters2->psCheckVariable = &( sBlockingProducerCount[ 0 ] );
/* The producer is not going to block - as soon as it posts the consumer will
* wake and remove the item so the producer should always have room to post. */
pxQueueParameters2->xBlockTime = xDontBlock;
/* Pass in the variable that this task is going to increment so we can check
* it is still running. */
pxQueueParameters2->psCheckVariable = &( sBlockingProducerCount[ 0 ] );
/* Note the producer has a lower priority than the consumer when the tasks are /* Note the producer has a lower priority than the consumer when the tasks are
spawned. */ * spawned. */
xTaskCreate( vBlockingQueueConsumer, "QConsB1", blckqSTACK_SIZE, ( void * ) pxQueueParameters1, uxPriority, NULL ); xTaskCreate( vBlockingQueueConsumer, "QConsB1", blckqSTACK_SIZE, ( void * ) pxQueueParameters1, uxPriority, NULL );
xTaskCreate( vBlockingQueueProducer, "QProdB2", blckqSTACK_SIZE, ( void * ) pxQueueParameters2, tskIDLE_PRIORITY, NULL ); xTaskCreate( vBlockingQueueProducer, "QProdB2", blckqSTACK_SIZE, ( void * ) pxQueueParameters2, tskIDLE_PRIORITY, NULL );
/* Create the second two tasks as described at the top of the file. This uses
the same mechanism but reverses the task priorities. */
pxQueueParameters3 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters3->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
pxQueueParameters3->xBlockTime = xDontBlock;
pxQueueParameters3->psCheckVariable = &( sBlockingProducerCount[ 1 ] );
pxQueueParameters4 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters4->xQueue = pxQueueParameters3->xQueue;
pxQueueParameters4->xBlockTime = xBlockTime;
pxQueueParameters4->psCheckVariable = &( sBlockingConsumerCount[ 1 ] );
xTaskCreate( vBlockingQueueProducer, "QProdB3", blckqSTACK_SIZE, ( void * ) pxQueueParameters3, tskIDLE_PRIORITY, NULL );
xTaskCreate( vBlockingQueueConsumer, "QConsB4", blckqSTACK_SIZE, ( void * ) pxQueueParameters4, uxPriority, NULL );
/* Create the last two tasks as described above. The mechanism is again just /* Create the second two tasks as described at the top of the file. This uses
the same. This time both parameter structures are given a block time. */ * the same mechanism but reverses the task priorities. */
pxQueueParameters5 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters5->xQueue = xQueueCreate( uxQueueSize5, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
pxQueueParameters5->xBlockTime = xBlockTime;
pxQueueParameters5->psCheckVariable = &( sBlockingProducerCount[ 2 ] );
pxQueueParameters6 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) ); pxQueueParameters3 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters6->xQueue = pxQueueParameters5->xQueue; pxQueueParameters3->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
pxQueueParameters6->xBlockTime = xBlockTime; pxQueueParameters3->xBlockTime = xDontBlock;
pxQueueParameters6->psCheckVariable = &( sBlockingConsumerCount[ 2 ] ); pxQueueParameters3->psCheckVariable = &( sBlockingProducerCount[ 1 ] );
xTaskCreate( vBlockingQueueProducer, "QProdB5", blckqSTACK_SIZE, ( void * ) pxQueueParameters5, tskIDLE_PRIORITY, NULL ); pxQueueParameters4 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
xTaskCreate( vBlockingQueueConsumer, "QConsB6", blckqSTACK_SIZE, ( void * ) pxQueueParameters6, tskIDLE_PRIORITY, NULL ); pxQueueParameters4->xQueue = pxQueueParameters3->xQueue;
pxQueueParameters4->xBlockTime = xBlockTime;
pxQueueParameters4->psCheckVariable = &( sBlockingConsumerCount[ 1 ] );
xTaskCreate( vBlockingQueueProducer, "QProdB3", blckqSTACK_SIZE, ( void * ) pxQueueParameters3, tskIDLE_PRIORITY, NULL );
xTaskCreate( vBlockingQueueConsumer, "QConsB4", blckqSTACK_SIZE, ( void * ) pxQueueParameters4, uxPriority, NULL );
/* Create the last two tasks as described above. The mechanism is again just
* the same. This time both parameter structures are given a block time. */
pxQueueParameters5 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters5->xQueue = xQueueCreate( uxQueueSize5, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
pxQueueParameters5->xBlockTime = xBlockTime;
pxQueueParameters5->psCheckVariable = &( sBlockingProducerCount[ 2 ] );
pxQueueParameters6 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters6->xQueue = pxQueueParameters5->xQueue;
pxQueueParameters6->xBlockTime = xBlockTime;
pxQueueParameters6->psCheckVariable = &( sBlockingConsumerCount[ 2 ] );
xTaskCreate( vBlockingQueueProducer, "QProdB5", blckqSTACK_SIZE, ( void * ) pxQueueParameters5, tskIDLE_PRIORITY, NULL );
xTaskCreate( vBlockingQueueConsumer, "QConsB6", blckqSTACK_SIZE, ( void * ) pxQueueParameters6, tskIDLE_PRIORITY, NULL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vBlockingQueueProducer( void *pvParameters ) static void vBlockingQueueProducer( void * pvParameters )
{ {
unsigned short usValue = 0; unsigned short usValue = 0;
xBlockingQueueParameters *pxQueueParameters; xBlockingQueueParameters * pxQueueParameters;
const char * const pcTaskStartMsg = "Blocking queue producer started.\r\n"; const char * const pcTaskStartMsg = "Blocking queue producer started.\r\n";
const char * const pcTaskErrorMsg = "Could not post on blocking queue\r\n"; const char * const pcTaskErrorMsg = "Could not post on blocking queue\r\n";
short sErrorEverOccurred = pdFALSE; short sErrorEverOccurred = pdFALSE;
pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters; pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
for( ;; ) for( ; ; )
{ {
if( xQueueSendToBack( pxQueueParameters->xQueue, ( void * ) &usValue, pxQueueParameters->xBlockTime ) != pdPASS ) if( xQueueSendToBack( pxQueueParameters->xQueue, ( void * ) &usValue, pxQueueParameters->xBlockTime ) != pdPASS )
{ {
vPrintDisplayMessage( &pcTaskErrorMsg ); vPrintDisplayMessage( &pcTaskErrorMsg );
sErrorEverOccurred = pdTRUE; sErrorEverOccurred = pdTRUE;
} }
else else
{ {
/* We have successfully posted a message, so increment the variable /* We have successfully posted a message, so increment the variable
used to check we are still running. */ * used to check we are still running. */
if( sErrorEverOccurred == pdFALSE ) if( sErrorEverOccurred == pdFALSE )
{ {
( *pxQueueParameters->psCheckVariable )++; ( *pxQueueParameters->psCheckVariable )++;
} }
/* Increment the variable we are going to post next time round. The /* Increment the variable we are going to post next time round. The
consumer will expect the numbers to follow in numerical order. */ * consumer will expect the numbers to follow in numerical order. */
++usValue; ++usValue;
} }
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vBlockingQueueConsumer( void *pvParameters ) static void vBlockingQueueConsumer( void * pvParameters )
{ {
unsigned short usData, usExpectedValue = 0; unsigned short usData, usExpectedValue = 0;
xBlockingQueueParameters *pxQueueParameters; xBlockingQueueParameters * pxQueueParameters;
const char * const pcTaskStartMsg = "Blocking queue consumer started.\r\n"; const char * const pcTaskStartMsg = "Blocking queue consumer started.\r\n";
const char * const pcTaskErrorMsg = "Incorrect value received on blocking queue.\r\n"; const char * const pcTaskErrorMsg = "Incorrect value received on blocking queue.\r\n";
short sErrorEverOccurred = pdFALSE; short sErrorEverOccurred = pdFALSE;
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters; pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
for( ;; ) for( ; ; )
{ {
if( xQueueReceive( pxQueueParameters->xQueue, &usData, pxQueueParameters->xBlockTime ) == pdPASS ) if( xQueueReceive( pxQueueParameters->xQueue, &usData, pxQueueParameters->xBlockTime ) == pdPASS )
{ {
if( usData != usExpectedValue ) if( usData != usExpectedValue )
{ {
vPrintDisplayMessage( &pcTaskErrorMsg ); vPrintDisplayMessage( &pcTaskErrorMsg );
/* Catch-up. */ /* Catch-up. */
usExpectedValue = usData; usExpectedValue = usData;
sErrorEverOccurred = pdTRUE; sErrorEverOccurred = pdTRUE;
} }
else else
{ {
/* We have successfully received a message, so increment the /* We have successfully received a message, so increment the
variable used to check we are still running. */ * variable used to check we are still running. */
if( sErrorEverOccurred == pdFALSE ) if( sErrorEverOccurred == pdFALSE )
{ {
( *pxQueueParameters->psCheckVariable )++; ( *pxQueueParameters->psCheckVariable )++;
} }
/* Increment the value we expect to remove from the queue next time /* Increment the value we expect to remove from the queue next time
round. */ * round. */
++usExpectedValue; ++usExpectedValue;
} }
} }
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running. */ /* This is called to check that all the created tasks are still running. */
portBASE_TYPE xAreBlockingQueuesStillRunning( void ) portBASE_TYPE xAreBlockingQueuesStillRunning( void )
{ {
static short sLastBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 }; static short sLastBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 };
static short sLastBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 }; static short sLastBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 };
portBASE_TYPE xReturn = pdPASS, xTasks; portBASE_TYPE xReturn = pdPASS, xTasks;
/* Not too worried about mutual exclusion on these variables as they are 16 /* Not too worried about mutual exclusion on these variables as they are 16
bits and we are only reading them. We also only care to see if they have * bits and we are only reading them. We also only care to see if they have
changed or not. * changed or not.
*
Loop through each check variable and return pdFALSE if any are found not * Loop through each check variable and return pdFALSE if any are found not
to have changed since the last call. */ * to have changed since the last call. */
for( xTasks = 0; xTasks < blckqNUM_TASK_SETS; xTasks++ ) for( xTasks = 0; xTasks < blckqNUM_TASK_SETS; xTasks++ )
{ {
if( sBlockingConsumerCount[ xTasks ] == sLastBlockingConsumerCount[ xTasks ] ) if( sBlockingConsumerCount[ xTasks ] == sLastBlockingConsumerCount[ xTasks ] )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
} }
sLastBlockingConsumerCount[ xTasks ] = sBlockingConsumerCount[ xTasks ];
sLastBlockingConsumerCount[ xTasks ] = sBlockingConsumerCount[ xTasks ];
if( sBlockingProducerCount[ xTasks ] == sLastBlockingProducerCount[ xTasks ] ) if( sBlockingProducerCount[ xTasks ] == sLastBlockingProducerCount[ xTasks ] )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
} }
sLastBlockingProducerCount[ xTasks ] = sBlockingProducerCount[ xTasks ];
}
return xReturn; sLastBlockingProducerCount[ xTasks ] = sBlockingProducerCount[ xTasks ];
}
return xReturn;
} }

View file

@ -27,24 +27,24 @@
/** /**
* This is a very simple queue test. See the BlockQ. c documentation for a more * This is a very simple queue test. See the BlockQ. c documentation for a more
* comprehensive version. * comprehensive version.
* *
* Creates two tasks that communicate over a single queue. One task acts as a * Creates two tasks that communicate over a single queue. One task acts as a
* producer, the other a consumer. * producer, the other a consumer.
* *
* The producer loops for three iteration, posting an incrementing number onto the * The producer loops for three iteration, posting an incrementing number onto the
* queue each cycle. It then delays for a fixed period before doing exactly the * queue each cycle. It then delays for a fixed period before doing exactly the
* same again. * same again.
* *
* The consumer loops emptying the queue. Each item removed from the queue is * The consumer loops emptying the queue. Each item removed from the queue is
* checked to ensure it contains the expected value. When the queue is empty it * checked to ensure it contains the expected value. When the queue is empty it
* blocks for a fixed period, then does the same again. * blocks for a fixed period, then does the same again.
* *
* All queue access is performed without blocking. The consumer completely empties * All queue access is performed without blocking. The consumer completely empties
* the queue each time it runs so the producer should never find the queue full. * the queue each time it runs so the producer should never find the queue full.
* *
* An error is flagged if the consumer obtains an unexpected value or the producer * An error is flagged if the consumer obtains an unexpected value or the producer
* find the queue is full. * find the queue is full.
* *
* \page PollQC pollQ.c * \page PollQC pollQ.c
@ -53,11 +53,11 @@
*/ */
/* /*
Changes from V2.0.0 * Changes from V2.0.0
*
+ Delay periods are now specified using variables and constants of + Delay periods are now specified using variables and constants of
TickType_t rather than unsigned long. + TickType_t rather than unsigned long.
*/ */
#include <stdlib.h> #include <stdlib.h>
@ -70,13 +70,13 @@ Changes from V2.0.0
/* Demo program include files. */ /* Demo program include files. */
#include "PollQ.h" #include "PollQ.h"
#define pollqSTACK_SIZE ( ( unsigned short ) configMINIMAL_STACK_SIZE ) #define pollqSTACK_SIZE ( ( unsigned short ) configMINIMAL_STACK_SIZE )
/* The task that posts the incrementing number onto the queue. */ /* The task that posts the incrementing number onto the queue. */
static void vPolledQueueProducer( void *pvParameters ); static void vPolledQueueProducer( void * pvParameters );
/* The task that empties the queue. */ /* The task that empties the queue. */
static void vPolledQueueConsumer( void *pvParameters ); static void vPolledQueueConsumer( void * pvParameters );
/* Variables that are used to check that the tasks are still running with no errors. */ /* Variables that are used to check that the tasks are still running with no errors. */
static volatile short sPollingConsumerCount = 0, sPollingProducerCount = 0; static volatile short sPollingConsumerCount = 0, sPollingProducerCount = 0;
@ -84,137 +84,139 @@ static volatile short sPollingConsumerCount = 0, sPollingProducerCount = 0;
void vStartPolledQueueTasks( unsigned portBASE_TYPE uxPriority ) void vStartPolledQueueTasks( unsigned portBASE_TYPE uxPriority )
{ {
static QueueHandle_t xPolledQueue; static QueueHandle_t xPolledQueue;
const unsigned portBASE_TYPE uxQueueSize = 10; const unsigned portBASE_TYPE uxQueueSize = 10;
/* Create the queue used by the producer and consumer. */ /* Create the queue used by the producer and consumer. */
xPolledQueue = xQueueCreate( uxQueueSize, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) ); xPolledQueue = xQueueCreate( uxQueueSize, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
/* Spawn the producer and consumer. */ /* Spawn the producer and consumer. */
xTaskCreate( vPolledQueueConsumer, "QConsNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, NULL ); xTaskCreate( vPolledQueueConsumer, "QConsNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, NULL );
xTaskCreate( vPolledQueueProducer, "QProdNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, NULL ); xTaskCreate( vPolledQueueProducer, "QProdNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, NULL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vPolledQueueProducer( void *pvParameters ) static void vPolledQueueProducer( void * pvParameters )
{ {
unsigned short usValue = 0, usLoop; unsigned short usValue = 0, usLoop;
QueueHandle_t *pxQueue; QueueHandle_t * pxQueue;
const TickType_t xDelay = ( TickType_t ) 200 / portTICK_PERIOD_MS; const TickType_t xDelay = ( TickType_t ) 200 / portTICK_PERIOD_MS;
const unsigned short usNumToProduce = 3; const unsigned short usNumToProduce = 3;
const char * const pcTaskStartMsg = "Polled queue producer started.\r\n"; const char * const pcTaskStartMsg = "Polled queue producer started.\r\n";
const char * const pcTaskErrorMsg = "Could not post on polled queue.\r\n"; const char * const pcTaskErrorMsg = "Could not post on polled queue.\r\n";
short sError = pdFALSE; short sError = pdFALSE;
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
/* The queue being used is passed in as the parameter. */ /* The queue being used is passed in as the parameter. */
pxQueue = ( QueueHandle_t * ) pvParameters; pxQueue = ( QueueHandle_t * ) pvParameters;
for( ;; ) for( ; ; )
{ {
for( usLoop = 0; usLoop < usNumToProduce; ++usLoop ) for( usLoop = 0; usLoop < usNumToProduce; ++usLoop )
{ {
/* Send an incrementing number on the queue without blocking. */ /* Send an incrementing number on the queue without blocking. */
if( xQueueSendToBack( *pxQueue, ( void * ) &usValue, ( TickType_t ) 0 ) != pdPASS ) if( xQueueSendToBack( *pxQueue, ( void * ) &usValue, ( TickType_t ) 0 ) != pdPASS )
{ {
/* We should never find the queue full - this is an error. */ /* We should never find the queue full - this is an error. */
vPrintDisplayMessage( &pcTaskErrorMsg ); vPrintDisplayMessage( &pcTaskErrorMsg );
sError = pdTRUE; sError = pdTRUE;
} }
else else
{ {
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If an error has ever been recorded we stop incrementing the /* If an error has ever been recorded we stop incrementing the
check variable. */ * check variable. */
++sPollingProducerCount; ++sPollingProducerCount;
} }
/* Update the value we are going to post next time around. */ /* Update the value we are going to post next time around. */
++usValue; ++usValue;
} }
} }
/* Wait before we start posting again to ensure the consumer runs and /* Wait before we start posting again to ensure the consumer runs and
empties the queue. */ * empties the queue. */
vTaskDelay( xDelay ); vTaskDelay( xDelay );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vPolledQueueConsumer( void *pvParameters ) static void vPolledQueueConsumer( void * pvParameters )
{ {
unsigned short usData, usExpectedValue = 0; unsigned short usData, usExpectedValue = 0;
QueueHandle_t *pxQueue; QueueHandle_t * pxQueue;
const TickType_t xDelay = ( TickType_t ) 200 / portTICK_PERIOD_MS; const TickType_t xDelay = ( TickType_t ) 200 / portTICK_PERIOD_MS;
const char * const pcTaskStartMsg = "Polled queue consumer started.\r\n"; const char * const pcTaskStartMsg = "Polled queue consumer started.\r\n";
const char * const pcTaskErrorMsg = "Incorrect value received on polled queue.\r\n"; const char * const pcTaskErrorMsg = "Incorrect value received on polled queue.\r\n";
short sError = pdFALSE; short sError = pdFALSE;
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
/* The queue being used is passed in as the parameter. */ /* The queue being used is passed in as the parameter. */
pxQueue = ( QueueHandle_t * ) pvParameters; pxQueue = ( QueueHandle_t * ) pvParameters;
for( ;; ) for( ; ; )
{ {
/* Loop until the queue is empty. */ /* Loop until the queue is empty. */
while( uxQueueMessagesWaiting( *pxQueue ) ) while( uxQueueMessagesWaiting( *pxQueue ) )
{ {
if( xQueueReceive( *pxQueue, &usData, ( TickType_t ) 0 ) == pdPASS ) if( xQueueReceive( *pxQueue, &usData, ( TickType_t ) 0 ) == pdPASS )
{ {
if( usData != usExpectedValue ) if( usData != usExpectedValue )
{ {
/* This is not what we expected to receive so an error has /* This is not what we expected to receive so an error has
occurred. */ * occurred. */
vPrintDisplayMessage( &pcTaskErrorMsg ); vPrintDisplayMessage( &pcTaskErrorMsg );
sError = pdTRUE; sError = pdTRUE;
/* Catch-up to the value we received so our next expected value
should again be correct. */
usExpectedValue = usData;
}
else
{
if( sError == pdFALSE )
{
/* Only increment the check variable if no errors have
occurred. */
++sPollingConsumerCount;
}
}
++usExpectedValue;
}
}
/* Now the queue is empty we block, allowing the producer to place more /* Catch-up to the value we received so our next expected value
items in the queue. */ * should again be correct. */
vTaskDelay( xDelay ); usExpectedValue = usData;
} }
else
{
if( sError == pdFALSE )
{
/* Only increment the check variable if no errors have
* occurred. */
++sPollingConsumerCount;
}
}
++usExpectedValue;
}
}
/* Now the queue is empty we block, allowing the producer to place more
* items in the queue. */
vTaskDelay( xDelay );
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running with no errors. */ /* This is called to check that all the created tasks are still running with no errors. */
portBASE_TYPE xArePollingQueuesStillRunning( void ) portBASE_TYPE xArePollingQueuesStillRunning( void )
{ {
static short sLastPollingConsumerCount = 0, sLastPollingProducerCount = 0; static short sLastPollingConsumerCount = 0, sLastPollingProducerCount = 0;
portBASE_TYPE xReturn; portBASE_TYPE xReturn;
if( ( sLastPollingConsumerCount == sPollingConsumerCount ) || if( ( sLastPollingConsumerCount == sPollingConsumerCount ) ||
( sLastPollingProducerCount == sPollingProducerCount ) ( sLastPollingProducerCount == sPollingProducerCount )
) )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
} }
else else
{ {
xReturn = pdTRUE; xReturn = pdTRUE;
} }
sLastPollingConsumerCount = sPollingConsumerCount; sLastPollingConsumerCount = sPollingConsumerCount;
sLastPollingProducerCount = sPollingProducerCount; sLastPollingProducerCount = sPollingProducerCount;
return xReturn; return xReturn;
} }

View file

@ -19,72 +19,72 @@
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 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. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* *
* https://www.FreeRTOS.org * https://www.FreeRTOS.org
* https://github.com/FreeRTOS * https://github.com/FreeRTOS
* *
*/ */
/** /**
* Creates two tasks that operate on an interrupt driven serial port. A loopback * Creates two tasks that operate on an interrupt driven serial port. A loopback
* connector should be used so that everything that is transmitted is also received. * connector should be used so that everything that is transmitted is also received.
* The serial port does not use any flow control. On a standard 9way 'D' connector * The serial port does not use any flow control. On a standard 9way 'D' connector
* pins two and three should be connected together. * pins two and three should be connected together.
* *
* The first task repeatedly sends a string to a queue, character at a time. The * The first task repeatedly sends a string to a queue, character at a time. The
* serial port interrupt will empty the queue and transmit the characters. The * serial port interrupt will empty the queue and transmit the characters. The
* task blocks for a pseudo random period before resending the string. * task blocks for a pseudo random period before resending the string.
* *
* The second task blocks on a queue waiting for a character to be received. * The second task blocks on a queue waiting for a character to be received.
* Characters received by the serial port interrupt routine are posted onto the * Characters received by the serial port interrupt routine are posted onto the
* queue - unblocking the task making it ready to execute. If this is then the * queue - unblocking the task making it ready to execute. If this is then the
* highest priority task ready to run it will run immediately - with a context * highest priority task ready to run it will run immediately - with a context
* switch occurring at the end of the interrupt service routine. The task * switch occurring at the end of the interrupt service routine. The task
* receiving characters is spawned with a higher priority than the task * receiving characters is spawned with a higher priority than the task
* transmitting the characters. * transmitting the characters.
* *
* With the loop back connector in place, one task will transmit a string and the * With the loop back connector in place, one task will transmit a string and the
* other will immediately receive it. The receiving task knows the string it * other will immediately receive it. The receiving task knows the string it
* expects to receive so can detect an error. * expects to receive so can detect an error.
* *
* This also creates a third task. This is used to test semaphore usage from an * This also creates a third task. This is used to test semaphore usage from an
* ISR and does nothing interesting. * ISR and does nothing interesting.
* *
* \page ComTestC comtest.c * \page ComTestC comtest.c
* \ingroup DemoFiles * \ingroup DemoFiles
* <HR> * <HR>
*/ */
/* /*
Changes from V1.00: * Changes from V1.00:
*
+ The priority of the Rx task has been lowered. Received characters are + The priority of the Rx task has been lowered. Received characters are
now processed (read from the queue) at the idle priority, allowing low + now processed (read from the queue) at the idle priority, allowing low
priority tasks to run evenly at times of a high communications overhead. + priority tasks to run evenly at times of a high communications overhead.
+
Changes from V1.01: + Changes from V1.01:
+
+ The Tx task now waits a pseudo random time between transmissions. + The Tx task now waits a pseudo random time between transmissions.
Previously a fixed period was used but this was not such a good test as + Previously a fixed period was used but this was not such a good test as
interrupts fired at regular intervals. + interrupts fired at regular intervals.
+
Changes From V1.2.0: + Changes From V1.2.0:
+
+ Use vSerialPutString() instead of single character puts. + Use vSerialPutString() instead of single character puts.
+ Only stop the check variable incrementing after two consecutive errors. + Only stop the check variable incrementing after two consecutive errors.
+
Changed from V1.2.5 + Changed from V1.2.5
+
+ Made the Rx task 2 priorities higher than the Tx task. Previously it was + Made the Rx task 2 priorities higher than the Tx task. Previously it was
only 1. This is done to tie in better with the other demo application + only 1. This is done to tie in better with the other demo application
tasks. + tasks.
+
Changes from V2.0.0 + Changes from V2.0.0
+
+ Delay periods are now specified using variables and constants of + Delay periods are now specified using variables and constants of
TickType_t rather than unsigned long. + TickType_t rather than unsigned long.
+ Slight modification to task priorities. + Slight modification to task priorities.
+
*/ */
/* Scheduler include files. */ /* Scheduler include files. */
@ -99,34 +99,34 @@ Changes from V2.0.0
#include "print.h" #include "print.h"
/* The Tx task will transmit the sequence of characters at a pseudo random /* The Tx task will transmit the sequence of characters at a pseudo random
interval. This is the maximum and minimum block time between sends. */ * interval. This is the maximum and minimum block time between sends. */
#define comTX_MAX_BLOCK_TIME ( ( TickType_t ) 0x15e ) #define comTX_MAX_BLOCK_TIME ( ( TickType_t ) 0x15e )
#define comTX_MIN_BLOCK_TIME ( ( TickType_t ) 0xc8 ) #define comTX_MIN_BLOCK_TIME ( ( TickType_t ) 0xc8 )
#define comMAX_CONSECUTIVE_ERRORS ( 2 ) #define comMAX_CONSECUTIVE_ERRORS ( 2 )
#define comSTACK_SIZE ( ( unsigned short ) 256 ) #define comSTACK_SIZE ( ( unsigned short ) 256 )
#define comRX_RELATIVE_PRIORITY ( 1 ) #define comRX_RELATIVE_PRIORITY ( 1 )
/* Handle to the com port used by both tasks. */ /* Handle to the com port used by both tasks. */
static xComPortHandle xPort; static xComPortHandle xPort;
/* The transmit function as described at the top of the file. */ /* The transmit function as described at the top of the file. */
static void vComTxTask( void *pvParameters ); static void vComTxTask( void * pvParameters );
/* The receive function as described at the top of the file. */ /* The receive function as described at the top of the file. */
static void vComRxTask( void *pvParameters ); static void vComRxTask( void * pvParameters );
/* The semaphore test function as described at the top of the file. */ /* The semaphore test function as described at the top of the file. */
static void vSemTestTask( void * pvParameters ); static void vSemTestTask( void * pvParameters );
/* The string that is repeatedly transmitted. */ /* The string that is repeatedly transmitted. */
const char * const pcMessageToExchange = "Send this message over and over again to check communications interrupts. " const char * const pcMessageToExchange = "Send this message over and over again to check communications interrupts. "
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n"; "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n";
/* Variables that are incremented on each cycle of each task. These are used to /* Variables that are incremented on each cycle of each task. These are used to
check that both tasks are still executing. */ * check that both tasks are still executing. */
volatile short sTxCount = 0, sRxCount = 0, sSemCount = 0; volatile short sTxCount = 0, sRxCount = 0, sSemCount = 0;
/* The handle to the semaphore test task. */ /* The handle to the semaphore test task. */
@ -134,212 +134,217 @@ static TaskHandle_t xSemTestTaskHandle = NULL;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vStartComTestTasks( unsigned portBASE_TYPE uxPriority, eCOMPort ePort, eBaud eBaudRate ) void vStartComTestTasks( unsigned portBASE_TYPE uxPriority,
eCOMPort ePort,
eBaud eBaudRate )
{ {
const unsigned portBASE_TYPE uxBufferLength = 255; const unsigned portBASE_TYPE uxBufferLength = 255;
/* Initialise the com port then spawn both tasks. */ /* Initialise the com port then spawn both tasks. */
xPort = xSerialPortInit( ePort, eBaudRate, serNO_PARITY, serBITS_8, serSTOP_1, uxBufferLength ); xPort = xSerialPortInit( ePort, eBaudRate, serNO_PARITY, serBITS_8, serSTOP_1, uxBufferLength );
xTaskCreate( vComTxTask, "COMTx", comSTACK_SIZE, NULL, uxPriority, NULL ); xTaskCreate( vComTxTask, "COMTx", comSTACK_SIZE, NULL, uxPriority, NULL );
xTaskCreate( vComRxTask, "COMRx", comSTACK_SIZE, NULL, uxPriority + comRX_RELATIVE_PRIORITY, NULL ); xTaskCreate( vComRxTask, "COMRx", comSTACK_SIZE, NULL, uxPriority + comRX_RELATIVE_PRIORITY, NULL );
xTaskCreate( vSemTestTask, "ISRSem", comSTACK_SIZE, NULL, tskIDLE_PRIORITY, &xSemTestTaskHandle ); xTaskCreate( vSemTestTask, "ISRSem", comSTACK_SIZE, NULL, tskIDLE_PRIORITY, &xSemTestTaskHandle );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vComTxTask( void *pvParameters ) static void vComTxTask( void * pvParameters )
{ {
const char * const pcTaskStartMsg = "COM Tx task started.\r\n"; const char * const pcTaskStartMsg = "COM Tx task started.\r\n";
TickType_t xTimeToWait; TickType_t xTimeToWait;
/* Stop warnings. */ /* Stop warnings. */
( void ) pvParameters; ( void ) pvParameters;
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
for( ;; ) for( ; ; )
{ {
/* Send the string to the serial port. */ /* Send the string to the serial port. */
vSerialPutString( xPort, pcMessageToExchange, strlen( pcMessageToExchange ) ); vSerialPutString( xPort, pcMessageToExchange, strlen( pcMessageToExchange ) );
/* We have posted all the characters in the string - increment the variable /* We have posted all the characters in the string - increment the variable
used to check that this task is still running, then wait before re-sending * used to check that this task is still running, then wait before re-sending
the string. */ * the string. */
sTxCount++; sTxCount++;
xTimeToWait = xTaskGetTickCount(); xTimeToWait = xTaskGetTickCount();
/* Make sure we don't wait too long... */ /* Make sure we don't wait too long... */
xTimeToWait %= comTX_MAX_BLOCK_TIME; xTimeToWait %= comTX_MAX_BLOCK_TIME;
/* ...but we do want to wait. */ /* ...but we do want to wait. */
if( xTimeToWait < comTX_MIN_BLOCK_TIME ) if( xTimeToWait < comTX_MIN_BLOCK_TIME )
{ {
xTimeToWait = comTX_MIN_BLOCK_TIME; xTimeToWait = comTX_MIN_BLOCK_TIME;
} }
vTaskDelay( xTimeToWait ); vTaskDelay( xTimeToWait );
} }
} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */ } /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vComRxTask( void *pvParameters ) static void vComRxTask( void * pvParameters )
{ {
const char * const pcTaskStartMsg = "COM Rx task started.\r\n"; const char * const pcTaskStartMsg = "COM Rx task started.\r\n";
const char * const pcTaskErrorMsg = "COM read error\r\n"; const char * const pcTaskErrorMsg = "COM read error\r\n";
const char * const pcTaskRestartMsg = "COM resynced\r\n"; const char * const pcTaskRestartMsg = "COM resynced\r\n";
const char * const pcTaskTimeoutMsg = "COM Rx timed out\r\n"; const char * const pcTaskTimeoutMsg = "COM Rx timed out\r\n";
const TickType_t xBlockTime = ( TickType_t ) 0xffff / portTICK_PERIOD_MS; const TickType_t xBlockTime = ( TickType_t ) 0xffff / portTICK_PERIOD_MS;
const char *pcExpectedChar; const char * pcExpectedChar;
portBASE_TYPE xGotChar; portBASE_TYPE xGotChar;
char cRxedChar; char cRxedChar;
short sResyncRequired, sConsecutiveErrors, sLatchedError; short sResyncRequired, sConsecutiveErrors, sLatchedError;
/* Stop warnings. */ /* Stop warnings. */
( void ) pvParameters; ( void ) pvParameters;
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
/* The first expected character is the first character in the string. */
pcExpectedChar = pcMessageToExchange;
sResyncRequired = pdFALSE;
sConsecutiveErrors = 0;
sLatchedError = pdFALSE;
for( ;; ) /* The first expected character is the first character in the string. */
{ pcExpectedChar = pcMessageToExchange;
/* Receive a message from the com port interrupt routine. If a message is sResyncRequired = pdFALSE;
not yet available the call will block the task. */ sConsecutiveErrors = 0;
xGotChar = xSerialGetChar( xPort, &cRxedChar, xBlockTime ); sLatchedError = pdFALSE;
if( xGotChar == pdTRUE )
{
if( sResyncRequired == pdTRUE )
{
/* We got out of sequence and are waiting for the start of the next
transmission of the string. */
if( cRxedChar == '\n' )
{
/* This is the end of the message so we can start again - with
the first character in the string being the next thing we expect
to receive. */
pcExpectedChar = pcMessageToExchange;
sResyncRequired = pdFALSE;
/* Queue a message for printing to say that we are going to try for( ; ; )
again. */ {
vPrintDisplayMessage( &pcTaskRestartMsg ); /* Receive a message from the com port interrupt routine. If a message is
* not yet available the call will block the task. */
xGotChar = xSerialGetChar( xPort, &cRxedChar, xBlockTime );
/* Stop incrementing the check variable, if consecutive errors occur. */ if( xGotChar == pdTRUE )
sConsecutiveErrors++; {
if( sConsecutiveErrors >= comMAX_CONSECUTIVE_ERRORS ) if( sResyncRequired == pdTRUE )
{ {
sLatchedError = pdTRUE; /* We got out of sequence and are waiting for the start of the next
} * transmission of the string. */
} if( cRxedChar == '\n' )
} {
else /* This is the end of the message so we can start again - with
{ * the first character in the string being the next thing we expect
/* We have received a character, but is it the expected character? */ * to receive. */
if( cRxedChar != *pcExpectedChar ) pcExpectedChar = pcMessageToExchange;
{ sResyncRequired = pdFALSE;
/* This was not the expected character so post a message for
printing to say that an error has occurred. We will then wait
to resynchronise. */
vPrintDisplayMessage( &pcTaskErrorMsg );
sResyncRequired = pdTRUE;
}
else
{
/* This was the expected character so next time we will expect
the next character in the string. Wrap back to the beginning
of the string when the null terminator has been reached. */
pcExpectedChar++;
if( *pcExpectedChar == '\0' )
{
pcExpectedChar = pcMessageToExchange;
/* We have got through the entire string without error. */ /* Queue a message for printing to say that we are going to try
sConsecutiveErrors = 0; * again. */
} vPrintDisplayMessage( &pcTaskRestartMsg );
}
}
/* Increment the count that is used to check that this task is still /* Stop incrementing the check variable, if consecutive errors occur. */
running. This is only done if an error has never occurred. */ sConsecutiveErrors++;
if( sLatchedError == pdFALSE )
{ if( sConsecutiveErrors >= comMAX_CONSECUTIVE_ERRORS )
sRxCount++; {
} sLatchedError = pdTRUE;
} }
else }
{ }
vPrintDisplayMessage( &pcTaskTimeoutMsg ); else
} {
} /* We have received a character, but is it the expected character? */
if( cRxedChar != *pcExpectedChar )
{
/* This was not the expected character so post a message for
* printing to say that an error has occurred. We will then wait
* to resynchronise. */
vPrintDisplayMessage( &pcTaskErrorMsg );
sResyncRequired = pdTRUE;
}
else
{
/* This was the expected character so next time we will expect
* the next character in the string. Wrap back to the beginning
* of the string when the null terminator has been reached. */
pcExpectedChar++;
if( *pcExpectedChar == '\0' )
{
pcExpectedChar = pcMessageToExchange;
/* We have got through the entire string without error. */
sConsecutiveErrors = 0;
}
}
}
/* Increment the count that is used to check that this task is still
* running. This is only done if an error has never occurred. */
if( sLatchedError == pdFALSE )
{
sRxCount++;
}
}
else
{
vPrintDisplayMessage( &pcTaskTimeoutMsg );
}
}
} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */ } /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vSemTestTask( void * pvParameters ) static void vSemTestTask( void * pvParameters )
{ {
const char * const pcTaskStartMsg = "ISR Semaphore test started.\r\n"; const char * const pcTaskStartMsg = "ISR Semaphore test started.\r\n";
portBASE_TYPE xError = pdFALSE; portBASE_TYPE xError = pdFALSE;
/* Stop warnings. */ /* Stop warnings. */
( void ) pvParameters; ( void ) pvParameters;
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
for( ;; ) for( ; ; )
{ {
if( xSerialWaitForSemaphore( xPort ) ) if( xSerialWaitForSemaphore( xPort ) )
{ {
if( xError == pdFALSE ) if( xError == pdFALSE )
{ {
sSemCount++; sSemCount++;
} }
} }
else else
{ {
xError = pdTRUE; xError = pdTRUE;
} }
} }
} /*lint !e715 !e830 !e818 pvParameters not used but function prototype must be standard for task function. */ } /*lint !e715 !e830 !e818 pvParameters not used but function prototype must be standard for task function. */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running. */ /* This is called to check that all the created tasks are still running. */
portBASE_TYPE xAreComTestTasksStillRunning( void ) portBASE_TYPE xAreComTestTasksStillRunning( void )
{ {
static short sLastTxCount = 0, sLastRxCount = 0, sLastSemCount = 0; static short sLastTxCount = 0, sLastRxCount = 0, sLastSemCount = 0;
portBASE_TYPE xReturn; portBASE_TYPE xReturn;
/* Not too worried about mutual exclusion on these variables as they are 16 /* Not too worried about mutual exclusion on these variables as they are 16
bits and we are only reading them. We also only care to see if they have * bits and we are only reading them. We also only care to see if they have
changed or not. */ * changed or not. */
if( ( sTxCount == sLastTxCount ) || ( sRxCount == sLastRxCount ) || ( sSemCount == sLastSemCount ) ) if( ( sTxCount == sLastTxCount ) || ( sRxCount == sLastRxCount ) || ( sSemCount == sLastSemCount ) )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
} }
else else
{ {
xReturn = pdTRUE; xReturn = pdTRUE;
} }
sLastTxCount = sTxCount; sLastTxCount = sTxCount;
sLastRxCount = sRxCount; sLastRxCount = sRxCount;
sLastSemCount = sSemCount; sLastSemCount = sSemCount;
return xReturn; return xReturn;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vComTestUnsuspendTask( void ) void vComTestUnsuspendTask( void )
{ {
/* The task that is suspended on the semaphore will be referenced from the /* The task that is suspended on the semaphore will be referenced from the
Suspended list as it is blocking indefinitely. This call just checks that * Suspended list as it is blocking indefinitely. This call just checks that
the kernel correctly detects this and does not attempt to unsuspend the * the kernel correctly detects this and does not attempt to unsuspend the
task. */ * task. */
xTaskResumeFromISR( xSemTestTaskHandle ); xTaskResumeFromISR( xSemTestTaskHandle );
} }

View file

@ -25,17 +25,17 @@
*/ */
/** /**
* Create a single persistent task which periodically dynamically creates another * Create a single persistent task which periodically dynamically creates another
* four tasks. The original task is called the creator task, the four tasks it * four tasks. The original task is called the creator task, the four tasks it
* creates are called suicidal tasks. * creates are called suicidal tasks.
* *
* Two of the created suicidal tasks kill one other suicidal task before killing * Two of the created suicidal tasks kill one other suicidal task before killing
* themselves - leaving just the original task remaining. * themselves - leaving just the original task remaining.
* *
* The creator task must be spawned after all of the other demo application tasks * The creator task must be spawned after all of the other demo application tasks
* as it keeps a check on the number of tasks under the scheduler control. The * as it keeps a check on the number of tasks under the scheduler control. The
* number of tasks it expects to see running should never be greater than the * number of tasks it expects to see running should never be greater than the
* number of tasks that were in existence when the creator task was spawned, plus * number of tasks that were in existence when the creator task was spawned, plus
* one set of four suicidal tasks. If this number is exceeded an error is flagged. * one set of four suicidal tasks. If this number is exceeded an error is flagged.
* *
* \page DeathC death.c * \page DeathC death.c
@ -44,11 +44,11 @@
*/ */
/* /*
Changes from V2.0.0 * Changes from V2.0.0
*
+ Delay periods are now specified using variables and constants of + Delay periods are now specified using variables and constants of
TickType_t rather than unsigned long. + TickType_t rather than unsigned long.
*/ */
#include <stdlib.h> #include <stdlib.h>
@ -60,66 +60,66 @@ Changes from V2.0.0
#include "death.h" #include "death.h"
#include "print.h" #include "print.h"
#define deathSTACK_SIZE ( ( unsigned short ) 512 ) #define deathSTACK_SIZE ( ( unsigned short ) 512 )
/* The task originally created which is responsible for periodically dynamically /* The task originally created which is responsible for periodically dynamically
creating another four tasks. */ * creating another four tasks. */
static void vCreateTasks( void *pvParameters ); static void vCreateTasks( void * pvParameters );
/* The task function of the dynamically created tasks. */ /* The task function of the dynamically created tasks. */
static void vSuicidalTask( void *pvParameters ); static void vSuicidalTask( void * pvParameters );
/* A variable which is incremented every time the dynamic tasks are created. This /* A variable which is incremented every time the dynamic tasks are created. This
is used to check that the task is still running. */ * is used to check that the task is still running. */
static volatile short sCreationCount = 0; static volatile short sCreationCount = 0;
/* Used to store the number of tasks that were originally running so the creator /* Used to store the number of tasks that were originally running so the creator
task can tell if any of the suicidal tasks have failed to die. */ * task can tell if any of the suicidal tasks have failed to die. */
static volatile unsigned portBASE_TYPE uxTasksRunningAtStart = 0; static volatile unsigned portBASE_TYPE uxTasksRunningAtStart = 0;
static const unsigned portBASE_TYPE uxMaxNumberOfExtraTasksRunning = 5; static const unsigned portBASE_TYPE uxMaxNumberOfExtraTasksRunning = 5;
/* Used to store a handle to the tasks that should be killed by a suicidal task, /* Used to store a handle to the tasks that should be killed by a suicidal task,
before it kills itself. */ * before it kills itself. */
TaskHandle_t xCreatedTask1, xCreatedTask2; TaskHandle_t xCreatedTask1, xCreatedTask2;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vCreateSuicidalTasks( unsigned portBASE_TYPE uxPriority ) void vCreateSuicidalTasks( unsigned portBASE_TYPE uxPriority )
{ {
unsigned portBASE_TYPE *puxPriority; unsigned portBASE_TYPE * puxPriority;
/* Create the Creator tasks - passing in as a parameter the priority at which /* Create the Creator tasks - passing in as a parameter the priority at which
the suicidal tasks should be created. */ * the suicidal tasks should be created. */
puxPriority = ( unsigned portBASE_TYPE * ) pvPortMalloc( sizeof( unsigned portBASE_TYPE ) ); puxPriority = ( unsigned portBASE_TYPE * ) pvPortMalloc( sizeof( unsigned portBASE_TYPE ) );
*puxPriority = uxPriority; *puxPriority = uxPriority;
xTaskCreate( vCreateTasks, "CREATOR", deathSTACK_SIZE, ( void * ) puxPriority, uxPriority, NULL ); xTaskCreate( vCreateTasks, "CREATOR", deathSTACK_SIZE, ( void * ) puxPriority, uxPriority, NULL );
/* Record the number of tasks that are running now so we know if any of the /* Record the number of tasks that are running now so we know if any of the
suicidal tasks have failed to be killed. */ * suicidal tasks have failed to be killed. */
uxTasksRunningAtStart = uxTaskGetNumberOfTasks(); uxTasksRunningAtStart = uxTaskGetNumberOfTasks();
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vSuicidalTask( void *pvParameters ) static void vSuicidalTask( void * pvParameters )
{ {
portDOUBLE d1, d2; portDOUBLE d1, d2;
TaskHandle_t xTaskToKill; TaskHandle_t xTaskToKill;
const TickType_t xDelay = ( TickType_t ) 500 / portTICK_PERIOD_MS; const TickType_t xDelay = ( TickType_t ) 500 / portTICK_PERIOD_MS;
if( pvParameters != NULL ) if( pvParameters != NULL )
{ {
/* This task is periodically created four times. Tow created tasks are /* This task is periodically created four times. Tow created tasks are
passed a handle to the other task so it can kill it before killing itself. * passed a handle to the other task so it can kill it before killing itself.
The other task is passed in null. */ * The other task is passed in null. */
xTaskToKill = *( TaskHandle_t* )pvParameters; xTaskToKill = *( TaskHandle_t * ) pvParameters;
} }
else else
{ {
xTaskToKill = NULL; xTaskToKill = NULL;
} }
for( ;; ) for( ; ; )
{ {
/* Do something random just to use some stack and registers. */ /* Do something random just to use some stack and registers. */
d1 = 2.4; d1 = 2.4;
@ -137,14 +137,14 @@ const TickType_t xDelay = ( TickType_t ) 500 / portTICK_PERIOD_MS;
vTaskDelete( NULL ); vTaskDelete( NULL );
} }
} }
}/*lint !e818 !e550 Function prototype must be as per standard for task functions. */ } /*lint !e818 !e550 Function prototype must be as per standard for task functions. */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vCreateTasks( void *pvParameters ) static void vCreateTasks( void * pvParameters )
{ {
const TickType_t xDelay = ( TickType_t ) 1000 / portTICK_PERIOD_MS; const TickType_t xDelay = ( TickType_t ) 1000 / portTICK_PERIOD_MS;
unsigned portBASE_TYPE uxPriority; unsigned portBASE_TYPE uxPriority;
const char * const pcTaskStartMsg = "Create task started.\r\n"; const char * const pcTaskStartMsg = "Create task started.\r\n";
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
@ -152,7 +152,7 @@ const char * const pcTaskStartMsg = "Create task started.\r\n";
uxPriority = *( unsigned portBASE_TYPE * ) pvParameters; uxPriority = *( unsigned portBASE_TYPE * ) pvParameters;
vPortFree( pvParameters ); vPortFree( pvParameters );
for( ;; ) for( ; ; )
{ {
/* Just loop round, delaying then creating the four suicidal tasks. */ /* Just loop round, delaying then creating the four suicidal tasks. */
vTaskDelay( xDelay ); vTaskDelay( xDelay );
@ -168,18 +168,19 @@ const char * const pcTaskStartMsg = "Create task started.\r\n";
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* This is called to check that the creator task is still running and that there /* This is called to check that the creator task is still running and that there
are not any more than four extra tasks. */ * are not any more than four extra tasks. */
portBASE_TYPE xIsCreateTaskStillRunning( void ) portBASE_TYPE xIsCreateTaskStillRunning( void )
{ {
static short sLastCreationCount = 0; static short sLastCreationCount = 0;
short sReturn = pdTRUE; short sReturn = pdTRUE;
unsigned portBASE_TYPE uxTasksRunningNow; unsigned portBASE_TYPE uxTasksRunningNow;
if( sLastCreationCount == sCreationCount ) if( sLastCreationCount == sCreationCount )
{ {
sReturn = pdFALSE; sReturn = pdFALSE;
} }
sLastCreationCount = sCreationCount; sLastCreationCount = sCreationCount;
uxTasksRunningNow = uxTaskGetNumberOfTasks(); uxTasksRunningNow = uxTaskGetNumberOfTasks();
@ -199,5 +200,3 @@ unsigned portBASE_TYPE uxTasksRunningNow;
return sReturn; return sReturn;
} }

View file

@ -26,31 +26,31 @@
*/ */
/** /**
* The first test creates three tasks - two counter tasks (one continuous count * The first test creates three tasks - two counter tasks (one continuous count
* and one limited count) and one controller. A "count" variable is shared * and one limited count) and one controller. A "count" variable is shared
* between all three tasks. The two counter tasks should never be in a "ready" * between all three tasks. The two counter tasks should never be in a "ready"
* state at the same time. The controller task runs at the same priority as * state at the same time. The controller task runs at the same priority as
* the continuous count task, and at a lower priority than the limited count * the continuous count task, and at a lower priority than the limited count
* task. * task.
* *
* One counter task loops indefinitely, incrementing the shared count variable * One counter task loops indefinitely, incrementing the shared count variable
* on each iteration. To ensure it has exclusive access to the variable it * on each iteration. To ensure it has exclusive access to the variable it
* raises it's priority above that of the controller task before each * raises it's priority above that of the controller task before each
* increment, lowering it again to it's original priority before starting the * increment, lowering it again to it's original priority before starting the
* next iteration. * next iteration.
* *
* The other counter task increments the shared count variable on each * The other counter task increments the shared count variable on each
* iteration of it's loop until the count has reached a limit of 0xff - at * iteration of it's loop until the count has reached a limit of 0xff - at
* which point it suspends itself. It will not start a new loop until the * which point it suspends itself. It will not start a new loop until the
* controller task has made it "ready" again by calling vTaskResume (). * controller task has made it "ready" again by calling vTaskResume ().
* This second counter task operates at a higher priority than controller * This second counter task operates at a higher priority than controller
* task so does not need to worry about mutual exclusion of the counter * task so does not need to worry about mutual exclusion of the counter
* variable. * variable.
* *
* The controller task is in two sections. The first section controls and * The controller task is in two sections. The first section controls and
* monitors the continuous count task. When this section is operational the * monitors the continuous count task. When this section is operational the
* limited count task is suspended. Likewise, the second section controls * limited count task is suspended. Likewise, the second section controls
* and monitors the limited count task. When this section is operational the * and monitors the limited count task. When this section is operational the
* continuous count task is suspended. * continuous count task is suspended.
* *
* In the first section the controller task first takes a copy of the shared * In the first section the controller task first takes a copy of the shared
@ -60,11 +60,11 @@
* the continuous count task will execute and increment the shared variable. * the continuous count task will execute and increment the shared variable.
* When the controller task wakes it checks that the continuous count task * When the controller task wakes it checks that the continuous count task
* has executed by comparing the copy of the shared variable with its current * has executed by comparing the copy of the shared variable with its current
* value. This time, to ensure mutual exclusion, the scheduler itself is * value. This time, to ensure mutual exclusion, the scheduler itself is
* suspended with a call to vTaskSuspendAll (). This is for demonstration * suspended with a call to vTaskSuspendAll (). This is for demonstration
* purposes only and is not a recommended technique due to its inefficiency. * purposes only and is not a recommended technique due to its inefficiency.
* *
* After a fixed number of iterations the controller task suspends the * After a fixed number of iterations the controller task suspends the
* continuous count task, and moves on to its second section. * continuous count task, and moves on to its second section.
* *
* At the start of the second section the shared variable is cleared to zero. * At the start of the second section the shared variable is cleared to zero.
@ -76,7 +76,7 @@
* a check on the shared variable to ensure everything is as expected. * a check on the shared variable to ensure everything is as expected.
* *
* *
* The second test consists of a couple of very simple tasks that post onto a * The second test consists of a couple of very simple tasks that post onto a
* queue while the scheduler is suspended. This test was added to test parts * queue while the scheduler is suspended. This test was added to test parts
* of the scheduler not exercised by the first test. * of the scheduler not exercised by the first test.
* *
@ -91,20 +91,20 @@
*/ */
/* /*
Changes from V2.0.0 * Changes from V2.0.0
*
+ Delay periods are now specified using variables and constants of + Delay periods are now specified using variables and constants of
TickType_t rather than unsigned long. + TickType_t rather than unsigned long.
+ Added a second, simple test that uses the functions + Added a second, simple test that uses the functions
vQueueReceiveWhenSuspendedTask() and vQueueSendWhenSuspendedTask(). + vQueueReceiveWhenSuspendedTask() and vQueueSendWhenSuspendedTask().
+
Changes from V3.1.1 + Changes from V3.1.1
+
+ Added a third simple test that uses the vTaskPrioritySet() function + Added a third simple test that uses the vTaskPrioritySet() function
while the scheduler is suspended. + while the scheduler is suspended.
+ Modified the controller task slightly to test the calling of + Modified the controller task slightly to test the calling of
vTaskResumeAll() while the scheduler is suspended. + vTaskResumeAll() while the scheduler is suspended.
*/ */
#include <stdlib.h> #include <stdlib.h>
@ -127,42 +127,42 @@ static void vContinuousIncrementTask( void * pvParameters );
static void vCounterControlTask( void * pvParameters ); static void vCounterControlTask( void * pvParameters );
/* The simple test functions that check sending and receiving while the /* The simple test functions that check sending and receiving while the
scheduler is suspended. */ * scheduler is suspended. */
static void vQueueReceiveWhenSuspendedTask( void *pvParameters ); static void vQueueReceiveWhenSuspendedTask( void * pvParameters );
static void vQueueSendWhenSuspendedTask( void *pvParameters ); static void vQueueSendWhenSuspendedTask( void * pvParameters );
/* The simple test functions that check raising and lowering of task priorities /* The simple test functions that check raising and lowering of task priorities
while the scheduler is suspended. */ * while the scheduler is suspended. */
static void prvChangePriorityWhenSuspendedTask( void *pvParameters ); static void prvChangePriorityWhenSuspendedTask( void * pvParameters );
static void prvChangePriorityHelperTask( void *pvParameters ); static void prvChangePriorityHelperTask( void * pvParameters );
/* Demo task specific constants. */ /* Demo task specific constants. */
#define priSTACK_SIZE ( ( unsigned short ) configMINIMAL_STACK_SIZE ) #define priSTACK_SIZE ( ( unsigned short ) configMINIMAL_STACK_SIZE )
#define priSLEEP_TIME ( ( TickType_t ) 50 ) #define priSLEEP_TIME ( ( TickType_t ) 50 )
#define priLOOPS ( 5 ) #define priLOOPS ( 5 )
#define priMAX_COUNT ( ( unsigned long ) 0xff ) #define priMAX_COUNT ( ( unsigned long ) 0xff )
#define priNO_BLOCK ( ( TickType_t ) 0 ) #define priNO_BLOCK ( ( TickType_t ) 0 )
#define priSUSPENDED_QUEUE_LENGTH ( 1 ) #define priSUSPENDED_QUEUE_LENGTH ( 1 )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Handles to the two counter tasks. These could be passed in as parameters /* Handles to the two counter tasks. These could be passed in as parameters
to the controller task to prevent them having to be file scope. */ * to the controller task to prevent them having to be file scope. */
static TaskHandle_t xContinuousIncrementHandle, xLimitedIncrementHandle, xChangePriorityWhenSuspendedHandle; static TaskHandle_t xContinuousIncrementHandle, xLimitedIncrementHandle, xChangePriorityWhenSuspendedHandle;
/* The shared counter variable. This is passed in as a parameter to the two /* The shared counter variable. This is passed in as a parameter to the two
counter variables for demonstration purposes. */ * counter variables for demonstration purposes. */
static unsigned long ulCounter; static unsigned long ulCounter;
/* Variable used in a similar way by the test that checks the raising and /* Variable used in a similar way by the test that checks the raising and
lowering of task priorities while the scheduler is suspended. */ * lowering of task priorities while the scheduler is suspended. */
static unsigned long ulPrioritySetCounter; static unsigned long ulPrioritySetCounter;
/* Variables used to check that the tasks are still operating without error. /* Variables used to check that the tasks are still operating without error.
Each complete iteration of the controller task increments this variable * Each complete iteration of the controller task increments this variable
provided no errors have been found. The variable maintaining the same value * provided no errors have been found. The variable maintaining the same value
is therefore indication of an error. */ * is therefore indication of an error. */
static unsigned short usCheckVariable = ( unsigned short ) 0; static unsigned short usCheckVariable = ( unsigned short ) 0;
static portBASE_TYPE xSuspendedQueueSendError = pdFALSE; static portBASE_TYPE xSuspendedQueueSendError = pdFALSE;
static portBASE_TYPE xSuspendedQueueReceiveError = pdFALSE; static portBASE_TYPE xSuspendedQueueReceiveError = pdFALSE;
@ -172,49 +172,50 @@ static portBASE_TYPE xPriorityRaiseWhenSuspendedError = pdFALSE;
QueueHandle_t xSuspendedTestQueue; QueueHandle_t xSuspendedTestQueue;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* /*
* Start the seven tasks as described at the top of the file. * Start the seven tasks as described at the top of the file.
* Note that the limited count task is given a higher priority. * Note that the limited count task is given a higher priority.
*/ */
void vStartDynamicPriorityTasks( void ) void vStartDynamicPriorityTasks( void )
{ {
xSuspendedTestQueue = xQueueCreate( priSUSPENDED_QUEUE_LENGTH, sizeof( unsigned long ) ); xSuspendedTestQueue = xQueueCreate( priSUSPENDED_QUEUE_LENGTH, sizeof( unsigned long ) );
xTaskCreate( vContinuousIncrementTask, "CONT_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY, &xContinuousIncrementHandle ); xTaskCreate( vContinuousIncrementTask, "CONT_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY, &xContinuousIncrementHandle );
xTaskCreate( vLimitedIncrementTask, "LIM_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY + 1, &xLimitedIncrementHandle ); xTaskCreate( vLimitedIncrementTask, "LIM_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY + 1, &xLimitedIncrementHandle );
xTaskCreate( vCounterControlTask, "C_CTRL", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); xTaskCreate( vCounterControlTask, "C_CTRL", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
xTaskCreate( vQueueSendWhenSuspendedTask, "SUSP_SEND", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); xTaskCreate( vQueueSendWhenSuspendedTask, "SUSP_SEND", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
xTaskCreate( vQueueReceiveWhenSuspendedTask, "SUSP_RECV", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); xTaskCreate( vQueueReceiveWhenSuspendedTask, "SUSP_RECV", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
xTaskCreate( prvChangePriorityWhenSuspendedTask, "1st_P_CHANGE", priSTACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL ); xTaskCreate( prvChangePriorityWhenSuspendedTask, "1st_P_CHANGE", priSTACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL );
xTaskCreate( prvChangePriorityHelperTask, "2nd_P_CHANGE", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, &xChangePriorityWhenSuspendedHandle ); xTaskCreate( prvChangePriorityHelperTask, "2nd_P_CHANGE", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, &xChangePriorityWhenSuspendedHandle );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* /*
* Just loops around incrementing the shared variable until the limit has been * Just loops around incrementing the shared variable until the limit has been
* reached. Once the limit has been reached it suspends itself. * reached. Once the limit has been reached it suspends itself.
*/ */
static void vLimitedIncrementTask( void * pvParameters ) static void vLimitedIncrementTask( void * pvParameters )
{ {
unsigned long *pulCounter; unsigned long * pulCounter;
/* Take a pointer to the shared variable from the parameters passed into /* Take a pointer to the shared variable from the parameters passed into
the task. */ * the task. */
pulCounter = ( unsigned long * ) pvParameters; pulCounter = ( unsigned long * ) pvParameters;
/* This will run before the control task, so the first thing it does is /* This will run before the control task, so the first thing it does is
suspend - the control task will resume it when ready. */ * suspend - the control task will resume it when ready. */
vTaskSuspend( NULL ); vTaskSuspend( NULL );
for( ;; ) for( ; ; )
{ {
/* Just count up to a value then suspend. */ /* Just count up to a value then suspend. */
( *pulCounter )++; ( *pulCounter )++;
if( *pulCounter >= priMAX_COUNT ) if( *pulCounter >= priMAX_COUNT )
{ {
vTaskSuspend( NULL ); vTaskSuspend( NULL );
} }
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -224,29 +225,29 @@ unsigned long *pulCounter;
*/ */
static void vContinuousIncrementTask( void * pvParameters ) static void vContinuousIncrementTask( void * pvParameters )
{ {
unsigned long *pulCounter; unsigned long * pulCounter;
unsigned portBASE_TYPE uxOurPriority; unsigned portBASE_TYPE uxOurPriority;
/* Take a pointer to the shared variable from the parameters passed into /* Take a pointer to the shared variable from the parameters passed into
the task. */ * the task. */
pulCounter = ( unsigned long * ) pvParameters; pulCounter = ( unsigned long * ) pvParameters;
/* Query our priority so we can raise it when exclusive access to the /* Query our priority so we can raise it when exclusive access to the
shared variable is required. */ * shared variable is required. */
uxOurPriority = uxTaskPriorityGet( NULL ); uxOurPriority = uxTaskPriorityGet( NULL );
for( ;; ) for( ; ; )
{ {
/* Raise our priority above the controller task to ensure a context /* Raise our priority above the controller task to ensure a context
switch does not occur while we are accessing this variable. */ * switch does not occur while we are accessing this variable. */
vTaskPrioritySet( NULL, uxOurPriority + 1 ); vTaskPrioritySet( NULL, uxOurPriority + 1 );
( *pulCounter )++; ( *pulCounter )++;
vTaskPrioritySet( NULL, uxOurPriority ); vTaskPrioritySet( NULL, uxOurPriority );
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
taskYIELD(); taskYIELD();
#endif #endif
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -255,324 +256,320 @@ unsigned portBASE_TYPE uxOurPriority;
*/ */
static void vCounterControlTask( void * pvParameters ) static void vCounterControlTask( void * pvParameters )
{ {
unsigned long ulLastCounter; unsigned long ulLastCounter;
short sLoops; short sLoops;
short sError = pdFALSE; short sError = pdFALSE;
const char * const pcTaskStartMsg = "Priority manipulation tasks started.\r\n"; const char * const pcTaskStartMsg = "Priority manipulation tasks started.\r\n";
const char * const pcTaskFailMsg = "Priority manipulation Task Failed\r\n"; const char * const pcTaskFailMsg = "Priority manipulation Task Failed\r\n";
/* Just to stop warning messages. */ /* Just to stop warning messages. */
( void ) pvParameters; ( void ) pvParameters;
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
for( ;; ) for( ; ; )
{ {
/* Start with the counter at zero. */ /* Start with the counter at zero. */
ulCounter = ( unsigned long ) 0; ulCounter = ( unsigned long ) 0;
/* First section : */ /* First section : */
/* Check the continuous count task is running. */ /* Check the continuous count task is running. */
for( sLoops = 0; sLoops < priLOOPS; sLoops++ ) for( sLoops = 0; sLoops < priLOOPS; sLoops++ )
{ {
/* Suspend the continuous count task so we can take a mirror of the /* Suspend the continuous count task so we can take a mirror of the
shared variable without risk of corruption. */ * shared variable without risk of corruption. */
vTaskSuspend( xContinuousIncrementHandle ); vTaskSuspend( xContinuousIncrementHandle );
ulLastCounter = ulCounter; ulLastCounter = ulCounter;
vTaskResume( xContinuousIncrementHandle ); vTaskResume( xContinuousIncrementHandle );
/* Now delay to ensure the other task has processor time. */
vTaskDelay( priSLEEP_TIME );
/* Check the shared variable again. This time to ensure mutual /* Now delay to ensure the other task has processor time. */
exclusion the whole scheduler will be locked. This is just for vTaskDelay( priSLEEP_TIME );
demo purposes! */
vTaskSuspendAll();
{
if( ulLastCounter == ulCounter )
{
/* The shared variable has not changed. There is a problem
with the continuous count task so flag an error. */
sError = pdTRUE;
xTaskResumeAll();
vPrintDisplayMessage( &pcTaskFailMsg );
vTaskSuspendAll();
}
}
xTaskResumeAll();
}
/* Check the shared variable again. This time to ensure mutual
* exclusion the whole scheduler will be locked. This is just for
* demo purposes! */
vTaskSuspendAll();
{
if( ulLastCounter == ulCounter )
{
/* The shared variable has not changed. There is a problem
* with the continuous count task so flag an error. */
sError = pdTRUE;
xTaskResumeAll();
vPrintDisplayMessage( &pcTaskFailMsg );
vTaskSuspendAll();
}
}
xTaskResumeAll();
}
/* Second section: */ /* Second section: */
/* Suspend the continuous counter task so it stops accessing the shared variable. */ /* Suspend the continuous counter task so it stops accessing the shared variable. */
vTaskSuspend( xContinuousIncrementHandle ); vTaskSuspend( xContinuousIncrementHandle );
/* Reset the variable. */ /* Reset the variable. */
ulCounter = ( unsigned long ) 0; ulCounter = ( unsigned long ) 0;
/* Resume the limited count task which has a higher priority than us. /* Resume the limited count task which has a higher priority than us.
We should therefore not return from this call until the limited count * We should therefore not return from this call until the limited count
task has suspended itself with a known value in the counter variable. * task has suspended itself with a known value in the counter variable.
The scheduler suspension is not necessary but is included for test * The scheduler suspension is not necessary but is included for test
purposes. */ * purposes. */
vTaskSuspendAll(); vTaskSuspendAll();
vTaskResume( xLimitedIncrementHandle ); vTaskResume( xLimitedIncrementHandle );
xTaskResumeAll(); xTaskResumeAll();
/* Does the counter variable have the expected value? */ /* Does the counter variable have the expected value? */
if( ulCounter != priMAX_COUNT ) if( ulCounter != priMAX_COUNT )
{ {
sError = pdTRUE; sError = pdTRUE;
vPrintDisplayMessage( &pcTaskFailMsg ); vPrintDisplayMessage( &pcTaskFailMsg );
} }
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If no errors have occurred then increment the check variable. */ /* If no errors have occurred then increment the check variable. */
portENTER_CRITICAL(); portENTER_CRITICAL();
usCheckVariable++; usCheckVariable++;
portEXIT_CRITICAL(); portEXIT_CRITICAL();
} }
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
taskYIELD(); taskYIELD();
#endif #endif
/* Resume the continuous count task and do it all again. */ /* Resume the continuous count task and do it all again. */
vTaskResume( xContinuousIncrementHandle ); vTaskResume( xContinuousIncrementHandle );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vQueueSendWhenSuspendedTask( void *pvParameters ) static void vQueueSendWhenSuspendedTask( void * pvParameters )
{ {
static unsigned long ulValueToSend = ( unsigned long ) 0; static unsigned long ulValueToSend = ( unsigned long ) 0;
const char * const pcTaskStartMsg = "Queue send while suspended task started.\r\n"; const char * const pcTaskStartMsg = "Queue send while suspended task started.\r\n";
const char * const pcTaskFailMsg = "Queue send while suspended failed.\r\n"; const char * const pcTaskFailMsg = "Queue send while suspended failed.\r\n";
/* Just to stop warning messages. */ /* Just to stop warning messages. */
( void ) pvParameters; ( void ) pvParameters;
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
for( ;; ) for( ; ; )
{ {
vTaskSuspendAll(); vTaskSuspendAll();
{ {
/* We must not block while the scheduler is suspended! */ /* We must not block while the scheduler is suspended! */
if( xQueueSend( xSuspendedTestQueue, ( void * ) &ulValueToSend, priNO_BLOCK ) != pdTRUE ) if( xQueueSend( xSuspendedTestQueue, ( void * ) &ulValueToSend, priNO_BLOCK ) != pdTRUE )
{ {
if( xSuspendedQueueSendError == pdFALSE ) if( xSuspendedQueueSendError == pdFALSE )
{ {
xTaskResumeAll(); xTaskResumeAll();
vPrintDisplayMessage( &pcTaskFailMsg ); vPrintDisplayMessage( &pcTaskFailMsg );
vTaskSuspendAll(); vTaskSuspendAll();
} }
xSuspendedQueueSendError = pdTRUE; xSuspendedQueueSendError = pdTRUE;
} }
} }
xTaskResumeAll(); xTaskResumeAll();
vTaskDelay( priSLEEP_TIME ); vTaskDelay( priSLEEP_TIME );
++ulValueToSend; ++ulValueToSend;
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vQueueReceiveWhenSuspendedTask( void *pvParameters ) static void vQueueReceiveWhenSuspendedTask( void * pvParameters )
{ {
static unsigned long ulExpectedValue = ( unsigned long ) 0, ulReceivedValue; static unsigned long ulExpectedValue = ( unsigned long ) 0, ulReceivedValue;
const char * const pcTaskStartMsg = "Queue receive while suspended task started.\r\n"; const char * const pcTaskStartMsg = "Queue receive while suspended task started.\r\n";
const char * const pcTaskFailMsg = "Queue receive while suspended failed.\r\n"; const char * const pcTaskFailMsg = "Queue receive while suspended failed.\r\n";
portBASE_TYPE xGotValue; portBASE_TYPE xGotValue;
/* Just to stop warning messages. */ /* Just to stop warning messages. */
( void ) pvParameters; ( void ) pvParameters;
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
for( ;; ) for( ; ; )
{ {
do do
{ {
/* Suspending the scheduler here is fairly pointless and /* Suspending the scheduler here is fairly pointless and
undesirable for a normal application. It is done here purely * undesirable for a normal application. It is done here purely
to test the scheduler. The inner xTaskResumeAll() should * to test the scheduler. The inner xTaskResumeAll() should
never return pdTRUE as the scheduler is still locked by the * never return pdTRUE as the scheduler is still locked by the
outer call. */ * outer call. */
vTaskSuspendAll(); vTaskSuspendAll();
{ {
vTaskSuspendAll(); vTaskSuspendAll();
{ {
xGotValue = xQueueReceive( xSuspendedTestQueue, ( void * ) &ulReceivedValue, priNO_BLOCK ); xGotValue = xQueueReceive( xSuspendedTestQueue, ( void * ) &ulReceivedValue, priNO_BLOCK );
} }
if( xTaskResumeAll() )
{
xSuspendedQueueReceiveError = pdTRUE;
}
}
xTaskResumeAll();
#if configUSE_PREEMPTION == 0 if( xTaskResumeAll() )
taskYIELD(); {
#endif xSuspendedQueueReceiveError = pdTRUE;
}
}
xTaskResumeAll();
} while( xGotValue == pdFALSE ); #if configUSE_PREEMPTION == 0
taskYIELD();
#endif
} while( xGotValue == pdFALSE );
if( ulReceivedValue != ulExpectedValue ) if( ulReceivedValue != ulExpectedValue )
{ {
if( xSuspendedQueueReceiveError == pdFALSE ) if( xSuspendedQueueReceiveError == pdFALSE )
{ {
vPrintDisplayMessage( &pcTaskFailMsg ); vPrintDisplayMessage( &pcTaskFailMsg );
} }
xSuspendedQueueReceiveError = pdTRUE;
}
++ulExpectedValue; xSuspendedQueueReceiveError = pdTRUE;
} }
++ulExpectedValue;
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvChangePriorityWhenSuspendedTask( void *pvParameters ) static void prvChangePriorityWhenSuspendedTask( void * pvParameters )
{ {
const char * const pcTaskStartMsg = "Priority change when suspended task started.\r\n"; const char * const pcTaskStartMsg = "Priority change when suspended task started.\r\n";
const char * const pcTaskFailMsg = "Priority change when suspended task failed.\r\n"; const char * const pcTaskFailMsg = "Priority change when suspended task failed.\r\n";
/* Just to stop warning messages. */ /* Just to stop warning messages. */
( void ) pvParameters; ( void ) pvParameters;
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
for( ;; )
{
/* Start with the counter at 0 so we know what the counter should be
when we check it next. */
ulPrioritySetCounter = ( unsigned long ) 0;
/* Resume the helper task. At this time it has a priority lower than for( ; ; )
ours so no context switch should occur. */ {
vTaskResume( xChangePriorityWhenSuspendedHandle ); /* Start with the counter at 0 so we know what the counter should be
* when we check it next. */
ulPrioritySetCounter = ( unsigned long ) 0;
/* Check to ensure the task just resumed has not executed. */ /* Resume the helper task. At this time it has a priority lower than
portENTER_CRITICAL(); * ours so no context switch should occur. */
{ vTaskResume( xChangePriorityWhenSuspendedHandle );
if( ulPrioritySetCounter != ( unsigned long ) 0 )
{
xPriorityRaiseWhenSuspendedError = pdTRUE;
vPrintDisplayMessage( &pcTaskFailMsg );
}
}
portEXIT_CRITICAL();
/* Now try raising the priority while the scheduler is suspended. */ /* Check to ensure the task just resumed has not executed. */
vTaskSuspendAll(); portENTER_CRITICAL();
{ {
vTaskPrioritySet( xChangePriorityWhenSuspendedHandle, ( configMAX_PRIORITIES - 1 ) ); if( ulPrioritySetCounter != ( unsigned long ) 0 )
{
xPriorityRaiseWhenSuspendedError = pdTRUE;
vPrintDisplayMessage( &pcTaskFailMsg );
}
}
portEXIT_CRITICAL();
/* Again, even though the helper task has a priority greater than /* Now try raising the priority while the scheduler is suspended. */
ours, it should not have executed yet because the scheduler is vTaskSuspendAll();
suspended. */ {
portENTER_CRITICAL(); vTaskPrioritySet( xChangePriorityWhenSuspendedHandle, ( configMAX_PRIORITIES - 1 ) );
{
if( ulPrioritySetCounter != ( unsigned long ) 0 )
{
xPriorityRaiseWhenSuspendedError = pdTRUE;
vPrintDisplayMessage( &pcTaskFailMsg );
}
}
portEXIT_CRITICAL();
}
xTaskResumeAll();
/* Now the scheduler has been resumed the helper task should
immediately preempt us and execute. When it executes it will increment
the ulPrioritySetCounter exactly once before suspending itself.
We should now always find the counter set to 1. */ /* Again, even though the helper task has a priority greater than
portENTER_CRITICAL(); * ours, it should not have executed yet because the scheduler is
{ * suspended. */
if( ulPrioritySetCounter != ( unsigned long ) 1 ) portENTER_CRITICAL();
{ {
xPriorityRaiseWhenSuspendedError = pdTRUE; if( ulPrioritySetCounter != ( unsigned long ) 0 )
vPrintDisplayMessage( &pcTaskFailMsg ); {
} xPriorityRaiseWhenSuspendedError = pdTRUE;
} vPrintDisplayMessage( &pcTaskFailMsg );
portEXIT_CRITICAL(); }
}
portEXIT_CRITICAL();
}
xTaskResumeAll();
/* Delay until we try this again. */ /* Now the scheduler has been resumed the helper task should
vTaskDelay( priSLEEP_TIME * 2 ); * immediately preempt us and execute. When it executes it will increment
* the ulPrioritySetCounter exactly once before suspending itself.
/* Set the priority of the helper task back ready for the next *
execution of this task. */ * We should now always find the counter set to 1. */
vTaskSuspendAll(); portENTER_CRITICAL();
vTaskPrioritySet( xChangePriorityWhenSuspendedHandle, tskIDLE_PRIORITY ); {
xTaskResumeAll(); if( ulPrioritySetCounter != ( unsigned long ) 1 )
} {
xPriorityRaiseWhenSuspendedError = pdTRUE;
vPrintDisplayMessage( &pcTaskFailMsg );
}
}
portEXIT_CRITICAL();
/* Delay until we try this again. */
vTaskDelay( priSLEEP_TIME * 2 );
/* Set the priority of the helper task back ready for the next
* execution of this task. */
vTaskSuspendAll();
vTaskPrioritySet( xChangePriorityWhenSuspendedHandle, tskIDLE_PRIORITY );
xTaskResumeAll();
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvChangePriorityHelperTask( void *pvParameters ) static void prvChangePriorityHelperTask( void * pvParameters )
{ {
/* Just to stop warning messages. */ /* Just to stop warning messages. */
( void ) pvParameters; ( void ) pvParameters;
for( ;; ) for( ; ; )
{ {
/* This is the helper task for prvChangePriorityWhenSuspendedTask(). /* This is the helper task for prvChangePriorityWhenSuspendedTask().
It has it's priority raised and lowered. When it runs it simply * It has it's priority raised and lowered. When it runs it simply
increments the counter then suspends itself again. This allows * increments the counter then suspends itself again. This allows
prvChangePriorityWhenSuspendedTask() to know how many times it has * prvChangePriorityWhenSuspendedTask() to know how many times it has
executed. */ * executed. */
ulPrioritySetCounter++; ulPrioritySetCounter++;
vTaskSuspend( NULL ); vTaskSuspend( NULL );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Called to check that all the created tasks are still running without error. */ /* Called to check that all the created tasks are still running without error. */
portBASE_TYPE xAreDynamicPriorityTasksStillRunning( void ) portBASE_TYPE xAreDynamicPriorityTasksStillRunning( void )
{ {
/* Keep a history of the check variables so we know if it has been incremented /* Keep a history of the check variables so we know if it has been incremented
since the last call. */ * since the last call. */
static unsigned short usLastTaskCheck = ( unsigned short ) 0; static unsigned short usLastTaskCheck = ( unsigned short ) 0;
portBASE_TYPE xReturn = pdTRUE; portBASE_TYPE xReturn = pdTRUE;
/* Check the tasks are still running by ensuring the check variable /* Check the tasks are still running by ensuring the check variable
is still incrementing. */ * is still incrementing. */
if( usCheckVariable == usLastTaskCheck ) if( usCheckVariable == usLastTaskCheck )
{ {
/* The check has not incremented so an error exists. */ /* The check has not incremented so an error exists. */
xReturn = pdFALSE; xReturn = pdFALSE;
} }
if( xSuspendedQueueSendError == pdTRUE ) if( xSuspendedQueueSendError == pdTRUE )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
} }
if( xSuspendedQueueReceiveError == pdTRUE ) if( xSuspendedQueueReceiveError == pdTRUE )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
} }
if( xPriorityRaiseWhenSuspendedError == pdTRUE ) if( xPriorityRaiseWhenSuspendedError == pdTRUE )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
} }
usLastTaskCheck = usCheckVariable; usLastTaskCheck = usCheckVariable;
return xReturn; return xReturn;
} }

View file

@ -60,309 +60,310 @@
#include "print.h" #include "print.h"
/* Demo specific constants. */ /* Demo specific constants. */
#define evtSTACK_SIZE ( ( unsigned portBASE_TYPE ) configMINIMAL_STACK_SIZE ) #define evtSTACK_SIZE ( ( unsigned portBASE_TYPE ) configMINIMAL_STACK_SIZE )
#define evtNUM_TASKS ( 4 ) #define evtNUM_TASKS ( 4 )
#define evtQUEUE_LENGTH ( ( unsigned portBASE_TYPE ) 3 ) #define evtQUEUE_LENGTH ( ( unsigned portBASE_TYPE ) 3 )
#define evtNO_DELAY 0 #define evtNO_DELAY 0
/* Just indexes used to uniquely identify the tasks. Note that two tasks are /* Just indexes used to uniquely identify the tasks. Note that two tasks are
'highest' priority. */ * 'highest' priority. */
#define evtHIGHEST_PRIORITY_INDEX_2 3 #define evtHIGHEST_PRIORITY_INDEX_2 3
#define evtHIGHEST_PRIORITY_INDEX_1 2 #define evtHIGHEST_PRIORITY_INDEX_1 2
#define evtMEDIUM_PRIORITY_INDEX 1 #define evtMEDIUM_PRIORITY_INDEX 1
#define evtLOWEST_PRIORITY_INDEX 0 #define evtLOWEST_PRIORITY_INDEX 0
/* Each event task increments one of these counters each time it reads data /* Each event task increments one of these counters each time it reads data
from the queue. */ * from the queue. */
static volatile portBASE_TYPE xTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 }; static volatile portBASE_TYPE xTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 };
/* Each time the controlling task posts onto the queue it increments the /* Each time the controlling task posts onto the queue it increments the
expected count of the task that it expected to read the data from the queue * expected count of the task that it expected to read the data from the queue
(i.e. the task with the highest priority that should be blocked on the queue). * (i.e. the task with the highest priority that should be blocked on the queue).
*
xExpectedTaskCounters are incremented from the controlling task, and * xExpectedTaskCounters are incremented from the controlling task, and
xTaskCounters are incremented from the individual event tasks - therefore * xTaskCounters are incremented from the individual event tasks - therefore
comparing xTaskCounters to xExpectedTaskCounters shows whether or not the * comparing xTaskCounters to xExpectedTaskCounters shows whether or not the
correct task was unblocked by the post. */ * correct task was unblocked by the post. */
static portBASE_TYPE xExpectedTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 }; static portBASE_TYPE xExpectedTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 };
/* Handles to the four event tasks. These are required to suspend and resume /* Handles to the four event tasks. These are required to suspend and resume
the tasks. */ * the tasks. */
static TaskHandle_t xCreatedTasks[ evtNUM_TASKS ]; static TaskHandle_t xCreatedTasks[ evtNUM_TASKS ];
/* The single queue onto which the controlling task posts, and the four event /* The single queue onto which the controlling task posts, and the four event
tasks block. */ * tasks block. */
static QueueHandle_t xQueue; static QueueHandle_t xQueue;
/* Flag used to indicate whether or not an error has occurred at any time. /* Flag used to indicate whether or not an error has occurred at any time.
An error is either the queue being full when not expected, or an unexpected * An error is either the queue being full when not expected, or an unexpected
task reading data from the queue. */ * task reading data from the queue. */
static portBASE_TYPE xHealthStatus = pdPASS; static portBASE_TYPE xHealthStatus = pdPASS;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Function that implements the event task. This is created four times. */ /* Function that implements the event task. This is created four times. */
static void prvMultiEventTask( void *pvParameters ); static void prvMultiEventTask( void * pvParameters );
/* Function that implements the controlling task. */ /* Function that implements the controlling task. */
static void prvEventControllerTask( void *pvParameters ); static void prvEventControllerTask( void * pvParameters );
/* This is a utility function that posts data to the queue, then compares /* This is a utility function that posts data to the queue, then compares
xExpectedTaskCounters with xTaskCounters to ensure everything worked as * xExpectedTaskCounters with xTaskCounters to ensure everything worked as
expected. * expected.
*
The event tasks all have higher priorities the controlling task. Therefore * The event tasks all have higher priorities the controlling task. Therefore
the controlling task will always get preempted between writhing to the queue * the controlling task will always get preempted between writhing to the queue
and checking the task counters. * and checking the task counters.
*
@param xExpectedTask The index to the task that the controlling task thinks * @param xExpectedTask The index to the task that the controlling task thinks
should be the highest priority task waiting for data, and * should be the highest priority task waiting for data, and
therefore the task that will unblock. * therefore the task that will unblock.
*
@param xIncrement The number of items that should be written to the queue. * @param xIncrement The number of items that should be written to the queue.
*/ */
static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask, portBASE_TYPE xIncrement ); static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask,
portBASE_TYPE xIncrement );
/* This is just incremented each cycle of the controlling tasks function so /* This is just incremented each cycle of the controlling tasks function so
the main application can ensure the test is still running. */ * the main application can ensure the test is still running. */
static portBASE_TYPE xCheckVariable = 0; static portBASE_TYPE xCheckVariable = 0;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vStartMultiEventTasks( void ) void vStartMultiEventTasks( void )
{ {
/* Create the queue to be used for all the communications. */ /* Create the queue to be used for all the communications. */
xQueue = xQueueCreate( evtQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) ); xQueue = xQueueCreate( evtQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );
/* Start the controlling task. This has the idle priority to ensure it is /* Start the controlling task. This has the idle priority to ensure it is
always preempted by the event tasks. */ * always preempted by the event tasks. */
xTaskCreate( prvEventControllerTask, "EvntCTRL", evtSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); xTaskCreate( prvEventControllerTask, "EvntCTRL", evtSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
/* Start the four event tasks. Note that two have priority 3, one /* Start the four event tasks. Note that two have priority 3, one
priority 2 and the other priority 1. */ * priority 2 and the other priority 1. */
xTaskCreate( prvMultiEventTask, "Event0", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 0 ] ), 1, &( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] ) ); xTaskCreate( prvMultiEventTask, "Event0", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 0 ] ), 1, &( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] ) );
xTaskCreate( prvMultiEventTask, "Event1", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 1 ] ), 2, &( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] ) ); xTaskCreate( prvMultiEventTask, "Event1", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 1 ] ), 2, &( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] ) );
xTaskCreate( prvMultiEventTask, "Event2", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 2 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] ) ); xTaskCreate( prvMultiEventTask, "Event2", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 2 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] ) );
xTaskCreate( prvMultiEventTask, "Event3", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 3 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] ) ); xTaskCreate( prvMultiEventTask, "Event3", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 3 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] ) );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvMultiEventTask( void *pvParameters ) static void prvMultiEventTask( void * pvParameters )
{ {
portBASE_TYPE *pxCounter; portBASE_TYPE * pxCounter;
unsigned portBASE_TYPE uxDummy; unsigned portBASE_TYPE uxDummy;
const char * const pcTaskStartMsg = "Multi event task started.\r\n"; const char * const pcTaskStartMsg = "Multi event task started.\r\n";
/* The variable this task will increment is passed in as a parameter. */ /* The variable this task will increment is passed in as a parameter. */
pxCounter = ( portBASE_TYPE * ) pvParameters; pxCounter = ( portBASE_TYPE * ) pvParameters;
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
for( ;; ) for( ; ; )
{ {
/* Block on the queue. */ /* Block on the queue. */
if( xQueueReceive( xQueue, &uxDummy, portMAX_DELAY ) ) if( xQueueReceive( xQueue, &uxDummy, portMAX_DELAY ) )
{ {
/* We unblocked by reading the queue - so simply increment /* We unblocked by reading the queue - so simply increment
the counter specific to this task instance. */ * the counter specific to this task instance. */
( *pxCounter )++; ( *pxCounter )++;
} }
else else
{ {
xHealthStatus = pdFAIL; xHealthStatus = pdFAIL;
} }
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvEventControllerTask( void *pvParameters ) static void prvEventControllerTask( void * pvParameters )
{ {
const char * const pcTaskStartMsg = "Multi event controller task started.\r\n"; const char * const pcTaskStartMsg = "Multi event controller task started.\r\n";
portBASE_TYPE xDummy = 0; portBASE_TYPE xDummy = 0;
/* Just to stop warnings. */ /* Just to stop warnings. */
( void ) pvParameters; ( void ) pvParameters;
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
for( ;; ) for( ; ; )
{ {
/* All tasks are blocked on the queue. When a message is posted one of /* All tasks are blocked on the queue. When a message is posted one of
the two tasks that share the highest priority should unblock to read * the two tasks that share the highest priority should unblock to read
the queue. The next message written should unblock the other task with * the queue. The next message written should unblock the other task with
the same high priority, and so on in order. No other task should * the same high priority, and so on in order. No other task should
unblock to read data as they have lower priorities. */ * unblock to read data as they have lower priorities. */
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 ); prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 ); prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 );
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 ); prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 ); prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 );
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 ); prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
/* For the rest of these tests we don't need the second 'highest' /* For the rest of these tests we don't need the second 'highest'
priority task - so it is suspended. */ * priority task - so it is suspended. */
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] ); vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );
/* Now suspend the other highest priority task. The medium priority /* Now suspend the other highest priority task. The medium priority
task will then be the task with the highest priority that remains * task will then be the task with the highest priority that remains
blocked on the queue. */ * blocked on the queue. */
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] ); vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
/* This time, when we post onto the queue we will expect the medium
priority task to unblock and preempt us. */
prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );
/* Now try resuming the highest priority task while the scheduler is /* This time, when we post onto the queue we will expect the medium
suspended. The task should start executing as soon as the scheduler * priority task to unblock and preempt us. */
is resumed - therefore when we post to the queue again, the highest prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );
priority task should again preempt us. */
vTaskSuspendAll();
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
xTaskResumeAll();
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
/* Now we are going to suspend the high and medium priority tasks. The
low priority task should then preempt us. Again the task suspension is
done with the whole scheduler suspended just for test purposes. */
vTaskSuspendAll();
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
xTaskResumeAll();
prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );
/* Do the same basic test another few times - selectively suspending
and resuming tasks and each time calling prvCheckTaskCounters() passing
to the function the number of the task we expected to be unblocked by
the post. */
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] ); /* Now try resuming the highest priority task while the scheduler is
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 ); * suspended. The task should start executing as soon as the scheduler
* is resumed - therefore when we post to the queue again, the highest
vTaskSuspendAll(); /* Just for test. */ * priority task should again preempt us. */
vTaskSuspendAll(); /* Just for test. */ vTaskSuspendAll();
vTaskSuspendAll(); /* Just for even more test. */ vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] ); xTaskResumeAll();
xTaskResumeAll(); prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
xTaskResumeAll();
xTaskResumeAll();
prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );
vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
/* Now a slight change, first suspend all tasks. */ /* Now we are going to suspend the high and medium priority tasks. The
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] ); * low priority task should then preempt us. Again the task suspension is
vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] ); * done with the whole scheduler suspended just for test purposes. */
vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] ); vTaskSuspendAll();
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
/* Now when we resume the low priority task and write to the queue 3 vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
times. We expect the low priority task to service the queue three xTaskResumeAll();
times. */ prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );
vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, evtQUEUE_LENGTH );
/* Again suspend all tasks (only the low priority task is not suspended
already). */
vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
/* This time we are going to suspend the scheduler, resume the low
priority task, then resume the high priority task. In this state we
will write to the queue three times. When the scheduler is resumed
we expect the high priority task to service all three messages. */
vTaskSuspendAll();
{
vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
for( xDummy = 0; xDummy < evtQUEUE_LENGTH; xDummy++ )
{
if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE )
{
xHealthStatus = pdFAIL;
}
}
/* The queue should not have been serviced yet!. The scheduler
is still suspended. */
if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
{
xHealthStatus = pdFAIL;
}
}
xTaskResumeAll();
/* We should have been preempted by resuming the scheduler - so by the /* Do the same basic test another few times - selectively suspending
time we are running again we expect the high priority task to have * and resuming tasks and each time calling prvCheckTaskCounters() passing
removed three items from the queue. */ * to the function the number of the task we expected to be unblocked by
xExpectedTaskCounters[ evtHIGHEST_PRIORITY_INDEX_1 ] += evtQUEUE_LENGTH; * the post. */
if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
{
xHealthStatus = pdFAIL;
}
/* The medium priority and second high priority tasks are still
suspended. Make sure to resume them before starting again. */
vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );
/* Just keep incrementing to show the task is still executing. */ vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
xCheckVariable++; prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
}
vTaskSuspendAll(); /* Just for test. */
vTaskSuspendAll(); /* Just for test. */
vTaskSuspendAll(); /* Just for even more test. */
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
xTaskResumeAll();
xTaskResumeAll();
xTaskResumeAll();
prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );
vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
/* Now a slight change, first suspend all tasks. */
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
/* Now when we resume the low priority task and write to the queue 3
* times. We expect the low priority task to service the queue three
* times. */
vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, evtQUEUE_LENGTH );
/* Again suspend all tasks (only the low priority task is not suspended
* already). */
vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
/* This time we are going to suspend the scheduler, resume the low
* priority task, then resume the high priority task. In this state we
* will write to the queue three times. When the scheduler is resumed
* we expect the high priority task to service all three messages. */
vTaskSuspendAll();
{
vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
for( xDummy = 0; xDummy < evtQUEUE_LENGTH; xDummy++ )
{
if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE )
{
xHealthStatus = pdFAIL;
}
}
/* The queue should not have been serviced yet!. The scheduler
* is still suspended. */
if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
{
xHealthStatus = pdFAIL;
}
}
xTaskResumeAll();
/* We should have been preempted by resuming the scheduler - so by the
* time we are running again we expect the high priority task to have
* removed three items from the queue. */
xExpectedTaskCounters[ evtHIGHEST_PRIORITY_INDEX_1 ] += evtQUEUE_LENGTH;
if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
{
xHealthStatus = pdFAIL;
}
/* The medium priority and second high priority tasks are still
* suspended. Make sure to resume them before starting again. */
vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );
/* Just keep incrementing to show the task is still executing. */
xCheckVariable++;
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask, portBASE_TYPE xIncrement ) static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask,
portBASE_TYPE xIncrement )
{ {
portBASE_TYPE xDummy = 0; portBASE_TYPE xDummy = 0;
/* Write to the queue the requested number of times. The data written is /* Write to the queue the requested number of times. The data written is
not important. */ * not important. */
for( xDummy = 0; xDummy < xIncrement; xDummy++ ) for( xDummy = 0; xDummy < xIncrement; xDummy++ )
{ {
if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE ) if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE )
{ {
/* Did not expect to ever find the queue full. */ /* Did not expect to ever find the queue full. */
xHealthStatus = pdFAIL; xHealthStatus = pdFAIL;
} }
} }
/* All the tasks blocked on the queue have a priority higher than the /* All the tasks blocked on the queue have a priority higher than the
controlling task. Writing to the queue will therefore have caused this * controlling task. Writing to the queue will therefore have caused this
task to be preempted. By the time this line executes the event task will * task to be preempted. By the time this line executes the event task will
have executed and incremented its counter. Increment the expected counter * have executed and incremented its counter. Increment the expected counter
to the same value. */ * to the same value. */
( xExpectedTaskCounters[ xExpectedTask ] ) += xIncrement; ( xExpectedTaskCounters[ xExpectedTask ] ) += xIncrement;
/* Check the actual counts and expected counts really are the same. */ /* Check the actual counts and expected counts really are the same. */
if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) ) if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
{ {
/* The counters were not the same. This means a task we did not expect /* The counters were not the same. This means a task we did not expect
to unblock actually did unblock. */ * to unblock actually did unblock. */
xHealthStatus = pdFAIL; xHealthStatus = pdFAIL;
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
portBASE_TYPE xAreMultiEventTasksStillRunning( void ) portBASE_TYPE xAreMultiEventTasksStillRunning( void )
{ {
static portBASE_TYPE xPreviousCheckVariable = 0; static portBASE_TYPE xPreviousCheckVariable = 0;
/* Called externally to periodically check that this test is still /* Called externally to periodically check that this test is still
operational. */ * operational. */
if( xPreviousCheckVariable == xCheckVariable ) if( xPreviousCheckVariable == xCheckVariable )
{ {
xHealthStatus = pdFAIL; xHealthStatus = pdFAIL;
} }
xPreviousCheckVariable = xCheckVariable; xPreviousCheckVariable = xCheckVariable;
return xHealthStatus; return xHealthStatus;
} }

View file

@ -27,13 +27,13 @@
/** /**
* Creates eight tasks, each of which flash an LED at a different rate. The first * Creates eight tasks, each of which flash an LED at a different rate. The first
* LED flashes every 125ms, the second every 250ms, the third every 375ms, etc. * LED flashes every 125ms, the second every 250ms, the third every 375ms, etc.
* *
* The LED flash tasks provide instant visual feedback. They show that the scheduler * The LED flash tasks provide instant visual feedback. They show that the scheduler
* is still operational. * is still operational.
* *
* The PC port uses the standard parallel port for outputs, the Flashlite 186 port * The PC port uses the standard parallel port for outputs, the Flashlite 186 port
* uses IO port F. * uses IO port F.
* *
* \page flashC flash.c * \page flashC flash.c
@ -42,16 +42,16 @@
*/ */
/* /*
Changes from V2.0.0 * Changes from V2.0.0
*
+ Delay periods are now specified using variables and constants of + Delay periods are now specified using variables and constants of
TickType_t rather than unsigned long. + TickType_t rather than unsigned long.
+
Changes from V2.1.1 + Changes from V2.1.1
+
+ The stack size now uses configMINIMAL_STACK_SIZE. + The stack size now uses configMINIMAL_STACK_SIZE.
+ String constants made file scope to decrease stack depth on 8051 port. + String constants made file scope to decrease stack depth on 8051 port.
*/ */
#include <stdlib.h> #include <stdlib.h>
@ -64,18 +64,18 @@ Changes from V2.1.1
#include "flash.h" #include "flash.h"
#include "print.h" #include "print.h"
#define ledSTACK_SIZE configMINIMAL_STACK_SIZE #define ledSTACK_SIZE configMINIMAL_STACK_SIZE
/* Structure used to pass parameters to the LED tasks. */ /* Structure used to pass parameters to the LED tasks. */
typedef struct LED_PARAMETERS typedef struct LED_PARAMETERS
{ {
unsigned portBASE_TYPE uxLED; /*< The output the task should use. */ unsigned portBASE_TYPE uxLED; /*< The output the task should use. */
TickType_t xFlashRate; /*< The rate at which the LED should flash. */ TickType_t xFlashRate; /*< The rate at which the LED should flash. */
} xLEDParameters; } xLEDParameters;
/* The task that is created eight times - each time with a different xLEDParaemtes /* The task that is created eight times - each time with a different xLEDParaemtes
structure passed in as the parameter. */ * structure passed in as the parameter. */
static void vLEDFlashTask( void *pvParameters ); static void vLEDFlashTask( void * pvParameters );
/* String to print if USE_STDIO is defined. */ /* String to print if USE_STDIO is defined. */
const char * const pcTaskStartMsg = "LED flash task started.\r\n"; const char * const pcTaskStartMsg = "LED flash task started.\r\n";
@ -84,45 +84,44 @@ const char * const pcTaskStartMsg = "LED flash task started.\r\n";
void vStartLEDFlashTasks( unsigned portBASE_TYPE uxPriority ) void vStartLEDFlashTasks( unsigned portBASE_TYPE uxPriority )
{ {
unsigned portBASE_TYPE uxLEDTask; unsigned portBASE_TYPE uxLEDTask;
xLEDParameters *pxLEDParameters; xLEDParameters * pxLEDParameters;
const unsigned portBASE_TYPE uxNumOfLEDs = 8; const unsigned portBASE_TYPE uxNumOfLEDs = 8;
const TickType_t xFlashRate = 125; const TickType_t xFlashRate = 125;
/* Create the eight tasks. */ /* Create the eight tasks. */
for( uxLEDTask = 0; uxLEDTask < uxNumOfLEDs; ++uxLEDTask ) for( uxLEDTask = 0; uxLEDTask < uxNumOfLEDs; ++uxLEDTask )
{ {
/* Create and complete the structure used to pass parameters to the next /* Create and complete the structure used to pass parameters to the next
created task. */ * created task. */
pxLEDParameters = ( xLEDParameters * ) pvPortMalloc( sizeof( xLEDParameters ) ); pxLEDParameters = ( xLEDParameters * ) pvPortMalloc( sizeof( xLEDParameters ) );
pxLEDParameters->uxLED = uxLEDTask; pxLEDParameters->uxLED = uxLEDTask;
pxLEDParameters->xFlashRate = ( xFlashRate + ( xFlashRate * ( TickType_t ) uxLEDTask ) ); pxLEDParameters->xFlashRate = ( xFlashRate + ( xFlashRate * ( TickType_t ) uxLEDTask ) );
pxLEDParameters->xFlashRate /= portTICK_PERIOD_MS; pxLEDParameters->xFlashRate /= portTICK_PERIOD_MS;
/* Spawn the task. */ /* Spawn the task. */
xTaskCreate( vLEDFlashTask, "LEDx", ledSTACK_SIZE, ( void * ) pxLEDParameters, uxPriority, ( TaskHandle_t * ) NULL ); xTaskCreate( vLEDFlashTask, "LEDx", ledSTACK_SIZE, ( void * ) pxLEDParameters, uxPriority, ( TaskHandle_t * ) NULL );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vLEDFlashTask( void *pvParameters ) static void vLEDFlashTask( void * pvParameters )
{ {
xLEDParameters *pxParameters; xLEDParameters * pxParameters;
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
pxParameters = ( xLEDParameters * ) pvParameters; pxParameters = ( xLEDParameters * ) pvParameters;
for(;;) for( ; ; )
{ {
/* Delay for half the flash period then turn the LED on. */ /* Delay for half the flash period then turn the LED on. */
vTaskDelay( pxParameters->xFlashRate / ( TickType_t ) 2 ); vTaskDelay( pxParameters->xFlashRate / ( TickType_t ) 2 );
vParTestToggleLED( pxParameters->uxLED ); vParTestToggleLED( pxParameters->uxLED );
/* Delay for half the flash period then turn the LED off. */ /* Delay for half the flash period then turn the LED off. */
vTaskDelay( pxParameters->xFlashRate / ( TickType_t ) 2 ); vTaskDelay( pxParameters->xFlashRate / ( TickType_t ) 2 );
vParTestToggleLED( pxParameters->uxLED ); vParTestToggleLED( pxParameters->uxLED );
} }
} }

View file

@ -26,22 +26,22 @@
*/ */
/* /*
Changes from V1.2.3 * Changes from V1.2.3
*
+ The created tasks now include calls to tskYIELD(), allowing them to be used + The created tasks now include calls to tskYIELD(), allowing them to be used
with the cooperative scheduler. + with the cooperative scheduler.
*/ */
/** /**
* Creates eight tasks, each of which loops continuously performing an (emulated) * Creates eight tasks, each of which loops continuously performing an (emulated)
* floating point calculation. * floating point calculation.
* *
* All the tasks run at the idle priority and never block or yield. This causes * All the tasks run at the idle priority and never block or yield. This causes
* all eight tasks to time slice with the idle task. Running at the idle priority * all eight tasks to time slice with the idle task. Running at the idle priority
* means that these tasks will get pre-empted any time another task is ready to run * means that these tasks will get pre-empted any time another task is ready to run
* or a time slice occurs. More often than not the pre-emption will occur mid * or a time slice occurs. More often than not the pre-emption will occur mid
* calculation, creating a good test of the schedulers context switch mechanism - a * calculation, creating a good test of the schedulers context switch mechanism - a
* calculation producing an unexpected result could be a symptom of a corruption in * calculation producing an unexpected result could be a symptom of a corruption in
* the context of a task. * the context of a task.
* *
* \page FlopC flop.c * \page FlopC flop.c
@ -60,272 +60,271 @@ Changes from V1.2.3
/* Demo program include files. */ /* Demo program include files. */
#include "flop.h" #include "flop.h"
#define mathSTACK_SIZE ( ( unsigned short ) 512 ) #define mathSTACK_SIZE ( ( unsigned short ) 512 )
#define mathNUMBER_OF_TASKS ( 8 ) #define mathNUMBER_OF_TASKS ( 8 )
/* Four tasks, each of which performs a different floating point calculation. /* Four tasks, each of which performs a different floating point calculation.
Each of the four is created twice. */ * Each of the four is created twice. */
static void vCompetingMathTask1( void *pvParameters ); static void vCompetingMathTask1( void * pvParameters );
static void vCompetingMathTask2( void *pvParameters ); static void vCompetingMathTask2( void * pvParameters );
static void vCompetingMathTask3( void *pvParameters ); static void vCompetingMathTask3( void * pvParameters );
static void vCompetingMathTask4( void *pvParameters ); static void vCompetingMathTask4( void * pvParameters );
/* These variables are used to check that all the tasks are still running. If a /* These variables are used to check that all the tasks are still running. If a
task gets a calculation wrong it will * task gets a calculation wrong it will
stop incrementing its check variable. */ * stop incrementing its check variable. */
static volatile unsigned short usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned short ) 0 }; static volatile unsigned short usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vStartMathTasks( unsigned portBASE_TYPE uxPriority ) void vStartMathTasks( unsigned portBASE_TYPE uxPriority )
{ {
xTaskCreate( vCompetingMathTask1, "Math1", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL ); xTaskCreate( vCompetingMathTask1, "Math1", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask2, "Math2", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL ); xTaskCreate( vCompetingMathTask2, "Math2", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask3, "Math3", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL ); xTaskCreate( vCompetingMathTask3, "Math3", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask4, "Math4", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL ); xTaskCreate( vCompetingMathTask4, "Math4", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask1, "Math5", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 4 ] ), uxPriority, NULL ); xTaskCreate( vCompetingMathTask1, "Math5", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 4 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask2, "Math6", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 5 ] ), uxPriority, NULL ); xTaskCreate( vCompetingMathTask2, "Math6", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 5 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask3, "Math7", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 6 ] ), uxPriority, NULL ); xTaskCreate( vCompetingMathTask3, "Math7", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 6 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask4, "Math8", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 7 ] ), uxPriority, NULL ); xTaskCreate( vCompetingMathTask4, "Math8", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 7 ] ), uxPriority, NULL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vCompetingMathTask1( void *pvParameters ) static void vCompetingMathTask1( void * pvParameters )
{ {
portDOUBLE d1, d2, d3, d4; portDOUBLE d1, d2, d3, d4;
volatile unsigned short *pusTaskCheckVariable; volatile unsigned short * pusTaskCheckVariable;
const portDOUBLE dAnswer = ( 123.4567 + 2345.6789 ) * -918.222; const portDOUBLE dAnswer = ( 123.4567 + 2345.6789 ) * -918.222;
const char * const pcTaskStartMsg = "Math task 1 started.\r\n"; const char * const pcTaskStartMsg = "Math task 1 started.\r\n";
const char * const pcTaskFailMsg = "Math task 1 failed.\r\n"; const char * const pcTaskFailMsg = "Math task 1 failed.\r\n";
short sError = pdFALSE; short sError = pdFALSE;
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters; pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */ /* Keep performing a calculation and checking the result against a constant. */
for(;;) for( ; ; )
{ {
d1 = 123.4567; d1 = 123.4567;
d2 = 2345.6789; d2 = 2345.6789;
d3 = -918.222; d3 = -918.222;
d4 = ( d1 + d2 ) * d3; d4 = ( d1 + d2 ) * d3;
taskYIELD(); taskYIELD();
/* If the calculation does not match the expected constant, stop the /* If the calculation does not match the expected constant, stop the
increment of the check variable. */ * increment of the check variable. */
if( fabs( d4 - dAnswer ) > 0.001 ) if( fabs( d4 - dAnswer ) > 0.001 )
{ {
vPrintDisplayMessage( &pcTaskFailMsg ); vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE; sError = pdTRUE;
} }
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct, increment the check /* If the calculation has always been correct, increment the check
variable so we know this task is still running okay. */ * variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++; ( *pusTaskCheckVariable )++;
} }
taskYIELD(); taskYIELD();
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vCompetingMathTask2( void *pvParameters ) static void vCompetingMathTask2( void * pvParameters )
{ {
portDOUBLE d1, d2, d3, d4; portDOUBLE d1, d2, d3, d4;
volatile unsigned short *pusTaskCheckVariable; volatile unsigned short * pusTaskCheckVariable;
const portDOUBLE dAnswer = ( -389.38 / 32498.2 ) * -2.0001; const portDOUBLE dAnswer = ( -389.38 / 32498.2 ) * -2.0001;
const char * const pcTaskStartMsg = "Math task 2 started.\r\n"; const char * const pcTaskStartMsg = "Math task 2 started.\r\n";
const char * const pcTaskFailMsg = "Math task 2 failed.\r\n"; const char * const pcTaskFailMsg = "Math task 2 failed.\r\n";
short sError = pdFALSE; short sError = pdFALSE;
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters; pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */ /* Keep performing a calculation and checking the result against a constant. */
for( ;; ) for( ; ; )
{ {
d1 = -389.38; d1 = -389.38;
d2 = 32498.2; d2 = 32498.2;
d3 = -2.0001; d3 = -2.0001;
d4 = ( d1 / d2 ) * d3; d4 = ( d1 / d2 ) * d3;
taskYIELD(); taskYIELD();
/* If the calculation does not match the expected constant, stop the
increment of the check variable. */
if( fabs( d4 - dAnswer ) > 0.001 )
{
vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE;
}
if( sError == pdFALSE ) /* If the calculation does not match the expected constant, stop the
{ * increment of the check variable. */
/* If the calculation has always been correct, increment the check if( fabs( d4 - dAnswer ) > 0.001 )
variable so we know {
this task is still running okay. */ vPrintDisplayMessage( &pcTaskFailMsg );
( *pusTaskCheckVariable )++; sError = pdTRUE;
} }
taskYIELD(); if( sError == pdFALSE )
} {
/* If the calculation has always been correct, increment the check
* variable so we know
* this task is still running okay. */
( *pusTaskCheckVariable )++;
}
taskYIELD();
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vCompetingMathTask3( void *pvParameters ) static void vCompetingMathTask3( void * pvParameters )
{ {
portDOUBLE *pdArray, dTotal1, dTotal2, dDifference; portDOUBLE * pdArray, dTotal1, dTotal2, dDifference;
volatile unsigned short *pusTaskCheckVariable; volatile unsigned short * pusTaskCheckVariable;
const unsigned short usArraySize = 250; const unsigned short usArraySize = 250;
unsigned short usPosition; unsigned short usPosition;
const char * const pcTaskStartMsg = "Math task 3 started.\r\n"; const char * const pcTaskStartMsg = "Math task 3 started.\r\n";
const char * const pcTaskFailMsg = "Math task 3 failed.\r\n"; const char * const pcTaskFailMsg = "Math task 3 failed.\r\n";
short sError = pdFALSE; short sError = pdFALSE;
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters; pusTaskCheckVariable = ( unsigned short * ) pvParameters;
pdArray = ( portDOUBLE * ) pvPortMalloc( ( size_t ) 250 * sizeof( portDOUBLE ) ); pdArray = ( portDOUBLE * ) pvPortMalloc( ( size_t ) 250 * sizeof( portDOUBLE ) );
/* Keep filling an array, keeping a running total of the values placed in the /* Keep filling an array, keeping a running total of the values placed in the
array. Then run through the array adding up all the values. If the two totals * array. Then run through the array adding up all the values. If the two totals
do not match, stop the check variable from incrementing. */ * do not match, stop the check variable from incrementing. */
for( ;; ) for( ; ; )
{ {
dTotal1 = 0.0; dTotal1 = 0.0;
dTotal2 = 0.0; dTotal2 = 0.0;
for( usPosition = 0; usPosition < usArraySize; usPosition++ ) for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{ {
pdArray[ usPosition ] = ( portDOUBLE ) usPosition + 5.5; pdArray[ usPosition ] = ( portDOUBLE ) usPosition + 5.5;
dTotal1 += ( portDOUBLE ) usPosition + 5.5; dTotal1 += ( portDOUBLE ) usPosition + 5.5;
} }
taskYIELD(); taskYIELD();
for( usPosition = 0; usPosition < usArraySize; usPosition++ ) for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{ {
dTotal2 += pdArray[ usPosition ]; dTotal2 += pdArray[ usPosition ];
} }
dDifference = dTotal1 - dTotal2; dDifference = dTotal1 - dTotal2;
if( fabs( dDifference ) > 0.001 )
{
vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE;
}
taskYIELD(); if( fabs( dDifference ) > 0.001 )
{
vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE;
}
if( sError == pdFALSE ) taskYIELD();
{
/* If the calculation has always been correct, increment the check if( sError == pdFALSE )
variable so we know this task is still running okay. */ {
( *pusTaskCheckVariable )++; /* If the calculation has always been correct, increment the check
} * variable so we know this task is still running okay. */
} ( *pusTaskCheckVariable )++;
}
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vCompetingMathTask4( void *pvParameters ) static void vCompetingMathTask4( void * pvParameters )
{ {
portDOUBLE *pdArray, dTotal1, dTotal2, dDifference; portDOUBLE * pdArray, dTotal1, dTotal2, dDifference;
volatile unsigned short *pusTaskCheckVariable; volatile unsigned short * pusTaskCheckVariable;
const unsigned short usArraySize = 250; const unsigned short usArraySize = 250;
unsigned short usPosition; unsigned short usPosition;
const char * const pcTaskStartMsg = "Math task 4 started.\r\n"; const char * const pcTaskStartMsg = "Math task 4 started.\r\n";
const char * const pcTaskFailMsg = "Math task 4 failed.\r\n"; const char * const pcTaskFailMsg = "Math task 4 failed.\r\n";
short sError = pdFALSE; short sError = pdFALSE;
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters; pusTaskCheckVariable = ( unsigned short * ) pvParameters;
pdArray = ( portDOUBLE * ) pvPortMalloc( ( size_t ) 250 * sizeof( portDOUBLE ) ); pdArray = ( portDOUBLE * ) pvPortMalloc( ( size_t ) 250 * sizeof( portDOUBLE ) );
/* Keep filling an array, keeping a running total of the values placed in the /* Keep filling an array, keeping a running total of the values placed in the
array. Then run through the array adding up all the values. If the two totals * array. Then run through the array adding up all the values. If the two totals
do not match, stop the check variable from incrementing. */ * do not match, stop the check variable from incrementing. */
for( ;; ) for( ; ; )
{ {
dTotal1 = 0.0; dTotal1 = 0.0;
dTotal2 = 0.0; dTotal2 = 0.0;
for( usPosition = 0; usPosition < usArraySize; usPosition++ ) for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{ {
pdArray[ usPosition ] = ( portDOUBLE ) usPosition * 12.123; pdArray[ usPosition ] = ( portDOUBLE ) usPosition * 12.123;
dTotal1 += ( portDOUBLE ) usPosition * 12.123; dTotal1 += ( portDOUBLE ) usPosition * 12.123;
} }
taskYIELD(); taskYIELD();
for( usPosition = 0; usPosition < usArraySize; usPosition++ ) for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{ {
dTotal2 += pdArray[ usPosition ]; dTotal2 += pdArray[ usPosition ];
} }
dDifference = dTotal1 - dTotal2; dDifference = dTotal1 - dTotal2;
if( fabs( dDifference ) > 0.001 )
{
vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE;
}
taskYIELD(); if( fabs( dDifference ) > 0.001 )
{
vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE;
}
if( sError == pdFALSE ) taskYIELD();
{
/* If the calculation has always been correct, increment the check if( sError == pdFALSE )
variable so we know this task is still running okay. */ {
( *pusTaskCheckVariable )++; /* If the calculation has always been correct, increment the check
} * variable so we know this task is still running okay. */
} ( *pusTaskCheckVariable )++;
}
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running. */ /* This is called to check that all the created tasks are still running. */
portBASE_TYPE xAreMathsTaskStillRunning( void ) portBASE_TYPE xAreMathsTaskStillRunning( void )
{ {
/* Keep a history of the check variables so we know if they have been incremented /* Keep a history of the check variables so we know if they have been incremented
since the last call. */ * since the last call. */
static unsigned short usLastTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned short ) 0 }; static unsigned short usLastTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
portBASE_TYPE xReturn = pdTRUE, xTask; portBASE_TYPE xReturn = pdTRUE, xTask;
/* Check the maths tasks are still running by ensuring their check variables /* Check the maths tasks are still running by ensuring their check variables
are still incrementing. */ * are still incrementing. */
for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ ) for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ )
{ {
if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] ) if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] )
{ {
/* The check has not incremented so an error exists. */ /* The check has not incremented so an error exists. */
xReturn = pdFALSE; xReturn = pdFALSE;
} }
usLastTaskCheck[ xTask ] = usTaskCheck[ xTask ]; usLastTaskCheck[ xTask ] = usTaskCheck[ xTask ];
} }
return xReturn; return xReturn;
} }

View file

@ -26,21 +26,21 @@
*/ */
/* /*
Changes from V1.2.3 * Changes from V1.2.3
*
+ The created tasks now include calls to tskYIELD(), allowing them to be used + The created tasks now include calls to tskYIELD(), allowing them to be used
with the cooperative scheduler. + with the cooperative scheduler.
*/ */
/** /**
* This does the same as flop. c, but uses variables of type long instead of * This does the same as flop. c, but uses variables of type long instead of
* type double. * type double.
* *
* As with flop. c, the tasks created in this file are a good test of the * As with flop. c, the tasks created in this file are a good test of the
* scheduler context switch mechanism. The processor has to access 32bit * scheduler context switch mechanism. The processor has to access 32bit
* variables in two or four chunks (depending on the processor). The low * variables in two or four chunks (depending on the processor). The low
* priority of these tasks means there is a high probability that a context * priority of these tasks means there is a high probability that a context
* switch will occur mid calculation. See the flop. c documentation for * switch will occur mid calculation. See the flop. c documentation for
* more information. * more information.
* *
* \page IntegerC integer.c * \page IntegerC integer.c
@ -49,11 +49,11 @@ Changes from V1.2.3
*/ */
/* /*
Changes from V1.2.1 * Changes from V1.2.1
*
+ The constants used in the calculations are larger to ensure the + The constants used in the calculations are larger to ensure the
optimiser does not truncate them to 16 bits. + optimiser does not truncate them to 16 bits.
*/ */
#include <stdlib.h> #include <stdlib.h>
@ -65,263 +65,262 @@ Changes from V1.2.1
/* Demo program include files. */ /* Demo program include files. */
#include "integer.h" #include "integer.h"
#define intgSTACK_SIZE ( ( unsigned short ) 256 ) #define intgSTACK_SIZE ( ( unsigned short ) 256 )
#define intgNUMBER_OF_TASKS ( 8 ) #define intgNUMBER_OF_TASKS ( 8 )
/* Four tasks, each of which performs a different calculation on four byte /* Four tasks, each of which performs a different calculation on four byte
variables. Each of the four is created twice. */ * variables. Each of the four is created twice. */
static void vCompeteingIntMathTask1( void *pvParameters ); static void vCompeteingIntMathTask1( void * pvParameters );
static void vCompeteingIntMathTask2( void *pvParameters ); static void vCompeteingIntMathTask2( void * pvParameters );
static void vCompeteingIntMathTask3( void *pvParameters ); static void vCompeteingIntMathTask3( void * pvParameters );
static void vCompeteingIntMathTask4( void *pvParameters ); static void vCompeteingIntMathTask4( void * pvParameters );
/* These variables are used to check that all the tasks are still running. If a /* These variables are used to check that all the tasks are still running. If a
task gets a calculation wrong it will stop incrementing its check variable. */ * task gets a calculation wrong it will stop incrementing its check variable. */
static volatile unsigned short usTaskCheck[ intgNUMBER_OF_TASKS ] = { ( unsigned short ) 0 }; static volatile unsigned short usTaskCheck[ intgNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vStartIntegerMathTasks( unsigned portBASE_TYPE uxPriority ) void vStartIntegerMathTasks( unsigned portBASE_TYPE uxPriority )
{ {
xTaskCreate( vCompeteingIntMathTask1, "IntMath1", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL ); xTaskCreate( vCompeteingIntMathTask1, "IntMath1", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL );
xTaskCreate( vCompeteingIntMathTask2, "IntMath2", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL ); xTaskCreate( vCompeteingIntMathTask2, "IntMath2", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL );
xTaskCreate( vCompeteingIntMathTask3, "IntMath3", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL ); xTaskCreate( vCompeteingIntMathTask3, "IntMath3", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL );
xTaskCreate( vCompeteingIntMathTask4, "IntMath4", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL ); xTaskCreate( vCompeteingIntMathTask4, "IntMath4", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL );
xTaskCreate( vCompeteingIntMathTask1, "IntMath5", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 4 ] ), uxPriority, NULL ); xTaskCreate( vCompeteingIntMathTask1, "IntMath5", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 4 ] ), uxPriority, NULL );
xTaskCreate( vCompeteingIntMathTask2, "IntMath6", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 5 ] ), uxPriority, NULL ); xTaskCreate( vCompeteingIntMathTask2, "IntMath6", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 5 ] ), uxPriority, NULL );
xTaskCreate( vCompeteingIntMathTask3, "IntMath7", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 6 ] ), uxPriority, NULL ); xTaskCreate( vCompeteingIntMathTask3, "IntMath7", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 6 ] ), uxPriority, NULL );
xTaskCreate( vCompeteingIntMathTask4, "IntMath8", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 7 ] ), uxPriority, NULL ); xTaskCreate( vCompeteingIntMathTask4, "IntMath8", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 7 ] ), uxPriority, NULL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vCompeteingIntMathTask1( void *pvParameters ) static void vCompeteingIntMathTask1( void * pvParameters )
{ {
long l1, l2, l3, l4; long l1, l2, l3, l4;
short sError = pdFALSE; short sError = pdFALSE;
volatile unsigned short *pusTaskCheckVariable; volatile unsigned short * pusTaskCheckVariable;
const long lAnswer = ( ( long ) 74565L + ( long ) 1234567L ) * ( long ) -918L; const long lAnswer = ( ( long ) 74565L + ( long ) 1234567L ) * ( long ) -918L;
const char * const pcTaskStartMsg = "Integer math task 1 started.\r\n"; const char * const pcTaskStartMsg = "Integer math task 1 started.\r\n";
const char * const pcTaskFailMsg = "Integer math task 1 failed.\r\n"; const char * const pcTaskFailMsg = "Integer math task 1 failed.\r\n";
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters; pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */ /* Keep performing a calculation and checking the result against a constant. */
for(;;) for( ; ; )
{ {
l1 = ( long ) 74565L; l1 = ( long ) 74565L;
l2 = ( long ) 1234567L; l2 = ( long ) 1234567L;
l3 = ( long ) -918L; l3 = ( long ) -918L;
l4 = ( l1 + l2 ) * l3; l4 = ( l1 + l2 ) * l3;
taskYIELD(); taskYIELD();
/* If the calculation does not match the expected constant, stop the /* If the calculation does not match the expected constant, stop the
increment of the check variable. */ * increment of the check variable. */
if( l4 != lAnswer ) if( l4 != lAnswer )
{ {
vPrintDisplayMessage( &pcTaskFailMsg ); vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE; sError = pdTRUE;
} }
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct, increment the check /* If the calculation has always been correct, increment the check
variable so we know this task is still running okay. */ * variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++; ( *pusTaskCheckVariable )++;
} }
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vCompeteingIntMathTask2( void *pvParameters ) static void vCompeteingIntMathTask2( void * pvParameters )
{ {
long l1, l2, l3, l4; long l1, l2, l3, l4;
short sError = pdFALSE; short sError = pdFALSE;
volatile unsigned short *pusTaskCheckVariable; volatile unsigned short * pusTaskCheckVariable;
const long lAnswer = ( ( long ) -389000L / ( long ) 329999L ) * ( long ) -89L; const long lAnswer = ( ( long ) -389000L / ( long ) 329999L ) * ( long ) -89L;
const char * const pcTaskStartMsg = "Integer math task 2 started.\r\n"; const char * const pcTaskStartMsg = "Integer math task 2 started.\r\n";
const char * const pcTaskFailMsg = "Integer math task 2 failed.\r\n"; const char * const pcTaskFailMsg = "Integer math task 2 failed.\r\n";
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters; pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */ /* Keep performing a calculation and checking the result against a constant. */
for( ;; ) for( ; ; )
{ {
l1 = -389000L; l1 = -389000L;
l2 = 329999L; l2 = 329999L;
l3 = -89L; l3 = -89L;
l4 = ( l1 / l2 ) * l3; l4 = ( l1 / l2 ) * l3;
taskYIELD(); taskYIELD();
/* If the calculation does not match the expected constant, stop the /* If the calculation does not match the expected constant, stop the
increment of the check variable. */ * increment of the check variable. */
if( l4 != lAnswer ) if( l4 != lAnswer )
{ {
vPrintDisplayMessage( &pcTaskFailMsg ); vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE; sError = pdTRUE;
} }
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct, increment the check /* If the calculation has always been correct, increment the check
variable so we know this task is still running okay. */ * variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++; ( *pusTaskCheckVariable )++;
} }
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vCompeteingIntMathTask3( void *pvParameters ) static void vCompeteingIntMathTask3( void * pvParameters )
{ {
long *plArray, lTotal1, lTotal2; long * plArray, lTotal1, lTotal2;
short sError = pdFALSE; short sError = pdFALSE;
volatile unsigned short *pusTaskCheckVariable; volatile unsigned short * pusTaskCheckVariable;
const unsigned short usArraySize = ( unsigned short ) 250; const unsigned short usArraySize = ( unsigned short ) 250;
unsigned short usPosition; unsigned short usPosition;
const char * const pcTaskStartMsg = "Integer math task 3 started.\r\n"; const char * const pcTaskStartMsg = "Integer math task 3 started.\r\n";
const char * const pcTaskFailMsg = "Integer math task 3 failed.\r\n"; const char * const pcTaskFailMsg = "Integer math task 3 failed.\r\n";
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters; pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Create the array we are going to use for our check calculation. */ /* Create the array we are going to use for our check calculation. */
plArray = ( long * ) pvPortMalloc( ( size_t ) 250 * sizeof( long ) ); plArray = ( long * ) pvPortMalloc( ( size_t ) 250 * sizeof( long ) );
/* Keep filling the array, keeping a running total of the values placed in the /* Keep filling the array, keeping a running total of the values placed in the
array. Then run through the array adding up all the values. If the two totals * array. Then run through the array adding up all the values. If the two totals
do not match, stop the check variable from incrementing. */ * do not match, stop the check variable from incrementing. */
for( ;; ) for( ; ; )
{ {
lTotal1 = ( long ) 0; lTotal1 = ( long ) 0;
lTotal2 = ( long ) 0; lTotal2 = ( long ) 0;
for( usPosition = 0; usPosition < usArraySize; usPosition++ ) for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{ {
plArray[ usPosition ] = ( long ) usPosition + ( long ) 5; plArray[ usPosition ] = ( long ) usPosition + ( long ) 5;
lTotal1 += ( long ) usPosition + ( long ) 5; lTotal1 += ( long ) usPosition + ( long ) 5;
} }
taskYIELD(); taskYIELD();
for( usPosition = 0; usPosition < usArraySize; usPosition++ ) for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{ {
lTotal2 += plArray[ usPosition ]; lTotal2 += plArray[ usPosition ];
} }
if( lTotal1 != lTotal2 ) if( lTotal1 != lTotal2 )
{ {
vPrintDisplayMessage( &pcTaskFailMsg ); vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE; sError = pdTRUE;
} }
taskYIELD(); taskYIELD();
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct, increment the check /* If the calculation has always been correct, increment the check
variable so we know this task is still running okay. */ * variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++; ( *pusTaskCheckVariable )++;
} }
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vCompeteingIntMathTask4( void *pvParameters ) static void vCompeteingIntMathTask4( void * pvParameters )
{ {
long *plArray, lTotal1, lTotal2; long * plArray, lTotal1, lTotal2;
short sError = pdFALSE; short sError = pdFALSE;
volatile unsigned short *pusTaskCheckVariable; volatile unsigned short * pusTaskCheckVariable;
const unsigned short usArraySize = 250; const unsigned short usArraySize = 250;
unsigned short usPosition; unsigned short usPosition;
const char * const pcTaskStartMsg = "Integer math task 4 started.\r\n"; const char * const pcTaskStartMsg = "Integer math task 4 started.\r\n";
const char * const pcTaskFailMsg = "Integer math task 4 failed.\r\n"; const char * const pcTaskFailMsg = "Integer math task 4 failed.\r\n";
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters; pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Create the array we are going to use for our check calculation. */ /* Create the array we are going to use for our check calculation. */
plArray = ( long * ) pvPortMalloc( ( size_t ) 250 * sizeof( long ) ); plArray = ( long * ) pvPortMalloc( ( size_t ) 250 * sizeof( long ) );
/* Keep filling the array, keeping a running total of the values placed in the /* Keep filling the array, keeping a running total of the values placed in the
array. Then run through the array adding up all the values. If the two totals * array. Then run through the array adding up all the values. If the two totals
do not match, stop the check variable from incrementing. */ * do not match, stop the check variable from incrementing. */
for( ;; ) for( ; ; )
{ {
lTotal1 = ( long ) 0; lTotal1 = ( long ) 0;
lTotal2 = ( long ) 0; lTotal2 = ( long ) 0;
for( usPosition = 0; usPosition < usArraySize; usPosition++ ) for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{ {
plArray[ usPosition ] = ( long ) usPosition * ( long ) 12; plArray[ usPosition ] = ( long ) usPosition * ( long ) 12;
lTotal1 += ( long ) usPosition * ( long ) 12; lTotal1 += ( long ) usPosition * ( long ) 12;
} }
taskYIELD(); taskYIELD();
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{
lTotal2 += plArray[ usPosition ];
}
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{
lTotal2 += plArray[ usPosition ];
}
if( lTotal1 != lTotal2 ) if( lTotal1 != lTotal2 )
{ {
vPrintDisplayMessage( &pcTaskFailMsg ); vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE; sError = pdTRUE;
} }
taskYIELD(); taskYIELD();
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct, increment the check /* If the calculation has always been correct, increment the check
variable so we know this task is still running okay. */ * variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++; ( *pusTaskCheckVariable )++;
} }
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running. */ /* This is called to check that all the created tasks are still running. */
portBASE_TYPE xAreIntegerMathsTaskStillRunning( void ) portBASE_TYPE xAreIntegerMathsTaskStillRunning( void )
{ {
/* Keep a history of the check variables so we know if they have been incremented /* Keep a history of the check variables so we know if they have been incremented
since the last call. */ * since the last call. */
static unsigned short usLastTaskCheck[ intgNUMBER_OF_TASKS ] = { ( unsigned short ) 0 }; static unsigned short usLastTaskCheck[ intgNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
portBASE_TYPE xReturn = pdTRUE, xTask; portBASE_TYPE xReturn = pdTRUE, xTask;
/* Check the maths tasks are still running by ensuring their check variables /* Check the maths tasks are still running by ensuring their check variables
are still incrementing. */ * are still incrementing. */
for( xTask = 0; xTask < intgNUMBER_OF_TASKS; xTask++ ) for( xTask = 0; xTask < intgNUMBER_OF_TASKS; xTask++ )
{ {
if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] ) if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] )
{ {
/* The check has not incremented so an error exists. */ /* The check has not incremented so an error exists. */
xReturn = pdFALSE; xReturn = pdFALSE;
} }
usLastTaskCheck[ xTask ] = usTaskCheck[ xTask ]; usLastTaskCheck[ xTask ] = usTaskCheck[ xTask ];
} }
return xReturn; return xReturn;
} }

View file

@ -26,22 +26,22 @@
*/ */
/** /**
* Manages a queue of strings that are waiting to be displayed. This is used to * Manages a queue of strings that are waiting to be displayed. This is used to
* ensure mutual exclusion of console output. * ensure mutual exclusion of console output.
* *
* A task wishing to display a message will call vPrintDisplayMessage (), with a * A task wishing to display a message will call vPrintDisplayMessage (), with a
* pointer to the string as the parameter. The pointer is posted onto the * pointer to the string as the parameter. The pointer is posted onto the
* xPrintQueue queue. * xPrintQueue queue.
* *
* The task spawned in main. c blocks on xPrintQueue. When a message becomes * The task spawned in main. c blocks on xPrintQueue. When a message becomes
* available it calls pcPrintGetNextMessage () to obtain a pointer to the next * available it calls pcPrintGetNextMessage () to obtain a pointer to the next
* string, then uses the functions defined in the portable layer FileIO. c to * string, then uses the functions defined in the portable layer FileIO. c to
* display the message. * display the message.
* *
* <b>NOTE:</b> * <b>NOTE:</b>
* Using console IO can disrupt real time performance - depending on the port. * Using console IO can disrupt real time performance - depending on the port.
* Standard C IO routines are not designed for real time applications. While * Standard C IO routines are not designed for real time applications. While
* standard IO is useful for demonstration and debugging an alternative method * standard IO is useful for demonstration and debugging an alternative method
* should be used if you actually require console IO as part of your application. * should be used if you actually require console IO as part of your application.
* *
* \page PrintC print.c * \page PrintC print.c
@ -50,11 +50,11 @@
*/ */
/* /*
Changes from V2.0.0 * Changes from V2.0.0
*
+ Delay periods are now specified using variables and constants of + Delay periods are now specified using variables and constants of
TickType_t rather than unsigned long. + TickType_t rather than unsigned long.
*/ */
#include <stdlib.h> #include <stdlib.h>
@ -71,36 +71,34 @@ static QueueHandle_t xPrintQueue;
void vPrintInitialise( void ) void vPrintInitialise( void )
{ {
const unsigned portBASE_TYPE uxQueueSize = 20; const unsigned portBASE_TYPE uxQueueSize = 20;
/* Create the queue on which errors will be reported. */ /* Create the queue on which errors will be reported. */
xPrintQueue = xQueueCreate( uxQueueSize, ( unsigned portBASE_TYPE ) sizeof( char * ) ); xPrintQueue = xQueueCreate( uxQueueSize, ( unsigned portBASE_TYPE ) sizeof( char * ) );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vPrintDisplayMessage( const char * const * ppcMessageToSend ) void vPrintDisplayMessage( const char * const * ppcMessageToSend )
{ {
#ifdef USE_STDIO #ifdef USE_STDIO
xQueueSend( xPrintQueue, ( void * ) ppcMessageToSend, ( TickType_t ) 0 ); xQueueSend( xPrintQueue, ( void * ) ppcMessageToSend, ( TickType_t ) 0 );
#else #else
/* Stop warnings. */ /* Stop warnings. */
( void ) ppcMessageToSend; ( void ) ppcMessageToSend;
#endif #endif
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
const char *pcPrintGetNextMessage( TickType_t xPrintRate ) const char * pcPrintGetNextMessage( TickType_t xPrintRate )
{ {
char *pcMessage; char * pcMessage;
if( xQueueReceive( xPrintQueue, &pcMessage, xPrintRate ) == pdPASS ) if( xQueueReceive( xPrintQueue, &pcMessage, xPrintRate ) == pdPASS )
{ {
return pcMessage; return pcMessage;
} }
else else
{ {
return NULL; return NULL;
} }
} }

View file

@ -26,24 +26,24 @@
*/ */
/** /**
* Creates two sets of two tasks. The tasks within a set share a variable, access * Creates two sets of two tasks. The tasks within a set share a variable, access
* to which is guarded by a semaphore. * to which is guarded by a semaphore.
* *
* Each task starts by attempting to obtain the semaphore. On obtaining a * Each task starts by attempting to obtain the semaphore. On obtaining a
* semaphore a task checks to ensure that the guarded variable has an expected * semaphore a task checks to ensure that the guarded variable has an expected
* value. It then clears the variable to zero before counting it back up to the * value. It then clears the variable to zero before counting it back up to the
* expected value in increments of 1. After each increment the variable is checked * expected value in increments of 1. After each increment the variable is checked
* to ensure it contains the value to which it was just set. When the starting * to ensure it contains the value to which it was just set. When the starting
* value is again reached the task releases the semaphore giving the other task in * value is again reached the task releases the semaphore giving the other task in
* the set a chance to do exactly the same thing. The starting value is high * the set a chance to do exactly the same thing. The starting value is high
* enough to ensure that a tick is likely to occur during the incrementing loop. * enough to ensure that a tick is likely to occur during the incrementing loop.
* *
* An error is flagged if at any time during the process a shared variable is * An error is flagged if at any time during the process a shared variable is
* found to have a value other than that expected. Such an occurrence would * found to have a value other than that expected. Such an occurrence would
* suggest an error in the mutual exclusion mechanism by which access to the * suggest an error in the mutual exclusion mechanism by which access to the
* variable is restricted. * variable is restricted.
* *
* The first set of two tasks poll their semaphore. The second set use blocking * The first set of two tasks poll their semaphore. The second set use blocking
* calls. * calls.
* *
* \page SemTestC semtest.c * \page SemTestC semtest.c
@ -52,24 +52,24 @@
*/ */
/* /*
Changes from V1.2.0: * Changes from V1.2.0:
*
+ The tasks that operate at the idle priority now use a lower expected + The tasks that operate at the idle priority now use a lower expected
count than those running at a higher priority. This prevents the low + count than those running at a higher priority. This prevents the low
priority tasks from signaling an error because they have not been + priority tasks from signaling an error because they have not been
scheduled enough time for each of them to count the shared variable to + scheduled enough time for each of them to count the shared variable to
the high value. + the high value.
+
Changes from V2.0.0 + Changes from V2.0.0
+
+ Delay periods are now specified using variables and constants of + Delay periods are now specified using variables and constants of
TickType_t rather than unsigned long. + TickType_t rather than unsigned long.
+
Changes from V2.1.1 + Changes from V2.1.1
+
+ The stack size now uses configMINIMAL_STACK_SIZE. + The stack size now uses configMINIMAL_STACK_SIZE.
+ String constants made file scope to decrease stack depth on 8051 port. + String constants made file scope to decrease stack depth on 8051 port.
*/ */
#include <stdlib.h> #include <stdlib.h>
@ -83,24 +83,24 @@ Changes from V2.1.1
#include "print.h" #include "print.h"
/* The value to which the shared variables are counted. */ /* The value to which the shared variables are counted. */
#define semtstBLOCKING_EXPECTED_VALUE ( ( unsigned long ) 0xfff ) #define semtstBLOCKING_EXPECTED_VALUE ( ( unsigned long ) 0xfff )
#define semtstNON_BLOCKING_EXPECTED_VALUE ( ( unsigned long ) 0xff ) #define semtstNON_BLOCKING_EXPECTED_VALUE ( ( unsigned long ) 0xff )
#define semtstSTACK_SIZE configMINIMAL_STACK_SIZE #define semtstSTACK_SIZE configMINIMAL_STACK_SIZE
#define semtstNUM_TASKS ( 4 ) #define semtstNUM_TASKS ( 4 )
#define semtstDELAY_FACTOR ( ( TickType_t ) 10 ) #define semtstDELAY_FACTOR ( ( TickType_t ) 10 )
/* The task function as described at the top of the file. */ /* The task function as described at the top of the file. */
static void prvSemaphoreTest( void *pvParameters ); static void prvSemaphoreTest( void * pvParameters );
/* Structure used to pass parameters to each task. */ /* Structure used to pass parameters to each task. */
typedef struct SEMAPHORE_PARAMETERS typedef struct SEMAPHORE_PARAMETERS
{ {
SemaphoreHandle_t xSemaphore; SemaphoreHandle_t xSemaphore;
volatile unsigned long *pulSharedVariable; volatile unsigned long * pulSharedVariable;
TickType_t xBlockTime; TickType_t xBlockTime;
} xSemaphoreParameters; } xSemaphoreParameters;
/* Variables used to check that all the tasks are still running without errors. */ /* Variables used to check that all the tasks are still running without errors. */
@ -115,171 +115,172 @@ const char * const pcSemaphoreTaskStart = "Guarded shared variable task started.
void vStartSemaphoreTasks( unsigned portBASE_TYPE uxPriority ) void vStartSemaphoreTasks( unsigned portBASE_TYPE uxPriority )
{ {
xSemaphoreParameters *pxFirstSemaphoreParameters, *pxSecondSemaphoreParameters; xSemaphoreParameters * pxFirstSemaphoreParameters, * pxSecondSemaphoreParameters;
const TickType_t xBlockTime = ( TickType_t ) 100; const TickType_t xBlockTime = ( TickType_t ) 100;
/* Create the structure used to pass parameters to the first two tasks. */ /* Create the structure used to pass parameters to the first two tasks. */
pxFirstSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) ); pxFirstSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );
if( pxFirstSemaphoreParameters != NULL ) if( pxFirstSemaphoreParameters != NULL )
{ {
/* Create the semaphore used by the first two tasks. */ /* Create the semaphore used by the first two tasks. */
vSemaphoreCreateBinary( pxFirstSemaphoreParameters->xSemaphore ); vSemaphoreCreateBinary( pxFirstSemaphoreParameters->xSemaphore );
if( pxFirstSemaphoreParameters->xSemaphore != NULL ) if( pxFirstSemaphoreParameters->xSemaphore != NULL )
{ {
/* Create the variable which is to be shared by the first two tasks. */ /* Create the variable which is to be shared by the first two tasks. */
pxFirstSemaphoreParameters->pulSharedVariable = ( unsigned long * ) pvPortMalloc( sizeof( unsigned long ) ); pxFirstSemaphoreParameters->pulSharedVariable = ( unsigned long * ) pvPortMalloc( sizeof( unsigned long ) );
/* Initialise the share variable to the value the tasks expect. */ /* Initialise the share variable to the value the tasks expect. */
*( pxFirstSemaphoreParameters->pulSharedVariable ) = semtstNON_BLOCKING_EXPECTED_VALUE; *( pxFirstSemaphoreParameters->pulSharedVariable ) = semtstNON_BLOCKING_EXPECTED_VALUE;
/* The first two tasks do not block on semaphore calls. */ /* The first two tasks do not block on semaphore calls. */
pxFirstSemaphoreParameters->xBlockTime = ( TickType_t ) 0; pxFirstSemaphoreParameters->xBlockTime = ( TickType_t ) 0;
/* Spawn the first two tasks. As they poll they operate at the idle priority. */ /* Spawn the first two tasks. As they poll they operate at the idle priority. */
xTaskCreate( prvSemaphoreTest, "PolSEM1", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( TaskHandle_t * ) NULL ); xTaskCreate( prvSemaphoreTest, "PolSEM1", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( TaskHandle_t * ) NULL );
xTaskCreate( prvSemaphoreTest, "PolSEM2", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( TaskHandle_t * ) NULL ); xTaskCreate( prvSemaphoreTest, "PolSEM2", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( TaskHandle_t * ) NULL );
} }
} }
/* Do exactly the same to create the second set of tasks, only this time /* Do exactly the same to create the second set of tasks, only this time
provide a block time for the semaphore calls. */ * provide a block time for the semaphore calls. */
pxSecondSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) ); pxSecondSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );
if( pxSecondSemaphoreParameters != NULL )
{
vSemaphoreCreateBinary( pxSecondSemaphoreParameters->xSemaphore );
if( pxSecondSemaphoreParameters->xSemaphore != NULL ) if( pxSecondSemaphoreParameters != NULL )
{ {
pxSecondSemaphoreParameters->pulSharedVariable = ( unsigned long * ) pvPortMalloc( sizeof( unsigned long ) ); vSemaphoreCreateBinary( pxSecondSemaphoreParameters->xSemaphore );
*( pxSecondSemaphoreParameters->pulSharedVariable ) = semtstBLOCKING_EXPECTED_VALUE;
pxSecondSemaphoreParameters->xBlockTime = xBlockTime / portTICK_PERIOD_MS;
xTaskCreate( prvSemaphoreTest, "BlkSEM1", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( TaskHandle_t * ) NULL ); if( pxSecondSemaphoreParameters->xSemaphore != NULL )
xTaskCreate( prvSemaphoreTest, "BlkSEM2", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( TaskHandle_t * ) NULL ); {
} pxSecondSemaphoreParameters->pulSharedVariable = ( unsigned long * ) pvPortMalloc( sizeof( unsigned long ) );
} *( pxSecondSemaphoreParameters->pulSharedVariable ) = semtstBLOCKING_EXPECTED_VALUE;
pxSecondSemaphoreParameters->xBlockTime = xBlockTime / portTICK_PERIOD_MS;
xTaskCreate( prvSemaphoreTest, "BlkSEM1", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( TaskHandle_t * ) NULL );
xTaskCreate( prvSemaphoreTest, "BlkSEM2", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( TaskHandle_t * ) NULL );
}
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvSemaphoreTest( void *pvParameters ) static void prvSemaphoreTest( void * pvParameters )
{ {
xSemaphoreParameters *pxParameters; xSemaphoreParameters * pxParameters;
volatile unsigned long *pulSharedVariable, ulExpectedValue; volatile unsigned long * pulSharedVariable, ulExpectedValue;
unsigned long ulCounter; unsigned long ulCounter;
short sError = pdFALSE, sCheckVariableToUse; short sError = pdFALSE, sCheckVariableToUse;
/* See which check variable to use. sNextCheckVariable is not semaphore /* See which check variable to use. sNextCheckVariable is not semaphore
protected! */ * protected! */
portENTER_CRITICAL(); portENTER_CRITICAL();
sCheckVariableToUse = sNextCheckVariable; sCheckVariableToUse = sNextCheckVariable;
sNextCheckVariable++; sNextCheckVariable++;
portEXIT_CRITICAL(); portEXIT_CRITICAL();
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcSemaphoreTaskStart ); vPrintDisplayMessage( &pcSemaphoreTaskStart );
/* A structure is passed in as the parameter. This contains the shared /* A structure is passed in as the parameter. This contains the shared
variable being guarded. */ * variable being guarded. */
pxParameters = ( xSemaphoreParameters * ) pvParameters; pxParameters = ( xSemaphoreParameters * ) pvParameters;
pulSharedVariable = pxParameters->pulSharedVariable; pulSharedVariable = pxParameters->pulSharedVariable;
/* If we are blocking we use a much higher count to ensure loads of context /* If we are blocking we use a much higher count to ensure loads of context
switches occur during the count. */ * switches occur during the count. */
if( pxParameters->xBlockTime > ( TickType_t ) 0 ) if( pxParameters->xBlockTime > ( TickType_t ) 0 )
{ {
ulExpectedValue = semtstBLOCKING_EXPECTED_VALUE; ulExpectedValue = semtstBLOCKING_EXPECTED_VALUE;
} }
else else
{ {
ulExpectedValue = semtstNON_BLOCKING_EXPECTED_VALUE; ulExpectedValue = semtstNON_BLOCKING_EXPECTED_VALUE;
} }
for( ;; ) for( ; ; )
{ {
/* Try to obtain the semaphore. */ /* Try to obtain the semaphore. */
if( xSemaphoreTake( pxParameters->xSemaphore, pxParameters->xBlockTime ) == pdPASS ) if( xSemaphoreTake( pxParameters->xSemaphore, pxParameters->xBlockTime ) == pdPASS )
{ {
/* We have the semaphore and so expect any other tasks using the /* We have the semaphore and so expect any other tasks using the
shared variable to have left it in the state we expect to find * shared variable to have left it in the state we expect to find
it. */ * it. */
if( *pulSharedVariable != ulExpectedValue ) if( *pulSharedVariable != ulExpectedValue )
{ {
vPrintDisplayMessage( &pcPollingSemaphoreTaskError ); vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
sError = pdTRUE; sError = pdTRUE;
} }
/* Clear the variable, then count it back up to the expected value
before releasing the semaphore. Would expect a context switch or
two during this time. */
for( ulCounter = ( unsigned long ) 0; ulCounter <= ulExpectedValue; ulCounter++ )
{
*pulSharedVariable = ulCounter;
if( *pulSharedVariable != ulCounter )
{
if( sError == pdFALSE )
{
vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
}
sError = pdTRUE;
}
}
/* Release the semaphore, and if no errors have occurred increment the check /* Clear the variable, then count it back up to the expected value
variable. */ * before releasing the semaphore. Would expect a context switch or
if( xSemaphoreGive( pxParameters->xSemaphore ) == pdFALSE ) * two during this time. */
{ for( ulCounter = ( unsigned long ) 0; ulCounter <= ulExpectedValue; ulCounter++ )
vPrintDisplayMessage( &pcPollingSemaphoreTaskError ); {
sError = pdTRUE; *pulSharedVariable = ulCounter;
}
if( sError == pdFALSE ) if( *pulSharedVariable != ulCounter )
{ {
if( sCheckVariableToUse < semtstNUM_TASKS ) if( sError == pdFALSE )
{ {
( sCheckVariables[ sCheckVariableToUse ] )++; vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
} }
}
/* If we have a block time then we are running at a priority higher sError = pdTRUE;
than the idle priority. This task takes a long time to complete }
a cycle (deliberately so to test the guarding) so will be starving }
out lower priority tasks. Block for some time to allow give lower
priority tasks some processor time. */ /* Release the semaphore, and if no errors have occurred increment the check
vTaskDelay( pxParameters->xBlockTime * semtstDELAY_FACTOR ); * variable. */
} if( xSemaphoreGive( pxParameters->xSemaphore ) == pdFALSE )
else {
{ vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
if( pxParameters->xBlockTime == ( TickType_t ) 0 ) sError = pdTRUE;
{ }
/* We have not got the semaphore yet, so no point using the
processor. We are not blocking when attempting to obtain the if( sError == pdFALSE )
semaphore. */ {
taskYIELD(); if( sCheckVariableToUse < semtstNUM_TASKS )
} {
} ( sCheckVariables[ sCheckVariableToUse ] )++;
} }
}
/* If we have a block time then we are running at a priority higher
* than the idle priority. This task takes a long time to complete
* a cycle (deliberately so to test the guarding) so will be starving
* out lower priority tasks. Block for some time to allow give lower
* priority tasks some processor time. */
vTaskDelay( pxParameters->xBlockTime * semtstDELAY_FACTOR );
}
else
{
if( pxParameters->xBlockTime == ( TickType_t ) 0 )
{
/* We have not got the semaphore yet, so no point using the
* processor. We are not blocking when attempting to obtain the
* semaphore. */
taskYIELD();
}
}
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running. */ /* This is called to check that all the created tasks are still running. */
BaseType_t xAreSemaphoreTasksStillRunning( void ) BaseType_t xAreSemaphoreTasksStillRunning( void )
{ {
static short sLastCheckVariables[ semtstNUM_TASKS ] = { 0 }; static short sLastCheckVariables[ semtstNUM_TASKS ] = { 0 };
portBASE_TYPE xTask, xReturn = pdTRUE; portBASE_TYPE xTask, xReturn = pdTRUE;
for( xTask = 0; xTask < semtstNUM_TASKS; xTask++ ) for( xTask = 0; xTask < semtstNUM_TASKS; xTask++ )
{ {
if( sLastCheckVariables[ xTask ] == sCheckVariables[ xTask ] ) if( sLastCheckVariables[ xTask ] == sCheckVariables[ xTask ] )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
} }
sLastCheckVariables[ xTask ] = sCheckVariables[ xTask ]; sLastCheckVariables[ xTask ] = sCheckVariables[ xTask ];
} }
return xReturn; return xReturn;
} }

File diff suppressed because it is too large Load diff

View file

@ -59,232 +59,232 @@
/* Demo program include files. */ /* Demo program include files. */
#include "BlockQ.h" #include "BlockQ.h"
#define blckqSTACK_SIZE configMINIMAL_STACK_SIZE #define blckqSTACK_SIZE configMINIMAL_STACK_SIZE
#define blckqNUM_TASK_SETS ( 3 ) #define blckqNUM_TASK_SETS ( 3 )
#if( configSUPPORT_DYNAMIC_ALLOCATION == 0 ) #if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
#error This example cannot be used if dynamic allocation is not allowed. #error This example cannot be used if dynamic allocation is not allowed.
#endif #endif
/* Structure used to pass parameters to the blocking queue tasks. */ /* Structure used to pass parameters to the blocking queue tasks. */
typedef struct BLOCKING_QUEUE_PARAMETERS typedef struct BLOCKING_QUEUE_PARAMETERS
{ {
QueueHandle_t xQueue; /*< The queue to be used by the task. */ QueueHandle_t xQueue; /*< The queue to be used by the task. */
TickType_t xBlockTime; /*< The block time to use on queue reads/writes. */ TickType_t xBlockTime; /*< The block time to use on queue reads/writes. */
volatile short *psCheckVariable; /*< Incremented on each successful cycle to check the task is still running. */ volatile short * psCheckVariable; /*< Incremented on each successful cycle to check the task is still running. */
} xBlockingQueueParameters; } xBlockingQueueParameters;
/* Task function that creates an incrementing number and posts it on a queue. */ /* Task function that creates an incrementing number and posts it on a queue. */
static portTASK_FUNCTION_PROTO( vBlockingQueueProducer, pvParameters ); static portTASK_FUNCTION_PROTO( vBlockingQueueProducer, pvParameters );
/* Task function that removes the incrementing number from a queue and checks that /* Task function that removes the incrementing number from a queue and checks that
it is the expected number. */ * it is the expected number. */
static portTASK_FUNCTION_PROTO( vBlockingQueueConsumer, pvParameters ); static portTASK_FUNCTION_PROTO( vBlockingQueueConsumer, pvParameters );
/* Variables which are incremented each time an item is removed from a queue, and /* Variables which are incremented each time an item is removed from a queue, and
found to be the expected value. * found to be the expected value.
These are used to check that the tasks are still running. */ * These are used to check that the tasks are still running. */
static volatile short sBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( uint16_t ) 0, ( uint16_t ) 0, ( uint16_t ) 0 }; static volatile short sBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( uint16_t ) 0, ( uint16_t ) 0, ( uint16_t ) 0 };
/* Variable which are incremented each time an item is posted on a queue. These /* Variable which are incremented each time an item is posted on a queue. These
are used to check that the tasks are still running. */ * are used to check that the tasks are still running. */
static volatile short sBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( uint16_t ) 0, ( uint16_t ) 0, ( uint16_t ) 0 }; static volatile short sBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( uint16_t ) 0, ( uint16_t ) 0, ( uint16_t ) 0 };
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vStartBlockingQueueTasks( UBaseType_t uxPriority ) void vStartBlockingQueueTasks( UBaseType_t uxPriority )
{ {
xBlockingQueueParameters *pxQueueParameters1, *pxQueueParameters2; xBlockingQueueParameters * pxQueueParameters1, * pxQueueParameters2;
xBlockingQueueParameters *pxQueueParameters3, *pxQueueParameters4; xBlockingQueueParameters * pxQueueParameters3, * pxQueueParameters4;
xBlockingQueueParameters *pxQueueParameters5, *pxQueueParameters6; xBlockingQueueParameters * pxQueueParameters5, * pxQueueParameters6;
const UBaseType_t uxQueueSize1 = 1, uxQueueSize5 = 5; const UBaseType_t uxQueueSize1 = 1, uxQueueSize5 = 5;
const TickType_t xBlockTime = pdMS_TO_TICKS( ( TickType_t ) 1000 ); const TickType_t xBlockTime = pdMS_TO_TICKS( ( TickType_t ) 1000 );
const TickType_t xDontBlock = ( TickType_t ) 0; const TickType_t xDontBlock = ( TickType_t ) 0;
/* Create the first two tasks as described at the top of the file. */ /* Create the first two tasks as described at the top of the file. */
/* First create the structure used to pass parameters to the consumer tasks. */ /* First create the structure used to pass parameters to the consumer tasks. */
pxQueueParameters1 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) ); pxQueueParameters1 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
/* Create the queue used by the first two tasks to pass the incrementing number. /* Create the queue used by the first two tasks to pass the incrementing number.
Pass a pointer to the queue in the parameter structure. */ * Pass a pointer to the queue in the parameter structure. */
pxQueueParameters1->xQueue = xQueueCreate( uxQueueSize1, ( UBaseType_t ) sizeof( uint16_t ) ); pxQueueParameters1->xQueue = xQueueCreate( uxQueueSize1, ( UBaseType_t ) sizeof( uint16_t ) );
/* The consumer is created first so gets a block time as described above. */ /* The consumer is created first so gets a block time as described above. */
pxQueueParameters1->xBlockTime = xBlockTime; pxQueueParameters1->xBlockTime = xBlockTime;
/* Pass in the variable that this task is going to increment so we can check it /* Pass in the variable that this task is going to increment so we can check it
is still running. */ * is still running. */
pxQueueParameters1->psCheckVariable = &( sBlockingConsumerCount[ 0 ] ); pxQueueParameters1->psCheckVariable = &( sBlockingConsumerCount[ 0 ] );
/* Create the structure used to pass parameters to the producer task. */ /* Create the structure used to pass parameters to the producer task. */
pxQueueParameters2 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) ); pxQueueParameters2 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
/* Pass the queue to this task also, using the parameter structure. */ /* Pass the queue to this task also, using the parameter structure. */
pxQueueParameters2->xQueue = pxQueueParameters1->xQueue; pxQueueParameters2->xQueue = pxQueueParameters1->xQueue;
/* The producer is not going to block - as soon as it posts the consumer will /* The producer is not going to block - as soon as it posts the consumer will
wake and remove the item so the producer should always have room to post. */ * wake and remove the item so the producer should always have room to post. */
pxQueueParameters2->xBlockTime = xDontBlock; pxQueueParameters2->xBlockTime = xDontBlock;
/* Pass in the variable that this task is going to increment so we can check /* Pass in the variable that this task is going to increment so we can check
it is still running. */ * it is still running. */
pxQueueParameters2->psCheckVariable = &( sBlockingProducerCount[ 0 ] ); pxQueueParameters2->psCheckVariable = &( sBlockingProducerCount[ 0 ] );
/* Note the producer has a lower priority than the consumer when the tasks are /* Note the producer has a lower priority than the consumer when the tasks are
spawned. */ * spawned. */
xTaskCreate( vBlockingQueueConsumer, "QConsB1", blckqSTACK_SIZE, ( void * ) pxQueueParameters1, uxPriority, NULL ); xTaskCreate( vBlockingQueueConsumer, "QConsB1", blckqSTACK_SIZE, ( void * ) pxQueueParameters1, uxPriority, NULL );
xTaskCreate( vBlockingQueueProducer, "QProdB2", blckqSTACK_SIZE, ( void * ) pxQueueParameters2, tskIDLE_PRIORITY, NULL ); xTaskCreate( vBlockingQueueProducer, "QProdB2", blckqSTACK_SIZE, ( void * ) pxQueueParameters2, tskIDLE_PRIORITY, NULL );
/* Create the second two tasks as described at the top of the file. This uses /* Create the second two tasks as described at the top of the file. This uses
the same mechanism but reverses the task priorities. */ * the same mechanism but reverses the task priorities. */
pxQueueParameters3 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) ); pxQueueParameters3 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters3->xQueue = xQueueCreate( uxQueueSize1, ( UBaseType_t ) sizeof( uint16_t ) ); pxQueueParameters3->xQueue = xQueueCreate( uxQueueSize1, ( UBaseType_t ) sizeof( uint16_t ) );
pxQueueParameters3->xBlockTime = xDontBlock; pxQueueParameters3->xBlockTime = xDontBlock;
pxQueueParameters3->psCheckVariable = &( sBlockingProducerCount[ 1 ] ); pxQueueParameters3->psCheckVariable = &( sBlockingProducerCount[ 1 ] );
pxQueueParameters4 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) ); pxQueueParameters4 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters4->xQueue = pxQueueParameters3->xQueue; pxQueueParameters4->xQueue = pxQueueParameters3->xQueue;
pxQueueParameters4->xBlockTime = xBlockTime; pxQueueParameters4->xBlockTime = xBlockTime;
pxQueueParameters4->psCheckVariable = &( sBlockingConsumerCount[ 1 ] ); pxQueueParameters4->psCheckVariable = &( sBlockingConsumerCount[ 1 ] );
xTaskCreate( vBlockingQueueConsumer, "QConsB3", blckqSTACK_SIZE, ( void * ) pxQueueParameters3, tskIDLE_PRIORITY, NULL ); xTaskCreate( vBlockingQueueConsumer, "QConsB3", blckqSTACK_SIZE, ( void * ) pxQueueParameters3, tskIDLE_PRIORITY, NULL );
xTaskCreate( vBlockingQueueProducer, "QProdB4", blckqSTACK_SIZE, ( void * ) pxQueueParameters4, uxPriority, NULL ); xTaskCreate( vBlockingQueueProducer, "QProdB4", blckqSTACK_SIZE, ( void * ) pxQueueParameters4, uxPriority, NULL );
/* Create the last two tasks as described above. The mechanism is again just /* Create the last two tasks as described above. The mechanism is again just
the same. This time both parameter structures are given a block time. */ * the same. This time both parameter structures are given a block time. */
pxQueueParameters5 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) ); pxQueueParameters5 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters5->xQueue = xQueueCreate( uxQueueSize5, ( UBaseType_t ) sizeof( uint16_t ) ); pxQueueParameters5->xQueue = xQueueCreate( uxQueueSize5, ( UBaseType_t ) sizeof( uint16_t ) );
pxQueueParameters5->xBlockTime = xBlockTime; pxQueueParameters5->xBlockTime = xBlockTime;
pxQueueParameters5->psCheckVariable = &( sBlockingProducerCount[ 2 ] ); pxQueueParameters5->psCheckVariable = &( sBlockingProducerCount[ 2 ] );
pxQueueParameters6 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) ); pxQueueParameters6 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters6->xQueue = pxQueueParameters5->xQueue; pxQueueParameters6->xQueue = pxQueueParameters5->xQueue;
pxQueueParameters6->xBlockTime = xBlockTime; pxQueueParameters6->xBlockTime = xBlockTime;
pxQueueParameters6->psCheckVariable = &( sBlockingConsumerCount[ 2 ] ); pxQueueParameters6->psCheckVariable = &( sBlockingConsumerCount[ 2 ] );
xTaskCreate( vBlockingQueueProducer, "QProdB5", blckqSTACK_SIZE, ( void * ) pxQueueParameters5, tskIDLE_PRIORITY, NULL ); xTaskCreate( vBlockingQueueProducer, "QProdB5", blckqSTACK_SIZE, ( void * ) pxQueueParameters5, tskIDLE_PRIORITY, NULL );
xTaskCreate( vBlockingQueueConsumer, "QConsB6", blckqSTACK_SIZE, ( void * ) pxQueueParameters6, tskIDLE_PRIORITY, NULL ); xTaskCreate( vBlockingQueueConsumer, "QConsB6", blckqSTACK_SIZE, ( void * ) pxQueueParameters6, tskIDLE_PRIORITY, NULL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static portTASK_FUNCTION( vBlockingQueueProducer, pvParameters ) static portTASK_FUNCTION( vBlockingQueueProducer, pvParameters )
{ {
uint16_t usValue = 0; uint16_t usValue = 0;
xBlockingQueueParameters *pxQueueParameters; xBlockingQueueParameters * pxQueueParameters;
short sErrorEverOccurred = pdFALSE; short sErrorEverOccurred = pdFALSE;
pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters; pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
for( ;; ) for( ; ; )
{ {
if( xQueueSend( pxQueueParameters->xQueue, ( void * ) &usValue, pxQueueParameters->xBlockTime ) != pdPASS ) if( xQueueSend( pxQueueParameters->xQueue, ( void * ) &usValue, pxQueueParameters->xBlockTime ) != pdPASS )
{ {
sErrorEverOccurred = pdTRUE; sErrorEverOccurred = pdTRUE;
} }
else else
{ {
/* We have successfully posted a message, so increment the variable /* We have successfully posted a message, so increment the variable
used to check we are still running. */ * used to check we are still running. */
if( sErrorEverOccurred == pdFALSE ) if( sErrorEverOccurred == pdFALSE )
{ {
( *pxQueueParameters->psCheckVariable )++; ( *pxQueueParameters->psCheckVariable )++;
} }
/* Increment the variable we are going to post next time round. The /* Increment the variable we are going to post next time round. The
consumer will expect the numbers to follow in numerical order. */ * consumer will expect the numbers to follow in numerical order. */
++usValue; ++usValue;
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
taskYIELD(); taskYIELD();
#endif #endif
} }
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static portTASK_FUNCTION( vBlockingQueueConsumer, pvParameters ) static portTASK_FUNCTION( vBlockingQueueConsumer, pvParameters )
{ {
uint16_t usData, usExpectedValue = 0; uint16_t usData, usExpectedValue = 0;
xBlockingQueueParameters *pxQueueParameters; xBlockingQueueParameters * pxQueueParameters;
short sErrorEverOccurred = pdFALSE; short sErrorEverOccurred = pdFALSE;
pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters; pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
for( ;; ) for( ; ; )
{ {
if( xQueueReceive( pxQueueParameters->xQueue, &usData, pxQueueParameters->xBlockTime ) == pdPASS ) if( xQueueReceive( pxQueueParameters->xQueue, &usData, pxQueueParameters->xBlockTime ) == pdPASS )
{ {
if( usData != usExpectedValue ) if( usData != usExpectedValue )
{ {
/* Catch-up. */ /* Catch-up. */
usExpectedValue = usData; usExpectedValue = usData;
sErrorEverOccurred = pdTRUE; sErrorEverOccurred = pdTRUE;
} }
else else
{ {
/* We have successfully received a message, so increment the /* We have successfully received a message, so increment the
variable used to check we are still running. */ * variable used to check we are still running. */
if( sErrorEverOccurred == pdFALSE ) if( sErrorEverOccurred == pdFALSE )
{ {
( *pxQueueParameters->psCheckVariable )++; ( *pxQueueParameters->psCheckVariable )++;
} }
/* Increment the value we expect to remove from the queue next time /* Increment the value we expect to remove from the queue next time
round. */ * round. */
++usExpectedValue; ++usExpectedValue;
} }
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
{ {
if( pxQueueParameters->xBlockTime == 0 ) if( pxQueueParameters->xBlockTime == 0 )
{ {
taskYIELD(); taskYIELD();
} }
} }
#endif #endif
} }
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running. */ /* This is called to check that all the created tasks are still running. */
BaseType_t xAreBlockingQueuesStillRunning( void ) BaseType_t xAreBlockingQueuesStillRunning( void )
{ {
static short sLastBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( uint16_t ) 0, ( uint16_t ) 0, ( uint16_t ) 0 }; static short sLastBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( uint16_t ) 0, ( uint16_t ) 0, ( uint16_t ) 0 };
static short sLastBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( uint16_t ) 0, ( uint16_t ) 0, ( uint16_t ) 0 }; static short sLastBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( uint16_t ) 0, ( uint16_t ) 0, ( uint16_t ) 0 };
BaseType_t xReturn = pdPASS, xTasks; BaseType_t xReturn = pdPASS, xTasks;
/* Not too worried about mutual exclusion on these variables as they are 16 /* Not too worried about mutual exclusion on these variables as they are 16
bits and we are only reading them. We also only care to see if they have * bits and we are only reading them. We also only care to see if they have
changed or not. * changed or not.
*
* Loop through each check variable to and return pdFALSE if any are found not
* to have changed since the last call. */
Loop through each check variable to and return pdFALSE if any are found not for( xTasks = 0; xTasks < blckqNUM_TASK_SETS; xTasks++ )
to have changed since the last call. */ {
if( sBlockingConsumerCount[ xTasks ] == sLastBlockingConsumerCount[ xTasks ] )
{
xReturn = pdFALSE;
}
for( xTasks = 0; xTasks < blckqNUM_TASK_SETS; xTasks++ ) sLastBlockingConsumerCount[ xTasks ] = sBlockingConsumerCount[ xTasks ];
{
if( sBlockingConsumerCount[ xTasks ] == sLastBlockingConsumerCount[ xTasks ] )
{
xReturn = pdFALSE;
}
sLastBlockingConsumerCount[ xTasks ] = sBlockingConsumerCount[ xTasks ];
if( sBlockingProducerCount[ xTasks ] == sLastBlockingProducerCount[ xTasks ] )
{
xReturn = pdFALSE;
}
if( sBlockingProducerCount[ xTasks ] == sLastBlockingProducerCount[ xTasks ] ) sLastBlockingProducerCount[ xTasks ] = sBlockingProducerCount[ xTasks ];
{ }
xReturn = pdFALSE;
}
sLastBlockingProducerCount[ xTasks ] = sBlockingProducerCount[ xTasks ];
}
return xReturn; return xReturn;
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -44,18 +44,18 @@
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* The priorities of the test tasks. */ /* The priorities of the test tasks. */
#define intsemMASTER_PRIORITY ( tskIDLE_PRIORITY ) #define intsemMASTER_PRIORITY ( tskIDLE_PRIORITY )
#define intsemSLAVE_PRIORITY ( tskIDLE_PRIORITY + 1 ) #define intsemSLAVE_PRIORITY ( tskIDLE_PRIORITY + 1 )
/* The rate at which the tick hook will give the mutex. */ /* The rate at which the tick hook will give the mutex. */
#define intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ( 100 ) #define intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ( 100 )
/* A block time of 0 means 'don't block'. */ /* A block time of 0 means 'don't block'. */
#define intsemNO_BLOCK 0 #define intsemNO_BLOCK 0
/* The maximum count value for the counting semaphore given from an /* The maximum count value for the counting semaphore given from an
interrupt. */ * interrupt. */
#define intsemMAX_COUNT 3 #define intsemMAX_COUNT 3
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -69,8 +69,8 @@ interrupt. */
* on a mutex that is shared between the master and the slave - which is a * on a mutex that is shared between the master and the slave - which is a
* separate mutex to that given by the interrupt. * separate mutex to that given by the interrupt.
*/ */
static void vInterruptMutexSlaveTask( void *pvParameters ); static void vInterruptMutexSlaveTask( void * pvParameters );
static void vInterruptMutexMasterTask( void *pvParameters ); static void vInterruptMutexMasterTask( void * pvParameters );
/* /*
* A test whereby the master takes the shared and interrupt mutexes in that * A test whereby the master takes the shared and interrupt mutexes in that
@ -90,37 +90,37 @@ static void prvTakeAndGiveInTheOppositeOrder( void );
* A simple task that interacts with an interrupt using a counting semaphore, * A simple task that interacts with an interrupt using a counting semaphore,
* primarily for code coverage purposes. * primarily for code coverage purposes.
*/ */
static void vInterruptCountingSemaphoreTask( void *pvParameters ); static void vInterruptCountingSemaphoreTask( void * pvParameters );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Flag that will be latched to pdTRUE should any unexpected behaviour be /* Flag that will be latched to pdTRUE should any unexpected behaviour be
detected in any of the tasks. */ * detected in any of the tasks. */
static volatile BaseType_t xErrorDetected = pdFALSE; static volatile BaseType_t xErrorDetected = pdFALSE;
/* Counters that are incremented on each cycle of a test. This is used to /* Counters that are incremented on each cycle of a test. This is used to
detect a stalled task - a test that is no longer running. */ * detect a stalled task - a test that is no longer running. */
static volatile uint32_t ulMasterLoops = 0, ulCountingSemaphoreLoops = 0; static volatile uint32_t ulMasterLoops = 0, ulCountingSemaphoreLoops = 0;
/* Handles of the test tasks that must be accessed from other test tasks. */ /* Handles of the test tasks that must be accessed from other test tasks. */
static TaskHandle_t xSlaveHandle; static TaskHandle_t xSlaveHandle;
/* A mutex which is given from an interrupt - although generally mutexes should /* A mutex which is given from an interrupt - although generally mutexes should
not be used given in interrupts (and definitely never taken in an interrupt) * not be used given in interrupts (and definitely never taken in an interrupt)
there are some circumstances when it may be desirable. */ * there are some circumstances when it may be desirable. */
static SemaphoreHandle_t xISRMutex = NULL; static SemaphoreHandle_t xISRMutex = NULL;
/* A counting semaphore which is given from an interrupt. */ /* A counting semaphore which is given from an interrupt. */
static SemaphoreHandle_t xISRCountingSemaphore = NULL; static SemaphoreHandle_t xISRCountingSemaphore = NULL;
/* A mutex which is shared between the master and slave tasks - the master /* A mutex which is shared between the master and slave tasks - the master
does both sharing of this mutex with the slave and receiving a mutex from the * does both sharing of this mutex with the slave and receiving a mutex from the
interrupt. */ * interrupt. */
static SemaphoreHandle_t xMasterSlaveMutex = NULL; static SemaphoreHandle_t xMasterSlaveMutex = NULL;
/* Flag that allows the master task to control when the interrupt gives or does /* Flag that allows the master task to control when the interrupt gives or does
not give the mutex. There is no mutual exclusion on this variable, but this is * not give the mutex. There is no mutual exclusion on this variable, but this is
only test code and it should be fine in the 32=bit test environment. */ * only test code and it should be fine in the 32=bit test environment. */
static BaseType_t xOkToGiveMutex = pdFALSE, xOkToGiveCountingSemaphore = pdFALSE; static BaseType_t xOkToGiveMutex = pdFALSE, xOkToGiveCountingSemaphore = pdFALSE;
/* Used to coordinate timing between tasks and the interrupt. */ /* Used to coordinate timing between tasks and the interrupt. */
@ -130,396 +130,402 @@ const TickType_t xInterruptGivePeriod = pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIV
void vStartInterruptSemaphoreTasks( void ) void vStartInterruptSemaphoreTasks( void )
{ {
/* Create the semaphores that are given from an interrupt. */ /* Create the semaphores that are given from an interrupt. */
xISRMutex = xSemaphoreCreateMutex(); xISRMutex = xSemaphoreCreateMutex();
configASSERT( xISRMutex ); configASSERT( xISRMutex );
xISRCountingSemaphore = xSemaphoreCreateCounting( intsemMAX_COUNT, 0 ); xISRCountingSemaphore = xSemaphoreCreateCounting( intsemMAX_COUNT, 0 );
configASSERT( xISRCountingSemaphore ); configASSERT( xISRCountingSemaphore );
/* Create the mutex that is shared between the master and slave tasks (the /* Create the mutex that is shared between the master and slave tasks (the
master receives a mutex from an interrupt and shares a mutex with the * master receives a mutex from an interrupt and shares a mutex with the
slave. */ * slave. */
xMasterSlaveMutex = xSemaphoreCreateMutex(); xMasterSlaveMutex = xSemaphoreCreateMutex();
configASSERT( xMasterSlaveMutex ); configASSERT( xMasterSlaveMutex );
/* Create the tasks that share mutexes between then and with interrupts. */ /* Create the tasks that share mutexes between then and with interrupts. */
xTaskCreate( vInterruptMutexSlaveTask, "IntMuS", configMINIMAL_STACK_SIZE, NULL, intsemSLAVE_PRIORITY, &xSlaveHandle ); xTaskCreate( vInterruptMutexSlaveTask, "IntMuS", configMINIMAL_STACK_SIZE, NULL, intsemSLAVE_PRIORITY, &xSlaveHandle );
xTaskCreate( vInterruptMutexMasterTask, "IntMuM", configMINIMAL_STACK_SIZE, NULL, intsemMASTER_PRIORITY, NULL ); xTaskCreate( vInterruptMutexMasterTask, "IntMuM", configMINIMAL_STACK_SIZE, NULL, intsemMASTER_PRIORITY, NULL );
/* Create the task that blocks on the counting semaphore. */ /* Create the task that blocks on the counting semaphore. */
xTaskCreate( vInterruptCountingSemaphoreTask, "IntCnt", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); xTaskCreate( vInterruptCountingSemaphoreTask, "IntCnt", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vInterruptMutexMasterTask( void *pvParameters ) static void vInterruptMutexMasterTask( void * pvParameters )
{ {
/* Just to avoid compiler warnings. */ /* Just to avoid compiler warnings. */
( void ) pvParameters; ( void ) pvParameters;
for( ;; ) for( ; ; )
{ {
prvTakeAndGiveInTheSameOrder(); prvTakeAndGiveInTheSameOrder();
/* Ensure not to starve out other tests. */ /* Ensure not to starve out other tests. */
ulMasterLoops++; ulMasterLoops++;
vTaskDelay( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ); vTaskDelay( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS );
prvTakeAndGiveInTheOppositeOrder(); prvTakeAndGiveInTheOppositeOrder();
/* Ensure not to starve out other tests. */ /* Ensure not to starve out other tests. */
ulMasterLoops++; ulMasterLoops++;
vTaskDelay( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ); vTaskDelay( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvTakeAndGiveInTheSameOrder( void ) static void prvTakeAndGiveInTheSameOrder( void )
{ {
/* Ensure the slave is suspended, and that this task is running at the /* Ensure the slave is suspended, and that this task is running at the
lower priority as expected as the start conditions. */ * lower priority as expected as the start conditions. */
#if( INCLUDE_eTaskGetState == 1 ) #if ( INCLUDE_eTaskGetState == 1 )
{ {
configASSERT( eTaskGetState( xSlaveHandle ) == eSuspended ); configASSERT( eTaskGetState( xSlaveHandle ) == eSuspended );
} }
#endif /* INCLUDE_eTaskGetState */ #endif /* INCLUDE_eTaskGetState */
if( uxTaskPriorityGet( NULL ) != intsemMASTER_PRIORITY ) if( uxTaskPriorityGet( NULL ) != intsemMASTER_PRIORITY )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Take the semaphore that is shared with the slave. */ /* Take the semaphore that is shared with the slave. */
if( xSemaphoreTake( xMasterSlaveMutex, intsemNO_BLOCK ) != pdPASS ) if( xSemaphoreTake( xMasterSlaveMutex, intsemNO_BLOCK ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* This task now has the mutex. Unsuspend the slave so it too /* This task now has the mutex. Unsuspend the slave so it too
attempts to take the mutex. */ * attempts to take the mutex. */
vTaskResume( xSlaveHandle ); vTaskResume( xSlaveHandle );
/* The slave has the higher priority so should now have executed and /* The slave has the higher priority so should now have executed and
blocked on the semaphore. */ * blocked on the semaphore. */
#if( INCLUDE_eTaskGetState == 1 ) #if ( INCLUDE_eTaskGetState == 1 )
{ {
configASSERT( eTaskGetState( xSlaveHandle ) == eBlocked ); configASSERT( eTaskGetState( xSlaveHandle ) == eBlocked );
} }
#endif /* INCLUDE_eTaskGetState */ #endif /* INCLUDE_eTaskGetState */
/* This task should now have inherited the priority of the slave /* This task should now have inherited the priority of the slave
task. */ * task. */
if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY ) if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Now wait a little longer than the time between ISR gives to also /* Now wait a little longer than the time between ISR gives to also
obtain the ISR mutex. */ * obtain the ISR mutex. */
xOkToGiveMutex = pdTRUE; xOkToGiveMutex = pdTRUE;
if( xSemaphoreTake( xISRMutex, ( xInterruptGivePeriod * 2 ) ) != pdPASS )
{
xErrorDetected = pdTRUE;
}
xOkToGiveMutex = pdFALSE;
/* Attempting to take again immediately should fail as the mutex is if( xSemaphoreTake( xISRMutex, ( xInterruptGivePeriod * 2 ) ) != pdPASS )
already held. */ {
if( xSemaphoreTake( xISRMutex, intsemNO_BLOCK ) != pdFAIL ) xErrorDetected = pdTRUE;
{ }
xErrorDetected = pdTRUE;
}
/* Should still be at the priority of the slave task. */ xOkToGiveMutex = pdFALSE;
if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
{
xErrorDetected = pdTRUE;
}
/* Give back the ISR semaphore to ensure the priority is not /* Attempting to take again immediately should fail as the mutex is
disinherited as the shared mutex (which the higher priority task is * already held. */
attempting to obtain) is still held. */ if( xSemaphoreTake( xISRMutex, intsemNO_BLOCK ) != pdFAIL )
if( xSemaphoreGive( xISRMutex ) != pdPASS ) {
{ xErrorDetected = pdTRUE;
xErrorDetected = pdTRUE; }
}
if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY ) /* Should still be at the priority of the slave task. */
{ if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
xErrorDetected = pdTRUE; {
} xErrorDetected = pdTRUE;
}
/* Finally give back the shared mutex. This time the higher priority /* Give back the ISR semaphore to ensure the priority is not
task should run before this task runs again - so this task should have * disinherited as the shared mutex (which the higher priority task is
disinherited the priority and the higher priority task should be in the * attempting to obtain) is still held. */
suspended state again. */ if( xSemaphoreGive( xISRMutex ) != pdPASS )
if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS ) {
{ xErrorDetected = pdTRUE;
xErrorDetected = pdTRUE; }
}
if( uxTaskPriorityGet( NULL ) != intsemMASTER_PRIORITY ) if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
#if( INCLUDE_eTaskGetState == 1 ) /* Finally give back the shared mutex. This time the higher priority
{ * task should run before this task runs again - so this task should have
configASSERT( eTaskGetState( xSlaveHandle ) == eSuspended ); * disinherited the priority and the higher priority task should be in the
} * suspended state again. */
#endif /* INCLUDE_eTaskGetState */ if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS )
{
xErrorDetected = pdTRUE;
}
/* Reset the mutex ready for the next round. */ if( uxTaskPriorityGet( NULL ) != intsemMASTER_PRIORITY )
xQueueReset( xISRMutex ); {
xErrorDetected = pdTRUE;
}
#if ( INCLUDE_eTaskGetState == 1 )
{
configASSERT( eTaskGetState( xSlaveHandle ) == eSuspended );
}
#endif /* INCLUDE_eTaskGetState */
/* Reset the mutex ready for the next round. */
xQueueReset( xISRMutex );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvTakeAndGiveInTheOppositeOrder( void ) static void prvTakeAndGiveInTheOppositeOrder( void )
{ {
/* Ensure the slave is suspended, and that this task is running at the /* Ensure the slave is suspended, and that this task is running at the
lower priority as expected as the start conditions. */ * lower priority as expected as the start conditions. */
#if( INCLUDE_eTaskGetState == 1 ) #if ( INCLUDE_eTaskGetState == 1 )
{ {
configASSERT( eTaskGetState( xSlaveHandle ) == eSuspended ); configASSERT( eTaskGetState( xSlaveHandle ) == eSuspended );
} }
#endif /* INCLUDE_eTaskGetState */ #endif /* INCLUDE_eTaskGetState */
if( uxTaskPriorityGet( NULL ) != intsemMASTER_PRIORITY ) if( uxTaskPriorityGet( NULL ) != intsemMASTER_PRIORITY )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Take the semaphore that is shared with the slave. */ /* Take the semaphore that is shared with the slave. */
if( xSemaphoreTake( xMasterSlaveMutex, intsemNO_BLOCK ) != pdPASS ) if( xSemaphoreTake( xMasterSlaveMutex, intsemNO_BLOCK ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* This task now has the mutex. Unsuspend the slave so it too /* This task now has the mutex. Unsuspend the slave so it too
attempts to take the mutex. */ * attempts to take the mutex. */
vTaskResume( xSlaveHandle ); vTaskResume( xSlaveHandle );
/* The slave has the higher priority so should now have executed and /* The slave has the higher priority so should now have executed and
blocked on the semaphore. */ * blocked on the semaphore. */
#if( INCLUDE_eTaskGetState == 1 ) #if ( INCLUDE_eTaskGetState == 1 )
{ {
configASSERT( eTaskGetState( xSlaveHandle ) == eBlocked ); configASSERT( eTaskGetState( xSlaveHandle ) == eBlocked );
} }
#endif /* INCLUDE_eTaskGetState */ #endif /* INCLUDE_eTaskGetState */
/* This task should now have inherited the priority of the slave /* This task should now have inherited the priority of the slave
task. */ * task. */
if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY ) if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Now wait a little longer than the time between ISR gives to also /* Now wait a little longer than the time between ISR gives to also
obtain the ISR mutex. */ * obtain the ISR mutex. */
xOkToGiveMutex = pdTRUE; xOkToGiveMutex = pdTRUE;
if( xSemaphoreTake( xISRMutex, ( xInterruptGivePeriod * 2 ) ) != pdPASS )
{
xErrorDetected = pdTRUE;
}
xOkToGiveMutex = pdFALSE;
/* Attempting to take again immediately should fail as the mutex is if( xSemaphoreTake( xISRMutex, ( xInterruptGivePeriod * 2 ) ) != pdPASS )
already held. */ {
if( xSemaphoreTake( xISRMutex, intsemNO_BLOCK ) != pdFAIL ) xErrorDetected = pdTRUE;
{ }
xErrorDetected = pdTRUE;
}
/* Should still be at the priority of the slave task. */ xOkToGiveMutex = pdFALSE;
if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
{
xErrorDetected = pdTRUE;
}
/* Give back the shared semaphore to ensure the priority is not disinherited /* Attempting to take again immediately should fail as the mutex is
as the ISR mutex is still held. The higher priority slave task should run * already held. */
before this task runs again. */ if( xSemaphoreTake( xISRMutex, intsemNO_BLOCK ) != pdFAIL )
if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS ) {
{ xErrorDetected = pdTRUE;
xErrorDetected = pdTRUE; }
}
/* Should still be at the priority of the slave task as this task still /* Should still be at the priority of the slave task. */
holds one semaphore (this is a simplification in the priority inheritance if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
mechanism. */ {
if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY ) xErrorDetected = pdTRUE;
{ }
xErrorDetected = pdTRUE;
}
/* Give back the ISR semaphore, which should result in the priority being /* Give back the shared semaphore to ensure the priority is not disinherited
disinherited as it was the last mutex held. */ * as the ISR mutex is still held. The higher priority slave task should run
if( xSemaphoreGive( xISRMutex ) != pdPASS ) * before this task runs again. */
{ if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS )
xErrorDetected = pdTRUE; {
} xErrorDetected = pdTRUE;
}
if( uxTaskPriorityGet( NULL ) != intsemMASTER_PRIORITY ) /* Should still be at the priority of the slave task as this task still
{ * holds one semaphore (this is a simplification in the priority inheritance
xErrorDetected = pdTRUE; * mechanism. */
} if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
{
xErrorDetected = pdTRUE;
}
/* Reset the mutex ready for the next round. */ /* Give back the ISR semaphore, which should result in the priority being
xQueueReset( xISRMutex ); * disinherited as it was the last mutex held. */
if( xSemaphoreGive( xISRMutex ) != pdPASS )
{
xErrorDetected = pdTRUE;
}
if( uxTaskPriorityGet( NULL ) != intsemMASTER_PRIORITY )
{
xErrorDetected = pdTRUE;
}
/* Reset the mutex ready for the next round. */
xQueueReset( xISRMutex );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vInterruptMutexSlaveTask( void *pvParameters ) static void vInterruptMutexSlaveTask( void * pvParameters )
{ {
/* Just to avoid compiler warnings. */ /* Just to avoid compiler warnings. */
( void ) pvParameters; ( void ) pvParameters;
for( ;; ) for( ; ; )
{ {
/* This task starts by suspending itself so when it executes can be /* This task starts by suspending itself so when it executes can be
controlled by the master task. */ * controlled by the master task. */
vTaskSuspend( NULL ); vTaskSuspend( NULL );
/* This task will execute when the master task already holds the mutex. /* This task will execute when the master task already holds the mutex.
Attempting to take the mutex will place this task in the Blocked * Attempting to take the mutex will place this task in the Blocked
state. */ * state. */
if( xSemaphoreTake( xMasterSlaveMutex, portMAX_DELAY ) != pdPASS ) if( xSemaphoreTake( xMasterSlaveMutex, portMAX_DELAY ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS ) if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vInterruptCountingSemaphoreTask( void *pvParameters ) static void vInterruptCountingSemaphoreTask( void * pvParameters )
{ {
BaseType_t xCount; BaseType_t xCount;
const TickType_t xDelay = pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ) * ( intsemMAX_COUNT + 1 ); const TickType_t xDelay = pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ) * ( intsemMAX_COUNT + 1 );
( void ) pvParameters; ( void ) pvParameters;
for( ;; ) for( ; ; )
{ {
/* Expect to start with the counting semaphore empty. */ /* Expect to start with the counting semaphore empty. */
if( uxQueueMessagesWaiting( ( QueueHandle_t ) xISRCountingSemaphore ) != 0 ) if( uxQueueMessagesWaiting( ( QueueHandle_t ) xISRCountingSemaphore ) != 0 )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Wait until it is expected that the interrupt will have filled the /* Wait until it is expected that the interrupt will have filled the
counting semaphore. */ * counting semaphore. */
xOkToGiveCountingSemaphore = pdTRUE; xOkToGiveCountingSemaphore = pdTRUE;
vTaskDelay( xDelay ); vTaskDelay( xDelay );
xOkToGiveCountingSemaphore = pdFALSE; xOkToGiveCountingSemaphore = pdFALSE;
/* Now it is expected that the counting semaphore is full. */ /* Now it is expected that the counting semaphore is full. */
if( uxQueueMessagesWaiting( ( QueueHandle_t ) xISRCountingSemaphore ) != intsemMAX_COUNT ) if( uxQueueMessagesWaiting( ( QueueHandle_t ) xISRCountingSemaphore ) != intsemMAX_COUNT )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
if( uxQueueSpacesAvailable( ( QueueHandle_t ) xISRCountingSemaphore ) != 0 ) if( uxQueueSpacesAvailable( ( QueueHandle_t ) xISRCountingSemaphore ) != 0 )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
ulCountingSemaphoreLoops++; ulCountingSemaphoreLoops++;
/* Expect to be able to take the counting semaphore intsemMAX_COUNT /* Expect to be able to take the counting semaphore intsemMAX_COUNT
times. A block time of 0 is used as the semaphore should already be * times. A block time of 0 is used as the semaphore should already be
there. */ * there. */
xCount = 0; xCount = 0;
while( xSemaphoreTake( xISRCountingSemaphore, 0 ) == pdPASS )
{
xCount++;
}
if( xCount != intsemMAX_COUNT ) while( xSemaphoreTake( xISRCountingSemaphore, 0 ) == pdPASS )
{ {
xErrorDetected = pdTRUE; xCount++;
} }
/* Now raise the priority of this task so it runs immediately that the if( xCount != intsemMAX_COUNT )
semaphore is given from the interrupt. */ {
vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 ); xErrorDetected = pdTRUE;
}
/* Block to wait for the semaphore to be given from the interrupt. */ /* Now raise the priority of this task so it runs immediately that the
xOkToGiveCountingSemaphore = pdTRUE; * semaphore is given from the interrupt. */
xSemaphoreTake( xISRCountingSemaphore, portMAX_DELAY ); vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
xSemaphoreTake( xISRCountingSemaphore, portMAX_DELAY );
xOkToGiveCountingSemaphore = pdFALSE;
/* Reset the priority so as not to disturbe other tests too much. */ /* Block to wait for the semaphore to be given from the interrupt. */
vTaskPrioritySet( NULL, tskIDLE_PRIORITY ); xOkToGiveCountingSemaphore = pdTRUE;
xSemaphoreTake( xISRCountingSemaphore, portMAX_DELAY );
xSemaphoreTake( xISRCountingSemaphore, portMAX_DELAY );
xOkToGiveCountingSemaphore = pdFALSE;
ulCountingSemaphoreLoops++; /* Reset the priority so as not to disturbe other tests too much. */
} vTaskPrioritySet( NULL, tskIDLE_PRIORITY );
ulCountingSemaphoreLoops++;
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vInterruptSemaphorePeriodicTest( void ) void vInterruptSemaphorePeriodicTest( void )
{ {
static TickType_t xLastGiveTime = 0; static TickType_t xLastGiveTime = 0;
BaseType_t xHigherPriorityTaskWoken = pdFALSE; BaseType_t xHigherPriorityTaskWoken = pdFALSE;
TickType_t xTimeNow; TickType_t xTimeNow;
/* No mutual exclusion on xOkToGiveMutex, but this is only test code (and /* No mutual exclusion on xOkToGiveMutex, but this is only test code (and
only executed on a 32-bit architecture) so ignore that in this case. */ * only executed on a 32-bit architecture) so ignore that in this case. */
xTimeNow = xTaskGetTickCountFromISR(); xTimeNow = xTaskGetTickCountFromISR();
if( ( ( TickType_t ) ( xTimeNow - xLastGiveTime ) ) >= pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ) )
{
configASSERT( xISRMutex );
if( xOkToGiveMutex != pdFALSE )
{
/* Null is used as the second parameter in this give, and non-NULL
in the other gives for code coverage reasons. */
xSemaphoreGiveFromISR( xISRMutex, NULL );
/* Second give attempt should fail. */ if( ( ( TickType_t ) ( xTimeNow - xLastGiveTime ) ) >= pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ) )
configASSERT( xSemaphoreGiveFromISR( xISRMutex, &xHigherPriorityTaskWoken ) == pdFAIL ); {
} configASSERT( xISRMutex );
if( xOkToGiveCountingSemaphore != pdFALSE ) if( xOkToGiveMutex != pdFALSE )
{ {
xSemaphoreGiveFromISR( xISRCountingSemaphore, &xHigherPriorityTaskWoken ); /* Null is used as the second parameter in this give, and non-NULL
} * in the other gives for code coverage reasons. */
xLastGiveTime = xTimeNow; xSemaphoreGiveFromISR( xISRMutex, NULL );
}
/* Remove compiler warnings about the value being set but not used. */ /* Second give attempt should fail. */
( void ) xHigherPriorityTaskWoken; configASSERT( xSemaphoreGiveFromISR( xISRMutex, &xHigherPriorityTaskWoken ) == pdFAIL );
}
if( xOkToGiveCountingSemaphore != pdFALSE )
{
xSemaphoreGiveFromISR( xISRCountingSemaphore, &xHigherPriorityTaskWoken );
}
xLastGiveTime = xTimeNow;
}
/* Remove compiler warnings about the value being set but not used. */
( void ) xHigherPriorityTaskWoken;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running. */ /* This is called to check that all the created tasks are still running. */
BaseType_t xAreInterruptSemaphoreTasksStillRunning( void ) BaseType_t xAreInterruptSemaphoreTasksStillRunning( void )
{ {
static uint32_t ulLastMasterLoopCounter = 0, ulLastCountingSemaphoreLoops = 0; static uint32_t ulLastMasterLoopCounter = 0, ulLastCountingSemaphoreLoops = 0;
/* If the demo tasks are running then it is expected that the loop counters /* If the demo tasks are running then it is expected that the loop counters
will have changed since this function was last called. */ * will have changed since this function was last called. */
if( ulLastMasterLoopCounter == ulMasterLoops ) if( ulLastMasterLoopCounter == ulMasterLoops )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
ulLastMasterLoopCounter = ulMasterLoops; ulLastMasterLoopCounter = ulMasterLoops;
if( ulLastCountingSemaphoreLoops == ulCountingSemaphoreLoops ) if( ulLastCountingSemaphoreLoops == ulCountingSemaphoreLoops )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
ulLastCountingSemaphoreLoops = ulCountingSemaphoreLoops++; ulLastCountingSemaphoreLoops = ulCountingSemaphoreLoops++;
/* Errors detected in the task itself will have latched xErrorDetected /* Errors detected in the task itself will have latched xErrorDetected
to true. */ * to true. */
return ( BaseType_t ) !xErrorDetected; return ( BaseType_t ) !xErrorDetected;
} }

View file

@ -19,8 +19,8 @@
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 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. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* *
* https://www.FreeRTOS.org * https://www.FreeRTOS.org
* https://github.com/FreeRTOS * https://github.com/FreeRTOS
* *
*/ */
@ -68,22 +68,22 @@
#include "MessageBufferAMP.h" #include "MessageBufferAMP.h"
/* Enough for 3 4 byte pointers, including the additional 4 bytes per message /* Enough for 3 4 byte pointers, including the additional 4 bytes per message
overhead of message buffers. */ * overhead of message buffers. */
#define mbaCONTROL_MESSAGE_BUFFER_SIZE ( 24 ) #define mbaCONTROL_MESSAGE_BUFFER_SIZE ( 24 )
/* Enough four 4 8 byte strings, plus the additional 4 bytes per message /* Enough four 4 8 byte strings, plus the additional 4 bytes per message
overhead of message buffers. */ * overhead of message buffers. */
#define mbaTASK_MESSAGE_BUFFER_SIZE ( 60 ) #define mbaTASK_MESSAGE_BUFFER_SIZE ( 60 )
/* The number of instances of prvCoreBTasks that are created. */ /* The number of instances of prvCoreBTasks that are created. */
#define mbaNUMBER_OF_CORE_B_TASKS 2 #define mbaNUMBER_OF_CORE_B_TASKS 2
/* A block time of 0 simply means, don't block. */ /* A block time of 0 simply means, don't block. */
#define mbaDONT_BLOCK 0 #define mbaDONT_BLOCK 0
/* Macro that mimics an interrupt service routine executing by simply calling /* Macro that mimics an interrupt service routine executing by simply calling
the routine inline. */ * the routine inline. */
#define mbaGENERATE_CORE_B_INTERRUPT() prvCoreBInterruptHandler() #define mbaGENERATE_CORE_B_INTERRUPT() prvCoreBInterruptHandler()
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -91,14 +91,14 @@ the routine inline. */
* Implementation of the task that, on a real dual core device, would run on * Implementation of the task that, on a real dual core device, would run on
* core A and send message to tasks running on core B. * core A and send message to tasks running on core B.
*/ */
static void prvCoreATask( void *pvParameters ); static void prvCoreATask( void * pvParameters );
/* /*
* Implementation of the task that, on a real dual core device, would run on * Implementation of the task that, on a real dual core device, would run on
* core B and receive message from core A. The demo creates two instances of * core B and receive message from core A. The demo creates two instances of
* this task. * this task.
*/ */
static void prvCoreBTasks( void *pvParameters ); static void prvCoreBTasks( void * pvParameters );
/* /*
* The function that, on a real dual core device, would handle inter-core * The function that, on a real dual core device, would handle inter-core
@ -112,218 +112,217 @@ static void prvCoreBInterruptHandler( void );
static MessageBufferHandle_t xCoreBMessageBuffers[ mbaNUMBER_OF_CORE_B_TASKS ]; static MessageBufferHandle_t xCoreBMessageBuffers[ mbaNUMBER_OF_CORE_B_TASKS ];
/* The control message buffer. This is used to pass the handle of the message /* The control message buffer. This is used to pass the handle of the message
message buffer that holds application data into the core to core interrupt * message buffer that holds application data into the core to core interrupt
service routine. */ * service routine. */
static MessageBufferHandle_t xControlMessageBuffer; static MessageBufferHandle_t xControlMessageBuffer;
/* Counters used to indicate to the check that the tasks are still executing. */ /* Counters used to indicate to the check that the tasks are still executing. */
static uint32_t ulCycleCounters[ mbaNUMBER_OF_CORE_B_TASKS ]; static uint32_t ulCycleCounters[ mbaNUMBER_OF_CORE_B_TASKS ];
/* Set to pdFALSE if any errors are detected. Used to inform the check task /* Set to pdFALSE if any errors are detected. Used to inform the check task
that something might be wrong. */ * that something might be wrong. */
BaseType_t xDemoStatus = pdPASS; BaseType_t xDemoStatus = pdPASS;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vStartMessageBufferAMPTasks( configSTACK_DEPTH_TYPE xStackSize ) void vStartMessageBufferAMPTasks( configSTACK_DEPTH_TYPE xStackSize )
{ {
BaseType_t x; BaseType_t x;
xControlMessageBuffer = xMessageBufferCreate( mbaCONTROL_MESSAGE_BUFFER_SIZE ); xControlMessageBuffer = xMessageBufferCreate( mbaCONTROL_MESSAGE_BUFFER_SIZE );
xTaskCreate( prvCoreATask, /* The function that implements the task. */ xTaskCreate( prvCoreATask, /* The function that implements the task. */
"AMPCoreA", /* Human readable name for the task. */ "AMPCoreA", /* Human readable name for the task. */
xStackSize, /* Stack size (in words!). */ xStackSize, /* Stack size (in words!). */
NULL, /* Task parameter is not used. */ NULL, /* Task parameter is not used. */
tskIDLE_PRIORITY, /* The priority at which the task is created. */ tskIDLE_PRIORITY, /* The priority at which the task is created. */
NULL ); /* No use for the task handle. */ NULL ); /* No use for the task handle. */
for( x = 0; x < mbaNUMBER_OF_CORE_B_TASKS; x++ ) for( x = 0; x < mbaNUMBER_OF_CORE_B_TASKS; x++ )
{ {
xCoreBMessageBuffers[ x ] = xMessageBufferCreate( mbaTASK_MESSAGE_BUFFER_SIZE ); xCoreBMessageBuffers[ x ] = xMessageBufferCreate( mbaTASK_MESSAGE_BUFFER_SIZE );
configASSERT( xCoreBMessageBuffers[ x ] ); configASSERT( xCoreBMessageBuffers[ x ] );
/* Pass the loop counter into the created task using the task's /* Pass the loop counter into the created task using the task's
parameter. The task then uses the value as an index into the * parameter. The task then uses the value as an index into the
ulCycleCounters and xCoreBMessageBuffers arrays. */ * ulCycleCounters and xCoreBMessageBuffers arrays. */
xTaskCreate( prvCoreBTasks, xTaskCreate( prvCoreBTasks,
"AMPCoreB1", "AMPCoreB1",
xStackSize, xStackSize,
( void * ) x, ( void * ) x,
tskIDLE_PRIORITY + 1, tskIDLE_PRIORITY + 1,
NULL ); NULL );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvCoreATask( void *pvParameters ) static void prvCoreATask( void * pvParameters )
{ {
BaseType_t x; BaseType_t x;
uint32_t ulNextValue = 0; uint32_t ulNextValue = 0;
const TickType_t xDelay = pdMS_TO_TICKS( 250 ); const TickType_t xDelay = pdMS_TO_TICKS( 250 );
char cString[ 15 ]; /* At least large enough to hold "4294967295\0" (0xffffffff). */ char cString[ 15 ]; /* At least large enough to hold "4294967295\0" (0xffffffff). */
/* Remove warning about unused parameters. */ /* Remove warning about unused parameters. */
( void ) pvParameters; ( void ) pvParameters;
for( ;; ) for( ; ; )
{ {
/* Create the next string to send. The value is incremented on each /* Create the next string to send. The value is incremented on each
loop iteration, and the length of the string changes as the number of * loop iteration, and the length of the string changes as the number of
digits in the value increases. */ * digits in the value increases. */
sprintf( cString, "%lu", ( unsigned long ) ulNextValue ); sprintf( cString, "%lu", ( unsigned long ) ulNextValue );
/* Send the value from this (pseudo) Core A to the tasks on the (pseudo) /* Send the value from this (pseudo) Core A to the tasks on the (pseudo)
Core B via the message buffers. This will result in sbSEND_COMPLETED() * Core B via the message buffers. This will result in sbSEND_COMPLETED()
being executed, which in turn will write the handle of the message * being executed, which in turn will write the handle of the message
buffer written to into xControlMessageBuffer then generate an interrupt * buffer written to into xControlMessageBuffer then generate an interrupt
in core B. */ * in core B. */
for( x = 0; x < mbaNUMBER_OF_CORE_B_TASKS; x++ ) for( x = 0; x < mbaNUMBER_OF_CORE_B_TASKS; x++ )
{ {
xMessageBufferSend( /* The message buffer to write to. */ xMessageBufferSend( /* The message buffer to write to. */
xCoreBMessageBuffers[ x ], xCoreBMessageBuffers[ x ],
/* The source of the data to send. */ /* The source of the data to send. */
( void * ) cString, ( void * ) cString,
/* The length of the data to send. */ /* The length of the data to send. */
strlen( cString ), strlen( cString ),
/* The block time, should the buffer be full. */ /* The block time, should the buffer be full. */
mbaDONT_BLOCK ); mbaDONT_BLOCK );
} }
/* Delay before repeating with a different and potentially different /* Delay before repeating with a different and potentially different
length string. */ * length string. */
vTaskDelay( xDelay ); vTaskDelay( xDelay );
ulNextValue++; ulNextValue++;
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvCoreBTasks( void *pvParameters ) static void prvCoreBTasks( void * pvParameters )
{ {
BaseType_t x; BaseType_t x;
size_t xReceivedBytes; size_t xReceivedBytes;
uint32_t ulNextValue = 0; uint32_t ulNextValue = 0;
char cExpectedString[ 15 ]; /* At least large enough to hold "4294967295\0" (0xffffffff). */ char cExpectedString[ 15 ]; /* At least large enough to hold "4294967295\0" (0xffffffff). */
char cReceivedString[ 15 ]; char cReceivedString[ 15 ];
/* The index into the xCoreBMessageBuffers and ulLoopCounter arrays is /* The index into the xCoreBMessageBuffers and ulLoopCounter arrays is
passed into this task using the task's parameter. */ * passed into this task using the task's parameter. */
x = ( BaseType_t ) pvParameters; x = ( BaseType_t ) pvParameters;
configASSERT( x < mbaNUMBER_OF_CORE_B_TASKS ); configASSERT( x < mbaNUMBER_OF_CORE_B_TASKS );
for( ;; ) for( ; ; )
{ {
/* Create the string that is expected to be received this time round. */ /* Create the string that is expected to be received this time round. */
sprintf( cExpectedString, "%lu", ( unsigned long ) ulNextValue ); sprintf( cExpectedString, "%lu", ( unsigned long ) ulNextValue );
/* Wait to receive the next message from core A. */ /* Wait to receive the next message from core A. */
memset( cReceivedString, 0x00, sizeof( cReceivedString ) ); memset( cReceivedString, 0x00, sizeof( cReceivedString ) );
xReceivedBytes = xMessageBufferReceive( /* The message buffer to receive from. */ xReceivedBytes = xMessageBufferReceive( /* The message buffer to receive from. */
xCoreBMessageBuffers[ x ], xCoreBMessageBuffers[ x ],
/* Location to store received data. */ /* Location to store received data. */
cReceivedString, cReceivedString,
/* Maximum number of bytes to receive. */ /* Maximum number of bytes to receive. */
sizeof( cReceivedString ), sizeof( cReceivedString ),
/* Ticks to wait if buffer is empty. */ /* Ticks to wait if buffer is empty. */
portMAX_DELAY ); portMAX_DELAY );
/* Check the number of bytes received was as expected. */ /* Check the number of bytes received was as expected. */
configASSERT( xReceivedBytes == strlen( cExpectedString ) ); configASSERT( xReceivedBytes == strlen( cExpectedString ) );
( void ) xReceivedBytes; /* Incase configASSERT() is not defined. */ ( void ) xReceivedBytes; /* Incase configASSERT() is not defined. */
/* If the received string matches that expected then increment the loop /* If the received string matches that expected then increment the loop
counter so the check task knows this task is still running. */ * counter so the check task knows this task is still running. */
if( strcmp( cReceivedString, cExpectedString ) == 0 ) if( strcmp( cReceivedString, cExpectedString ) == 0 )
{ {
( ulCycleCounters[ x ] )++; ( ulCycleCounters[ x ] )++;
} }
else else
{ {
xDemoStatus = pdFAIL; xDemoStatus = pdFAIL;
} }
/* Expect the next string in sequence the next time around. */ /* Expect the next string in sequence the next time around. */
ulNextValue++; ulNextValue++;
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Called by the reimplementation of sbSEND_COMPLETED(), which can be defined /* Called by the reimplementation of sbSEND_COMPLETED(), which can be defined
as follows in FreeRTOSConfig.h: * as follows in FreeRTOSConfig.h:
#define sbSEND_COMPLETED( pxStreamBuffer ) vGenerateCoreBInterrupt( pxStreamBuffer ) #define sbSEND_COMPLETED( pxStreamBuffer ) vGenerateCoreBInterrupt( pxStreamBuffer )
*/ */
void vGenerateCoreBInterrupt( void * xUpdatedMessageBuffer ) void vGenerateCoreBInterrupt( void * xUpdatedMessageBuffer )
{ {
MessageBufferHandle_t xUpdatedBuffer = ( MessageBufferHandle_t ) xUpdatedMessageBuffer; MessageBufferHandle_t xUpdatedBuffer = ( MessageBufferHandle_t ) xUpdatedMessageBuffer;
/* If sbSEND_COMPLETED() has been implemented as above, then this function /* If sbSEND_COMPLETED() has been implemented as above, then this function
is called from within xMessageBufferSend(). As this function also calls * is called from within xMessageBufferSend(). As this function also calls
xMessageBufferSend() itself it is necessary to guard against a recursive * xMessageBufferSend() itself it is necessary to guard against a recursive
call. If the message buffer just updated is the message buffer written to * call. If the message buffer just updated is the message buffer written to
by this function, then this is a recursive call, and the function can just * by this function, then this is a recursive call, and the function can just
exit without taking further action. */ * exit without taking further action. */
if( xUpdatedBuffer != xControlMessageBuffer ) if( xUpdatedBuffer != xControlMessageBuffer )
{ {
/* Use xControlMessageBuffer to pass the handle of the message buffer /* Use xControlMessageBuffer to pass the handle of the message buffer
written to by core A to the interrupt handler about to be generated in * written to by core A to the interrupt handler about to be generated in
core B. */ * core B. */
xMessageBufferSend( xControlMessageBuffer, &xUpdatedBuffer, sizeof( xUpdatedBuffer ), mbaDONT_BLOCK ); xMessageBufferSend( xControlMessageBuffer, &xUpdatedBuffer, sizeof( xUpdatedBuffer ), mbaDONT_BLOCK );
/* This is where the interrupt would be generated. In this case it is /* This is where the interrupt would be generated. In this case it is
not a genuine interrupt handler that executes, just a standard function * not a genuine interrupt handler that executes, just a standard function
call. */ * call. */
mbaGENERATE_CORE_B_INTERRUPT(); mbaGENERATE_CORE_B_INTERRUPT();
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Handler for the interrupts that are triggered on core A but execute on core /* Handler for the interrupts that are triggered on core A but execute on core
B. */ * B. */
static void prvCoreBInterruptHandler( void ) static void prvCoreBInterruptHandler( void )
{ {
MessageBufferHandle_t xUpdatedMessageBuffer; MessageBufferHandle_t xUpdatedMessageBuffer;
BaseType_t xHigherPriorityTaskWoken = pdFALSE; BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* xControlMessageBuffer contains the handle of the message buffer that /* xControlMessageBuffer contains the handle of the message buffer that
contains data. */ * contains data. */
if( xMessageBufferReceive( xControlMessageBuffer, if( xMessageBufferReceive( xControlMessageBuffer,
&xUpdatedMessageBuffer, &xUpdatedMessageBuffer,
sizeof( xUpdatedMessageBuffer ), sizeof( xUpdatedMessageBuffer ),
mbaDONT_BLOCK ) == sizeof( xUpdatedMessageBuffer ) ) mbaDONT_BLOCK ) == sizeof( xUpdatedMessageBuffer ) )
{ {
/* Call the API function that sends a notification to any task that is /* Call the API function that sends a notification to any task that is
blocked on the xUpdatedMessageBuffer message buffer waiting for data to * blocked on the xUpdatedMessageBuffer message buffer waiting for data to
arrive. */ * arrive. */
xMessageBufferSendCompletedFromISR( xUpdatedMessageBuffer, &xHigherPriorityTaskWoken ); xMessageBufferSendCompletedFromISR( xUpdatedMessageBuffer, &xHigherPriorityTaskWoken );
} }
/* Normal FreeRTOS yield from interrupt semantics, where /* Normal FreeRTOS yield from interrupt semantics, where
xHigherPriorityTaskWoken is initialized to pdFALSE and will then get set to * xHigherPriorityTaskWoken is initialized to pdFALSE and will then get set to
pdTRUE if the interrupt safe API unblocks a task that has a priority above * pdTRUE if the interrupt safe API unblocks a task that has a priority above
that of the currently executing task. */ * that of the currently executing task. */
portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xAreMessageBufferAMPTasksStillRunning( void ) BaseType_t xAreMessageBufferAMPTasksStillRunning( void )
{ {
static uint32_t ulLastCycleCounters[ mbaNUMBER_OF_CORE_B_TASKS ] = { 0 }; static uint32_t ulLastCycleCounters[ mbaNUMBER_OF_CORE_B_TASKS ] = { 0 };
BaseType_t x; BaseType_t x;
/* Called by the check task to determine the health status of the tasks /* Called by the check task to determine the health status of the tasks
implemented in this demo. */ * implemented in this demo. */
for( x = 0; x < mbaNUMBER_OF_CORE_B_TASKS; x++ ) for( x = 0; x < mbaNUMBER_OF_CORE_B_TASKS; x++ )
{ {
if( ulLastCycleCounters[ x ] == ulCycleCounters[ x ] ) if( ulLastCycleCounters[ x ] == ulCycleCounters[ x ] )
{ {
xDemoStatus = pdFAIL; xDemoStatus = pdFAIL;
} }
else else
{ {
ulLastCycleCounters[ x ] = ulCycleCounters[ x ]; ulLastCycleCounters[ x ] = ulCycleCounters[ x ];
} }
} }
return xDemoStatus; return xDemoStatus;
} }

File diff suppressed because it is too large Load diff

View file

@ -49,11 +49,11 @@
*/ */
/* /*
Changes from V2.0.0 * Changes from V2.0.0
*
+ Delay periods are now specified using variables and constants of + Delay periods are now specified using variables and constants of
TickType_t rather than uint32_t. + TickType_t rather than uint32_t.
*/ */
#include <stdlib.h> #include <stdlib.h>
@ -65,13 +65,13 @@ Changes from V2.0.0
/* Demo program include files. */ /* Demo program include files. */
#include "PollQ.h" #include "PollQ.h"
#define pollqSTACK_SIZE configMINIMAL_STACK_SIZE #define pollqSTACK_SIZE configMINIMAL_STACK_SIZE
#define pollqQUEUE_SIZE ( 10 ) #define pollqQUEUE_SIZE ( 10 )
#define pollqPRODUCER_DELAY ( pdMS_TO_TICKS( ( TickType_t ) 200 ) ) #define pollqPRODUCER_DELAY ( pdMS_TO_TICKS( ( TickType_t ) 200 ) )
#define pollqCONSUMER_DELAY ( pollqPRODUCER_DELAY - ( TickType_t ) ( 20 / portTICK_PERIOD_MS ) ) #define pollqCONSUMER_DELAY ( pollqPRODUCER_DELAY - ( TickType_t ) ( 20 / portTICK_PERIOD_MS ) )
#define pollqNO_DELAY ( ( TickType_t ) 0 ) #define pollqNO_DELAY ( ( TickType_t ) 0 )
#define pollqVALUES_TO_PRODUCE ( ( BaseType_t ) 3 ) #define pollqVALUES_TO_PRODUCE ( ( BaseType_t ) 3 )
#define pollqINITIAL_VALUE ( ( BaseType_t ) 0 ) #define pollqINITIAL_VALUE ( ( BaseType_t ) 0 )
/* The task that posts the incrementing number onto the queue. */ /* The task that posts the incrementing number onto the queue. */
static portTASK_FUNCTION_PROTO( vPolledQueueProducer, pvParameters ); static portTASK_FUNCTION_PROTO( vPolledQueueProducer, pvParameters );
@ -80,144 +80,144 @@ static portTASK_FUNCTION_PROTO( vPolledQueueProducer, pvParameters );
static portTASK_FUNCTION_PROTO( vPolledQueueConsumer, pvParameters ); static portTASK_FUNCTION_PROTO( vPolledQueueConsumer, pvParameters );
/* Variables that are used to check that the tasks are still running with no /* Variables that are used to check that the tasks are still running with no
errors. */ * errors. */
static volatile BaseType_t xPollingConsumerCount = pollqINITIAL_VALUE, xPollingProducerCount = pollqINITIAL_VALUE; static volatile BaseType_t xPollingConsumerCount = pollqINITIAL_VALUE, xPollingProducerCount = pollqINITIAL_VALUE;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vStartPolledQueueTasks( UBaseType_t uxPriority ) void vStartPolledQueueTasks( UBaseType_t uxPriority )
{ {
static QueueHandle_t xPolledQueue; static QueueHandle_t xPolledQueue;
/* Create the queue used by the producer and consumer. */ /* Create the queue used by the producer and consumer. */
xPolledQueue = xQueueCreate( pollqQUEUE_SIZE, ( UBaseType_t ) sizeof( uint16_t ) ); xPolledQueue = xQueueCreate( pollqQUEUE_SIZE, ( UBaseType_t ) sizeof( uint16_t ) );
if( xPolledQueue != NULL ) if( xPolledQueue != NULL )
{ {
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
in use. The queue registry is provided as a means for kernel aware * in use. The queue registry is provided as a means for kernel aware
debuggers to locate queues and has no purpose if a kernel aware debugger * debuggers to locate queues and has no purpose if a kernel aware debugger
is not being used. The call to vQueueAddToRegistry() will be removed * is not being used. The call to vQueueAddToRegistry() will be removed
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is * by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
defined to be less than 1. */ * defined to be less than 1. */
vQueueAddToRegistry( xPolledQueue, "Poll_Test_Queue" ); vQueueAddToRegistry( xPolledQueue, "Poll_Test_Queue" );
/* Spawn the producer and consumer. */ /* Spawn the producer and consumer. */
xTaskCreate( vPolledQueueConsumer, "QConsNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, ( TaskHandle_t * ) NULL ); xTaskCreate( vPolledQueueConsumer, "QConsNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, ( TaskHandle_t * ) NULL );
xTaskCreate( vPolledQueueProducer, "QProdNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, ( TaskHandle_t * ) NULL ); xTaskCreate( vPolledQueueProducer, "QProdNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, ( TaskHandle_t * ) NULL );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static portTASK_FUNCTION( vPolledQueueProducer, pvParameters ) static portTASK_FUNCTION( vPolledQueueProducer, pvParameters )
{ {
uint16_t usValue = ( uint16_t ) 0; uint16_t usValue = ( uint16_t ) 0;
BaseType_t xError = pdFALSE, xLoop; BaseType_t xError = pdFALSE, xLoop;
for( ;; ) for( ; ; )
{ {
for( xLoop = 0; xLoop < pollqVALUES_TO_PRODUCE; xLoop++ ) for( xLoop = 0; xLoop < pollqVALUES_TO_PRODUCE; xLoop++ )
{ {
/* Send an incrementing number on the queue without blocking. */ /* Send an incrementing number on the queue without blocking. */
if( xQueueSend( *( ( QueueHandle_t * ) pvParameters ), ( void * ) &usValue, pollqNO_DELAY ) != pdPASS ) if( xQueueSend( *( ( QueueHandle_t * ) pvParameters ), ( void * ) &usValue, pollqNO_DELAY ) != pdPASS )
{ {
/* We should never find the queue full so if we get here there /* We should never find the queue full so if we get here there
has been an error. */ * has been an error. */
xError = pdTRUE; xError = pdTRUE;
} }
else else
{ {
if( xError == pdFALSE ) if( xError == pdFALSE )
{ {
/* If an error has ever been recorded we stop incrementing the /* If an error has ever been recorded we stop incrementing the
check variable. */ * check variable. */
portENTER_CRITICAL(); portENTER_CRITICAL();
xPollingProducerCount++; xPollingProducerCount++;
portEXIT_CRITICAL(); portEXIT_CRITICAL();
} }
/* Update the value we are going to post next time around. */ /* Update the value we are going to post next time around. */
usValue++; usValue++;
} }
} }
/* Wait before we start posting again to ensure the consumer runs and /* Wait before we start posting again to ensure the consumer runs and
empties the queue. */ * empties the queue. */
vTaskDelay( pollqPRODUCER_DELAY ); vTaskDelay( pollqPRODUCER_DELAY );
} }
} /*lint !e818 Function prototype must conform to API. */ } /*lint !e818 Function prototype must conform to API. */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static portTASK_FUNCTION( vPolledQueueConsumer, pvParameters ) static portTASK_FUNCTION( vPolledQueueConsumer, pvParameters )
{ {
uint16_t usData, usExpectedValue = ( uint16_t ) 0; uint16_t usData, usExpectedValue = ( uint16_t ) 0;
BaseType_t xError = pdFALSE; BaseType_t xError = pdFALSE;
for( ;; ) for( ; ; )
{ {
/* Loop until the queue is empty. */ /* Loop until the queue is empty. */
while( uxQueueMessagesWaiting( *( ( QueueHandle_t * ) pvParameters ) ) ) while( uxQueueMessagesWaiting( *( ( QueueHandle_t * ) pvParameters ) ) )
{ {
if( xQueueReceive( *( ( QueueHandle_t * ) pvParameters ), &usData, pollqNO_DELAY ) == pdPASS ) if( xQueueReceive( *( ( QueueHandle_t * ) pvParameters ), &usData, pollqNO_DELAY ) == pdPASS )
{ {
if( usData != usExpectedValue ) if( usData != usExpectedValue )
{ {
/* This is not what we expected to receive so an error has /* This is not what we expected to receive so an error has
occurred. */ * occurred. */
xError = pdTRUE; xError = pdTRUE;
/* Catch-up to the value we received so our next expected /* Catch-up to the value we received so our next expected
value should again be correct. */ * value should again be correct. */
usExpectedValue = usData; usExpectedValue = usData;
} }
else else
{ {
if( xError == pdFALSE ) if( xError == pdFALSE )
{ {
/* Only increment the check variable if no errors have /* Only increment the check variable if no errors have
occurred. */ * occurred. */
portENTER_CRITICAL(); portENTER_CRITICAL();
xPollingConsumerCount++; xPollingConsumerCount++;
portEXIT_CRITICAL(); portEXIT_CRITICAL();
} }
} }
/* Next time round we would expect the number to be one higher. */ /* Next time round we would expect the number to be one higher. */
usExpectedValue++; usExpectedValue++;
} }
} }
/* Now the queue is empty we block, allowing the producer to place more /* Now the queue is empty we block, allowing the producer to place more
items in the queue. */ * items in the queue. */
vTaskDelay( pollqCONSUMER_DELAY ); vTaskDelay( pollqCONSUMER_DELAY );
} }
} /*lint !e818 Function prototype must conform to API. */ } /*lint !e818 Function prototype must conform to API. */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running with no errors. */ /* This is called to check that all the created tasks are still running with no errors. */
BaseType_t xArePollingQueuesStillRunning( void ) BaseType_t xArePollingQueuesStillRunning( void )
{ {
BaseType_t xReturn; BaseType_t xReturn;
/* Check both the consumer and producer poll count to check they have both /* Check both the consumer and producer poll count to check they have both
been changed since out last trip round. We do not need a critical section * been changed since out last trip round. We do not need a critical section
around the check variables as this is called from a higher priority than * around the check variables as this is called from a higher priority than
the other tasks that access the same variables. */ * the other tasks that access the same variables. */
if( ( xPollingConsumerCount == pollqINITIAL_VALUE ) || if( ( xPollingConsumerCount == pollqINITIAL_VALUE ) ||
( xPollingProducerCount == pollqINITIAL_VALUE ) ( xPollingProducerCount == pollqINITIAL_VALUE )
) )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
} }
else else
{ {
xReturn = pdTRUE; xReturn = pdTRUE;
} }
/* Set the check variables back down so we know if they have been /* Set the check variables back down so we know if they have been
incremented the next time around. */ * incremented the next time around. */
xPollingConsumerCount = pollqINITIAL_VALUE; xPollingConsumerCount = pollqINITIAL_VALUE;
xPollingProducerCount = pollqINITIAL_VALUE; xPollingProducerCount = pollqINITIAL_VALUE;
return xReturn; return xReturn;
} }

View file

@ -43,14 +43,14 @@
/* Demo program include files. */ /* Demo program include files. */
#include "QPeek.h" #include "QPeek.h"
#define qpeekQUEUE_LENGTH ( 5 ) #define qpeekQUEUE_LENGTH ( 5 )
#define qpeekNO_BLOCK ( 0 ) #define qpeekNO_BLOCK ( 0 )
#define qpeekSHORT_DELAY ( 10 ) #define qpeekSHORT_DELAY ( 10 )
#define qpeekLOW_PRIORITY ( tskIDLE_PRIORITY + 0 ) #define qpeekLOW_PRIORITY ( tskIDLE_PRIORITY + 0 )
#define qpeekMEDIUM_PRIORITY ( tskIDLE_PRIORITY + 1 ) #define qpeekMEDIUM_PRIORITY ( tskIDLE_PRIORITY + 1 )
#define qpeekHIGH_PRIORITY ( tskIDLE_PRIORITY + 2 ) #define qpeekHIGH_PRIORITY ( tskIDLE_PRIORITY + 2 )
#define qpeekHIGHEST_PRIORITY ( tskIDLE_PRIORITY + 3 ) #define qpeekHIGHEST_PRIORITY ( tskIDLE_PRIORITY + 3 )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -59,19 +59,19 @@
* Each task is given a different priority to demonstrate the order in which * Each task is given a different priority to demonstrate the order in which
* tasks are woken as data is peeked from a queue. * tasks are woken as data is peeked from a queue.
*/ */
static void prvLowPriorityPeekTask( void *pvParameters ); static void prvLowPriorityPeekTask( void * pvParameters );
static void prvMediumPriorityPeekTask( void *pvParameters ); static void prvMediumPriorityPeekTask( void * pvParameters );
static void prvHighPriorityPeekTask( void *pvParameters ); static void prvHighPriorityPeekTask( void * pvParameters );
static void prvHighestPriorityPeekTask( void *pvParameters ); static void prvHighestPriorityPeekTask( void * pvParameters );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Flag that will be latched to pdTRUE should any unexpected behaviour be /* Flag that will be latched to pdTRUE should any unexpected behaviour be
detected in any of the tasks. */ * detected in any of the tasks. */
static volatile BaseType_t xErrorDetected = pdFALSE; static volatile BaseType_t xErrorDetected = pdFALSE;
/* Counter that is incremented on each cycle of a test. This is used to /* Counter that is incremented on each cycle of a test. This is used to
detect a stalled task - a test that is no longer running. */ * detect a stalled task - a test that is no longer running. */
static volatile uint32_t ulLoopCounter = 0; static volatile uint32_t ulLoopCounter = 0;
/* Handles to the test tasks. */ /* Handles to the test tasks. */
@ -80,361 +80,362 @@ TaskHandle_t xMediumPriorityTask, xHighPriorityTask, xHighestPriorityTask;
void vStartQueuePeekTasks( void ) void vStartQueuePeekTasks( void )
{ {
QueueHandle_t xQueue; QueueHandle_t xQueue;
/* Create the queue that we are going to use for the test/demo. */ /* Create the queue that we are going to use for the test/demo. */
xQueue = xQueueCreate( qpeekQUEUE_LENGTH, sizeof( uint32_t ) ); xQueue = xQueueCreate( qpeekQUEUE_LENGTH, sizeof( uint32_t ) );
if( xQueue != NULL ) if( xQueue != NULL )
{ {
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
in use. The queue registry is provided as a means for kernel aware * in use. The queue registry is provided as a means for kernel aware
debuggers to locate queues and has no purpose if a kernel aware debugger * debuggers to locate queues and has no purpose if a kernel aware debugger
is not being used. The call to vQueueAddToRegistry() will be removed * is not being used. The call to vQueueAddToRegistry() will be removed
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is * by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
defined to be less than 1. */ * defined to be less than 1. */
vQueueAddToRegistry( xQueue, "QPeek_Test_Queue" ); vQueueAddToRegistry( xQueue, "QPeek_Test_Queue" );
/* Create the demo tasks and pass it the queue just created. We are /* Create the demo tasks and pass it the queue just created. We are
passing the queue handle by value so it does not matter that it is declared * passing the queue handle by value so it does not matter that it is declared
on the stack here. */ * on the stack here. */
xTaskCreate( prvLowPriorityPeekTask, "PeekL", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekLOW_PRIORITY, NULL ); xTaskCreate( prvLowPriorityPeekTask, "PeekL", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekLOW_PRIORITY, NULL );
xTaskCreate( prvMediumPriorityPeekTask, "PeekM", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekMEDIUM_PRIORITY, &xMediumPriorityTask ); xTaskCreate( prvMediumPriorityPeekTask, "PeekM", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekMEDIUM_PRIORITY, &xMediumPriorityTask );
xTaskCreate( prvHighPriorityPeekTask, "PeekH1", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekHIGH_PRIORITY, &xHighPriorityTask ); xTaskCreate( prvHighPriorityPeekTask, "PeekH1", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekHIGH_PRIORITY, &xHighPriorityTask );
xTaskCreate( prvHighestPriorityPeekTask, "PeekH2", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekHIGHEST_PRIORITY, &xHighestPriorityTask ); xTaskCreate( prvHighestPriorityPeekTask, "PeekH2", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekHIGHEST_PRIORITY, &xHighestPriorityTask );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvHighestPriorityPeekTask( void *pvParameters ) static void prvHighestPriorityPeekTask( void * pvParameters )
{ {
QueueHandle_t xQueue = ( QueueHandle_t ) pvParameters; QueueHandle_t xQueue = ( QueueHandle_t ) pvParameters;
uint32_t ulValue; uint32_t ulValue;
#ifdef USE_STDIO #ifdef USE_STDIO
{ {
void vPrintDisplayMessage( const char * const * ppcMessageToSend ); void vPrintDisplayMessage( const char * const * ppcMessageToSend );
const char * const pcTaskStartMsg = "Queue peek test started.\r\n"; const char * const pcTaskStartMsg = "Queue peek test started.\r\n";
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
} }
#endif #endif
for( ;; ) for( ; ; )
{ {
/* Try peeking from the queue. The queue should be empty so we will /* Try peeking from the queue. The queue should be empty so we will
block, allowing the high priority task to execute. */ * block, allowing the high priority task to execute. */
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS ) if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
{ {
/* We expected to have received something by the time we unblock. */ /* We expected to have received something by the time we unblock. */
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* When we reach here the high and medium priority tasks should still /* When we reach here the high and medium priority tasks should still
be blocked on the queue. We unblocked because the low priority task * be blocked on the queue. We unblocked because the low priority task
wrote a value to the queue, which we should have peeked. Peeking the * wrote a value to the queue, which we should have peeked. Peeking the
data (rather than receiving it) will leave the data on the queue, so * data (rather than receiving it) will leave the data on the queue, so
the high priority task should then have also been unblocked, but not * the high priority task should then have also been unblocked, but not
yet executed. */ * yet executed. */
if( ulValue != 0x11223344 ) if( ulValue != 0x11223344 )
{ {
/* We did not receive the expected value. */ /* We did not receive the expected value. */
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
if( uxQueueMessagesWaiting( xQueue ) != 1 ) if( uxQueueMessagesWaiting( xQueue ) != 1 )
{ {
/* The message should have been left on the queue. */ /* The message should have been left on the queue. */
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Now we are going to actually receive the data, so when the high /* Now we are going to actually receive the data, so when the high
priority task runs it will find the queue empty and return to the * priority task runs it will find the queue empty and return to the
blocked state. */ * blocked state. */
ulValue = 0; ulValue = 0;
if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
{
/* We expected to receive the value. */
xErrorDetected = pdTRUE;
}
if( ulValue != 0x11223344 ) if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
{ {
/* We did not receive the expected value - which should have been /* We expected to receive the value. */
the same value as was peeked. */ xErrorDetected = pdTRUE;
xErrorDetected = pdTRUE; }
}
/* Now we will block again as the queue is once more empty. The low if( ulValue != 0x11223344 )
priority task can then execute again. */ {
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS ) /* We did not receive the expected value - which should have been
{ * the same value as was peeked. */
/* We expected to have received something by the time we unblock. */ xErrorDetected = pdTRUE;
xErrorDetected = pdTRUE; }
}
/* When we get here the low priority task should have again written to the /* Now we will block again as the queue is once more empty. The low
queue. */ * priority task can then execute again. */
if( ulValue != 0x01234567 ) if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
{ {
/* We did not receive the expected value. */ /* We expected to have received something by the time we unblock. */
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
if( uxQueueMessagesWaiting( xQueue ) != 1 ) /* When we get here the low priority task should have again written to the
{ * queue. */
/* The message should have been left on the queue. */ if( ulValue != 0x01234567 )
xErrorDetected = pdTRUE; {
} /* We did not receive the expected value. */
xErrorDetected = pdTRUE;
}
/* We only peeked the data, so suspending ourselves now should enable if( uxQueueMessagesWaiting( xQueue ) != 1 )
the high priority task to also peek the data. The high priority task {
will have been unblocked when we peeked the data as we left the data /* The message should have been left on the queue. */
in the queue. */ xErrorDetected = pdTRUE;
vTaskSuspend( NULL ); }
/* We only peeked the data, so suspending ourselves now should enable
* the high priority task to also peek the data. The high priority task
* will have been unblocked when we peeked the data as we left the data
* in the queue. */
vTaskSuspend( NULL );
/* This time we are going to do the same as the above test, but the
* high priority task is going to receive the data, rather than peek it.
* This means that the medium priority task should never peek the value. */
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
{
xErrorDetected = pdTRUE;
}
/* This time we are going to do the same as the above test, but the if( ulValue != 0xaabbaabb )
high priority task is going to receive the data, rather than peek it. {
This means that the medium priority task should never peek the value. */ xErrorDetected = pdTRUE;
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS ) }
{
xErrorDetected = pdTRUE;
}
if( ulValue != 0xaabbaabb ) vTaskSuspend( NULL );
{ }
xErrorDetected = pdTRUE;
}
vTaskSuspend( NULL );
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvHighPriorityPeekTask( void *pvParameters ) static void prvHighPriorityPeekTask( void * pvParameters )
{ {
QueueHandle_t xQueue = ( QueueHandle_t ) pvParameters; QueueHandle_t xQueue = ( QueueHandle_t ) pvParameters;
uint32_t ulValue; uint32_t ulValue;
for( ;; ) for( ; ; )
{ {
/* Try peeking from the queue. The queue should be empty so we will /* Try peeking from the queue. The queue should be empty so we will
block, allowing the medium priority task to execute. Both the high * block, allowing the medium priority task to execute. Both the high
and highest priority tasks will then be blocked on the queue. */ * and highest priority tasks will then be blocked on the queue. */
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS ) if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
{ {
/* We expected to have received something by the time we unblock. */ /* We expected to have received something by the time we unblock. */
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* When we get here the highest priority task should have peeked the data /* When we get here the highest priority task should have peeked the data
(unblocking this task) then suspended (allowing this task to also peek * (unblocking this task) then suspended (allowing this task to also peek
the data). */ * the data). */
if( ulValue != 0x01234567 ) if( ulValue != 0x01234567 )
{ {
/* We did not receive the expected value. */ /* We did not receive the expected value. */
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
if( uxQueueMessagesWaiting( xQueue ) != 1 ) if( uxQueueMessagesWaiting( xQueue ) != 1 )
{ {
/* The message should have been left on the queue. */ /* The message should have been left on the queue. */
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* We only peeked the data, so suspending ourselves now should enable /* We only peeked the data, so suspending ourselves now should enable
the medium priority task to also peek the data. The medium priority task * the medium priority task to also peek the data. The medium priority task
will have been unblocked when we peeked the data as we left the data * will have been unblocked when we peeked the data as we left the data
in the queue. */ * in the queue. */
vTaskSuspend( NULL ); vTaskSuspend( NULL );
/* This time we are going actually receive the value, so the medium
* priority task will never peek the data - we removed it from the queue. */
if( xQueueReceive( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
{
xErrorDetected = pdTRUE;
}
/* This time we are going actually receive the value, so the medium if( ulValue != 0xaabbaabb )
priority task will never peek the data - we removed it from the queue. */ {
if( xQueueReceive( xQueue, &ulValue, portMAX_DELAY ) != pdPASS ) xErrorDetected = pdTRUE;
{ }
xErrorDetected = pdTRUE;
}
if( ulValue != 0xaabbaabb ) vTaskSuspend( NULL );
{ }
xErrorDetected = pdTRUE;
}
vTaskSuspend( NULL );
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvMediumPriorityPeekTask( void *pvParameters ) static void prvMediumPriorityPeekTask( void * pvParameters )
{ {
QueueHandle_t xQueue = ( QueueHandle_t ) pvParameters; QueueHandle_t xQueue = ( QueueHandle_t ) pvParameters;
uint32_t ulValue; uint32_t ulValue;
for( ;; ) for( ; ; )
{ {
/* Try peeking from the queue. The queue should be empty so we will /* Try peeking from the queue. The queue should be empty so we will
block, allowing the low priority task to execute. The highest, high * block, allowing the low priority task to execute. The highest, high
and medium priority tasks will then all be blocked on the queue. */ * and medium priority tasks will then all be blocked on the queue. */
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS ) if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
{ {
/* We expected to have received something by the time we unblock. */ /* We expected to have received something by the time we unblock. */
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* When we get here the high priority task should have peeked the data /* When we get here the high priority task should have peeked the data
(unblocking this task) then suspended (allowing this task to also peek * (unblocking this task) then suspended (allowing this task to also peek
the data). */ * the data). */
if( ulValue != 0x01234567 ) if( ulValue != 0x01234567 )
{ {
/* We did not receive the expected value. */ /* We did not receive the expected value. */
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
if( uxQueueMessagesWaiting( xQueue ) != 1 ) if( uxQueueMessagesWaiting( xQueue ) != 1 )
{ {
/* The message should have been left on the queue. */ /* The message should have been left on the queue. */
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Just so we know the test is still running. */ /* Just so we know the test is still running. */
ulLoopCounter++; ulLoopCounter++;
/* Now we can suspend ourselves so the low priority task can execute /* Now we can suspend ourselves so the low priority task can execute
again. */ * again. */
vTaskSuspend( NULL ); vTaskSuspend( NULL );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvLowPriorityPeekTask( void *pvParameters ) static void prvLowPriorityPeekTask( void * pvParameters )
{ {
QueueHandle_t xQueue = ( QueueHandle_t ) pvParameters; QueueHandle_t xQueue = ( QueueHandle_t ) pvParameters;
uint32_t ulValue; uint32_t ulValue;
for( ;; ) for( ; ; )
{ {
/* Write some data to the queue. This should unblock the highest /* Write some data to the queue. This should unblock the highest
priority task that is waiting to peek data from the queue. */ * priority task that is waiting to peek data from the queue. */
ulValue = 0x11223344; ulValue = 0x11223344;
if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
{
/* We were expecting the queue to be empty so we should not of
had a problem writing to the queue. */
xErrorDetected = pdTRUE;
}
#if configUSE_PREEMPTION == 0 if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
taskYIELD(); {
#endif /* We were expecting the queue to be empty so we should not of
* had a problem writing to the queue. */
xErrorDetected = pdTRUE;
}
/* By the time we get here the data should have been removed from #if configUSE_PREEMPTION == 0
the queue. */ taskYIELD();
if( uxQueueMessagesWaiting( xQueue ) != 0 ) #endif
{
xErrorDetected = pdTRUE;
}
/* Write another value to the queue, again waking the highest priority /* By the time we get here the data should have been removed from
task that is blocked on the queue. */ * the queue. */
ulValue = 0x01234567; if( uxQueueMessagesWaiting( xQueue ) != 0 )
if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS ) {
{ xErrorDetected = pdTRUE;
/* We were expecting the queue to be empty so we should not of }
had a problem writing to the queue. */
xErrorDetected = pdTRUE;
}
#if configUSE_PREEMPTION == 0 /* Write another value to the queue, again waking the highest priority
taskYIELD(); * task that is blocked on the queue. */
#endif ulValue = 0x01234567;
/* All the other tasks should now have successfully peeked the data. if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
The data is still in the queue so we should be able to receive it. */ {
ulValue = 0; /* We were expecting the queue to be empty so we should not of
if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS ) * had a problem writing to the queue. */
{ xErrorDetected = pdTRUE;
/* We expected to receive the data. */ }
xErrorDetected = pdTRUE;
}
if( ulValue != 0x01234567 ) #if configUSE_PREEMPTION == 0
{ taskYIELD();
/* We did not receive the expected value. */ #endif
xErrorDetected = pdTRUE;
}
/* Lets just delay a while as this is an intensive test as we don't /* All the other tasks should now have successfully peeked the data.
want to starve other tests of processing time. */ * The data is still in the queue so we should be able to receive it. */
vTaskDelay( qpeekSHORT_DELAY ); ulValue = 0;
/* Unsuspend the other tasks so we can repeat the test - this time if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
however not all the other tasks will peek the data as the high {
priority task is actually going to remove it from the queue. Send /* We expected to receive the data. */
to front is used just to be different. As the queue is empty it xErrorDetected = pdTRUE;
makes no difference to the result. */ }
vTaskResume( xMediumPriorityTask );
vTaskResume( xHighPriorityTask );
vTaskResume( xHighestPriorityTask );
#if( configUSE_PREEMPTION == 0 ) if( ulValue != 0x01234567 )
taskYIELD(); {
#endif /* We did not receive the expected value. */
xErrorDetected = pdTRUE;
}
ulValue = 0xaabbaabb; /* Lets just delay a while as this is an intensive test as we don't
if( xQueueSendToFront( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS ) * want to starve other tests of processing time. */
{ vTaskDelay( qpeekSHORT_DELAY );
/* We were expecting the queue to be empty so we should not of
had a problem writing to the queue. */
xErrorDetected = pdTRUE;
}
#if configUSE_PREEMPTION == 0 /* Unsuspend the other tasks so we can repeat the test - this time
taskYIELD(); * however not all the other tasks will peek the data as the high
#endif * priority task is actually going to remove it from the queue. Send
* to front is used just to be different. As the queue is empty it
* makes no difference to the result. */
vTaskResume( xMediumPriorityTask );
vTaskResume( xHighPriorityTask );
vTaskResume( xHighestPriorityTask );
/* This time we should find that the queue is empty. The high priority #if ( configUSE_PREEMPTION == 0 )
task actually removed the data rather than just peeking it. */ taskYIELD();
if( xQueuePeek( xQueue, &ulValue, qpeekNO_BLOCK ) != errQUEUE_EMPTY ) #endif
{
/* We expected to receive the data. */
xErrorDetected = pdTRUE;
}
/* Unsuspend the highest and high priority tasks so we can go back ulValue = 0xaabbaabb;
and repeat the whole thing. The medium priority task should not be
suspended as it was not able to peek the data in this last case. */
vTaskResume( xHighPriorityTask );
vTaskResume( xHighestPriorityTask );
/* Lets just delay a while as this is an intensive test as we don't if( xQueueSendToFront( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
want to starve other tests of processing time. */ {
vTaskDelay( qpeekSHORT_DELAY ); /* We were expecting the queue to be empty so we should not of
} * had a problem writing to the queue. */
xErrorDetected = pdTRUE;
}
#if configUSE_PREEMPTION == 0
taskYIELD();
#endif
/* This time we should find that the queue is empty. The high priority
* task actually removed the data rather than just peeking it. */
if( xQueuePeek( xQueue, &ulValue, qpeekNO_BLOCK ) != errQUEUE_EMPTY )
{
/* We expected to receive the data. */
xErrorDetected = pdTRUE;
}
/* Unsuspend the highest and high priority tasks so we can go back
* and repeat the whole thing. The medium priority task should not be
* suspended as it was not able to peek the data in this last case. */
vTaskResume( xHighPriorityTask );
vTaskResume( xHighestPriorityTask );
/* Lets just delay a while as this is an intensive test as we don't
* want to starve other tests of processing time. */
vTaskDelay( qpeekSHORT_DELAY );
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running. */ /* This is called to check that all the created tasks are still running. */
BaseType_t xAreQueuePeekTasksStillRunning( void ) BaseType_t xAreQueuePeekTasksStillRunning( void )
{ {
static uint32_t ulLastLoopCounter = 0; static uint32_t ulLastLoopCounter = 0;
/* If the demo task is still running then we expect the loopcounter to /* If the demo task is still running then we expect the loopcounter to
have incremented since this function was last called. */ * have incremented since this function was last called. */
if( ulLastLoopCounter == ulLoopCounter ) if( ulLastLoopCounter == ulLoopCounter )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
ulLastLoopCounter = ulLoopCounter; ulLastLoopCounter = ulLoopCounter;
/* Errors detected in the task itself will have latched xErrorDetected /* Errors detected in the task itself will have latched xErrorDetected
to true. */ * to true. */
return ( BaseType_t ) !xErrorDetected; return ( BaseType_t ) !xErrorDetected;
} }

View file

@ -39,192 +39,198 @@
#include "QueueOverwrite.h" #include "QueueOverwrite.h"
/* A block time of 0 just means "don't block". */ /* A block time of 0 just means "don't block". */
#define qoDONT_BLOCK 0 #define qoDONT_BLOCK 0
/* Number of times to overwrite the value in the queue. */ /* Number of times to overwrite the value in the queue. */
#define qoLOOPS 5 #define qoLOOPS 5
/* The task that uses the queue. */ /* The task that uses the queue. */
static void prvQueueOverwriteTask( void *pvParameters ); static void prvQueueOverwriteTask( void * pvParameters );
/* Variable that is incremented on each loop of prvQueueOverwriteTask() provided /* Variable that is incremented on each loop of prvQueueOverwriteTask() provided
prvQueueOverwriteTask() has not found any errors. */ * prvQueueOverwriteTask() has not found any errors. */
static uint32_t ulLoopCounter = 0; static uint32_t ulLoopCounter = 0;
/* Set to pdFALSE if an error is discovered by the /* Set to pdFALSE if an error is discovered by the
vQueueOverwritePeriodicISRDemo() function. */ * vQueueOverwritePeriodicISRDemo() function. */
static BaseType_t xISRTestStatus = pdPASS; static BaseType_t xISRTestStatus = pdPASS;
/* The queue that is accessed from the ISR. The queue accessed by the task is /* The queue that is accessed from the ISR. The queue accessed by the task is
created inside the task itself. */ * created inside the task itself. */
static QueueHandle_t xISRQueue = NULL; static QueueHandle_t xISRQueue = NULL;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vStartQueueOverwriteTask( UBaseType_t uxPriority ) void vStartQueueOverwriteTask( UBaseType_t uxPriority )
{ {
const UBaseType_t uxQueueLength = 1; const UBaseType_t uxQueueLength = 1;
/* Create the queue used by the ISR. xQueueOverwriteFromISR() should only /* Create the queue used by the ISR. xQueueOverwriteFromISR() should only
be used on queues that have a length of 1. */ * be used on queues that have a length of 1. */
xISRQueue = xQueueCreate( uxQueueLength, ( UBaseType_t ) sizeof( uint32_t ) ); xISRQueue = xQueueCreate( uxQueueLength, ( UBaseType_t ) sizeof( uint32_t ) );
/* Create the test task. The queue used by the test task is created inside /* Create the test task. The queue used by the test task is created inside
the task itself. */ * the task itself. */
xTaskCreate( prvQueueOverwriteTask, "QOver", configMINIMAL_STACK_SIZE, NULL, uxPriority, ( TaskHandle_t * ) NULL ); xTaskCreate( prvQueueOverwriteTask, "QOver", configMINIMAL_STACK_SIZE, NULL, uxPriority, ( TaskHandle_t * ) NULL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvQueueOverwriteTask( void *pvParameters ) static void prvQueueOverwriteTask( void * pvParameters )
{ {
QueueHandle_t xTaskQueue; QueueHandle_t xTaskQueue;
const UBaseType_t uxQueueLength = 1; const UBaseType_t uxQueueLength = 1;
uint32_t ulValue, ulStatus = pdPASS, x; uint32_t ulValue, ulStatus = pdPASS, x;
/* The parameter is not used. */ /* The parameter is not used. */
( void ) pvParameters; ( void ) pvParameters;
/* Create the queue. xQueueOverwrite() should only be used on queues that /* Create the queue. xQueueOverwrite() should only be used on queues that
have a length of 1. */ * have a length of 1. */
xTaskQueue = xQueueCreate( uxQueueLength, ( UBaseType_t ) sizeof( uint32_t ) ); xTaskQueue = xQueueCreate( uxQueueLength, ( UBaseType_t ) sizeof( uint32_t ) );
configASSERT( xTaskQueue ); configASSERT( xTaskQueue );
for( ;; ) for( ; ; )
{ {
/* The queue is empty. Writing to the queue then reading from the queue /* The queue is empty. Writing to the queue then reading from the queue
should return the item written. */ * should return the item written. */
ulValue = 10; ulValue = 10;
xQueueOverwrite( xTaskQueue, &ulValue ); xQueueOverwrite( xTaskQueue, &ulValue );
ulValue = 0; ulValue = 0;
xQueueReceive( xTaskQueue, &ulValue, qoDONT_BLOCK ); xQueueReceive( xTaskQueue, &ulValue, qoDONT_BLOCK );
if( ulValue != 10 ) if( ulValue != 10 )
{ {
ulStatus = pdFAIL; ulStatus = pdFAIL;
} }
/* Now try writing to the queue several times. Each time the value /* Now try writing to the queue several times. Each time the value
in the queue should get overwritten. */ * in the queue should get overwritten. */
for( x = 0; x < qoLOOPS; x++ ) for( x = 0; x < qoLOOPS; x++ )
{ {
/* Write to the queue. */ /* Write to the queue. */
xQueueOverwrite( xTaskQueue, &x ); xQueueOverwrite( xTaskQueue, &x );
/* Check the value in the queue is that written, even though the /* Check the value in the queue is that written, even though the
queue was not necessarily empty. */ * queue was not necessarily empty. */
xQueuePeek( xTaskQueue, &ulValue, qoDONT_BLOCK ); xQueuePeek( xTaskQueue, &ulValue, qoDONT_BLOCK );
if( ulValue != x )
{
ulStatus = pdFAIL;
}
/* There should always be one item in the queue. */ if( ulValue != x )
if( uxQueueMessagesWaiting( xTaskQueue ) != uxQueueLength ) {
{ ulStatus = pdFAIL;
ulStatus = pdFAIL; }
}
}
/* Empty the queue again. */ /* There should always be one item in the queue. */
xQueueReceive( xTaskQueue, &ulValue, qoDONT_BLOCK ); if( uxQueueMessagesWaiting( xTaskQueue ) != uxQueueLength )
{
ulStatus = pdFAIL;
}
}
if( uxQueueMessagesWaiting( xTaskQueue ) != 0 ) /* Empty the queue again. */
{ xQueueReceive( xTaskQueue, &ulValue, qoDONT_BLOCK );
ulStatus = pdFAIL;
}
if( ulStatus != pdFAIL ) if( uxQueueMessagesWaiting( xTaskQueue ) != 0 )
{ {
/* Increment a counter to show this task is still running without ulStatus = pdFAIL;
error. */ }
ulLoopCounter++;
}
#if( configUSE_PREEMPTION == 0 ) if( ulStatus != pdFAIL )
taskYIELD(); {
#endif /* Increment a counter to show this task is still running without
} * error. */
ulLoopCounter++;
}
#if ( configUSE_PREEMPTION == 0 )
taskYIELD();
#endif
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xIsQueueOverwriteTaskStillRunning( void ) BaseType_t xIsQueueOverwriteTaskStillRunning( void )
{ {
BaseType_t xReturn; BaseType_t xReturn;
if( xISRTestStatus != pdPASS ) if( xISRTestStatus != pdPASS )
{ {
xReturn = pdFAIL; xReturn = pdFAIL;
} }
else if( ulLoopCounter > 0 ) else if( ulLoopCounter > 0 )
{ {
xReturn = pdPASS; xReturn = pdPASS;
} }
else else
{ {
/* The task has either stalled of discovered an error. */ /* The task has either stalled of discovered an error. */
xReturn = pdFAIL; xReturn = pdFAIL;
} }
ulLoopCounter = 0; ulLoopCounter = 0;
return xReturn; return xReturn;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vQueueOverwritePeriodicISRDemo( void ) void vQueueOverwritePeriodicISRDemo( void )
{ {
static uint32_t ulCallCount = 0; static uint32_t ulCallCount = 0;
const uint32_t ulTx1 = 10UL, ulTx2 = 20UL, ulNumberOfSwitchCases = 3UL; const uint32_t ulTx1 = 10UL, ulTx2 = 20UL, ulNumberOfSwitchCases = 3UL;
uint32_t ulRx; uint32_t ulRx;
/* This function should be called from an interrupt, such as the tick hook /* This function should be called from an interrupt, such as the tick hook
function vApplicationTickHook(). */ * function vApplicationTickHook(). */
configASSERT( xISRQueue ); configASSERT( xISRQueue );
switch( ulCallCount ) switch( ulCallCount )
{ {
case 0: case 0:
/* The queue is empty. Write ulTx1 to the queue. In this demo the
last parameter is not used because there are no tasks blocked on
this queue. */
xQueueOverwriteFromISR( xISRQueue, &ulTx1, NULL );
/* Peek the queue to check it holds the expected value. */ /* The queue is empty. Write ulTx1 to the queue. In this demo the
xQueuePeekFromISR( xISRQueue, &ulRx ); * last parameter is not used because there are no tasks blocked on
if( ulRx != ulTx1 ) * this queue. */
{ xQueueOverwriteFromISR( xISRQueue, &ulTx1, NULL );
xISRTestStatus = pdFAIL;
}
break;
case 1: /* Peek the queue to check it holds the expected value. */
/* The queue already holds ulTx1. Overwrite the value in the queue xQueuePeekFromISR( xISRQueue, &ulRx );
with ulTx2. */
xQueueOverwriteFromISR( xISRQueue, &ulTx2, NULL );
break;
case 2: if( ulRx != ulTx1 )
/* Read from the queue to empty the queue again. The value read {
should be ulTx2. */ xISRTestStatus = pdFAIL;
xQueueReceiveFromISR( xISRQueue, &ulRx, NULL ); }
if( ulRx != ulTx2 ) break;
{
xISRTestStatus = pdFAIL;
}
break;
}
/* Run the next case in the switch statement above next time this function case 1:
is called. */
ulCallCount++;
if( ulCallCount >= ulNumberOfSwitchCases ) /* The queue already holds ulTx1. Overwrite the value in the queue
{ * with ulTx2. */
/* Go back to the start. */ xQueueOverwriteFromISR( xISRQueue, &ulTx2, NULL );
ulCallCount = 0; break;
}
case 2:
/* Read from the queue to empty the queue again. The value read
* should be ulTx2. */
xQueueReceiveFromISR( xISRQueue, &ulRx, NULL );
if( ulRx != ulTx2 )
{
xISRTestStatus = pdFAIL;
}
break;
}
/* Run the next case in the switch statement above next time this function
* is called. */
ulCallCount++;
if( ulCallCount >= ulNumberOfSwitchCases )
{
/* Go back to the start. */
ulCallCount = 0;
}
} }

File diff suppressed because it is too large Load diff

View file

@ -51,131 +51,132 @@
/* Demo includes. */ /* Demo includes. */
#include "QueueSetPolling.h" #include "QueueSetPolling.h"
#if( configUSE_QUEUE_SETS == 1 ) /* Remove tests if queue sets are not defined. */ #if ( configUSE_QUEUE_SETS == 1 ) /* Remove tests if queue sets are not defined. */
/* The length of each created queue. */ /* The length of each created queue. */
#define setpollQUEUE_LENGTH 10 #define setpollQUEUE_LENGTH 10
/* Block times used in this demo. A block time or 0 means "don't block". */ /* Block times used in this demo. A block time or 0 means "don't block". */
#define setpollDONT_BLOCK 0 #define setpollDONT_BLOCK 0
/* The ISR sends to the queue every setpollISR_TX_PERIOD ticks. */ /* The ISR sends to the queue every setpollISR_TX_PERIOD ticks. */
#define queuesetISR_TX_PERIOD ( 50UL ) #define queuesetISR_TX_PERIOD ( 50UL )
/* /*
* The task that reads from the queue set. * The task that reads from the queue set.
*/ */
static void prvQueueSetReceivingTask( void *pvParameters ); static void prvQueueSetReceivingTask( void * pvParameters );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* The queue that is added to the set. */ /* The queue that is added to the set. */
static QueueHandle_t xQueue = NULL; static QueueHandle_t xQueue = NULL;
/* The handle of the queue set to which the queue is added. */ /* The handle of the queue set to which the queue is added. */
static QueueSetHandle_t xQueueSet = NULL; static QueueSetHandle_t xQueueSet = NULL;
/* Set to pdFAIL if an error is detected by any queue set task. /* Set to pdFAIL if an error is detected by any queue set task.
ulCycleCounter will only be incremented if xQueueSetTasksSatus equals pdPASS. */ * ulCycleCounter will only be incremented if xQueueSetTasksSatus equals pdPASS. */
static volatile BaseType_t xQueueSetPollStatus = pdPASS; static volatile BaseType_t xQueueSetPollStatus = pdPASS;
/* Counter used to ensure the task is still running. */ /* Counter used to ensure the task is still running. */
static uint32_t ulCycleCounter = 0; static uint32_t ulCycleCounter = 0;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vStartQueueSetPollingTask( void ) void vStartQueueSetPollingTask( void )
{ {
/* Create the queue that is added to the set, the set, and add the queue to /* Create the queue that is added to the set, the set, and add the queue to
the set. */ * the set. */
xQueue = xQueueCreate( setpollQUEUE_LENGTH, sizeof( uint32_t ) ); xQueue = xQueueCreate( setpollQUEUE_LENGTH, sizeof( uint32_t ) );
xQueueSet = xQueueCreateSet( setpollQUEUE_LENGTH ); xQueueSet = xQueueCreateSet( setpollQUEUE_LENGTH );
if( ( xQueue != NULL ) && ( xQueueSet != NULL ) ) if( ( xQueue != NULL ) && ( xQueueSet != NULL ) )
{ {
xQueueAddToSet( xQueue, xQueueSet ); xQueueAddToSet( xQueue, xQueueSet );
/* Create the task. */ /* Create the task. */
xTaskCreate( prvQueueSetReceivingTask, "SetPoll", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); xTaskCreate( prvQueueSetReceivingTask, "SetPoll", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvQueueSetReceivingTask( void *pvParameters ) static void prvQueueSetReceivingTask( void * pvParameters )
{ {
uint32_t ulReceived, ulExpected = 0; uint32_t ulReceived, ulExpected = 0;
QueueHandle_t xActivatedQueue; QueueHandle_t xActivatedQueue;
/* Remove compiler warnings. */ /* Remove compiler warnings. */
( void ) pvParameters; ( void ) pvParameters;
for( ;; ) for( ; ; )
{ {
/* Is a message waiting? A block time is not used to ensure the queue /* Is a message waiting? A block time is not used to ensure the queue
set is polled while it is being written to from an interrupt. */ * set is polled while it is being written to from an interrupt. */
xActivatedQueue = xQueueSelectFromSet( xQueueSet, setpollDONT_BLOCK ); xActivatedQueue = xQueueSelectFromSet( xQueueSet, setpollDONT_BLOCK );
if( xActivatedQueue != NULL ) if( xActivatedQueue != NULL )
{ {
/* Reading from the queue should pass with a zero block time as /* Reading from the queue should pass with a zero block time as
this task will only run when something has been posted to a task * this task will only run when something has been posted to a task
in the queue set. */ * in the queue set. */
if( xQueueReceive( xActivatedQueue, &ulReceived, setpollDONT_BLOCK ) != pdPASS ) if( xQueueReceive( xActivatedQueue, &ulReceived, setpollDONT_BLOCK ) != pdPASS )
{ {
xQueueSetPollStatus = pdFAIL; xQueueSetPollStatus = pdFAIL;
} }
if( ulReceived == ulExpected ) if( ulReceived == ulExpected )
{ {
ulExpected++; ulExpected++;
} }
else else
{ {
xQueueSetPollStatus = pdFAIL; xQueueSetPollStatus = pdFAIL;
} }
if( xQueueSetPollStatus == pdPASS ) if( xQueueSetPollStatus == pdPASS )
{ {
ulCycleCounter++; ulCycleCounter++;
} }
} }
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vQueueSetPollingInterruptAccess( void ) void vQueueSetPollingInterruptAccess( void )
{ {
static uint32_t ulCallCount = 0, ulValueToSend = 0; static uint32_t ulCallCount = 0, ulValueToSend = 0;
/* It is intended that this function is called from the tick hook /* It is intended that this function is called from the tick hook
function, so each call is one tick period apart. */ * function, so each call is one tick period apart. */
ulCallCount++; ulCallCount++;
if( ulCallCount > queuesetISR_TX_PERIOD )
{
ulCallCount = 0;
if( xQueueSendFromISR( xQueue, ( void * ) &ulValueToSend, NULL ) == pdPASS ) if( ulCallCount > queuesetISR_TX_PERIOD )
{ {
/* Send the next value next time. */ ulCallCount = 0;
ulValueToSend++;
} if( xQueueSendFromISR( xQueue, ( void * ) &ulValueToSend, NULL ) == pdPASS )
} {
} /* Send the next value next time. */
ulValueToSend++;
}
}
}
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xAreQueueSetPollTasksStillRunning( void ) BaseType_t xAreQueueSetPollTasksStillRunning( void )
{ {
static uint32_t ulLastCycleCounter = 0; static uint32_t ulLastCycleCounter = 0;
if( ulLastCycleCounter == ulCycleCounter ) if( ulLastCycleCounter == ulCycleCounter )
{ {
xQueueSetPollStatus = pdFAIL; xQueueSetPollStatus = pdFAIL;
} }
ulLastCycleCounter = ulCycleCounter; ulLastCycleCounter = ulCycleCounter;
return xQueueSetPollStatus; return xQueueSetPollStatus;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -48,13 +48,13 @@
/* Demo app includes. */ /* Demo app includes. */
#include "StreamBufferInterrupt.h" #include "StreamBufferInterrupt.h"
#define sbiSTREAM_BUFFER_LENGTH_BYTES ( ( size_t ) 100 ) #define sbiSTREAM_BUFFER_LENGTH_BYTES ( ( size_t ) 100 )
#define sbiSTREAM_BUFFER_TRIGGER_LEVEL_10 ( ( BaseType_t ) 10 ) #define sbiSTREAM_BUFFER_TRIGGER_LEVEL_10 ( ( BaseType_t ) 10 )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Implements the task that receives a stream of bytes from the interrupt. */ /* Implements the task that receives a stream of bytes from the interrupt. */
static void prvReceivingTask( void *pvParameters ); static void prvReceivingTask( void * pvParameters );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -62,167 +62,168 @@ static void prvReceivingTask( void *pvParameters );
static StreamBufferHandle_t xStreamBuffer = NULL; static StreamBufferHandle_t xStreamBuffer = NULL;
/* The string that is sent from the interrupt to the task four bytes at a /* The string that is sent from the interrupt to the task four bytes at a
time. Must be multiple of 4 bytes long as the ISR sends 4 bytes at a time*/ * time. Must be multiple of 4 bytes long as the ISR sends 4 bytes at a time*/
static const char * pcStringToSend = "_____Hello FreeRTOS_____"; static const char * pcStringToSend = "_____Hello FreeRTOS_____";
/* The string to task is looking for, which must be a substring of /* The string to task is looking for, which must be a substring of
pcStringToSend. */ * pcStringToSend. */
static const char * pcStringToReceive = "Hello FreeRTOS"; static const char * pcStringToReceive = "Hello FreeRTOS";
/* Set to pdFAIL if anything unexpected happens. */ /* Set to pdFAIL if anything unexpected happens. */
static BaseType_t xDemoStatus = pdPASS; static BaseType_t xDemoStatus = pdPASS;
/* Incremented each time pcStringToReceive is correctly received, provided no /* Incremented each time pcStringToReceive is correctly received, provided no
errors have occurred. Used so the check task can check this task is still * errors have occurred. Used so the check task can check this task is still
running as expected. */ * running as expected. */
static uint32_t ulCycleCount = 0; static uint32_t ulCycleCount = 0;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vStartStreamBufferInterruptDemo( void ) void vStartStreamBufferInterruptDemo( void )
{ {
/* Create the stream buffer that sends data from the interrupt to the /* Create the stream buffer that sends data from the interrupt to the
task, and create the task. */ * task, and create the task. */
xStreamBuffer = xStreamBufferCreate( /* The buffer length in bytes. */ xStreamBuffer = xStreamBufferCreate( /* The buffer length in bytes. */
sbiSTREAM_BUFFER_LENGTH_BYTES, sbiSTREAM_BUFFER_LENGTH_BYTES,
/* The stream buffer's trigger level. */ /* The stream buffer's trigger level. */
sbiSTREAM_BUFFER_TRIGGER_LEVEL_10 ); sbiSTREAM_BUFFER_TRIGGER_LEVEL_10 );
xTaskCreate( prvReceivingTask, /* The function that implements the task. */ xTaskCreate( prvReceivingTask, /* The function that implements the task. */
"StrIntRx", /* Human readable name for the task. */ "StrIntRx", /* Human readable name for the task. */
configMINIMAL_STACK_SIZE, /* Stack size (in words!). */ configMINIMAL_STACK_SIZE, /* Stack size (in words!). */
NULL, /* Task parameter is not used. */ NULL, /* Task parameter is not used. */
tskIDLE_PRIORITY + 2, /* The priority at which the task is created. */ tskIDLE_PRIORITY + 2, /* The priority at which the task is created. */
NULL ); /* No use for the task handle. */ NULL ); /* No use for the task handle. */
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvReceivingTask( void *pvParameters ) static void prvReceivingTask( void * pvParameters )
{ {
char cRxBuffer[ 20 ]; char cRxBuffer[ 20 ];
BaseType_t xNextByte = 0; BaseType_t xNextByte = 0;
/* Remove warning about unused parameters. */ /* Remove warning about unused parameters. */
( void ) pvParameters; ( void ) pvParameters;
/* Make sure the string will fit in the Rx buffer, including the NULL /* Make sure the string will fit in the Rx buffer, including the NULL
terminator. */ * terminator. */
configASSERT( sizeof( cRxBuffer ) > strlen( pcStringToReceive ) ); configASSERT( sizeof( cRxBuffer ) > strlen( pcStringToReceive ) );
/* Make sure the stream buffer has been created. */ /* Make sure the stream buffer has been created. */
configASSERT( xStreamBuffer != NULL ); configASSERT( xStreamBuffer != NULL );
/* Start with the Rx buffer in a known state. */ /* Start with the Rx buffer in a known state. */
memset( cRxBuffer, 0x00, sizeof( cRxBuffer ) ); memset( cRxBuffer, 0x00, sizeof( cRxBuffer ) );
for( ;; ) for( ; ; )
{ {
/* Keep receiving characters until the end of the string is received. /* Keep receiving characters until the end of the string is received.
Note: An infinite block time is used to simplify the example. Infinite * Note: An infinite block time is used to simplify the example. Infinite
block times are not recommended in production code as they do not allow * block times are not recommended in production code as they do not allow
for error recovery. */ * for error recovery. */
xStreamBufferReceive( /* The stream buffer data is being received from. */ xStreamBufferReceive( /* The stream buffer data is being received from. */
xStreamBuffer, xStreamBuffer,
/* Where to place received data. */ /* Where to place received data. */
( void * ) &( cRxBuffer[ xNextByte ] ), ( void * ) &( cRxBuffer[ xNextByte ] ),
/* The number of bytes to receive. */ /* The number of bytes to receive. */
sizeof( char ), sizeof( char ),
/* The time to wait for the next data if the buffer
is empty. */
portMAX_DELAY );
/* If xNextByte is 0 then this task is looking for the start of the /* The time to wait for the next data if the buffer
string, which is 'H'. */ * is empty. */
if( xNextByte == 0 ) portMAX_DELAY );
{
if( cRxBuffer[ xNextByte ] == 'H' )
{
/* The start of the string has been found. Now receive
characters until the end of the string is found. */
xNextByte++;
}
}
else
{
/* Receiving characters while looking for the end of the string,
which is an 'S'. */
if( cRxBuffer[ xNextByte ] == 'S' )
{
/* The string has now been received. Check its validity. */
if( strcmp( cRxBuffer, pcStringToReceive ) != 0 )
{
xDemoStatus = pdFAIL;
}
/* Return to start looking for the beginning of the string /* If xNextByte is 0 then this task is looking for the start of the
again. */ * string, which is 'H'. */
memset( cRxBuffer, 0x00, sizeof( cRxBuffer ) ); if( xNextByte == 0 )
xNextByte = 0; {
if( cRxBuffer[ xNextByte ] == 'H' )
{
/* The start of the string has been found. Now receive
* characters until the end of the string is found. */
xNextByte++;
}
}
else
{
/* Receiving characters while looking for the end of the string,
* which is an 'S'. */
if( cRxBuffer[ xNextByte ] == 'S' )
{
/* The string has now been received. Check its validity. */
if( strcmp( cRxBuffer, pcStringToReceive ) != 0 )
{
xDemoStatus = pdFAIL;
}
/* Increment the cycle count as an indication to the check task /* Return to start looking for the beginning of the string
that this demo is still running. */ * again. */
if( xDemoStatus == pdPASS ) memset( cRxBuffer, 0x00, sizeof( cRxBuffer ) );
{ xNextByte = 0;
ulCycleCount++;
}
}
else
{
/* Receive the next character the next time around, while
continuing to look for the end of the string. */
xNextByte++;
configASSERT( ( size_t ) xNextByte < sizeof( cRxBuffer ) ); /* Increment the cycle count as an indication to the check task
} * that this demo is still running. */
} if( xDemoStatus == pdPASS )
} {
ulCycleCount++;
}
}
else
{
/* Receive the next character the next time around, while
* continuing to look for the end of the string. */
xNextByte++;
configASSERT( ( size_t ) xNextByte < sizeof( cRxBuffer ) );
}
}
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vBasicStreamBufferSendFromISR( void ) void vBasicStreamBufferSendFromISR( void )
{ {
static size_t xNextByteToSend = 0; static size_t xNextByteToSend = 0;
const BaseType_t xCallsBetweenSends = 100, xBytesToSend = 4; const BaseType_t xCallsBetweenSends = 100, xBytesToSend = 4;
static BaseType_t xCallCount = 0; static BaseType_t xCallCount = 0;
/* Is it time to write to the stream buffer again? */ /* Is it time to write to the stream buffer again? */
xCallCount++; xCallCount++;
if( xCallCount > xCallsBetweenSends )
{
xCallCount = 0;
/* Send the next four bytes to the stream buffer. */ if( xCallCount > xCallsBetweenSends )
xStreamBufferSendFromISR( xStreamBuffer, {
( const void * ) ( pcStringToSend + xNextByteToSend ), xCallCount = 0;
xBytesToSend,
NULL );
/* Send the next four bytes the next time around, wrapping to the start /* Send the next four bytes to the stream buffer. */
of the string if necessary. */ xStreamBufferSendFromISR( xStreamBuffer,
xNextByteToSend += xBytesToSend; ( const void * ) ( pcStringToSend + xNextByteToSend ),
xBytesToSend,
NULL );
if( xNextByteToSend >= strlen( pcStringToSend ) ) /* Send the next four bytes the next time around, wrapping to the start
{ * of the string if necessary. */
xNextByteToSend = 0; xNextByteToSend += xBytesToSend;
}
} if( xNextByteToSend >= strlen( pcStringToSend ) )
{
xNextByteToSend = 0;
}
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xIsInterruptStreamBufferDemoStillRunning( void ) BaseType_t xIsInterruptStreamBufferDemoStillRunning( void )
{ {
uint32_t ulLastCycleCount = 0; uint32_t ulLastCycleCount = 0;
/* Check the demo is still running. */ /* Check the demo is still running. */
if( ulLastCycleCount == ulCycleCount ) if( ulLastCycleCount == ulCycleCount )
{ {
xDemoStatus = pdFAIL; xDemoStatus = pdFAIL;
} }
else else
{ {
ulLastCycleCount = ulCycleCount; ulLastCycleCount = ulCycleCount;
} }
return xDemoStatus; return xDemoStatus;
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -41,30 +41,30 @@
/* Task priorities and stack sizes. Allow these to be overridden. */ /* Task priorities and stack sizes. Allow these to be overridden. */
#ifndef bktPRIMARY_PRIORITY #ifndef bktPRIMARY_PRIORITY
#define bktPRIMARY_PRIORITY ( configMAX_PRIORITIES - 3 ) #define bktPRIMARY_PRIORITY ( configMAX_PRIORITIES - 3 )
#endif #endif
#ifndef bktSECONDARY_PRIORITY #ifndef bktSECONDARY_PRIORITY
#define bktSECONDARY_PRIORITY ( configMAX_PRIORITIES - 4 ) #define bktSECONDARY_PRIORITY ( configMAX_PRIORITIES - 4 )
#endif #endif
#ifndef bktBLOCK_TIME_TASK_STACK_SIZE #ifndef bktBLOCK_TIME_TASK_STACK_SIZE
#define bktBLOCK_TIME_TASK_STACK_SIZE configMINIMAL_STACK_SIZE #define bktBLOCK_TIME_TASK_STACK_SIZE configMINIMAL_STACK_SIZE
#endif #endif
/* Task behaviour. */ /* Task behaviour. */
#define bktQUEUE_LENGTH ( 5 ) #define bktQUEUE_LENGTH ( 5 )
#define bktSHORT_WAIT pdMS_TO_TICKS( ( TickType_t ) 20 ) #define bktSHORT_WAIT pdMS_TO_TICKS( ( TickType_t ) 20 )
#define bktPRIMARY_BLOCK_TIME ( 10 ) #define bktPRIMARY_BLOCK_TIME ( 10 )
#define bktALLOWABLE_MARGIN ( 15 ) #define bktALLOWABLE_MARGIN ( 15 )
#define bktTIME_TO_BLOCK ( 175 ) #define bktTIME_TO_BLOCK ( 175 )
#define bktDONT_BLOCK ( ( TickType_t ) 0 ) #define bktDONT_BLOCK ( ( TickType_t ) 0 )
#define bktRUN_INDICATOR ( ( UBaseType_t ) 0x55 ) #define bktRUN_INDICATOR ( ( UBaseType_t ) 0x55 )
/* In case the demo does not have software timers enabled, as this file uses /* In case the demo does not have software timers enabled, as this file uses
the configTIMER_TASK_PRIORITY setting. */ * the configTIMER_TASK_PRIORITY setting. */
#ifndef configTIMER_TASK_PRIORITY #ifndef configTIMER_TASK_PRIORITY
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) #define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -72,8 +72,8 @@ the configTIMER_TASK_PRIORITY setting. */
/* /*
* The two test tasks. Their behaviour is commented within the functions. * The two test tasks. Their behaviour is commented within the functions.
*/ */
static void vPrimaryBlockTimeTestTask( void *pvParameters ); static void vPrimaryBlockTimeTestTask( void * pvParameters );
static void vSecondaryBlockTimeTestTask( void *pvParameters ); static void vSecondaryBlockTimeTestTask( void * pvParameters );
/* /*
* Very basic tests to verify the block times are as expected. * Very basic tests to verify the block times are as expected.
@ -86,7 +86,7 @@ static void prvBasicDelayTests( void );
static QueueHandle_t xTestQueue; static QueueHandle_t xTestQueue;
/* Handle to the secondary task is required by the primary task for calls /* Handle to the secondary task is required by the primary task for calls
to vTaskSuspend/Resume(). */ * to vTaskSuspend/Resume(). */
static TaskHandle_t xSecondary; static TaskHandle_t xSecondary;
/* Used to ensure that tasks are still executing without error. */ /* Used to ensure that tasks are still executing without error. */
@ -94,495 +94,505 @@ static volatile BaseType_t xPrimaryCycles = 0, xSecondaryCycles = 0;
static volatile BaseType_t xErrorOccurred = pdFALSE; static volatile BaseType_t xErrorOccurred = pdFALSE;
/* Provides a simple mechanism for the primary task to know when the /* Provides a simple mechanism for the primary task to know when the
secondary task has executed. */ * secondary task has executed. */
static volatile UBaseType_t xRunIndicator; static volatile UBaseType_t xRunIndicator;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vCreateBlockTimeTasks( void ) void vCreateBlockTimeTasks( void )
{ {
/* Create the queue on which the two tasks block. */ /* Create the queue on which the two tasks block. */
xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( BaseType_t ) ); xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( BaseType_t ) );
if( xTestQueue != NULL ) if( xTestQueue != NULL )
{ {
/* vQueueAddToRegistry() adds the queue to the queue registry, if one /* vQueueAddToRegistry() adds the queue to the queue registry, if one
is in use. The queue registry is provided as a means for kernel aware * is in use. The queue registry is provided as a means for kernel aware
debuggers to locate queues and has no purpose if a kernel aware * debuggers to locate queues and has no purpose if a kernel aware
debugger is not being used. The call to vQueueAddToRegistry() will be * debugger is not being used. The call to vQueueAddToRegistry() will be
removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not * removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not
defined or is defined to be less than 1. */ * defined or is defined to be less than 1. */
vQueueAddToRegistry( xTestQueue, "Block_Time_Queue" ); vQueueAddToRegistry( xTestQueue, "Block_Time_Queue" );
/* Create the two test tasks. */ /* Create the two test tasks. */
xTaskCreate( vPrimaryBlockTimeTestTask, "BTest1", bktBLOCK_TIME_TASK_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL ); xTaskCreate( vPrimaryBlockTimeTestTask, "BTest1", bktBLOCK_TIME_TASK_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
xTaskCreate( vSecondaryBlockTimeTestTask, "BTest2", bktBLOCK_TIME_TASK_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary ); xTaskCreate( vSecondaryBlockTimeTestTask, "BTest2", bktBLOCK_TIME_TASK_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vPrimaryBlockTimeTestTask( void *pvParameters ) static void vPrimaryBlockTimeTestTask( void * pvParameters )
{ {
BaseType_t xItem, xData; BaseType_t xItem, xData;
TickType_t xTimeWhenBlocking; TickType_t xTimeWhenBlocking;
TickType_t xTimeToBlock, xBlockedTime; TickType_t xTimeToBlock, xBlockedTime;
( void ) pvParameters; ( void ) pvParameters;
for( ;; ) for( ; ; )
{ {
/********************************************************************* /*********************************************************************
Test 0 * Test 0
*
* Basic vTaskDelay() and vTaskDelayUntil() tests. */
prvBasicDelayTests();
Basic vTaskDelay() and vTaskDelayUntil() tests. */ /*********************************************************************
prvBasicDelayTests(); * Test 1
*
* Simple block time wakeup test on queue receives. */
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
{
/* The queue is empty. Attempt to read from the queue using a block
* time. When we wake, ensure the delta in time is as expected. */
xTimeToBlock = ( TickType_t ) ( bktPRIMARY_BLOCK_TIME << xItem );
xTimeWhenBlocking = xTaskGetTickCount();
/********************************************************************* /* We should unblock after xTimeToBlock having not received
Test 1 * anything on the queue. */
if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
{
xErrorOccurred = pdTRUE;
}
Simple block time wakeup test on queue receives. */ /* How long were we blocked for? */
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
{
/* The queue is empty. Attempt to read from the queue using a block
time. When we wake, ensure the delta in time is as expected. */
xTimeToBlock = ( TickType_t ) ( bktPRIMARY_BLOCK_TIME << xItem );
xTimeWhenBlocking = xTaskGetTickCount(); if( xBlockedTime < xTimeToBlock )
{
/* Should not have blocked for less than we requested. */
xErrorOccurred = pdTRUE;
}
/* We should unblock after xTimeToBlock having not received if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
anything on the queue. */ {
if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY ) /* Should not have blocked for longer than we requested,
{ * although we would not necessarily run as soon as we were
xErrorOccurred = pdTRUE; * unblocked so a margin is allowed. */
} xErrorOccurred = pdTRUE;
}
}
/* How long were we blocked for? */ /*********************************************************************
xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking; * Test 2
*
* Simple block time wakeup test on queue sends.
*
* First fill the queue. It should be empty so all sends should pass. */
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
{
if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
{
xErrorOccurred = pdTRUE;
}
if( xBlockedTime < xTimeToBlock ) #if configUSE_PREEMPTION == 0
{ taskYIELD();
/* Should not have blocked for less than we requested. */ #endif
xErrorOccurred = pdTRUE; }
}
if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) ) for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
{ {
/* Should not have blocked for longer than we requested, /* The queue is full. Attempt to write to the queue using a block
although we would not necessarily run as soon as we were * time. When we wake, ensure the delta in time is as expected. */
unblocked so a margin is allowed. */ xTimeToBlock = ( TickType_t ) ( bktPRIMARY_BLOCK_TIME << xItem );
xErrorOccurred = pdTRUE;
}
}
/********************************************************************* xTimeWhenBlocking = xTaskGetTickCount();
Test 2
Simple block time wakeup test on queue sends. /* We should unblock after xTimeToBlock having not received
* anything on the queue. */
if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
{
xErrorOccurred = pdTRUE;
}
First fill the queue. It should be empty so all sends should pass. */ /* How long were we blocked for? */
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
{
if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
{
xErrorOccurred = pdTRUE;
}
#if configUSE_PREEMPTION == 0 if( xBlockedTime < xTimeToBlock )
taskYIELD(); {
#endif /* Should not have blocked for less than we requested. */
} xErrorOccurred = pdTRUE;
}
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
{ {
/* The queue is full. Attempt to write to the queue using a block /* Should not have blocked for longer than we requested,
time. When we wake, ensure the delta in time is as expected. */ * although we would not necessarily run as soon as we were
xTimeToBlock = ( TickType_t ) ( bktPRIMARY_BLOCK_TIME << xItem ); * unblocked so a margin is allowed. */
xErrorOccurred = pdTRUE;
}
}
xTimeWhenBlocking = xTaskGetTickCount(); /*********************************************************************
* Test 3
*
* Wake the other task, it will block attempting to post to the queue.
* When we read from the queue the other task will wake, but before it
* can run we will post to the queue again. When the other task runs it
* will find the queue still full, even though it was woken. It should
* recognise that its block time has not expired and return to block for
* the remains of its block time.
*
* Wake the other task so it blocks attempting to post to the already
* full queue. */
xRunIndicator = 0;
vTaskResume( xSecondary );
/* We should unblock after xTimeToBlock having not received /* We need to wait a little to ensure the other task executes. */
anything on the queue. */ while( xRunIndicator != bktRUN_INDICATOR )
if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL ) {
{ /* The other task has not yet executed. */
xErrorOccurred = pdTRUE; vTaskDelay( bktSHORT_WAIT );
} }
/* How long were we blocked for? */ /* Make sure the other task is blocked on the queue. */
xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking; vTaskDelay( bktSHORT_WAIT );
xRunIndicator = 0;
if( xBlockedTime < xTimeToBlock ) for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
{ {
/* Should not have blocked for less than we requested. */ /* Now when we make space on the queue the other task should wake
xErrorOccurred = pdTRUE; * but not execute as this task has higher priority. */
} if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
{
xErrorOccurred = pdTRUE;
}
if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) ) /* Now fill the queue again before the other task gets a chance to
{ * execute. If the other task had executed we would find the queue
/* Should not have blocked for longer than we requested, * full ourselves, and the other task have set xRunIndicator. */
although we would not necessarily run as soon as we were if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
unblocked so a margin is allowed. */ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
}
/********************************************************************* if( xRunIndicator == bktRUN_INDICATOR )
Test 3 {
/* The other task should not have executed. */
xErrorOccurred = pdTRUE;
}
Wake the other task, it will block attempting to post to the queue. /* Raise the priority of the other task so it executes and blocks
When we read from the queue the other task will wake, but before it * on the queue again. */
can run we will post to the queue again. When the other task runs it vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
will find the queue still full, even though it was woken. It should
recognise that its block time has not expired and return to block for
the remains of its block time.
Wake the other task so it blocks attempting to post to the already /* The other task should now have re-blocked without exiting the
full queue. */ * queue function. */
xRunIndicator = 0; if( xRunIndicator == bktRUN_INDICATOR )
vTaskResume( xSecondary ); {
/* The other task should not have executed outside of the
* queue function. */
xErrorOccurred = pdTRUE;
}
/* We need to wait a little to ensure the other task executes. */ /* Set the priority back down. */
while( xRunIndicator != bktRUN_INDICATOR ) vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
{ }
/* The other task has not yet executed. */
vTaskDelay( bktSHORT_WAIT );
}
/* Make sure the other task is blocked on the queue. */
vTaskDelay( bktSHORT_WAIT );
xRunIndicator = 0;
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) /* Let the other task timeout. When it unblockes it will check that it
{ * unblocked at the correct time, then suspend itself. */
/* Now when we make space on the queue the other task should wake while( xRunIndicator != bktRUN_INDICATOR )
but not execute as this task has higher priority. */ {
if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS ) vTaskDelay( bktSHORT_WAIT );
{ }
xErrorOccurred = pdTRUE;
}
/* Now fill the queue again before the other task gets a chance to vTaskDelay( bktSHORT_WAIT );
execute. If the other task had executed we would find the queue xRunIndicator = 0;
full ourselves, and the other task have set xRunIndicator. */
if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
{
xErrorOccurred = pdTRUE;
}
if( xRunIndicator == bktRUN_INDICATOR ) /*********************************************************************
{ * Test 4
/* The other task should not have executed. */ *
xErrorOccurred = pdTRUE; * As per test 3 - but with the send and receive the other way around.
} * The other task blocks attempting to read from the queue.
*
* Empty the queue. We should find that it is full. */
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
{
if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
{
xErrorOccurred = pdTRUE;
}
}
/* Raise the priority of the other task so it executes and blocks /* Wake the other task so it blocks attempting to read from the
on the queue again. */ * already empty queue. */
vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 ); vTaskResume( xSecondary );
/* The other task should now have re-blocked without exiting the /* We need to wait a little to ensure the other task executes. */
queue function. */ while( xRunIndicator != bktRUN_INDICATOR )
if( xRunIndicator == bktRUN_INDICATOR ) {
{ vTaskDelay( bktSHORT_WAIT );
/* The other task should not have executed outside of the }
queue function. */
xErrorOccurred = pdTRUE;
}
/* Set the priority back down. */ vTaskDelay( bktSHORT_WAIT );
vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY ); xRunIndicator = 0;
}
/* Let the other task timeout. When it unblockes it will check that it for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
unblocked at the correct time, then suspend itself. */ {
while( xRunIndicator != bktRUN_INDICATOR ) /* Now when we place an item on the queue the other task should
{ * wake but not execute as this task has higher priority. */
vTaskDelay( bktSHORT_WAIT ); if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
} {
vTaskDelay( bktSHORT_WAIT ); xErrorOccurred = pdTRUE;
xRunIndicator = 0; }
/* Now empty the queue again before the other task gets a chance to
* execute. If the other task had executed we would find the queue
* empty ourselves, and the other task would be suspended. */
if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
{
xErrorOccurred = pdTRUE;
}
/********************************************************************* if( xRunIndicator == bktRUN_INDICATOR )
Test 4 {
/* The other task should not have executed. */
xErrorOccurred = pdTRUE;
}
As per test 3 - but with the send and receive the other way around. /* Raise the priority of the other task so it executes and blocks
The other task blocks attempting to read from the queue. * on the queue again. */
vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
Empty the queue. We should find that it is full. */ /* The other task should now have re-blocked without exiting the
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) * queue function. */
{ if( xRunIndicator == bktRUN_INDICATOR )
if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS ) {
{ /* The other task should not have executed outside of the
xErrorOccurred = pdTRUE; * queue function. */
} xErrorOccurred = pdTRUE;
} }
/* Wake the other task so it blocks attempting to read from the vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
already empty queue. */ }
vTaskResume( xSecondary );
/* We need to wait a little to ensure the other task executes. */ /* Let the other task timeout. When it unblockes it will check that it
while( xRunIndicator != bktRUN_INDICATOR ) * unblocked at the correct time, then suspend itself. */
{ while( xRunIndicator != bktRUN_INDICATOR )
vTaskDelay( bktSHORT_WAIT ); {
} vTaskDelay( bktSHORT_WAIT );
vTaskDelay( bktSHORT_WAIT ); }
xRunIndicator = 0;
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) vTaskDelay( bktSHORT_WAIT );
{
/* Now when we place an item on the queue the other task should
wake but not execute as this task has higher priority. */
if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
{
xErrorOccurred = pdTRUE;
}
/* Now empty the queue again before the other task gets a chance to xPrimaryCycles++;
execute. If the other task had executed we would find the queue }
empty ourselves, and the other task would be suspended. */
if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
{
xErrorOccurred = pdTRUE;
}
if( xRunIndicator == bktRUN_INDICATOR )
{
/* The other task should not have executed. */
xErrorOccurred = pdTRUE;
}
/* Raise the priority of the other task so it executes and blocks
on the queue again. */
vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
/* The other task should now have re-blocked without exiting the
queue function. */
if( xRunIndicator == bktRUN_INDICATOR )
{
/* The other task should not have executed outside of the
queue function. */
xErrorOccurred = pdTRUE;
}
vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
}
/* Let the other task timeout. When it unblockes it will check that it
unblocked at the correct time, then suspend itself. */
while( xRunIndicator != bktRUN_INDICATOR )
{
vTaskDelay( bktSHORT_WAIT );
}
vTaskDelay( bktSHORT_WAIT );
xPrimaryCycles++;
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vSecondaryBlockTimeTestTask( void *pvParameters ) static void vSecondaryBlockTimeTestTask( void * pvParameters )
{ {
TickType_t xTimeWhenBlocking, xBlockedTime; TickType_t xTimeWhenBlocking, xBlockedTime;
BaseType_t xData; BaseType_t xData;
( void ) pvParameters; ( void ) pvParameters;
for( ;; ) for( ; ; )
{ {
/********************************************************************* /*********************************************************************
Test 0, 1 and 2 * Test 0, 1 and 2
*
* This task does not participate in these tests. */
vTaskSuspend( NULL );
This task does not participate in these tests. */ /*********************************************************************
vTaskSuspend( NULL ); * Test 3
*
* The first thing we do is attempt to read from the queue. It should be
* full so we block. Note the time before we block so we can check the
* wake time is as per that expected. */
xTimeWhenBlocking = xTaskGetTickCount();
/********************************************************************* /* We should unblock after bktTIME_TO_BLOCK having not sent anything to
Test 3 * the queue. */
xData = 0;
xRunIndicator = bktRUN_INDICATOR;
The first thing we do is attempt to read from the queue. It should be if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
full so we block. Note the time before we block so we can check the {
wake time is as per that expected. */ xErrorOccurred = pdTRUE;
xTimeWhenBlocking = xTaskGetTickCount(); }
/* We should unblock after bktTIME_TO_BLOCK having not sent anything to /* How long were we inside the send function? */
the queue. */ xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
xData = 0;
xRunIndicator = bktRUN_INDICATOR;
if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
{
xErrorOccurred = pdTRUE;
}
/* How long were we inside the send function? */ /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking; if( xBlockedTime < bktTIME_TO_BLOCK )
{
xErrorOccurred = pdTRUE;
}
/* We should not have blocked for less time than bktTIME_TO_BLOCK. */ /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
if( xBlockedTime < bktTIME_TO_BLOCK ) * either. A margin is permitted as we would not necessarily run as
{ * soon as we unblocked. */
xErrorOccurred = pdTRUE; if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
} {
xErrorOccurred = pdTRUE;
}
/* We should of not blocked for much longer than bktALLOWABLE_MARGIN /* Suspend ready for test 3. */
either. A margin is permitted as we would not necessarily run as xRunIndicator = bktRUN_INDICATOR;
soon as we unblocked. */ vTaskSuspend( NULL );
if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
{
xErrorOccurred = pdTRUE;
}
/* Suspend ready for test 3. */ /*********************************************************************
xRunIndicator = bktRUN_INDICATOR; * Test 4
vTaskSuspend( NULL ); *
* As per test three, but with the send and receive reversed. */
xTimeWhenBlocking = xTaskGetTickCount();
/********************************************************************* /* We should unblock after bktTIME_TO_BLOCK having not received
Test 4 * anything on the queue. */
xRunIndicator = bktRUN_INDICATOR;
As per test three, but with the send and receive reversed. */ if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
xTimeWhenBlocking = xTaskGetTickCount(); {
xErrorOccurred = pdTRUE;
}
/* We should unblock after bktTIME_TO_BLOCK having not received xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
anything on the queue. */
xRunIndicator = bktRUN_INDICATOR;
if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
{
xErrorOccurred = pdTRUE;
}
xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking; /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
if( xBlockedTime < bktTIME_TO_BLOCK )
{
xErrorOccurred = pdTRUE;
}
/* We should not have blocked for less time than bktTIME_TO_BLOCK. */ /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
if( xBlockedTime < bktTIME_TO_BLOCK ) * either. A margin is permitted as we would not necessarily run as soon
{ * as we unblocked. */
xErrorOccurred = pdTRUE; if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
} {
xErrorOccurred = pdTRUE;
}
/* We should of not blocked for much longer than bktALLOWABLE_MARGIN xRunIndicator = bktRUN_INDICATOR;
either. A margin is permitted as we would not necessarily run as soon
as we unblocked. */
if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
{
xErrorOccurred = pdTRUE;
}
xRunIndicator = bktRUN_INDICATOR; xSecondaryCycles++;
}
xSecondaryCycles++;
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvBasicDelayTests( void ) static void prvBasicDelayTests( void )
{ {
TickType_t xPreTime, xPostTime, x, xLastUnblockTime, xExpectedUnblockTime; TickType_t xPreTime, xPostTime, x, xLastUnblockTime, xExpectedUnblockTime;
const TickType_t xPeriod = 75, xCycles = 5, xAllowableMargin = ( bktALLOWABLE_MARGIN >> 1 ), xHalfPeriod = xPeriod / ( TickType_t ) 2; const TickType_t xPeriod = 75, xCycles = 5, xAllowableMargin = ( bktALLOWABLE_MARGIN >> 1 ), xHalfPeriod = xPeriod / ( TickType_t ) 2;
BaseType_t xDidBlock; BaseType_t xDidBlock;
/* Temporarily increase priority so the timing is more accurate, but not so /* Temporarily increase priority so the timing is more accurate, but not so
high as to disrupt the timer tests. */ * high as to disrupt the timer tests. */
vTaskPrioritySet( NULL, configTIMER_TASK_PRIORITY - 1 ); vTaskPrioritySet( NULL, configTIMER_TASK_PRIORITY - 1 );
/* Crude check to too see that vTaskDelay() blocks for the expected /* Crude check to too see that vTaskDelay() blocks for the expected
period. */ * period. */
xPreTime = xTaskGetTickCount(); xPreTime = xTaskGetTickCount();
vTaskDelay( bktTIME_TO_BLOCK ); vTaskDelay( bktTIME_TO_BLOCK );
xPostTime = xTaskGetTickCount(); xPostTime = xTaskGetTickCount();
/* The priority is higher, so the allowable margin is halved when compared /* The priority is higher, so the allowable margin is halved when compared
to the other tests in this file. */ * to the other tests in this file. */
if( ( xPostTime - xPreTime ) > ( bktTIME_TO_BLOCK + xAllowableMargin ) ) if( ( xPostTime - xPreTime ) > ( bktTIME_TO_BLOCK + xAllowableMargin ) )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
/* Now crude tests to check the vTaskDelayUntil() functionality. */ /* Now crude tests to check the vTaskDelayUntil() functionality. */
xPostTime = xTaskGetTickCount(); xPostTime = xTaskGetTickCount();
xLastUnblockTime = xPostTime; xLastUnblockTime = xPostTime;
for( x = 0; x < xCycles; x++ ) for( x = 0; x < xCycles; x++ )
{ {
/* Calculate the next expected unblock time from the time taken before /* Calculate the next expected unblock time from the time taken before
this loop was entered. */ * this loop was entered. */
xExpectedUnblockTime = xPostTime + ( x * xPeriod ); xExpectedUnblockTime = xPostTime + ( x * xPeriod );
vTaskDelayUntil( &xLastUnblockTime, xPeriod ); vTaskDelayUntil( &xLastUnblockTime, xPeriod );
if( ( xTaskGetTickCount() - xExpectedUnblockTime ) > ( bktTIME_TO_BLOCK + xAllowableMargin ) ) if( ( xTaskGetTickCount() - xExpectedUnblockTime ) > ( bktTIME_TO_BLOCK + xAllowableMargin ) )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
xPrimaryCycles++; xPrimaryCycles++;
} }
/* Crude tests for return value of xTaskDelayUntil(). First a standard block /* Crude tests for return value of xTaskDelayUntil(). First a standard block
should return that the task does block. */ * should return that the task does block. */
xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod ); xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod );
if( xDidBlock != pdTRUE )
{
xErrorOccurred = pdTRUE;
}
/* Now delay a few ticks so repeating the above block period will not block for if( xDidBlock != pdTRUE )
the full amount of time, but will still block. */ {
vTaskDelay( xHalfPeriod ); xErrorOccurred = pdTRUE;
xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod ); }
if( xDidBlock != pdTRUE )
{
xErrorOccurred = pdTRUE;
}
/* This time block for longer than xPeriod before calling xTaskDelayUntil() so /* Now delay a few ticks so repeating the above block period will not block for
the call to xTaskDelayUntil() should not block. */ * the full amount of time, but will still block. */
vTaskDelay( xPeriod ); vTaskDelay( xHalfPeriod );
xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod ); xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod );
if( xDidBlock != pdFALSE )
{
xErrorOccurred = pdTRUE;
}
/* Catch up. */ if( xDidBlock != pdTRUE )
xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod ); {
if( xDidBlock != pdTRUE ) xErrorOccurred = pdTRUE;
{ }
xErrorOccurred = pdTRUE;
}
/* Again block for slightly longer than a period so ensure the time is in the /* This time block for longer than xPeriod before calling xTaskDelayUntil() so
past next time xTaskDelayUntil() gets called. */ * the call to xTaskDelayUntil() should not block. */
vTaskDelay( xPeriod + xAllowableMargin ); vTaskDelay( xPeriod );
xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod ); xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod );
if( xDidBlock != pdFALSE )
{
xErrorOccurred = pdTRUE;
}
/* Reset to the original task priority ready for the other tests. */ if( xDidBlock != pdFALSE )
vTaskPrioritySet( NULL, bktPRIMARY_PRIORITY ); {
xErrorOccurred = pdTRUE;
}
/* Catch up. */
xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod );
if( xDidBlock != pdTRUE )
{
xErrorOccurred = pdTRUE;
}
/* Again block for slightly longer than a period so ensure the time is in the
* past next time xTaskDelayUntil() gets called. */
vTaskDelay( xPeriod + xAllowableMargin );
xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod );
if( xDidBlock != pdFALSE )
{
xErrorOccurred = pdTRUE;
}
/* Reset to the original task priority ready for the other tests. */
vTaskPrioritySet( NULL, bktPRIMARY_PRIORITY );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xAreBlockTimeTestTasksStillRunning( void ) BaseType_t xAreBlockTimeTestTasksStillRunning( void )
{ {
static BaseType_t xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0; static BaseType_t xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
BaseType_t xReturn = pdPASS; BaseType_t xReturn = pdPASS;
/* Have both tasks performed at least one cycle since this function was /* Have both tasks performed at least one cycle since this function was
last called? */ * last called? */
if( xPrimaryCycles == xLastPrimaryCycleCount ) if( xPrimaryCycles == xLastPrimaryCycleCount )
{ {
xReturn = pdFAIL; xReturn = pdFAIL;
} }
if( xSecondaryCycles == xLastSecondaryCycleCount ) if( xSecondaryCycles == xLastSecondaryCycleCount )
{ {
xReturn = pdFAIL; xReturn = pdFAIL;
} }
if( xErrorOccurred == pdTRUE ) if( xErrorOccurred == pdTRUE )
{ {
xReturn = pdFAIL; xReturn = pdFAIL;
} }
xLastSecondaryCycleCount = xSecondaryCycles; xLastSecondaryCycleCount = xSecondaryCycles;
xLastPrimaryCycleCount = xPrimaryCycles; xLastPrimaryCycleCount = xPrimaryCycles;
return xReturn; return xReturn;
} }

View file

@ -67,30 +67,30 @@
#include "comtest.h" #include "comtest.h"
#include "partest.h" #include "partest.h"
#define comSTACK_SIZE configMINIMAL_STACK_SIZE #define comSTACK_SIZE configMINIMAL_STACK_SIZE
#define comTX_LED_OFFSET ( 0 ) #define comTX_LED_OFFSET ( 0 )
#define comRX_LED_OFFSET ( 1 ) #define comRX_LED_OFFSET ( 1 )
#define comTOTAL_PERMISSIBLE_ERRORS ( 2 ) #define comTOTAL_PERMISSIBLE_ERRORS ( 2 )
/* The Tx task will transmit the sequence of characters at a pseudo random /* The Tx task will transmit the sequence of characters at a pseudo random
interval. This is the maximum and minimum block time between sends. */ * interval. This is the maximum and minimum block time between sends. */
#define comTX_MAX_BLOCK_TIME ( ( TickType_t ) 0x96 ) #define comTX_MAX_BLOCK_TIME ( ( TickType_t ) 0x96 )
#define comTX_MIN_BLOCK_TIME ( ( TickType_t ) 0x32 ) #define comTX_MIN_BLOCK_TIME ( ( TickType_t ) 0x32 )
#define comOFFSET_TIME ( ( TickType_t ) 3 ) #define comOFFSET_TIME ( ( TickType_t ) 3 )
/* We should find that each character can be queued for Tx immediately and we /* We should find that each character can be queued for Tx immediately and we
don't have to block to send. */ * don't have to block to send. */
#define comNO_BLOCK ( ( TickType_t ) 0 ) #define comNO_BLOCK ( ( TickType_t ) 0 )
/* The Rx task will block on the Rx queue for a long period. */ /* The Rx task will block on the Rx queue for a long period. */
#define comRX_BLOCK_TIME ( ( TickType_t ) 0xffff ) #define comRX_BLOCK_TIME ( ( TickType_t ) 0xffff )
/* The sequence transmitted is from comFIRST_BYTE to and including comLAST_BYTE. */ /* The sequence transmitted is from comFIRST_BYTE to and including comLAST_BYTE. */
#define comFIRST_BYTE ( 'A' ) #define comFIRST_BYTE ( 'A' )
#define comLAST_BYTE ( 'X' ) #define comLAST_BYTE ( 'X' )
#define comBUFFER_LEN ( ( UBaseType_t ) ( comLAST_BYTE - comFIRST_BYTE ) + ( UBaseType_t ) 1 ) #define comBUFFER_LEN ( ( UBaseType_t ) ( comLAST_BYTE - comFIRST_BYTE ) + ( UBaseType_t ) 1 )
#define comINITIAL_RX_COUNT_VALUE ( 0 ) #define comINITIAL_RX_COUNT_VALUE ( 0 )
/* Handle to the com port used by both tasks. */ /* Handle to the com port used by both tasks. */
static xComPortHandle xPort = NULL; static xComPortHandle xPort = NULL;
@ -102,164 +102,165 @@ static portTASK_FUNCTION_PROTO( vComTxTask, pvParameters );
static portTASK_FUNCTION_PROTO( vComRxTask, pvParameters ); static portTASK_FUNCTION_PROTO( vComRxTask, pvParameters );
/* The LED that should be toggled by the Rx and Tx tasks. The Rx task will /* The LED that should be toggled by the Rx and Tx tasks. The Rx task will
toggle LED ( uxBaseLED + comRX_LED_OFFSET). The Tx task will toggle LED * toggle LED ( uxBaseLED + comRX_LED_OFFSET). The Tx task will toggle LED
( uxBaseLED + comTX_LED_OFFSET ). */ * ( uxBaseLED + comTX_LED_OFFSET ). */
static UBaseType_t uxBaseLED = 0; static UBaseType_t uxBaseLED = 0;
/* Check variable used to ensure no error have occurred. The Rx task will /* Check variable used to ensure no error have occurred. The Rx task will
increment this variable after every successfully received sequence. If at any * increment this variable after every successfully received sequence. If at any
time the sequence is incorrect the the variable will stop being incremented. */ * time the sequence is incorrect the the variable will stop being incremented. */
static volatile UBaseType_t uxRxLoops = comINITIAL_RX_COUNT_VALUE; static volatile UBaseType_t uxRxLoops = comINITIAL_RX_COUNT_VALUE;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vAltStartComTestTasks( UBaseType_t uxPriority, uint32_t ulBaudRate, UBaseType_t uxLED ) void vAltStartComTestTasks( UBaseType_t uxPriority,
uint32_t ulBaudRate,
UBaseType_t uxLED )
{ {
/* Initialise the com port then spawn the Rx and Tx tasks. */ /* Initialise the com port then spawn the Rx and Tx tasks. */
uxBaseLED = uxLED; uxBaseLED = uxLED;
xSerialPortInitMinimal( ulBaudRate, comBUFFER_LEN ); xSerialPortInitMinimal( ulBaudRate, comBUFFER_LEN );
/* The Tx task is spawned with a lower priority than the Rx task. */ /* The Tx task is spawned with a lower priority than the Rx task. */
xTaskCreate( vComTxTask, "COMTx", comSTACK_SIZE, NULL, uxPriority - 1, ( TaskHandle_t * ) NULL ); xTaskCreate( vComTxTask, "COMTx", comSTACK_SIZE, NULL, uxPriority - 1, ( TaskHandle_t * ) NULL );
xTaskCreate( vComRxTask, "COMRx", comSTACK_SIZE, NULL, uxPriority, ( TaskHandle_t * ) NULL ); xTaskCreate( vComRxTask, "COMRx", comSTACK_SIZE, NULL, uxPriority, ( TaskHandle_t * ) NULL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static portTASK_FUNCTION( vComTxTask, pvParameters ) static portTASK_FUNCTION( vComTxTask, pvParameters )
{ {
char cByteToSend; char cByteToSend;
TickType_t xTimeToWait; TickType_t xTimeToWait;
/* Just to stop compiler warnings. */ /* Just to stop compiler warnings. */
( void ) pvParameters; ( void ) pvParameters;
for( ;; ) for( ; ; )
{ {
/* Simply transmit a sequence of characters from comFIRST_BYTE to /* Simply transmit a sequence of characters from comFIRST_BYTE to
comLAST_BYTE. */ * comLAST_BYTE. */
for( cByteToSend = comFIRST_BYTE; cByteToSend <= comLAST_BYTE; cByteToSend++ ) for( cByteToSend = comFIRST_BYTE; cByteToSend <= comLAST_BYTE; cByteToSend++ )
{ {
if( xSerialPutChar( xPort, cByteToSend, comNO_BLOCK ) == pdPASS ) if( xSerialPutChar( xPort, cByteToSend, comNO_BLOCK ) == pdPASS )
{ {
vParTestToggleLED( uxBaseLED + comTX_LED_OFFSET ); vParTestToggleLED( uxBaseLED + comTX_LED_OFFSET );
} }
} }
/* Turn the LED off while we are not doing anything. */ /* Turn the LED off while we are not doing anything. */
vParTestSetLED( uxBaseLED + comTX_LED_OFFSET, pdFALSE ); vParTestSetLED( uxBaseLED + comTX_LED_OFFSET, pdFALSE );
/* We have posted all the characters in the string - wait before /* We have posted all the characters in the string - wait before
re-sending. Wait a pseudo-random time as this will provide a better * re-sending. Wait a pseudo-random time as this will provide a better
test. */ * test. */
xTimeToWait = xTaskGetTickCount() + comOFFSET_TIME; xTimeToWait = xTaskGetTickCount() + comOFFSET_TIME;
/* Make sure we don't wait too long... */ /* Make sure we don't wait too long... */
xTimeToWait %= comTX_MAX_BLOCK_TIME; xTimeToWait %= comTX_MAX_BLOCK_TIME;
/* ...but we do want to wait. */ /* ...but we do want to wait. */
if( xTimeToWait < comTX_MIN_BLOCK_TIME ) if( xTimeToWait < comTX_MIN_BLOCK_TIME )
{ {
xTimeToWait = comTX_MIN_BLOCK_TIME; xTimeToWait = comTX_MIN_BLOCK_TIME;
} }
vTaskDelay( xTimeToWait ); vTaskDelay( xTimeToWait );
} }
} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */ } /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static portTASK_FUNCTION( vComRxTask, pvParameters ) static portTASK_FUNCTION( vComRxTask, pvParameters )
{ {
signed char cExpectedByte, cByteRxed; signed char cExpectedByte, cByteRxed;
BaseType_t xResyncRequired = pdFALSE, xErrorOccurred = pdFALSE; BaseType_t xResyncRequired = pdFALSE, xErrorOccurred = pdFALSE;
/* Just to stop compiler warnings. */ /* Just to stop compiler warnings. */
( void ) pvParameters; ( void ) pvParameters;
for( ;; ) for( ; ; )
{ {
/* We expect to receive the characters from comFIRST_BYTE to /* We expect to receive the characters from comFIRST_BYTE to
comLAST_BYTE in an incrementing order. Loop to receive each byte. */ * comLAST_BYTE in an incrementing order. Loop to receive each byte. */
for( cExpectedByte = comFIRST_BYTE; cExpectedByte <= comLAST_BYTE; cExpectedByte++ ) for( cExpectedByte = comFIRST_BYTE; cExpectedByte <= comLAST_BYTE; cExpectedByte++ )
{ {
/* Block on the queue that contains received bytes until a byte is /* Block on the queue that contains received bytes until a byte is
available. */ * available. */
if( xSerialGetChar( xPort, &cByteRxed, comRX_BLOCK_TIME ) ) if( xSerialGetChar( xPort, &cByteRxed, comRX_BLOCK_TIME ) )
{ {
/* Was this the byte we were expecting? If so, toggle the LED, /* Was this the byte we were expecting? If so, toggle the LED,
otherwise we are out on sync and should break out of the loop * otherwise we are out on sync and should break out of the loop
until the expected character sequence is about to restart. */ * until the expected character sequence is about to restart. */
if( cByteRxed == cExpectedByte ) if( cByteRxed == cExpectedByte )
{ {
vParTestToggleLED( uxBaseLED + comRX_LED_OFFSET ); vParTestToggleLED( uxBaseLED + comRX_LED_OFFSET );
} }
else else
{ {
xResyncRequired = pdTRUE; xResyncRequired = pdTRUE;
break; /*lint !e960 Non-switch break allowed. */ break; /*lint !e960 Non-switch break allowed. */
} }
} }
} }
/* Turn the LED off while we are not doing anything. */ /* Turn the LED off while we are not doing anything. */
vParTestSetLED( uxBaseLED + comRX_LED_OFFSET, pdFALSE ); vParTestSetLED( uxBaseLED + comRX_LED_OFFSET, pdFALSE );
/* Did we break out of the loop because the characters were received in /* Did we break out of the loop because the characters were received in
an unexpected order? If so wait here until the character sequence is * an unexpected order? If so wait here until the character sequence is
about to restart. */ * about to restart. */
if( xResyncRequired == pdTRUE ) if( xResyncRequired == pdTRUE )
{ {
while( cByteRxed != comLAST_BYTE ) while( cByteRxed != comLAST_BYTE )
{ {
/* Block until the next char is available. */ /* Block until the next char is available. */
xSerialGetChar( xPort, &cByteRxed, comRX_BLOCK_TIME ); xSerialGetChar( xPort, &cByteRxed, comRX_BLOCK_TIME );
} }
/* Note that an error occurred which caused us to have to resync. /* Note that an error occurred which caused us to have to resync.
We use this to stop incrementing the loop counter so * We use this to stop incrementing the loop counter so
sAreComTestTasksStillRunning() will return false - indicating an * sAreComTestTasksStillRunning() will return false - indicating an
error. */ * error. */
xErrorOccurred++; xErrorOccurred++;
/* We have now resynced with the Tx task and can continue. */ /* We have now resynced with the Tx task and can continue. */
xResyncRequired = pdFALSE; xResyncRequired = pdFALSE;
} }
else else
{ {
if( xErrorOccurred < comTOTAL_PERMISSIBLE_ERRORS ) if( xErrorOccurred < comTOTAL_PERMISSIBLE_ERRORS )
{ {
/* Increment the count of successful loops. As error /* Increment the count of successful loops. As error
occurring (i.e. an unexpected character being received) will * occurring (i.e. an unexpected character being received) will
prevent this counter being incremented for the rest of the * prevent this counter being incremented for the rest of the
execution. Don't worry about mutual exclusion on this * execution. Don't worry about mutual exclusion on this
variable - it doesn't really matter as we just want it * variable - it doesn't really matter as we just want it
to change. */ * to change. */
uxRxLoops++; uxRxLoops++;
} }
} }
} }
} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */ } /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xAreComTestTasksStillRunning( void ) BaseType_t xAreComTestTasksStillRunning( void )
{ {
BaseType_t xReturn; BaseType_t xReturn;
/* If the count of successful reception loops has not changed than at /* 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) * some time an error occurred (i.e. a character was received out of sequence)
and we will return false. */ * and we will return false. */
if( uxRxLoops == comINITIAL_RX_COUNT_VALUE ) if( uxRxLoops == comINITIAL_RX_COUNT_VALUE )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
} }
else else
{ {
xReturn = pdTRUE; xReturn = pdTRUE;
} }
/* Reset the count of successful Rx loops. When this function is called /* Reset the count of successful Rx loops. When this function is called
again we expect this to have been incremented. */ * again we expect this to have been incremented. */
uxRxLoops = comINITIAL_RX_COUNT_VALUE; uxRxLoops = comINITIAL_RX_COUNT_VALUE;
return xReturn; return xReturn;
} }

View file

@ -19,8 +19,8 @@
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 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. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* *
* https://www.FreeRTOS.org * https://www.FreeRTOS.org
* https://github.com/FreeRTOS * https://github.com/FreeRTOS
* *
*/ */
@ -57,11 +57,11 @@
#include "timers.h" #include "timers.h"
#ifndef configUSE_TIMERS #ifndef configUSE_TIMERS
#error This demo uses timers. configUSE_TIMERS must be set to 1 in FreeRTOSConfig.h. #error This demo uses timers. configUSE_TIMERS must be set to 1 in FreeRTOSConfig.h.
#endif #endif
#if configUSE_TIMERS != 1 #if configUSE_TIMERS != 1
#error This demo uses timers. configUSE_TIMERS must be set to 1 in FreeRTOSConfig.h. #error This demo uses timers. configUSE_TIMERS must be set to 1 in FreeRTOSConfig.h.
#endif #endif
@ -71,240 +71,246 @@
#include "partest.h" #include "partest.h"
/* The size of the stack given to the Rx task. */ /* The size of the stack given to the Rx task. */
#define comSTACK_SIZE configMINIMAL_STACK_SIZE #define comSTACK_SIZE configMINIMAL_STACK_SIZE
/* See the comment above the declaration of the uxBaseLED variable. */ /* See the comment above the declaration of the uxBaseLED variable. */
#define comTX_LED_OFFSET ( 0 ) #define comTX_LED_OFFSET ( 0 )
#define comRX_LED_OFFSET ( 1 ) #define comRX_LED_OFFSET ( 1 )
/* The Tx timer transmits the sequence of characters at a pseudo random /* The Tx timer transmits the sequence of characters at a pseudo random
interval that is capped between comTX_MAX_BLOCK_TIME and * interval that is capped between comTX_MAX_BLOCK_TIME and
comTX_MIN_BLOCK_TIME. */ * comTX_MIN_BLOCK_TIME. */
#define comTX_MAX_BLOCK_TIME ( ( TickType_t ) 0x96 ) #define comTX_MAX_BLOCK_TIME ( ( TickType_t ) 0x96 )
#define comTX_MIN_BLOCK_TIME ( ( TickType_t ) 0x32 ) #define comTX_MIN_BLOCK_TIME ( ( TickType_t ) 0x32 )
#define comOFFSET_TIME ( ( TickType_t ) 3 ) #define comOFFSET_TIME ( ( TickType_t ) 3 )
/* States for the simple state machine implemented in the Rx task. */ /* States for the simple state machine implemented in the Rx task. */
#define comtstWAITING_START_OF_STRING 0 #define comtstWAITING_START_OF_STRING 0
#define comtstWAITING_END_OF_STRING 1 #define comtstWAITING_END_OF_STRING 1
/* A short delay in ticks - this delay is used to allow the Rx queue to fill up /* 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 * 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 * 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 * between transmissions. It could be worked out more scientifically from the
baud rate being used. */ * baud rate being used. */
#define comSHORT_DELAY ( comTX_MIN_BLOCK_TIME >> ( TickType_t ) 2 ) #define comSHORT_DELAY ( comTX_MIN_BLOCK_TIME >> ( TickType_t ) 2 )
/* The string that is transmitted and received. */ /* The string that is transmitted and received. */
#define comTRANSACTED_STRING "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" #define comTRANSACTED_STRING "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
/* A block time of 0 simply means "don't block". */ /* A block time of 0 simply means "don't block". */
#define comtstDONT_BLOCK ( TickType_t ) 0 #define comtstDONT_BLOCK ( TickType_t ) 0
/* Handle to the com port used by both tasks. */ /* Handle to the com port used by both tasks. */
static xComPortHandle xPort = NULL; static xComPortHandle xPort = NULL;
/* The callback function allocated to the transmit timer, as described in the /* The callback function allocated to the transmit timer, as described in the
comments at the top of this file. */ * comments at the top of this file. */
static void prvComTxTimerCallback( TimerHandle_t xTimer ); static void prvComTxTimerCallback( TimerHandle_t xTimer );
/* The receive task as described in the comments at the top of this file. */ /* The receive task as described in the comments at the top of this file. */
static void vComRxTask( void *pvParameters ); static void vComRxTask( void * pvParameters );
/* The Rx task will toggle LED ( uxBaseLED + comRX_LED_OFFSET). The Tx task /* The Rx task will toggle LED ( uxBaseLED + comRX_LED_OFFSET). The Tx task
will toggle LED ( uxBaseLED + comTX_LED_OFFSET ). */ * will toggle LED ( uxBaseLED + comTX_LED_OFFSET ). */
static UBaseType_t uxBaseLED = 0; static UBaseType_t uxBaseLED = 0;
/* The Rx task toggles uxRxLoops on each successful iteration of its defined /* The Rx task toggles uxRxLoops on each successful iteration of its defined
function - provided no errors have ever been latched. If this variable stops * function - provided no errors have ever been latched. If this variable stops
incrementing, then an error has occurred. */ * incrementing, then an error has occurred. */
static volatile UBaseType_t uxRxLoops = 0UL; static volatile UBaseType_t uxRxLoops = 0UL;
/* The timer used to periodically transmit the string. This is the timer that /* The timer used to periodically transmit the string. This is the timer that
has prvComTxTimerCallback allocated to it as its callback function. */ * has prvComTxTimerCallback allocated to it as its callback function. */
static TimerHandle_t xTxTimer = NULL; static TimerHandle_t xTxTimer = NULL;
/* The string length is held at file scope so the Tx timer does not need to /* The string length is held at file scope so the Tx timer does not need to
calculate it each time it executes. */ * calculate it each time it executes. */
static size_t xStringLength = 0U; static size_t xStringLength = 0U;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vStartComTestStringsTasks( UBaseType_t uxPriority, uint32_t ulBaudRate, UBaseType_t uxLED ) void vStartComTestStringsTasks( UBaseType_t uxPriority,
uint32_t ulBaudRate,
UBaseType_t uxLED )
{ {
/* Store values that are used at run time. */ /* Store values that are used at run time. */
uxBaseLED = uxLED; uxBaseLED = uxLED;
/* Calculate the string length here, rather than each time the Tx timer /* Calculate the string length here, rather than each time the Tx timer
executes. */ * executes. */
xStringLength = strlen( comTRANSACTED_STRING ); xStringLength = strlen( comTRANSACTED_STRING );
/* Include the null terminator in the string length as this is used to /* Include the null terminator in the string length as this is used to
detect the end of the string in the Rx task. */ * detect the end of the string in the Rx task. */
xStringLength++; xStringLength++;
/* Initialise the com port, then spawn the Rx task and create the Tx /* Initialise the com port, then spawn the Rx task and create the Tx
timer. */ * timer. */
xSerialPortInitMinimal( ulBaudRate, ( xStringLength * 2U ) ); xSerialPortInitMinimal( ulBaudRate, ( xStringLength * 2U ) );
/* Create the Rx task and the Tx timer. The timer is started from the /* Create the Rx task and the Tx timer. The timer is started from the
Rx task. */ * Rx task. */
xTaskCreate( vComRxTask, "COMRx", comSTACK_SIZE, NULL, uxPriority, ( TaskHandle_t * ) NULL ); xTaskCreate( vComRxTask, "COMRx", comSTACK_SIZE, NULL, uxPriority, ( TaskHandle_t * ) NULL );
xTxTimer = xTimerCreate( "TxTimer", comTX_MIN_BLOCK_TIME, pdFALSE, NULL, prvComTxTimerCallback ); xTxTimer = xTimerCreate( "TxTimer", comTX_MIN_BLOCK_TIME, pdFALSE, NULL, prvComTxTimerCallback );
configASSERT( xTxTimer ); configASSERT( xTxTimer );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvComTxTimerCallback( TimerHandle_t xTimer ) static void prvComTxTimerCallback( TimerHandle_t xTimer )
{ {
TickType_t xTimeToWait; TickType_t xTimeToWait;
/* The parameter is not used in this case. */ /* The parameter is not used in this case. */
( void ) xTimer; ( void ) xTimer;
/* Send the string. How this is actually performed depends on the /* Send the string. How this is actually performed depends on the
sample driver provided with this demo. However - as this is a timer, * 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 * it executes in the context of the timer task and therefore must not
block. */ * block. */
vSerialPutString( xPort, comTRANSACTED_STRING, xStringLength ); vSerialPutString( xPort, comTRANSACTED_STRING, xStringLength );
/* Toggle an LED to give a visible indication that another transmission /* Toggle an LED to give a visible indication that another transmission
has been performed. */ * has been performed. */
vParTestToggleLED( uxBaseLED + comTX_LED_OFFSET ); vParTestToggleLED( uxBaseLED + comTX_LED_OFFSET );
/* Wait a pseudo random time before sending the string again. */ /* Wait a pseudo random time before sending the string again. */
xTimeToWait = xTaskGetTickCount() + comOFFSET_TIME; xTimeToWait = xTaskGetTickCount() + comOFFSET_TIME;
/* Ensure the time to wait is not greater than comTX_MAX_BLOCK_TIME. */ /* Ensure the time to wait is not greater than comTX_MAX_BLOCK_TIME. */
xTimeToWait %= comTX_MAX_BLOCK_TIME; xTimeToWait %= comTX_MAX_BLOCK_TIME;
/* Ensure the time to wait is not less than comTX_MIN_BLOCK_TIME. */ /* Ensure the time to wait is not less than comTX_MIN_BLOCK_TIME. */
if( xTimeToWait < comTX_MIN_BLOCK_TIME ) if( xTimeToWait < comTX_MIN_BLOCK_TIME )
{ {
xTimeToWait = comTX_MIN_BLOCK_TIME; xTimeToWait = comTX_MIN_BLOCK_TIME;
} }
/* Reset the timer to run again xTimeToWait ticks from now. This function /* 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 * is called from the context of the timer task, so the block time must not
be anything other than zero. */ * be anything other than zero. */
xTimerChangePeriod( xTxTimer, xTimeToWait, comtstDONT_BLOCK ); xTimerChangePeriod( xTxTimer, xTimeToWait, comtstDONT_BLOCK );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void vComRxTask( void *pvParameters ) static void vComRxTask( void * pvParameters )
{ {
BaseType_t xState = comtstWAITING_START_OF_STRING, xErrorOccurred = pdFALSE; BaseType_t xState = comtstWAITING_START_OF_STRING, xErrorOccurred = pdFALSE;
char *pcExpectedByte, cRxedChar; char * pcExpectedByte, cRxedChar;
const xComPortHandle xPort = NULL; const xComPortHandle xPort = NULL;
/* The parameter is not used in this example. */ /* The parameter is not used in this example. */
( void ) pvParameters; ( void ) pvParameters;
/* Start the Tx timer. This only needs to be started once, as it will /* Start the Tx timer. This only needs to be started once, as it will
reset itself thereafter. */ * reset itself thereafter. */
xTimerStart( xTxTimer, portMAX_DELAY ); xTimerStart( xTxTimer, portMAX_DELAY );
/* The first expected Rx character is the first in the string that is /* The first expected Rx character is the first in the string that is
transmitted. */ * transmitted. */
pcExpectedByte = comTRANSACTED_STRING; pcExpectedByte = comTRANSACTED_STRING;
for( ;; ) for( ; ; )
{ {
/* Wait for the next character. */ /* Wait for the next character. */
if( xSerialGetChar( xPort, &cRxedChar, ( comTX_MAX_BLOCK_TIME * 2 ) ) == pdFALSE ) if( xSerialGetChar( xPort, &cRxedChar, ( comTX_MAX_BLOCK_TIME * 2 ) ) == pdFALSE )
{ {
/* A character definitely should have been received by now. As a /* A character definitely should have been received by now. As a
character was not received an error must have occurred (which might * character was not received an error must have occurred (which might
just be that the loopback connector is not fitted). */ * just be that the loopback connector is not fitted). */
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
switch( xState ) switch( xState )
{ {
case comtstWAITING_START_OF_STRING: 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 if( cRxedChar == *pcExpectedByte )
to contain more than one character, and therefore prevent {
thrashing reads to the queue, and repetitive context /* The received character was the first character of the
switches as each character is received. */ * string. Move to the next state to check each character
vTaskDelay( comSHORT_DELAY ); * as it comes in until the entire string has been received. */
} xState = comtstWAITING_END_OF_STRING;
break; pcExpectedByte++;
case comtstWAITING_END_OF_STRING: /* Block for a short period. This just allows the Rx queue
if( cRxedChar == *pcExpectedByte ) * to contain more than one character, and therefore prevent
{ * thrashing reads to the queue, and repetitive context
/* The received character was the expected character. Was * switches as each character is received. */
it the last character in the string - i.e. the null vTaskDelay( comSHORT_DELAY );
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 break;
complete string has been received. */
vParTestToggleLED( uxBaseLED + comRX_LED_OFFSET );
}
/* Go back to wait for the start of the next string. */ case comtstWAITING_END_OF_STRING:
pcExpectedByte = 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: if( cRxedChar == *pcExpectedByte )
/* Should not get here. Stop the Rx loop counter from {
incrementing to latch the error. */ /* The received character was the expected character. Was
xErrorOccurred = pdTRUE; * it the last character in the string - i.e. the null
break; * 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 = 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;
}
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xAreComTestTasksStillRunning( void ) BaseType_t xAreComTestTasksStillRunning( void )
{ {
BaseType_t xReturn; BaseType_t xReturn;
/* If the count of successful reception loops has not changed than at /* 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) * some time an error occurred (i.e. a character was received out of sequence)
and false is returned. */ * and false is returned. */
if( uxRxLoops == 0UL ) if( uxRxLoops == 0UL )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
} }
else else
{ {
xReturn = pdTRUE; xReturn = pdTRUE;
} }
/* Reset the count of successful Rx loops. When this function is called /* Reset the count of successful Rx loops. When this function is called
again it should have been incremented again. */ * again it should have been incremented again. */
uxRxLoops = 0UL; uxRxLoops = 0UL;
return xReturn; return xReturn;
} }

View file

@ -39,24 +39,24 @@
#include "countsem.h" #include "countsem.h"
/* The maximum count value that the semaphore used for the demo can hold. */ /* The maximum count value that the semaphore used for the demo can hold. */
#define countMAX_COUNT_VALUE ( 200 ) #define countMAX_COUNT_VALUE ( 200 )
/* Constants used to indicate whether or not the semaphore should have been /* Constants used to indicate whether or not the semaphore should have been
created with its maximum count value, or its minimum count value. These * created with its maximum count value, or its minimum count value. These
numbers are used to ensure that the pointers passed in as the task parameters * numbers are used to ensure that the pointers passed in as the task parameters
are valid. */ * are valid. */
#define countSTART_AT_MAX_COUNT ( 0xaa ) #define countSTART_AT_MAX_COUNT ( 0xaa )
#define countSTART_AT_ZERO ( 0x55 ) #define countSTART_AT_ZERO ( 0x55 )
/* Two tasks are created for the test. One uses a semaphore created with its /* Two tasks are created for the test. One uses a semaphore created with its
count value set to the maximum, and one with the count value set to zero. */ * count value set to the maximum, and one with the count value set to zero. */
#define countNUM_TEST_TASKS ( 2 ) #define countNUM_TEST_TASKS ( 2 )
#define countDONT_BLOCK ( 0 ) #define countDONT_BLOCK ( 0 )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Flag that will be latched to pdTRUE should any unexpected behaviour be /* Flag that will be latched to pdTRUE should any unexpected behaviour be
detected in any of the tasks. */ * detected in any of the tasks. */
static volatile BaseType_t xErrorDetected = pdFALSE; static volatile BaseType_t xErrorDetected = pdFALSE;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -67,36 +67,38 @@ static volatile BaseType_t xErrorDetected = pdFALSE;
* 'take' is inspected, with an error being flagged if it is found not to be * 'take' is inspected, with an error being flagged if it is found not to be
* the expected result. * the expected result.
*/ */
static void prvCountingSemaphoreTask( void *pvParameters ); static void prvCountingSemaphoreTask( void * pvParameters );
/* /*
* Utility function to increment the semaphore count value up from zero to * Utility function to increment the semaphore count value up from zero to
* countMAX_COUNT_VALUE. * countMAX_COUNT_VALUE.
*/ */
static void prvIncrementSemaphoreCount( SemaphoreHandle_t xSemaphore, volatile UBaseType_t *puxLoopCounter ); static void prvIncrementSemaphoreCount( SemaphoreHandle_t xSemaphore,
volatile UBaseType_t * puxLoopCounter );
/* /*
* Utility function to decrement the semaphore count value up from * Utility function to decrement the semaphore count value up from
* countMAX_COUNT_VALUE to zero. * countMAX_COUNT_VALUE to zero.
*/ */
static void prvDecrementSemaphoreCount( SemaphoreHandle_t xSemaphore, volatile UBaseType_t *puxLoopCounter ); static void prvDecrementSemaphoreCount( SemaphoreHandle_t xSemaphore,
volatile UBaseType_t * puxLoopCounter );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* The structure that is passed into the task as the task parameter. */ /* The structure that is passed into the task as the task parameter. */
typedef struct COUNT_SEM_STRUCT typedef struct COUNT_SEM_STRUCT
{ {
/* The semaphore to be used for the demo. */ /* The semaphore to be used for the demo. */
SemaphoreHandle_t xSemaphore; SemaphoreHandle_t xSemaphore;
/* Set to countSTART_AT_MAX_COUNT if the semaphore should be created with /* Set to countSTART_AT_MAX_COUNT if the semaphore should be created with
its count value set to its max count value, or countSTART_AT_ZERO if it * its count value set to its max count value, or countSTART_AT_ZERO if it
should have been created with its count value set to 0. */ * should have been created with its count value set to 0. */
UBaseType_t uxExpectedStartCount; UBaseType_t uxExpectedStartCount;
/* Incremented on each cycle of the demo task. Used to detect a stalled /* Incremented on each cycle of the demo task. Used to detect a stalled
task. */ * task. */
volatile UBaseType_t uxLoopCounter; volatile UBaseType_t uxLoopCounter;
} xCountSemStruct; } xCountSemStruct;
/* Two structures are defined, one is passed to each test task. */ /* Two structures are defined, one is passed to each test task. */
@ -106,183 +108,184 @@ static xCountSemStruct xParameters[ countNUM_TEST_TASKS ];
void vStartCountingSemaphoreTasks( void ) void vStartCountingSemaphoreTasks( void )
{ {
/* Create the semaphores that we are going to use for the test/demo. The /* Create the semaphores that we are going to use for the test/demo. The
first should be created such that it starts at its maximum count value, * first should be created such that it starts at its maximum count value,
the second should be created such that it starts with a count value of zero. */ * the second should be created such that it starts with a count value of zero. */
xParameters[ 0 ].xSemaphore = xSemaphoreCreateCounting( countMAX_COUNT_VALUE, countMAX_COUNT_VALUE ); xParameters[ 0 ].xSemaphore = xSemaphoreCreateCounting( countMAX_COUNT_VALUE, countMAX_COUNT_VALUE );
xParameters[ 0 ].uxExpectedStartCount = countSTART_AT_MAX_COUNT; xParameters[ 0 ].uxExpectedStartCount = countSTART_AT_MAX_COUNT;
xParameters[ 0 ].uxLoopCounter = 0; xParameters[ 0 ].uxLoopCounter = 0;
xParameters[ 1 ].xSemaphore = xSemaphoreCreateCounting( countMAX_COUNT_VALUE, 0 ); xParameters[ 1 ].xSemaphore = xSemaphoreCreateCounting( countMAX_COUNT_VALUE, 0 );
xParameters[ 1 ].uxExpectedStartCount = 0; xParameters[ 1 ].uxExpectedStartCount = 0;
xParameters[ 1 ].uxLoopCounter = 0; xParameters[ 1 ].uxLoopCounter = 0;
/* Were the semaphores created? */ /* Were the semaphores created? */
if( ( xParameters[ 0 ].xSemaphore != NULL ) || ( xParameters[ 1 ].xSemaphore != NULL ) ) if( ( xParameters[ 0 ].xSemaphore != NULL ) || ( xParameters[ 1 ].xSemaphore != NULL ) )
{ {
/* vQueueAddToRegistry() adds the semaphore to the registry, if one is /* vQueueAddToRegistry() adds the semaphore to the registry, if one is
in use. The registry is provided as a means for kernel aware * in use. The registry is provided as a means for kernel aware
debuggers to locate semaphores and has no purpose if a kernel aware * debuggers to locate semaphores and has no purpose if a kernel aware
debugger is not being used. The call to vQueueAddToRegistry() will be * debugger is not being used. The call to vQueueAddToRegistry() will be
removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not * removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not
defined or is defined to be less than 1. */ * defined or is defined to be less than 1. */
vQueueAddToRegistry( ( QueueHandle_t ) xParameters[ 0 ].xSemaphore, "Counting_Sem_1" ); vQueueAddToRegistry( ( QueueHandle_t ) xParameters[ 0 ].xSemaphore, "Counting_Sem_1" );
vQueueAddToRegistry( ( QueueHandle_t ) xParameters[ 1 ].xSemaphore, "Counting_Sem_2" ); vQueueAddToRegistry( ( QueueHandle_t ) xParameters[ 1 ].xSemaphore, "Counting_Sem_2" );
/* Create the demo tasks, passing in the semaphore to use as the parameter. */ /* Create the demo tasks, passing in the semaphore to use as the parameter. */
xTaskCreate( prvCountingSemaphoreTask, "CNT1", configMINIMAL_STACK_SIZE, ( void * ) &( xParameters[ 0 ] ), tskIDLE_PRIORITY, NULL ); xTaskCreate( prvCountingSemaphoreTask, "CNT1", configMINIMAL_STACK_SIZE, ( void * ) &( xParameters[ 0 ] ), tskIDLE_PRIORITY, NULL );
xTaskCreate( prvCountingSemaphoreTask, "CNT2", configMINIMAL_STACK_SIZE, ( void * ) &( xParameters[ 1 ] ), tskIDLE_PRIORITY, NULL ); xTaskCreate( prvCountingSemaphoreTask, "CNT2", configMINIMAL_STACK_SIZE, ( void * ) &( xParameters[ 1 ] ), tskIDLE_PRIORITY, NULL );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvDecrementSemaphoreCount( SemaphoreHandle_t xSemaphore, volatile UBaseType_t *puxLoopCounter ) static void prvDecrementSemaphoreCount( SemaphoreHandle_t xSemaphore,
volatile UBaseType_t * puxLoopCounter )
{ {
UBaseType_t ux; UBaseType_t ux;
/* If the semaphore count is at its maximum then we should not be able to /* If the semaphore count is at its maximum then we should not be able to
'give' the semaphore. */ * 'give' the semaphore. */
if( xSemaphoreGive( xSemaphore ) == pdPASS ) if( xSemaphoreGive( xSemaphore ) == pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* We should be able to 'take' the semaphore countMAX_COUNT_VALUE times. */ /* We should be able to 'take' the semaphore countMAX_COUNT_VALUE times. */
for( ux = 0; ux < countMAX_COUNT_VALUE; ux++ ) for( ux = 0; ux < countMAX_COUNT_VALUE; ux++ )
{ {
configASSERT( uxSemaphoreGetCount( xSemaphore ) == ( countMAX_COUNT_VALUE - ux ) ); configASSERT( uxSemaphoreGetCount( xSemaphore ) == ( countMAX_COUNT_VALUE - ux ) );
if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) != pdPASS ) if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) != pdPASS )
{ {
/* We expected to be able to take the semaphore. */ /* We expected to be able to take the semaphore. */
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
( *puxLoopCounter )++; ( *puxLoopCounter )++;
} }
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
taskYIELD(); taskYIELD();
#endif #endif
/* If the semaphore count is zero then we should not be able to 'take' /* If the semaphore count is zero then we should not be able to 'take'
the semaphore. */ * the semaphore. */
configASSERT( uxSemaphoreGetCount( xSemaphore ) == 0 ); configASSERT( uxSemaphoreGetCount( xSemaphore ) == 0 );
if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) == pdPASS )
{ if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) == pdPASS )
xErrorDetected = pdTRUE; {
} xErrorDetected = pdTRUE;
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvIncrementSemaphoreCount( SemaphoreHandle_t xSemaphore, volatile UBaseType_t *puxLoopCounter ) static void prvIncrementSemaphoreCount( SemaphoreHandle_t xSemaphore,
volatile UBaseType_t * puxLoopCounter )
{ {
UBaseType_t ux; UBaseType_t ux;
/* If the semaphore count is zero then we should not be able to 'take' /* If the semaphore count is zero then we should not be able to 'take'
the semaphore. */ * the semaphore. */
if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) == pdPASS ) if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) == pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* We should be able to 'give' the semaphore countMAX_COUNT_VALUE times. */ /* We should be able to 'give' the semaphore countMAX_COUNT_VALUE times. */
for( ux = 0; ux < countMAX_COUNT_VALUE; ux++ ) for( ux = 0; ux < countMAX_COUNT_VALUE; ux++ )
{ {
configASSERT( uxSemaphoreGetCount( xSemaphore ) == ux ); configASSERT( uxSemaphoreGetCount( xSemaphore ) == ux );
if( xSemaphoreGive( xSemaphore ) != pdPASS ) if( xSemaphoreGive( xSemaphore ) != pdPASS )
{ {
/* We expected to be able to take the semaphore. */ /* We expected to be able to take the semaphore. */
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
( *puxLoopCounter )++; ( *puxLoopCounter )++;
} }
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
taskYIELD(); taskYIELD();
#endif #endif
/* If the semaphore count is at its maximum then we should not be able to /* If the semaphore count is at its maximum then we should not be able to
'give' the semaphore. */ * 'give' the semaphore. */
if( xSemaphoreGive( xSemaphore ) == pdPASS ) if( xSemaphoreGive( xSemaphore ) == pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvCountingSemaphoreTask( void *pvParameters ) static void prvCountingSemaphoreTask( void * pvParameters )
{ {
xCountSemStruct *pxParameter; xCountSemStruct * pxParameter;
#ifdef USE_STDIO #ifdef USE_STDIO
void vPrintDisplayMessage( const char * const * ppcMessageToSend ); void vPrintDisplayMessage( const char * const * ppcMessageToSend );
const char * const pcTaskStartMsg = "Counting semaphore demo started.\r\n"; const char * const pcTaskStartMsg = "Counting semaphore demo started.\r\n";
/* Queue a message for printing to say the task has started. */ /* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
#endif #endif
/* The semaphore to be used was passed as the parameter. */ /* The semaphore to be used was passed as the parameter. */
pxParameter = ( xCountSemStruct * ) pvParameters; pxParameter = ( xCountSemStruct * ) pvParameters;
/* Did we expect to find the semaphore already at its max count value, or /* Did we expect to find the semaphore already at its max count value, or
at zero? */ * at zero? */
if( pxParameter->uxExpectedStartCount == countSTART_AT_MAX_COUNT ) if( pxParameter->uxExpectedStartCount == countSTART_AT_MAX_COUNT )
{ {
prvDecrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) ); prvDecrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) );
} }
/* Now we expect the semaphore count to be 0, so this time there is an /* Now we expect the semaphore count to be 0, so this time there is an
error if we can take the semaphore. */ * error if we can take the semaphore. */
if( xSemaphoreTake( pxParameter->xSemaphore, 0 ) == pdPASS ) if( xSemaphoreTake( pxParameter->xSemaphore, 0 ) == pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
for( ;; ) for( ; ; )
{ {
prvIncrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) ); prvIncrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) );
prvDecrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) ); prvDecrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xAreCountingSemaphoreTasksStillRunning( void ) BaseType_t xAreCountingSemaphoreTasksStillRunning( void )
{ {
static UBaseType_t uxLastCount0 = 0, uxLastCount1 = 0; static UBaseType_t uxLastCount0 = 0, uxLastCount1 = 0;
BaseType_t xReturn = pdPASS; BaseType_t xReturn = pdPASS;
/* Return fail if any 'give' or 'take' did not result in the expected /* Return fail if any 'give' or 'take' did not result in the expected
behaviour. */ * behaviour. */
if( xErrorDetected != pdFALSE ) if( xErrorDetected != pdFALSE )
{ {
xReturn = pdFAIL; xReturn = pdFAIL;
} }
/* Return fail if either task is not still incrementing its loop counter. */ /* Return fail if either task is not still incrementing its loop counter. */
if( uxLastCount0 == xParameters[ 0 ].uxLoopCounter ) if( uxLastCount0 == xParameters[ 0 ].uxLoopCounter )
{ {
xReturn = pdFAIL; xReturn = pdFAIL;
} }
else else
{ {
uxLastCount0 = xParameters[ 0 ].uxLoopCounter; uxLastCount0 = xParameters[ 0 ].uxLoopCounter;
} }
if( uxLastCount1 == xParameters[ 1 ].uxLoopCounter ) if( uxLastCount1 == xParameters[ 1 ].uxLoopCounter )
{ {
xReturn = pdFAIL; xReturn = pdFAIL;
} }
else else
{ {
uxLastCount1 = xParameters[ 1 ].uxLoopCounter; uxLastCount1 = xParameters[ 1 ].uxLoopCounter;
} }
return xReturn; return xReturn;
} }

View file

@ -61,34 +61,36 @@
#include "crflash.h" #include "crflash.h"
/* The queue should only need to be of length 1. See the description at the /* The queue should only need to be of length 1. See the description at the
top of the file. */ * top of the file. */
#define crfQUEUE_LENGTH 1 #define crfQUEUE_LENGTH 1
#define crfFIXED_DELAY_PRIORITY 0 #define crfFIXED_DELAY_PRIORITY 0
#define crfFLASH_PRIORITY 1 #define crfFLASH_PRIORITY 1
/* Only one flash co-routine is created so the index is not significant. */ /* Only one flash co-routine is created so the index is not significant. */
#define crfFLASH_INDEX 0 #define crfFLASH_INDEX 0
/* Don't allow more than crfMAX_FLASH_TASKS 'fixed delay' co-routines to be /* Don't allow more than crfMAX_FLASH_TASKS 'fixed delay' co-routines to be
created. */ * created. */
#define crfMAX_FLASH_TASKS 8 #define crfMAX_FLASH_TASKS 8
/* We don't want to block when posting to the queue. */ /* We don't want to block when posting to the queue. */
#define crfPOSTING_BLOCK_TIME 0 #define crfPOSTING_BLOCK_TIME 0
/* /*
* The 'fixed delay' co-routine as described at the top of the file. * The 'fixed delay' co-routine as described at the top of the file.
*/ */
static void prvFixedDelayCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex ); static void prvFixedDelayCoRoutine( CoRoutineHandle_t xHandle,
UBaseType_t uxIndex );
/* /*
* The 'flash' co-routine as described at the top of the file. * The 'flash' co-routine as described at the top of the file.
*/ */
static void prvFlashCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex ); static void prvFlashCoRoutine( CoRoutineHandle_t xHandle,
UBaseType_t uxIndex );
/* The queue used to pass data between the 'fixed delay' co-routines and the /* The queue used to pass data between the 'fixed delay' co-routines and the
'flash' co-routine. */ * 'flash' co-routine. */
static QueueHandle_t xFlashQueue; static QueueHandle_t xFlashQueue;
/* This will be set to pdFALSE if we detect an error. */ /* This will be set to pdFALSE if we detect an error. */
@ -101,108 +103,113 @@ static BaseType_t xCoRoutineFlashStatus = pdPASS;
*/ */
void vStartFlashCoRoutines( UBaseType_t uxNumberToCreate ) void vStartFlashCoRoutines( UBaseType_t uxNumberToCreate )
{ {
UBaseType_t uxIndex; UBaseType_t uxIndex;
if( uxNumberToCreate > crfMAX_FLASH_TASKS ) if( uxNumberToCreate > crfMAX_FLASH_TASKS )
{ {
uxNumberToCreate = crfMAX_FLASH_TASKS; uxNumberToCreate = crfMAX_FLASH_TASKS;
} }
/* Create the queue used to pass data between the co-routines. */ /* Create the queue used to pass data between the co-routines. */
xFlashQueue = xQueueCreate( crfQUEUE_LENGTH, sizeof( UBaseType_t ) ); xFlashQueue = xQueueCreate( crfQUEUE_LENGTH, sizeof( UBaseType_t ) );
if( xFlashQueue ) if( xFlashQueue )
{ {
/* Create uxNumberToCreate 'fixed delay' co-routines. */ /* Create uxNumberToCreate 'fixed delay' co-routines. */
for( uxIndex = 0; uxIndex < uxNumberToCreate; uxIndex++ ) for( uxIndex = 0; uxIndex < uxNumberToCreate; uxIndex++ )
{ {
xCoRoutineCreate( prvFixedDelayCoRoutine, crfFIXED_DELAY_PRIORITY, uxIndex ); xCoRoutineCreate( prvFixedDelayCoRoutine, crfFIXED_DELAY_PRIORITY, uxIndex );
} }
/* Create the 'flash' co-routine. */ /* Create the 'flash' co-routine. */
xCoRoutineCreate( prvFlashCoRoutine, crfFLASH_PRIORITY, crfFLASH_INDEX ); xCoRoutineCreate( prvFlashCoRoutine, crfFLASH_PRIORITY, crfFLASH_INDEX );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvFixedDelayCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex ) static void prvFixedDelayCoRoutine( CoRoutineHandle_t xHandle,
UBaseType_t uxIndex )
{ {
/* Even though this is a co-routine the xResult variable does not need to be /* Even though this is a co-routine the xResult variable does not need to be
static as we do not need it to maintain its state between blocks. */ * static as we do not need it to maintain its state between blocks. */
BaseType_t xResult; BaseType_t xResult;
/* The uxIndex parameter of the co-routine function is used as an index into /* The uxIndex parameter of the co-routine function is used as an index into
the xFlashRates array to obtain the delay period to use. */ * the xFlashRates array to obtain the delay period to use. */
static const TickType_t xFlashRates[ crfMAX_FLASH_TASKS ] = { 150 / portTICK_PERIOD_MS, static const TickType_t xFlashRates[ crfMAX_FLASH_TASKS ] =
200 / portTICK_PERIOD_MS, {
250 / portTICK_PERIOD_MS, 150 / portTICK_PERIOD_MS,
300 / portTICK_PERIOD_MS, 200 / portTICK_PERIOD_MS,
350 / portTICK_PERIOD_MS, 250 / portTICK_PERIOD_MS,
400 / portTICK_PERIOD_MS, 300 / portTICK_PERIOD_MS,
450 / portTICK_PERIOD_MS, 350 / portTICK_PERIOD_MS,
500 / portTICK_PERIOD_MS }; 400 / portTICK_PERIOD_MS,
450 / portTICK_PERIOD_MS,
500 / portTICK_PERIOD_MS
};
/* Co-routines MUST start with a call to crSTART. */ /* Co-routines MUST start with a call to crSTART. */
crSTART( xHandle ); crSTART( xHandle );
for( ;; ) for( ; ; )
{ {
/* Post our uxIndex value onto the queue. This is used as the LED to /* Post our uxIndex value onto the queue. This is used as the LED to
flash. */ * flash. */
crQUEUE_SEND( xHandle, xFlashQueue, ( void * ) &uxIndex, crfPOSTING_BLOCK_TIME, &xResult ); crQUEUE_SEND( xHandle, xFlashQueue, ( void * ) &uxIndex, crfPOSTING_BLOCK_TIME, &xResult );
if( xResult != pdPASS ) if( xResult != pdPASS )
{ {
/* For the reasons stated at the top of the file we should always /* For the reasons stated at the top of the file we should always
find that we can post to the queue. If we could not then an error * find that we can post to the queue. If we could not then an error
has occurred. */ * has occurred. */
xCoRoutineFlashStatus = pdFAIL; xCoRoutineFlashStatus = pdFAIL;
} }
crDELAY( xHandle, xFlashRates[ uxIndex ] ); crDELAY( xHandle, xFlashRates[ uxIndex ] );
} }
/* Co-routines MUST end with a call to crEND. */ /* Co-routines MUST end with a call to crEND. */
crEND(); crEND();
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvFlashCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex ) static void prvFlashCoRoutine( CoRoutineHandle_t xHandle,
UBaseType_t uxIndex )
{ {
/* Even though this is a co-routine the variable do not need to be /* Even though this is a co-routine the variable do not need to be
static as we do not need it to maintain their state between blocks. */ * static as we do not need it to maintain their state between blocks. */
BaseType_t xResult; BaseType_t xResult;
UBaseType_t uxLEDToFlash; UBaseType_t uxLEDToFlash;
/* Co-routines MUST start with a call to crSTART. */ /* Co-routines MUST start with a call to crSTART. */
crSTART( xHandle ); crSTART( xHandle );
( void ) uxIndex; ( void ) uxIndex;
for( ;; ) for( ; ; )
{ {
/* Block to wait for the number of the LED to flash. */ /* Block to wait for the number of the LED to flash. */
crQUEUE_RECEIVE( xHandle, xFlashQueue, &uxLEDToFlash, portMAX_DELAY, &xResult ); crQUEUE_RECEIVE( xHandle, xFlashQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
if( xResult != pdPASS ) if( xResult != pdPASS )
{ {
/* We would not expect to wake unless we received something. */ /* We would not expect to wake unless we received something. */
xCoRoutineFlashStatus = pdFAIL; xCoRoutineFlashStatus = pdFAIL;
} }
else else
{ {
/* We received the number of an LED to flash - flash it! */ /* We received the number of an LED to flash - flash it! */
vParTestToggleLED( uxLEDToFlash ); vParTestToggleLED( uxLEDToFlash );
} }
} }
/* Co-routines MUST end with a call to crEND. */ /* Co-routines MUST end with a call to crEND. */
crEND(); crEND();
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xAreFlashCoRoutinesStillRunning( void ) BaseType_t xAreFlashCoRoutinesStillRunning( void )
{ {
/* Return pdPASS or pdFAIL depending on whether an error has been detected /* Return pdPASS or pdFAIL depending on whether an error has been detected
or not. */ * or not. */
return xCoRoutineFlashStatus; return xCoRoutineFlashStatus;
} }

View file

@ -57,27 +57,28 @@
#include "crhook.h" #include "crhook.h"
/* The number of 'hook' co-routines that are to be created. */ /* The number of 'hook' co-routines that are to be created. */
#define hookNUM_HOOK_CO_ROUTINES ( 4 ) #define hookNUM_HOOK_CO_ROUTINES ( 4 )
/* The number of times the tick hook should be called before a character is /* The number of times the tick hook should be called before a character is
posted to the 'hook' co-routines. */ * posted to the 'hook' co-routines. */
#define hookTICK_CALLS_BEFORE_POST ( 500 ) #define hookTICK_CALLS_BEFORE_POST ( 500 )
/* There should never be more than one item in any queue at any time. */ /* There should never be more than one item in any queue at any time. */
#define hookHOOK_QUEUE_LENGTH ( 1 ) #define hookHOOK_QUEUE_LENGTH ( 1 )
/* Don't block when initially posting to the queue. */ /* Don't block when initially posting to the queue. */
#define hookNO_BLOCK_TIME ( 0 ) #define hookNO_BLOCK_TIME ( 0 )
/* The priority relative to other co-routines (rather than tasks) that the /* The priority relative to other co-routines (rather than tasks) that the
'hook' co-routines should take. */ * 'hook' co-routines should take. */
#define mainHOOK_CR_PRIORITY ( 1 ) #define mainHOOK_CR_PRIORITY ( 1 )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* /*
* The co-routine function itself. * The co-routine function itself.
*/ */
static void prvHookCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex ); static void prvHookCoRoutine( CoRoutineHandle_t xHandle,
UBaseType_t uxIndex );
/* /*
@ -90,13 +91,13 @@ void vApplicationTickHook( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Queues used to send data FROM a co-routine TO the tick hook function. /* Queues used to send data FROM a co-routine TO the tick hook function.
The hook functions received (Rx's) on these queues. One queue per * The hook functions received (Rx's) on these queues. One queue per
'hook' co-routine. */ * 'hook' co-routine. */
static QueueHandle_t xHookRxQueues[ hookNUM_HOOK_CO_ROUTINES ]; static QueueHandle_t xHookRxQueues[ hookNUM_HOOK_CO_ROUTINES ];
/* Queues used to send data FROM the tick hook TO a co-routine function. /* Queues used to send data FROM the tick hook TO a co-routine function.
The hood function transmits (Tx's) on these queues. One queue per * The hood function transmits (Tx's) on these queues. One queue per
'hook' co-routine. */ * 'hook' co-routine. */
static QueueHandle_t xHookTxQueues[ hookNUM_HOOK_CO_ROUTINES ]; static QueueHandle_t xHookTxQueues[ hookNUM_HOOK_CO_ROUTINES ];
/* Set to true if an error is detected at any time. */ /* Set to true if an error is detected at any time. */
@ -106,127 +107,128 @@ static BaseType_t xCoRoutineErrorDetected = pdFALSE;
void vStartHookCoRoutines( void ) void vStartHookCoRoutines( void )
{ {
UBaseType_t uxIndex, uxValueToPost = 0; UBaseType_t uxIndex, uxValueToPost = 0;
for( uxIndex = 0; uxIndex < hookNUM_HOOK_CO_ROUTINES; uxIndex++ ) for( uxIndex = 0; uxIndex < hookNUM_HOOK_CO_ROUTINES; uxIndex++ )
{ {
/* Create a queue to transmit to and receive from each 'hook' /* Create a queue to transmit to and receive from each 'hook'
co-routine. */ * co-routine. */
xHookRxQueues[ uxIndex ] = xQueueCreate( hookHOOK_QUEUE_LENGTH, sizeof( UBaseType_t ) ); xHookRxQueues[ uxIndex ] = xQueueCreate( hookHOOK_QUEUE_LENGTH, sizeof( UBaseType_t ) );
xHookTxQueues[ uxIndex ] = xQueueCreate( hookHOOK_QUEUE_LENGTH, sizeof( UBaseType_t ) ); xHookTxQueues[ uxIndex ] = xQueueCreate( hookHOOK_QUEUE_LENGTH, sizeof( UBaseType_t ) );
/* To start things off the tick hook function expects the queue it /* To start things off the tick hook function expects the queue it
uses to receive data to contain a value. */ * uses to receive data to contain a value. */
xQueueSend( xHookRxQueues[ uxIndex ], &uxValueToPost, hookNO_BLOCK_TIME ); xQueueSend( xHookRxQueues[ uxIndex ], &uxValueToPost, hookNO_BLOCK_TIME );
/* Create the 'hook' co-routine itself. */ /* Create the 'hook' co-routine itself. */
xCoRoutineCreate( prvHookCoRoutine, mainHOOK_CR_PRIORITY, uxIndex ); xCoRoutineCreate( prvHookCoRoutine, mainHOOK_CR_PRIORITY, uxIndex );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static UBaseType_t uxCallCounter = 0, uxNumberToPost = 0; static UBaseType_t uxCallCounter = 0, uxNumberToPost = 0;
void vApplicationTickHook( void ) void vApplicationTickHook( void )
{ {
UBaseType_t uxReceivedNumber; UBaseType_t uxReceivedNumber;
BaseType_t xIndex, xCoRoutineWoken; BaseType_t xIndex, xCoRoutineWoken;
/* Is it time to talk to the 'hook' co-routines again? */ /* Is it time to talk to the 'hook' co-routines again? */
uxCallCounter++; uxCallCounter++;
if( uxCallCounter >= hookTICK_CALLS_BEFORE_POST )
{
uxCallCounter = 0;
for( xIndex = 0; xIndex < hookNUM_HOOK_CO_ROUTINES; xIndex++ ) if( uxCallCounter >= hookTICK_CALLS_BEFORE_POST )
{ {
xCoRoutineWoken = pdFALSE; uxCallCounter = 0;
if( crQUEUE_RECEIVE_FROM_ISR( xHookRxQueues[ xIndex ], &uxReceivedNumber, &xCoRoutineWoken ) != pdPASS )
{
/* There is no reason why we would not expect the queue to
contain a value. */
xCoRoutineErrorDetected = pdTRUE;
}
else
{
/* Each queue used to receive data from the 'hook' co-routines
should contain the number we last posted to the same co-routine. */
if( uxReceivedNumber != uxNumberToPost )
{
xCoRoutineErrorDetected = pdTRUE;
}
/* Nothing should be blocked waiting to post to the queue. */ for( xIndex = 0; xIndex < hookNUM_HOOK_CO_ROUTINES; xIndex++ )
if( xCoRoutineWoken != pdFALSE ) {
{ xCoRoutineWoken = pdFALSE;
xCoRoutineErrorDetected = pdTRUE;
}
}
}
/* Start the next cycle by posting the next number onto each Tx queue. */ if( crQUEUE_RECEIVE_FROM_ISR( xHookRxQueues[ xIndex ], &uxReceivedNumber, &xCoRoutineWoken ) != pdPASS )
uxNumberToPost++; {
/* There is no reason why we would not expect the queue to
* contain a value. */
xCoRoutineErrorDetected = pdTRUE;
}
else
{
/* Each queue used to receive data from the 'hook' co-routines
* should contain the number we last posted to the same co-routine. */
if( uxReceivedNumber != uxNumberToPost )
{
xCoRoutineErrorDetected = pdTRUE;
}
for( xIndex = 0; xIndex < hookNUM_HOOK_CO_ROUTINES; xIndex++ ) /* Nothing should be blocked waiting to post to the queue. */
{ if( xCoRoutineWoken != pdFALSE )
if( crQUEUE_SEND_FROM_ISR( xHookTxQueues[ xIndex ], &uxNumberToPost, pdFALSE ) != pdTRUE ) {
{ xCoRoutineErrorDetected = pdTRUE;
/* Posting to the queue should have woken the co-routine that }
was blocked on the queue. */ }
xCoRoutineErrorDetected = pdTRUE; }
}
} /* Start the next cycle by posting the next number onto each Tx queue. */
} uxNumberToPost++;
for( xIndex = 0; xIndex < hookNUM_HOOK_CO_ROUTINES; xIndex++ )
{
if( crQUEUE_SEND_FROM_ISR( xHookTxQueues[ xIndex ], &uxNumberToPost, pdFALSE ) != pdTRUE )
{
/* Posting to the queue should have woken the co-routine that
* was blocked on the queue. */
xCoRoutineErrorDetected = pdTRUE;
}
}
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvHookCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex ) static void prvHookCoRoutine( CoRoutineHandle_t xHandle,
UBaseType_t uxIndex )
{ {
static UBaseType_t uxReceivedValue[ hookNUM_HOOK_CO_ROUTINES ]; static UBaseType_t uxReceivedValue[ hookNUM_HOOK_CO_ROUTINES ];
BaseType_t xResult; BaseType_t xResult;
/* Each co-routine MUST start with a call to crSTART(); */ /* Each co-routine MUST start with a call to crSTART(); */
crSTART( xHandle ); crSTART( xHandle );
for( ;; ) for( ; ; )
{ {
/* Wait to receive a value from the tick hook. */ /* Wait to receive a value from the tick hook. */
xResult = pdFAIL; xResult = pdFAIL;
crQUEUE_RECEIVE( xHandle, xHookTxQueues[ uxIndex ], &( uxReceivedValue[ uxIndex ] ), portMAX_DELAY, &xResult ); crQUEUE_RECEIVE( xHandle, xHookTxQueues[ uxIndex ], &( uxReceivedValue[ uxIndex ] ), portMAX_DELAY, &xResult );
/* There is no reason why we should not have received something on /* There is no reason why we should not have received something on
the queue. */ * the queue. */
if( xResult != pdPASS ) if( xResult != pdPASS )
{ {
xCoRoutineErrorDetected = pdTRUE; xCoRoutineErrorDetected = pdTRUE;
} }
/* Send the same number back to the idle hook so it can verify it. */ /* Send the same number back to the idle hook so it can verify it. */
xResult = pdFAIL; xResult = pdFAIL;
crQUEUE_SEND( xHandle, xHookRxQueues[ uxIndex ], &( uxReceivedValue[ uxIndex ] ), hookNO_BLOCK_TIME, &xResult ); crQUEUE_SEND( xHandle, xHookRxQueues[ uxIndex ], &( uxReceivedValue[ uxIndex ] ), hookNO_BLOCK_TIME, &xResult );
if( xResult != pdPASS )
{
/* There is no reason why we should not have been able to post to
the queue. */
xCoRoutineErrorDetected = pdTRUE;
}
}
/* Each co-routine MUST end with a call to crEND(). */ if( xResult != pdPASS )
crEND(); {
/* There is no reason why we should not have been able to post to
* the queue. */
xCoRoutineErrorDetected = pdTRUE;
}
}
/* Each co-routine MUST end with a call to crEND(). */
crEND();
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xAreHookCoRoutinesStillRunning( void ) BaseType_t xAreHookCoRoutinesStillRunning( void )
{ {
if( xCoRoutineErrorDetected ) if( xCoRoutineErrorDetected )
{ {
return pdFALSE; return pdFALSE;
} }
else else
{ {
return pdTRUE; return pdTRUE;
} }
} }

View file

@ -54,150 +54,148 @@
/* Demo program include files. */ /* Demo program include files. */
#include "death.h" #include "death.h"
#define deathSTACK_SIZE ( configMINIMAL_STACK_SIZE + 60 ) #define deathSTACK_SIZE ( configMINIMAL_STACK_SIZE + 60 )
/* The task originally created which is responsible for periodically dynamically /* The task originally created which is responsible for periodically dynamically
creating another four tasks. */ * creating another four tasks. */
static portTASK_FUNCTION_PROTO( vCreateTasks, pvParameters ); static portTASK_FUNCTION_PROTO( vCreateTasks, pvParameters );
/* The task function of the dynamically created tasks. */ /* The task function of the dynamically created tasks. */
static portTASK_FUNCTION_PROTO( vSuicidalTask, pvParameters ); static portTASK_FUNCTION_PROTO( vSuicidalTask, pvParameters );
/* A variable which is incremented every time the dynamic tasks are created. This /* A variable which is incremented every time the dynamic tasks are created. This
is used to check that the task is still running. */ * is used to check that the task is still running. */
static volatile uint16_t usCreationCount = 0; static volatile uint16_t usCreationCount = 0;
/* Used to store the number of tasks that were originally running so the creator /* Used to store the number of tasks that were originally running so the creator
task can tell if any of the suicidal tasks have failed to die. * task can tell if any of the suicidal tasks have failed to die.
*/ */
static volatile UBaseType_t uxTasksRunningAtStart = 0; static volatile UBaseType_t uxTasksRunningAtStart = 0;
/* When a task deletes itself, it stack and TCB are cleaned up by the Idle task. /* When a task deletes itself, it stack and TCB are cleaned up by the Idle task.
Under heavy load the idle task might not get much processing time, so it would * Under heavy load the idle task might not get much processing time, so it would
be legitimate for several tasks to remain undeleted for a short period. There * be legitimate for several tasks to remain undeleted for a short period. There
may also be a few other unexpected tasks if, for example, the tasks that test * may also be a few other unexpected tasks if, for example, the tasks that test
static allocation are also being used. */ * static allocation are also being used. */
static const UBaseType_t uxMaxNumberOfExtraTasksRunning = 3; static const UBaseType_t uxMaxNumberOfExtraTasksRunning = 3;
/* Used to store a handle to the task that should be killed by a suicidal task, /* Used to store a handle to the task that should be killed by a suicidal task,
before it kills itself. */ * before it kills itself. */
TaskHandle_t xCreatedTask; TaskHandle_t xCreatedTask;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vCreateSuicidalTasks( UBaseType_t uxPriority ) void vCreateSuicidalTasks( UBaseType_t uxPriority )
{ {
xTaskCreate( vCreateTasks, "CREATOR", deathSTACK_SIZE, ( void * ) NULL, uxPriority, NULL ); xTaskCreate( vCreateTasks, "CREATOR", deathSTACK_SIZE, ( void * ) NULL, uxPriority, NULL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static portTASK_FUNCTION( vSuicidalTask, pvParameters ) static portTASK_FUNCTION( vSuicidalTask, pvParameters )
{ {
volatile long l1, l2; volatile long l1, l2;
TaskHandle_t xTaskToKill; TaskHandle_t xTaskToKill;
const TickType_t xDelay = pdMS_TO_TICKS( ( TickType_t ) 200 ); const TickType_t xDelay = pdMS_TO_TICKS( ( TickType_t ) 200 );
/* Test deletion of a task's secure context, if any. */ /* Test deletion of a task's secure context, if any. */
portALLOCATE_SECURE_CONTEXT( configMINIMAL_SECURE_STACK_SIZE ); portALLOCATE_SECURE_CONTEXT( configMINIMAL_SECURE_STACK_SIZE );
if( pvParameters != NULL ) if( pvParameters != NULL )
{ {
/* This task is periodically created four times. Two created tasks are /* This task is periodically created four times. Two created tasks are
passed a handle to the other task so it can kill it before killing itself. * passed a handle to the other task so it can kill it before killing itself.
The other task is passed in null. */ * The other task is passed in null. */
xTaskToKill = *( TaskHandle_t* )pvParameters; xTaskToKill = *( TaskHandle_t * ) pvParameters;
} }
else else
{ {
xTaskToKill = NULL; xTaskToKill = NULL;
} }
for( ;; ) for( ; ; )
{ {
/* Do something random just to use some stack and registers. */ /* Do something random just to use some stack and registers. */
l1 = 2; l1 = 2;
l2 = 89; l2 = 89;
l2 *= l1; l2 *= l1;
vTaskDelay( xDelay ); vTaskDelay( xDelay );
if( xTaskToKill != NULL ) if( xTaskToKill != NULL )
{ {
/* Make sure the other task has a go before we delete it. */ /* Make sure the other task has a go before we delete it. */
vTaskDelay( ( TickType_t ) 0 ); vTaskDelay( ( TickType_t ) 0 );
/* Kill the other task that was created by vCreateTasks(). */ /* Kill the other task that was created by vCreateTasks(). */
vTaskDelete( xTaskToKill ); vTaskDelete( xTaskToKill );
/* Kill ourselves. */ /* Kill ourselves. */
vTaskDelete( NULL ); vTaskDelete( NULL );
} }
} }
}/*lint !e818 !e550 Function prototype must be as per standard for task functions. */ } /*lint !e818 !e550 Function prototype must be as per standard for task functions. */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static portTASK_FUNCTION( vCreateTasks, pvParameters ) static portTASK_FUNCTION( vCreateTasks, pvParameters )
{ {
const TickType_t xDelay = pdMS_TO_TICKS( ( TickType_t ) 1000 ); const TickType_t xDelay = pdMS_TO_TICKS( ( TickType_t ) 1000 );
UBaseType_t uxPriority; UBaseType_t uxPriority;
/* Remove compiler warning about unused parameter. */ /* Remove compiler warning about unused parameter. */
( void ) pvParameters; ( void ) pvParameters;
/* Delay at the start to ensure tasks created by other demos have been /* Delay at the start to ensure tasks created by other demos have been
created before storing the current number of tasks. */ * created before storing the current number of tasks. */
vTaskDelay( xDelay ); vTaskDelay( xDelay );
uxTasksRunningAtStart = ( UBaseType_t ) uxTaskGetNumberOfTasks(); uxTasksRunningAtStart = ( UBaseType_t ) uxTaskGetNumberOfTasks();
uxPriority = uxTaskPriorityGet( NULL ); uxPriority = uxTaskPriorityGet( NULL );
for( ;; ) for( ; ; )
{ {
/* Just loop round, delaying then creating the four suicidal tasks. */ /* Just loop round, delaying then creating the four suicidal tasks. */
vTaskDelay( xDelay ); vTaskDelay( xDelay );
xCreatedTask = NULL; xCreatedTask = NULL;
xTaskCreate( vSuicidalTask, "SUICID1", configMINIMAL_STACK_SIZE, NULL, uxPriority, &xCreatedTask ); xTaskCreate( vSuicidalTask, "SUICID1", configMINIMAL_STACK_SIZE, NULL, uxPriority, &xCreatedTask );
xTaskCreate( vSuicidalTask, "SUICID2", configMINIMAL_STACK_SIZE, &xCreatedTask, uxPriority, NULL ); xTaskCreate( vSuicidalTask, "SUICID2", configMINIMAL_STACK_SIZE, &xCreatedTask, uxPriority, NULL );
++usCreationCount; ++usCreationCount;
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* This is called to check that the creator task is still running and that there /* This is called to check that the creator task is still running and that there
are not any more than four extra tasks. */ * are not any more than four extra tasks. */
BaseType_t xIsCreateTaskStillRunning( void ) BaseType_t xIsCreateTaskStillRunning( void )
{ {
static uint16_t usLastCreationCount = 0xfff; static uint16_t usLastCreationCount = 0xfff;
BaseType_t xReturn = pdTRUE; BaseType_t xReturn = pdTRUE;
static UBaseType_t uxTasksRunningNow; static UBaseType_t uxTasksRunningNow;
if( usLastCreationCount == usCreationCount ) if( usLastCreationCount == usCreationCount )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
} }
else else
{ {
usLastCreationCount = usCreationCount; usLastCreationCount = usCreationCount;
} }
uxTasksRunningNow = ( UBaseType_t ) uxTaskGetNumberOfTasks(); uxTasksRunningNow = ( UBaseType_t ) uxTaskGetNumberOfTasks();
if( uxTasksRunningNow < uxTasksRunningAtStart ) if( uxTasksRunningNow < uxTasksRunningAtStart )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
} }
else if( ( uxTasksRunningNow - uxTasksRunningAtStart ) > uxMaxNumberOfExtraTasksRunning ) else if( ( uxTasksRunningNow - uxTasksRunningAtStart ) > uxMaxNumberOfExtraTasksRunning )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
} }
else else
{ {
/* Everything is okay. */ /* Everything is okay. */
} }
return xReturn; return xReturn;
} }

View file

@ -106,29 +106,29 @@ static portTASK_FUNCTION_PROTO( vQueueSendWhenSuspendedTask, pvParameters );
/* Demo task specific constants. */ /* Demo task specific constants. */
#ifndef priSUSPENDED_RX_TASK_STACK_SIZE #ifndef priSUSPENDED_RX_TASK_STACK_SIZE
#define priSUSPENDED_RX_TASK_STACK_SIZE ( configMINIMAL_STACK_SIZE ) #define priSUSPENDED_RX_TASK_STACK_SIZE ( configMINIMAL_STACK_SIZE )
#endif #endif
#define priSTACK_SIZE ( configMINIMAL_STACK_SIZE ) #define priSTACK_SIZE ( configMINIMAL_STACK_SIZE )
#define priSLEEP_TIME pdMS_TO_TICKS( 128 ) #define priSLEEP_TIME pdMS_TO_TICKS( 128 )
#define priLOOPS ( 5 ) #define priLOOPS ( 5 )
#define priMAX_COUNT ( ( uint32_t ) 0xff ) #define priMAX_COUNT ( ( uint32_t ) 0xff )
#define priNO_BLOCK ( ( TickType_t ) 0 ) #define priNO_BLOCK ( ( TickType_t ) 0 )
#define priSUSPENDED_QUEUE_LENGTH ( 1 ) #define priSUSPENDED_QUEUE_LENGTH ( 1 )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Handles to the two counter tasks. These could be passed in as parameters /* Handles to the two counter tasks. These could be passed in as parameters
to the controller task to prevent them having to be file scope. */ * to the controller task to prevent them having to be file scope. */
static TaskHandle_t xContinuousIncrementHandle, xLimitedIncrementHandle; static TaskHandle_t xContinuousIncrementHandle, xLimitedIncrementHandle;
/* The shared counter variable. This is passed in as a parameter to the two /* The shared counter variable. This is passed in as a parameter to the two
counter variables for demonstration purposes. */ * counter variables for demonstration purposes. */
static uint32_t ulCounter; static uint32_t ulCounter;
/* Variables used to check that the tasks are still operating without error. /* Variables used to check that the tasks are still operating without error.
Each complete iteration of the controller task increments this variable * Each complete iteration of the controller task increments this variable
provided no errors have been found. The variable maintaining the same value * provided no errors have been found. The variable maintaining the same value
is therefore indication of an error. */ * is therefore indication of an error. */
static volatile uint16_t usCheckVariable = ( uint16_t ) 0; static volatile uint16_t usCheckVariable = ( uint16_t ) 0;
static volatile BaseType_t xSuspendedQueueSendError = pdFALSE; static volatile BaseType_t xSuspendedQueueSendError = pdFALSE;
static volatile BaseType_t xSuspendedQueueReceiveError = pdFALSE; static volatile BaseType_t xSuspendedQueueReceiveError = pdFALSE;
@ -137,35 +137,36 @@ static volatile BaseType_t xSuspendedQueueReceiveError = pdFALSE;
QueueHandle_t xSuspendedTestQueue; QueueHandle_t xSuspendedTestQueue;
/* The value the queue receive task expects to receive next. This is file /* The value the queue receive task expects to receive next. This is file
scope so xAreDynamicPriorityTasksStillRunning() can ensure it is still * scope so xAreDynamicPriorityTasksStillRunning() can ensure it is still
incrementing. */ * incrementing. */
static uint32_t ulExpectedValue = ( uint32_t ) 0; static uint32_t ulExpectedValue = ( uint32_t ) 0;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* /*
* Start the three tasks as described at the top of the file. * Start the three tasks as described at the top of the file.
* Note that the limited count task is given a higher priority. * Note that the limited count task is given a higher priority.
*/ */
void vStartDynamicPriorityTasks( void ) void vStartDynamicPriorityTasks( void )
{ {
xSuspendedTestQueue = xQueueCreate( priSUSPENDED_QUEUE_LENGTH, sizeof( uint32_t ) ); xSuspendedTestQueue = xQueueCreate( priSUSPENDED_QUEUE_LENGTH, sizeof( uint32_t ) );
if( xSuspendedTestQueue != NULL ) if( xSuspendedTestQueue != NULL )
{ {
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
in use. The queue registry is provided as a means for kernel aware * in use. The queue registry is provided as a means for kernel aware
debuggers to locate queues and has no purpose if a kernel aware debugger * debuggers to locate queues and has no purpose if a kernel aware debugger
is not being used. The call to vQueueAddToRegistry() will be removed * is not being used. The call to vQueueAddToRegistry() will be removed
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is * by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
defined to be less than 1. */ * defined to be less than 1. */
vQueueAddToRegistry( xSuspendedTestQueue, "Suspended_Test_Queue" ); vQueueAddToRegistry( xSuspendedTestQueue, "Suspended_Test_Queue" );
xTaskCreate( vContinuousIncrementTask, "CNT_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY, &xContinuousIncrementHandle ); xTaskCreate( vContinuousIncrementTask, "CNT_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY, &xContinuousIncrementHandle );
xTaskCreate( vLimitedIncrementTask, "LIM_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY + 1, &xLimitedIncrementHandle ); xTaskCreate( vLimitedIncrementTask, "LIM_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY + 1, &xLimitedIncrementHandle );
xTaskCreate( vCounterControlTask, "C_CTRL", priSUSPENDED_RX_TASK_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); xTaskCreate( vCounterControlTask, "C_CTRL", priSUSPENDED_RX_TASK_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
xTaskCreate( vQueueSendWhenSuspendedTask, "SUSP_TX", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); xTaskCreate( vQueueSendWhenSuspendedTask, "SUSP_TX", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
xTaskCreate( vQueueReceiveWhenSuspendedTask, "SUSP_RX", priSUSPENDED_RX_TASK_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); xTaskCreate( vQueueReceiveWhenSuspendedTask, "SUSP_RX", priSUSPENDED_RX_TASK_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -175,26 +176,26 @@ void vStartDynamicPriorityTasks( void )
*/ */
static portTASK_FUNCTION( vLimitedIncrementTask, pvParameters ) static portTASK_FUNCTION( vLimitedIncrementTask, pvParameters )
{ {
volatile uint32_t *pulCounter; volatile uint32_t * pulCounter;
/* Take a pointer to the shared variable from the parameters passed into /* Take a pointer to the shared variable from the parameters passed into
the task. */ * the task. */
pulCounter = ( volatile uint32_t * ) pvParameters; pulCounter = ( volatile uint32_t * ) pvParameters;
/* This will run before the control task, so the first thing it does is /* This will run before the control task, so the first thing it does is
suspend - the control task will resume it when ready. */ * suspend - the control task will resume it when ready. */
vTaskSuspend( NULL ); vTaskSuspend( NULL );
for( ;; ) for( ; ; )
{ {
/* Just count up to a value then suspend. */ /* Just count up to a value then suspend. */
( *pulCounter )++; ( *pulCounter )++;
if( *pulCounter >= priMAX_COUNT ) if( *pulCounter >= priMAX_COUNT )
{ {
vTaskSuspend( NULL ); vTaskSuspend( NULL );
} }
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -204,34 +205,34 @@ volatile uint32_t *pulCounter;
*/ */
static portTASK_FUNCTION( vContinuousIncrementTask, pvParameters ) static portTASK_FUNCTION( vContinuousIncrementTask, pvParameters )
{ {
volatile uint32_t *pulCounter; volatile uint32_t * pulCounter;
UBaseType_t uxOurPriority; UBaseType_t uxOurPriority;
/* Take a pointer to the shared variable from the parameters passed into /* Take a pointer to the shared variable from the parameters passed into
the task. */ * the task. */
pulCounter = ( volatile uint32_t * ) pvParameters; pulCounter = ( volatile uint32_t * ) pvParameters;
/* Query our priority so we can raise it when exclusive access to the /* Query our priority so we can raise it when exclusive access to the
shared variable is required. */ * shared variable is required. */
uxOurPriority = uxTaskPriorityGet( NULL ); uxOurPriority = uxTaskPriorityGet( NULL );
for( ;; ) for( ; ; )
{ {
/* Raise the priority above the controller task to ensure a context /* Raise the priority above the controller task to ensure a context
switch does not occur while the variable is being accessed. */ * switch does not occur while the variable is being accessed. */
vTaskPrioritySet( NULL, uxOurPriority + 1 ); vTaskPrioritySet( NULL, uxOurPriority + 1 );
{ {
configASSERT( ( uxTaskPriorityGet( NULL ) == ( uxOurPriority + 1 ) ) ); configASSERT( ( uxTaskPriorityGet( NULL ) == ( uxOurPriority + 1 ) ) );
( *pulCounter )++; ( *pulCounter )++;
} }
vTaskPrioritySet( NULL, uxOurPriority ); vTaskPrioritySet( NULL, uxOurPriority );
#if( configUSE_PREEMPTION == 0 ) #if ( configUSE_PREEMPTION == 0 )
taskYIELD(); taskYIELD();
#endif #endif
configASSERT( ( uxTaskPriorityGet( NULL ) == uxOurPriority ) ); configASSERT( ( uxTaskPriorityGet( NULL ) == uxOurPriority ) );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -240,200 +241,200 @@ UBaseType_t uxOurPriority;
*/ */
static portTASK_FUNCTION( vCounterControlTask, pvParameters ) static portTASK_FUNCTION( vCounterControlTask, pvParameters )
{ {
uint32_t ulLastCounter; uint32_t ulLastCounter;
short sLoops; short sLoops;
short sError = pdFALSE; short sError = pdFALSE;
/* Just to stop warning messages. */ /* Just to stop warning messages. */
( void ) pvParameters; ( void ) pvParameters;
for( ;; ) for( ; ; )
{ {
/* Start with the counter at zero. */ /* Start with the counter at zero. */
ulCounter = ( uint32_t ) 0; ulCounter = ( uint32_t ) 0;
/* First section : */ /* First section : */
/* Check the continuous count task is running. */ /* Check the continuous count task is running. */
for( sLoops = 0; sLoops < priLOOPS; sLoops++ ) for( sLoops = 0; sLoops < priLOOPS; sLoops++ )
{ {
/* Suspend the continuous count task so we can take a mirror of the /* Suspend the continuous count task so we can take a mirror of the
shared variable without risk of corruption. This is not really * shared variable without risk of corruption. This is not really
needed as the other task raises its priority above this task's * needed as the other task raises its priority above this task's
priority. */ * priority. */
vTaskSuspend( xContinuousIncrementHandle ); vTaskSuspend( xContinuousIncrementHandle );
{ {
#if( INCLUDE_eTaskGetState == 1 ) #if ( INCLUDE_eTaskGetState == 1 )
{ {
configASSERT( eTaskGetState( xContinuousIncrementHandle ) == eSuspended ); configASSERT( eTaskGetState( xContinuousIncrementHandle ) == eSuspended );
} }
#endif /* INCLUDE_eTaskGetState */ #endif /* INCLUDE_eTaskGetState */
ulLastCounter = ulCounter; ulLastCounter = ulCounter;
} }
vTaskResume( xContinuousIncrementHandle ); vTaskResume( xContinuousIncrementHandle );
#if( configUSE_PREEMPTION == 0 ) #if ( configUSE_PREEMPTION == 0 )
taskYIELD(); taskYIELD();
#endif #endif
#if( INCLUDE_eTaskGetState == 1 ) #if ( INCLUDE_eTaskGetState == 1 )
{ {
configASSERT( eTaskGetState( xContinuousIncrementHandle ) == eReady ); configASSERT( eTaskGetState( xContinuousIncrementHandle ) == eReady );
} }
#endif /* INCLUDE_eTaskGetState */ #endif /* INCLUDE_eTaskGetState */
/* Now delay to ensure the other task has processor time. */ /* Now delay to ensure the other task has processor time. */
vTaskDelay( priSLEEP_TIME ); vTaskDelay( priSLEEP_TIME );
/* Check the shared variable again. This time to ensure mutual /* Check the shared variable again. This time to ensure mutual
exclusion the whole scheduler will be locked. This is just for * exclusion the whole scheduler will be locked. This is just for
demo purposes! */ * demo purposes! */
vTaskSuspendAll(); vTaskSuspendAll();
{ {
if( ulLastCounter == ulCounter ) if( ulLastCounter == ulCounter )
{ {
/* The shared variable has not changed. There is a problem /* The shared variable has not changed. There is a problem
with the continuous count task so flag an error. */ * with the continuous count task so flag an error. */
sError = pdTRUE; sError = pdTRUE;
} }
} }
xTaskResumeAll(); xTaskResumeAll();
} }
/* Second section: */ /* Second section: */
/* Suspend the continuous counter task so it stops accessing the shared /* Suspend the continuous counter task so it stops accessing the shared
variable. */ * variable. */
vTaskSuspend( xContinuousIncrementHandle ); vTaskSuspend( xContinuousIncrementHandle );
/* Reset the variable. */ /* Reset the variable. */
ulCounter = ( uint32_t ) 0; ulCounter = ( uint32_t ) 0;
#if( INCLUDE_eTaskGetState == 1 ) #if ( INCLUDE_eTaskGetState == 1 )
{ {
configASSERT( eTaskGetState( xLimitedIncrementHandle ) == eSuspended ); configASSERT( eTaskGetState( xLimitedIncrementHandle ) == eSuspended );
} }
#endif /* INCLUDE_eTaskGetState */ #endif /* INCLUDE_eTaskGetState */
/* Resume the limited count task which has a higher priority than us. /* Resume the limited count task which has a higher priority than us.
We should therefore not return from this call until the limited count * We should therefore not return from this call until the limited count
task has suspended itself with a known value in the counter variable. */ * task has suspended itself with a known value in the counter variable. */
vTaskResume( xLimitedIncrementHandle ); vTaskResume( xLimitedIncrementHandle );
#if( configUSE_PREEMPTION == 0 ) #if ( configUSE_PREEMPTION == 0 )
taskYIELD(); taskYIELD();
#endif #endif
/* This task should not run again until xLimitedIncrementHandle has /* This task should not run again until xLimitedIncrementHandle has
suspended itself. */ * suspended itself. */
#if( INCLUDE_eTaskGetState == 1 ) #if ( INCLUDE_eTaskGetState == 1 )
{ {
configASSERT( eTaskGetState( xLimitedIncrementHandle ) == eSuspended ); configASSERT( eTaskGetState( xLimitedIncrementHandle ) == eSuspended );
} }
#endif /* INCLUDE_eTaskGetState */ #endif /* INCLUDE_eTaskGetState */
/* Does the counter variable have the expected value? */ /* Does the counter variable have the expected value? */
if( ulCounter != priMAX_COUNT ) if( ulCounter != priMAX_COUNT )
{ {
sError = pdTRUE; sError = pdTRUE;
} }
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If no errors have occurred then increment the check variable. */ /* If no errors have occurred then increment the check variable. */
portENTER_CRITICAL(); portENTER_CRITICAL();
usCheckVariable++; usCheckVariable++;
portEXIT_CRITICAL(); portEXIT_CRITICAL();
} }
/* Resume the continuous count task and do it all again. */ /* Resume the continuous count task and do it all again. */
vTaskResume( xContinuousIncrementHandle ); vTaskResume( xContinuousIncrementHandle );
#if( configUSE_PREEMPTION == 0 ) #if ( configUSE_PREEMPTION == 0 )
taskYIELD(); taskYIELD();
#endif #endif
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static portTASK_FUNCTION( vQueueSendWhenSuspendedTask, pvParameters ) static portTASK_FUNCTION( vQueueSendWhenSuspendedTask, pvParameters )
{ {
static uint32_t ulValueToSend = ( uint32_t ) 0; static uint32_t ulValueToSend = ( uint32_t ) 0;
/* Just to stop warning messages. */ /* Just to stop warning messages. */
( void ) pvParameters; ( void ) pvParameters;
for( ;; ) for( ; ; )
{ {
vTaskSuspendAll(); vTaskSuspendAll();
{ {
/* We must not block while the scheduler is suspended! */ /* We must not block while the scheduler is suspended! */
if( xQueueSend( xSuspendedTestQueue, ( void * ) &ulValueToSend, priNO_BLOCK ) != pdTRUE ) if( xQueueSend( xSuspendedTestQueue, ( void * ) &ulValueToSend, priNO_BLOCK ) != pdTRUE )
{ {
xSuspendedQueueSendError = pdTRUE; xSuspendedQueueSendError = pdTRUE;
} }
} }
xTaskResumeAll(); xTaskResumeAll();
vTaskDelay( priSLEEP_TIME ); vTaskDelay( priSLEEP_TIME );
++ulValueToSend; ++ulValueToSend;
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static portTASK_FUNCTION( vQueueReceiveWhenSuspendedTask, pvParameters ) static portTASK_FUNCTION( vQueueReceiveWhenSuspendedTask, pvParameters )
{ {
uint32_t ulReceivedValue; uint32_t ulReceivedValue;
BaseType_t xGotValue; BaseType_t xGotValue;
/* Just to stop warning messages. */ /* Just to stop warning messages. */
( void ) pvParameters; ( void ) pvParameters;
for( ;; ) for( ; ; )
{ {
do do
{ {
/* Suspending the scheduler here is fairly pointless and /* Suspending the scheduler here is fairly pointless and
undesirable for a normal application. It is done here purely * undesirable for a normal application. It is done here purely
to test the scheduler. The inner xTaskResumeAll() should * to test the scheduler. The inner xTaskResumeAll() should
never return pdTRUE as the scheduler is still locked by the * never return pdTRUE as the scheduler is still locked by the
outer call. */ * outer call. */
vTaskSuspendAll(); vTaskSuspendAll();
{ {
vTaskSuspendAll(); vTaskSuspendAll();
{ {
xGotValue = xQueueReceive( xSuspendedTestQueue, ( void * ) &ulReceivedValue, priNO_BLOCK ); xGotValue = xQueueReceive( xSuspendedTestQueue, ( void * ) &ulReceivedValue, priNO_BLOCK );
} }
if( xTaskResumeAll() != pdFALSE )
{
xSuspendedQueueReceiveError = pdTRUE;
}
}
xTaskResumeAll();
#if configUSE_PREEMPTION == 0 if( xTaskResumeAll() != pdFALSE )
{ {
taskYIELD(); xSuspendedQueueReceiveError = pdTRUE;
} }
#endif }
xTaskResumeAll();
} while( xGotValue == pdFALSE ); #if configUSE_PREEMPTION == 0
{
taskYIELD();
}
#endif
} while( xGotValue == pdFALSE );
if( ulReceivedValue != ulExpectedValue ) if( ulReceivedValue != ulExpectedValue )
{ {
xSuspendedQueueReceiveError = pdTRUE; xSuspendedQueueReceiveError = pdTRUE;
} }
if( xSuspendedQueueReceiveError != pdTRUE ) if( xSuspendedQueueReceiveError != pdTRUE )
{ {
/* Only increment the variable if an error has not occurred. This /* Only increment the variable if an error has not occurred. This
allows xAreDynamicPriorityTasksStillRunning() to check for stalled * allows xAreDynamicPriorityTasksStillRunning() to check for stalled
tasks as well as explicit errors. */ * tasks as well as explicit errors. */
++ulExpectedValue; ++ulExpectedValue;
} }
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -441,39 +442,39 @@ BaseType_t xGotValue;
BaseType_t xAreDynamicPriorityTasksStillRunning( void ) BaseType_t xAreDynamicPriorityTasksStillRunning( void )
{ {
/* Keep a history of the check variables so we know if it has been incremented /* Keep a history of the check variables so we know if it has been incremented
since the last call. */ * since the last call. */
static uint16_t usLastTaskCheck = ( uint16_t ) 0; static uint16_t usLastTaskCheck = ( uint16_t ) 0;
static uint32_t ulLastExpectedValue = ( uint32_t ) 0U; static uint32_t ulLastExpectedValue = ( uint32_t ) 0U;
BaseType_t xReturn = pdTRUE; BaseType_t xReturn = pdTRUE;
/* Check the tasks are still running by ensuring the check variable /* Check the tasks are still running by ensuring the check variable
is still incrementing. */ * is still incrementing. */
if( usCheckVariable == usLastTaskCheck ) if( usCheckVariable == usLastTaskCheck )
{ {
/* The check has not incremented so an error exists. */ /* The check has not incremented so an error exists. */
xReturn = pdFALSE; xReturn = pdFALSE;
} }
if( ulExpectedValue == ulLastExpectedValue ) if( ulExpectedValue == ulLastExpectedValue )
{ {
/* The value being received by the queue receive task has not /* The value being received by the queue receive task has not
incremented so an error exists. */ * incremented so an error exists. */
xReturn = pdFALSE; xReturn = pdFALSE;
} }
if( xSuspendedQueueSendError == pdTRUE ) if( xSuspendedQueueSendError == pdTRUE )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
} }
if( xSuspendedQueueReceiveError == pdTRUE ) if( xSuspendedQueueReceiveError == pdTRUE )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
} }
usLastTaskCheck = usCheckVariable; usLastTaskCheck = usCheckVariable;
ulLastExpectedValue = ulExpectedValue; ulLastExpectedValue = ulExpectedValue;
return xReturn; return xReturn;
} }

View file

@ -49,12 +49,12 @@
#include "partest.h" #include "partest.h"
#include "flash.h" #include "flash.h"
#define ledSTACK_SIZE configMINIMAL_STACK_SIZE #define ledSTACK_SIZE configMINIMAL_STACK_SIZE
#define ledNUMBER_OF_LEDS ( 3 ) #define ledNUMBER_OF_LEDS ( 3 )
#define ledFLASH_RATE_BASE ( ( TickType_t ) 333 ) #define ledFLASH_RATE_BASE ( ( TickType_t ) 333 )
/* Variable used by the created tasks to calculate the LED number to use, and /* Variable used by the created tasks to calculate the LED number to use, and
the rate at which they should flash the LED. */ * the rate at which they should flash the LED. */
static volatile UBaseType_t uxFlashTaskNumber = 0; static volatile UBaseType_t uxFlashTaskNumber = 0;
/* The task that is created three times. */ /* The task that is created three times. */
@ -64,56 +64,55 @@ static portTASK_FUNCTION_PROTO( vLEDFlashTask, pvParameters );
void vStartLEDFlashTasks( UBaseType_t uxPriority ) void vStartLEDFlashTasks( UBaseType_t uxPriority )
{ {
BaseType_t xLEDTask; BaseType_t xLEDTask;
/* Create the three tasks. */ /* Create the three tasks. */
for( xLEDTask = 0; xLEDTask < ledNUMBER_OF_LEDS; ++xLEDTask ) for( xLEDTask = 0; xLEDTask < ledNUMBER_OF_LEDS; ++xLEDTask )
{ {
/* Spawn the task. */ /* Spawn the task. */
xTaskCreate( vLEDFlashTask, "LEDx", ledSTACK_SIZE, NULL, uxPriority, ( TaskHandle_t * ) NULL ); xTaskCreate( vLEDFlashTask, "LEDx", ledSTACK_SIZE, NULL, uxPriority, ( TaskHandle_t * ) NULL );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static portTASK_FUNCTION( vLEDFlashTask, pvParameters ) static portTASK_FUNCTION( vLEDFlashTask, pvParameters )
{ {
TickType_t xFlashRate, xLastFlashTime; TickType_t xFlashRate, xLastFlashTime;
UBaseType_t uxLED; UBaseType_t uxLED;
/* The parameters are not used. */ /* The parameters are not used. */
( void ) pvParameters; ( void ) pvParameters;
/* Calculate the LED and flash rate. */ /* Calculate the LED and flash rate. */
portENTER_CRITICAL(); portENTER_CRITICAL();
{ {
/* See which of the eight LED's we should use. */ /* See which of the eight LED's we should use. */
uxLED = uxFlashTaskNumber; uxLED = uxFlashTaskNumber;
/* Update so the next task uses the next LED. */ /* Update so the next task uses the next LED. */
uxFlashTaskNumber++; uxFlashTaskNumber++;
} }
portEXIT_CRITICAL(); portEXIT_CRITICAL();
xFlashRate = ledFLASH_RATE_BASE + ( ledFLASH_RATE_BASE * ( TickType_t ) uxLED ); xFlashRate = ledFLASH_RATE_BASE + ( ledFLASH_RATE_BASE * ( TickType_t ) uxLED );
xFlashRate /= portTICK_PERIOD_MS; xFlashRate /= portTICK_PERIOD_MS;
/* We will turn the LED on and off again in the delay period, so each /* We will turn the LED on and off again in the delay period, so each
delay is only half the total period. */ * delay is only half the total period. */
xFlashRate /= ( TickType_t ) 2; xFlashRate /= ( TickType_t ) 2;
/* We need to initialise xLastFlashTime prior to the first call to /* We need to initialise xLastFlashTime prior to the first call to
vTaskDelayUntil(). */ * vTaskDelayUntil(). */
xLastFlashTime = xTaskGetTickCount(); xLastFlashTime = xTaskGetTickCount();
for(;;) for( ; ; )
{ {
/* Delay for half the flash period then turn the LED on. */ /* Delay for half the flash period then turn the LED on. */
vTaskDelayUntil( &xLastFlashTime, xFlashRate ); vTaskDelayUntil( &xLastFlashTime, xFlashRate );
vParTestToggleLED( uxLED ); vParTestToggleLED( uxLED );
/* Delay for half the flash period then turn the LED off. */ /* Delay for half the flash period then turn the LED off. */
vTaskDelayUntil( &xLastFlashTime, xFlashRate ); vTaskDelayUntil( &xLastFlashTime, xFlashRate );
vParTestToggleLED( uxLED ); vParTestToggleLED( uxLED );
} }
} /*lint !e715 !e818 !e830 Function definition must be standard for task creation. */ } /*lint !e715 !e818 !e830 Function definition must be standard for task creation. */

View file

@ -39,10 +39,10 @@
#include "flash_timer.h" #include "flash_timer.h"
/* The toggle rates are all a multple of ledFLASH_RATE_BASE. */ /* The toggle rates are all a multple of ledFLASH_RATE_BASE. */
#define ledFLASH_RATE_BASE ( ( ( TickType_t ) 333 ) / portTICK_PERIOD_MS ) #define ledFLASH_RATE_BASE ( ( ( TickType_t ) 333 ) / portTICK_PERIOD_MS )
/* A block time of zero simple means "don't block". */ /* A block time of zero simple means "don't block". */
#define ledDONT_BLOCK ( ( TickType_t ) 0 ) #define ledDONT_BLOCK ( ( TickType_t ) 0 )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -57,42 +57,40 @@ static void prvLEDTimerCallback( TimerHandle_t xTimer );
void vStartLEDFlashTimers( UBaseType_t uxNumberOfLEDs ) void vStartLEDFlashTimers( UBaseType_t uxNumberOfLEDs )
{ {
UBaseType_t uxLEDTimer; UBaseType_t uxLEDTimer;
TimerHandle_t xTimer; TimerHandle_t xTimer;
/* Create and start the requested number of timers. */ /* Create and start the requested number of timers. */
for( uxLEDTimer = 0; uxLEDTimer < uxNumberOfLEDs; ++uxLEDTimer ) for( uxLEDTimer = 0; uxLEDTimer < uxNumberOfLEDs; ++uxLEDTimer )
{ {
/* Create the timer. */ /* Create the timer. */
xTimer = xTimerCreate( "Flasher", /* A text name, purely to help debugging. */ xTimer = xTimerCreate( "Flasher", /* A text name, purely to help debugging. */
ledFLASH_RATE_BASE * ( uxLEDTimer + 1 ),/* The timer period, which is a multiple of ledFLASH_RATE_BASE. */ ledFLASH_RATE_BASE * ( uxLEDTimer + 1 ), /* The timer period, which is a multiple of ledFLASH_RATE_BASE. */
pdTRUE, /* This is an auto-reload timer, so xAutoReload is set to pdTRUE. */ pdTRUE, /* This is an auto-reload timer, so xAutoReload is set to pdTRUE. */
( void * ) uxLEDTimer, /* The ID is used to identify the timer within the timer callback function, as each timer uses the same callback. */ ( void * ) uxLEDTimer, /* The ID is used to identify the timer within the timer callback function, as each timer uses the same callback. */
prvLEDTimerCallback /* Each timer uses the same callback. */ prvLEDTimerCallback /* Each timer uses the same callback. */
); );
/* If the timer was created successfully, attempt to start it. If the /* If the timer was created successfully, attempt to start it. If the
scheduler has not yet been started then the timer command queue must * scheduler has not yet been started then the timer command queue must
be long enough to hold each command sent to it until such time that the * be long enough to hold each command sent to it until such time that the
scheduler is started. The timer command queue length is set by * scheduler is started. The timer command queue length is set by
configTIMER_QUEUE_LENGTH in FreeRTOSConfig.h. */ * configTIMER_QUEUE_LENGTH in FreeRTOSConfig.h. */
if( xTimer != NULL ) if( xTimer != NULL )
{ {
xTimerStart( xTimer, ledDONT_BLOCK ); xTimerStart( xTimer, ledDONT_BLOCK );
} }
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvLEDTimerCallback( TimerHandle_t xTimer ) static void prvLEDTimerCallback( TimerHandle_t xTimer )
{ {
BaseType_t xTimerID; BaseType_t xTimerID;
/* The timer ID is used to identify the timer that has actually expired as /* The timer ID is used to identify the timer that has actually expired as
each timer uses the same callback. The ID is then also used as the number * each timer uses the same callback. The ID is then also used as the number
of the LED that is to be toggled. */ * of the LED that is to be toggled. */
xTimerID = ( BaseType_t ) pvTimerGetTimerID( xTimer ); xTimerID = ( BaseType_t ) pvTimerGetTimerID( xTimer );
vParTestToggleLED( xTimerID ); vParTestToggleLED( xTimerID );
} }

View file

@ -50,300 +50,298 @@
#include "flop.h" #include "flop.h"
#ifndef mathSTACK_SIZE #ifndef mathSTACK_SIZE
#define mathSTACK_SIZE configMINIMAL_STACK_SIZE #define mathSTACK_SIZE configMINIMAL_STACK_SIZE
#endif #endif
#define mathNUMBER_OF_TASKS ( 4 ) #define mathNUMBER_OF_TASKS ( 4 )
/* Four tasks, each of which performs a different floating point calculation. /* Four tasks, each of which performs a different floating point calculation.
Each of the four is created twice. */ * Each of the four is created twice. */
static portTASK_FUNCTION_PROTO( vCompetingMathTask1, pvParameters ); static portTASK_FUNCTION_PROTO( vCompetingMathTask1, pvParameters );
static portTASK_FUNCTION_PROTO( vCompetingMathTask2, pvParameters ); static portTASK_FUNCTION_PROTO( vCompetingMathTask2, pvParameters );
static portTASK_FUNCTION_PROTO( vCompetingMathTask3, pvParameters ); static portTASK_FUNCTION_PROTO( vCompetingMathTask3, pvParameters );
static portTASK_FUNCTION_PROTO( vCompetingMathTask4, pvParameters ); static portTASK_FUNCTION_PROTO( vCompetingMathTask4, pvParameters );
/* These variables are used to check that all the tasks are still running. If a /* These variables are used to check that all the tasks are still running. If a
task gets a calculation wrong it will stop setting its check variable. */ * task gets a calculation wrong it will stop setting its check variable. */
static uint16_t usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( uint16_t ) 0 }; static uint16_t usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( uint16_t ) 0 };
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vStartMathTasks( UBaseType_t uxPriority ) void vStartMathTasks( UBaseType_t uxPriority )
{ {
xTaskCreate( vCompetingMathTask1, "Math1", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL ); xTaskCreate( vCompetingMathTask1, "Math1", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask2, "Math2", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL ); xTaskCreate( vCompetingMathTask2, "Math2", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask3, "Math3", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL ); xTaskCreate( vCompetingMathTask3, "Math3", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask4, "Math4", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL ); xTaskCreate( vCompetingMathTask4, "Math4", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static portTASK_FUNCTION( vCompetingMathTask1, pvParameters ) static portTASK_FUNCTION( vCompetingMathTask1, pvParameters )
{ {
volatile portDOUBLE d1, d2, d3, d4; volatile portDOUBLE d1, d2, d3, d4;
volatile uint16_t *pusTaskCheckVariable; volatile uint16_t * pusTaskCheckVariable;
volatile portDOUBLE dAnswer; volatile portDOUBLE dAnswer;
short sError = pdFALSE; short sError = pdFALSE;
/* Some ports require that tasks that use a hardware floating point unit /* Some ports require that tasks that use a hardware floating point unit
tell the kernel that they require a floating point context before any * tell the kernel that they require a floating point context before any
floating point instructions are executed. */ * floating point instructions are executed. */
portTASK_USES_FLOATING_POINT(); portTASK_USES_FLOATING_POINT();
d1 = 123.4567; d1 = 123.4567;
d2 = 2345.6789; d2 = 2345.6789;
d3 = -918.222; d3 = -918.222;
dAnswer = ( d1 + d2 ) * d3; dAnswer = ( d1 + d2 ) * d3;
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( volatile uint16_t * ) pvParameters; pusTaskCheckVariable = ( volatile uint16_t * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */ /* Keep performing a calculation and checking the result against a constant. */
for(;;) for( ; ; )
{ {
d1 = 123.4567; d1 = 123.4567;
d2 = 2345.6789; d2 = 2345.6789;
d3 = -918.222; d3 = -918.222;
d4 = ( d1 + d2 ) * d3; d4 = ( d1 + d2 ) * d3;
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
taskYIELD(); taskYIELD();
#endif #endif
/* If the calculation does not match the expected constant, stop the /* If the calculation does not match the expected constant, stop the
increment of the check variable. */ * increment of the check variable. */
if( fabs( d4 - dAnswer ) > 0.001 ) if( fabs( d4 - dAnswer ) > 0.001 )
{ {
sError = pdTRUE; sError = pdTRUE;
} }
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct then set set the check /* If the calculation has always been correct then set set the check
variable. The check variable will get set to pdFALSE each time * variable. The check variable will get set to pdFALSE each time
xAreMathsTaskStillRunning() is executed. */ * xAreMathsTaskStillRunning() is executed. */
( *pusTaskCheckVariable ) = pdTRUE; ( *pusTaskCheckVariable ) = pdTRUE;
} }
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
taskYIELD(); taskYIELD();
#endif #endif
}
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static portTASK_FUNCTION( vCompetingMathTask2, pvParameters ) static portTASK_FUNCTION( vCompetingMathTask2, pvParameters )
{ {
volatile portDOUBLE d1, d2, d3, d4; volatile portDOUBLE d1, d2, d3, d4;
volatile uint16_t *pusTaskCheckVariable; volatile uint16_t * pusTaskCheckVariable;
volatile portDOUBLE dAnswer; volatile portDOUBLE dAnswer;
short sError = pdFALSE; short sError = pdFALSE;
/* Some ports require that tasks that use a hardware floating point unit /* Some ports require that tasks that use a hardware floating point unit
tell the kernel that they require a floating point context before any * tell the kernel that they require a floating point context before any
floating point instructions are executed. */ * floating point instructions are executed. */
portTASK_USES_FLOATING_POINT(); portTASK_USES_FLOATING_POINT();
d1 = -389.38; d1 = -389.38;
d2 = 32498.2; d2 = 32498.2;
d3 = -2.0001; d3 = -2.0001;
dAnswer = ( d1 / d2 ) * d3; dAnswer = ( d1 / d2 ) * d3;
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( volatile uint16_t * ) pvParameters; pusTaskCheckVariable = ( volatile uint16_t * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */ /* Keep performing a calculation and checking the result against a constant. */
for( ;; ) for( ; ; )
{ {
d1 = -389.38; d1 = -389.38;
d2 = 32498.2; d2 = 32498.2;
d3 = -2.0001; d3 = -2.0001;
d4 = ( d1 / d2 ) * d3; d4 = ( d1 / d2 ) * d3;
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
taskYIELD(); taskYIELD();
#endif #endif
/* If the calculation does not match the expected constant, stop the /* If the calculation does not match the expected constant, stop the
increment of the check variable. */ * increment of the check variable. */
if( fabs( d4 - dAnswer ) > 0.001 ) if( fabs( d4 - dAnswer ) > 0.001 )
{ {
sError = pdTRUE; sError = pdTRUE;
} }
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct then set set the check /* If the calculation has always been correct then set set the check
variable. The check variable will get set to pdFALSE each time * variable. The check variable will get set to pdFALSE each time
xAreMathsTaskStillRunning() is executed. */ * xAreMathsTaskStillRunning() is executed. */
( *pusTaskCheckVariable ) = pdTRUE; ( *pusTaskCheckVariable ) = pdTRUE;
} }
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
taskYIELD(); taskYIELD();
#endif #endif
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static portTASK_FUNCTION( vCompetingMathTask3, pvParameters ) static portTASK_FUNCTION( vCompetingMathTask3, pvParameters )
{ {
volatile portDOUBLE *pdArray, dTotal1, dTotal2, dDifference; volatile portDOUBLE * pdArray, dTotal1, dTotal2, dDifference;
volatile uint16_t *pusTaskCheckVariable; volatile uint16_t * pusTaskCheckVariable;
const size_t xArraySize = 10; const size_t xArraySize = 10;
size_t xPosition; size_t xPosition;
short sError = pdFALSE; short sError = pdFALSE;
/* Some ports require that tasks that use a hardware floating point unit /* Some ports require that tasks that use a hardware floating point unit
tell the kernel that they require a floating point context before any * tell the kernel that they require a floating point context before any
floating point instructions are executed. */ * floating point instructions are executed. */
portTASK_USES_FLOATING_POINT(); portTASK_USES_FLOATING_POINT();
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( volatile uint16_t * ) pvParameters; pusTaskCheckVariable = ( volatile uint16_t * ) pvParameters;
pdArray = ( portDOUBLE * ) pvPortMalloc( xArraySize * sizeof( portDOUBLE ) ); pdArray = ( portDOUBLE * ) pvPortMalloc( xArraySize * sizeof( portDOUBLE ) );
/* Keep filling an array, keeping a running total of the values placed in the /* Keep filling an array, keeping a running total of the values placed in the
array. Then run through the array adding up all the values. If the two totals * array. Then run through the array adding up all the values. If the two totals
do not match, stop the check variable from incrementing. */ * do not match, stop the check variable from incrementing. */
for( ;; ) for( ; ; )
{ {
dTotal1 = 0.0; dTotal1 = 0.0;
dTotal2 = 0.0; dTotal2 = 0.0;
for( xPosition = 0; xPosition < xArraySize; xPosition++ ) for( xPosition = 0; xPosition < xArraySize; xPosition++ )
{ {
pdArray[ xPosition ] = ( portDOUBLE ) xPosition + 5.5; pdArray[ xPosition ] = ( portDOUBLE ) xPosition + 5.5;
dTotal1 += ( portDOUBLE ) xPosition + 5.5; dTotal1 += ( portDOUBLE ) xPosition + 5.5;
} }
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
taskYIELD(); taskYIELD();
#endif #endif
for( xPosition = 0; xPosition < xArraySize; xPosition++ ) for( xPosition = 0; xPosition < xArraySize; xPosition++ )
{ {
dTotal2 += pdArray[ xPosition ]; dTotal2 += pdArray[ xPosition ];
} }
dDifference = dTotal1 - dTotal2; dDifference = dTotal1 - dTotal2;
if( fabs( dDifference ) > 0.001 )
{
sError = pdTRUE;
}
#if configUSE_PREEMPTION == 0 if( fabs( dDifference ) > 0.001 )
taskYIELD(); {
#endif sError = pdTRUE;
}
if( sError == pdFALSE ) #if configUSE_PREEMPTION == 0
{ taskYIELD();
/* If the calculation has always been correct then set set the check #endif
variable. The check variable will get set to pdFALSE each time
xAreMathsTaskStillRunning() is executed. */ if( sError == pdFALSE )
( *pusTaskCheckVariable ) = pdTRUE; {
} /* If the calculation has always been correct then set set the check
} * variable. The check variable will get set to pdFALSE each time
* xAreMathsTaskStillRunning() is executed. */
( *pusTaskCheckVariable ) = pdTRUE;
}
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static portTASK_FUNCTION( vCompetingMathTask4, pvParameters ) static portTASK_FUNCTION( vCompetingMathTask4, pvParameters )
{ {
volatile portDOUBLE *pdArray, dTotal1, dTotal2, dDifference; volatile portDOUBLE * pdArray, dTotal1, dTotal2, dDifference;
volatile uint16_t *pusTaskCheckVariable; volatile uint16_t * pusTaskCheckVariable;
const size_t xArraySize = 10; const size_t xArraySize = 10;
size_t xPosition; size_t xPosition;
short sError = pdFALSE; short sError = pdFALSE;
/* Some ports require that tasks that use a hardware floating point unit /* Some ports require that tasks that use a hardware floating point unit
tell the kernel that they require a floating point context before any * tell the kernel that they require a floating point context before any
floating point instructions are executed. */ * floating point instructions are executed. */
portTASK_USES_FLOATING_POINT(); portTASK_USES_FLOATING_POINT();
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( volatile uint16_t * ) pvParameters; pusTaskCheckVariable = ( volatile uint16_t * ) pvParameters;
pdArray = ( portDOUBLE * ) pvPortMalloc( xArraySize * sizeof( portDOUBLE ) ); pdArray = ( portDOUBLE * ) pvPortMalloc( xArraySize * sizeof( portDOUBLE ) );
/* Keep filling an array, keeping a running total of the values placed in the /* Keep filling an array, keeping a running total of the values placed in the
array. Then run through the array adding up all the values. If the two totals * array. Then run through the array adding up all the values. If the two totals
do not match, stop the check variable from incrementing. */ * do not match, stop the check variable from incrementing. */
for( ;; ) for( ; ; )
{ {
dTotal1 = 0.0; dTotal1 = 0.0;
dTotal2 = 0.0; dTotal2 = 0.0;
for( xPosition = 0; xPosition < xArraySize; xPosition++ ) for( xPosition = 0; xPosition < xArraySize; xPosition++ )
{ {
pdArray[ xPosition ] = ( portDOUBLE ) xPosition * 12.123; pdArray[ xPosition ] = ( portDOUBLE ) xPosition * 12.123;
dTotal1 += ( portDOUBLE ) xPosition * 12.123; dTotal1 += ( portDOUBLE ) xPosition * 12.123;
} }
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
taskYIELD(); taskYIELD();
#endif #endif
for( xPosition = 0; xPosition < xArraySize; xPosition++ ) for( xPosition = 0; xPosition < xArraySize; xPosition++ )
{ {
dTotal2 += pdArray[ xPosition ]; dTotal2 += pdArray[ xPosition ];
} }
dDifference = dTotal1 - dTotal2; dDifference = dTotal1 - dTotal2;
if( fabs( dDifference ) > 0.001 )
{
sError = pdTRUE;
}
#if configUSE_PREEMPTION == 0 if( fabs( dDifference ) > 0.001 )
taskYIELD(); {
#endif sError = pdTRUE;
}
if( sError == pdFALSE ) #if configUSE_PREEMPTION == 0
{ taskYIELD();
/* If the calculation has always been correct then set set the check #endif
variable. The check variable will get set to pdFALSE each time
xAreMathsTaskStillRunning() is executed. */ if( sError == pdFALSE )
( *pusTaskCheckVariable ) = pdTRUE; {
} /* If the calculation has always been correct then set set the check
} * variable. The check variable will get set to pdFALSE each time
* xAreMathsTaskStillRunning() is executed. */
( *pusTaskCheckVariable ) = pdTRUE;
}
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running. */ /* This is called to check that all the created tasks are still running. */
BaseType_t xAreMathsTaskStillRunning( void ) BaseType_t xAreMathsTaskStillRunning( void )
{ {
BaseType_t xReturn = pdPASS, xTask; BaseType_t xReturn = pdPASS, xTask;
/* Check the maths tasks are still running by ensuring their check variables /* Check the maths tasks are still running by ensuring their check variables
have been set to pdPASS. */ * have been set to pdPASS. */
for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ ) for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ )
{ {
if( usTaskCheck[ xTask ] != pdTRUE ) if( usTaskCheck[ xTask ] != pdTRUE )
{ {
/* The check has not been set so the associated task has either /* The check has not been set so the associated task has either
stalled or detected an error. */ * stalled or detected an error. */
xReturn = pdFAIL; xReturn = pdFAIL;
} }
else else
{ {
/* Reset the variable so it can be checked again the next time this /* Reset the variable so it can be checked again the next time this
function is executed. */ * function is executed. */
usTaskCheck[ xTask ] = pdFALSE; usTaskCheck[ xTask ] = pdFALSE;
} }
} }
return xReturn; return xReturn;
} }

View file

@ -42,122 +42,121 @@
#include "integer.h" #include "integer.h"
/* The constants used in the calculation. */ /* The constants used in the calculation. */
#define intgCONST1 ( ( long ) 123 ) #define intgCONST1 ( ( long ) 123 )
#define intgCONST2 ( ( long ) 234567 ) #define intgCONST2 ( ( long ) 234567 )
#define intgCONST3 ( ( long ) -3 ) #define intgCONST3 ( ( long ) -3 )
#define intgCONST4 ( ( long ) 7 ) #define intgCONST4 ( ( long ) 7 )
#define intgEXPECTED_ANSWER ( ( ( intgCONST1 + intgCONST2 ) * intgCONST3 ) / intgCONST4 ) #define intgEXPECTED_ANSWER ( ( ( intgCONST1 + intgCONST2 ) * intgCONST3 ) / intgCONST4 )
#define intgSTACK_SIZE configMINIMAL_STACK_SIZE #define intgSTACK_SIZE configMINIMAL_STACK_SIZE
/* As this is the minimal version, we will only create one task. */ /* As this is the minimal version, we will only create one task. */
#define intgNUMBER_OF_TASKS ( 1 ) #define intgNUMBER_OF_TASKS ( 1 )
/* The task function. Repeatedly performs a 32 bit calculation, checking the /* The task function. Repeatedly performs a 32 bit calculation, checking the
result against the expected result. If the result is incorrect then the * result against the expected result. If the result is incorrect then the
context switch must have caused some corruption. */ * context switch must have caused some corruption. */
static portTASK_FUNCTION_PROTO( vCompeteingIntMathTask, pvParameters ); static portTASK_FUNCTION_PROTO( vCompeteingIntMathTask, pvParameters );
/* Variables that are set to true within the calculation task to indicate /* Variables that are set to true within the calculation task to indicate
that the task is still executing. The check task sets the variable back to * that the task is still executing. The check task sets the variable back to
false, flagging an error if the variable is still false the next time it * false, flagging an error if the variable is still false the next time it
is called. */ * is called. */
static BaseType_t xTaskCheck[ intgNUMBER_OF_TASKS ] = { ( BaseType_t ) pdFALSE }; static BaseType_t xTaskCheck[ intgNUMBER_OF_TASKS ] = { ( BaseType_t ) pdFALSE };
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vStartIntegerMathTasks( UBaseType_t uxPriority ) void vStartIntegerMathTasks( UBaseType_t uxPriority )
{ {
short sTask; short sTask;
for( sTask = 0; sTask < intgNUMBER_OF_TASKS; sTask++ ) for( sTask = 0; sTask < intgNUMBER_OF_TASKS; sTask++ )
{ {
xTaskCreate( vCompeteingIntMathTask, "IntMath", intgSTACK_SIZE, ( void * ) &( xTaskCheck[ sTask ] ), uxPriority, ( TaskHandle_t * ) NULL ); xTaskCreate( vCompeteingIntMathTask, "IntMath", intgSTACK_SIZE, ( void * ) &( xTaskCheck[ sTask ] ), uxPriority, ( TaskHandle_t * ) NULL );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static portTASK_FUNCTION( vCompeteingIntMathTask, pvParameters ) static portTASK_FUNCTION( vCompeteingIntMathTask, pvParameters )
{ {
/* These variables are all effectively set to constants so they are volatile to /* These variables are all effectively set to constants so they are volatile to
ensure the compiler does not just get rid of them. */ * ensure the compiler does not just get rid of them. */
volatile long lValue; volatile long lValue;
short sError = pdFALSE; short sError = pdFALSE;
volatile BaseType_t *pxTaskHasExecuted; volatile BaseType_t * pxTaskHasExecuted;
/* Set a pointer to the variable we are going to set to true each /* Set a pointer to the variable we are going to set to true each
iteration. This is also a good test of the parameter passing mechanism * iteration. This is also a good test of the parameter passing mechanism
within each port. */ * within each port. */
pxTaskHasExecuted = ( volatile BaseType_t * ) pvParameters; pxTaskHasExecuted = ( volatile BaseType_t * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */ /* Keep performing a calculation and checking the result against a constant. */
for( ;; ) for( ; ; )
{ {
/* Perform the calculation. This will store partial value in /* Perform the calculation. This will store partial value in
registers, resulting in a good test of the context switch mechanism. */ * registers, resulting in a good test of the context switch mechanism. */
lValue = intgCONST1; lValue = intgCONST1;
lValue += intgCONST2; lValue += intgCONST2;
/* Yield in case cooperative scheduling is being used. */ /* Yield in case cooperative scheduling is being used. */
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
{ {
taskYIELD(); taskYIELD();
} }
#endif #endif
/* Finish off the calculation. */ /* Finish off the calculation. */
lValue *= intgCONST3; lValue *= intgCONST3;
lValue /= intgCONST4; lValue /= intgCONST4;
/* If the calculation is found to be incorrect we stop setting the /* If the calculation is found to be incorrect we stop setting the
TaskHasExecuted variable so the check task can see an error has * TaskHasExecuted variable so the check task can see an error has
occurred. */ * occurred. */
if( lValue != intgEXPECTED_ANSWER ) /*lint !e774 volatile used to prevent this being optimised out. */ if( lValue != intgEXPECTED_ANSWER ) /*lint !e774 volatile used to prevent this being optimised out. */
{ {
sError = pdTRUE; sError = pdTRUE;
} }
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* We have not encountered any errors, so set the flag that show /* We have not encountered any errors, so set the flag that show
we are still executing. This will be periodically cleared by * we are still executing. This will be periodically cleared by
the check task. */ * the check task. */
portENTER_CRITICAL(); portENTER_CRITICAL();
*pxTaskHasExecuted = pdTRUE; *pxTaskHasExecuted = pdTRUE;
portEXIT_CRITICAL(); portEXIT_CRITICAL();
} }
/* Yield in case cooperative scheduling is being used. */ /* Yield in case cooperative scheduling is being used. */
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
{ {
taskYIELD(); taskYIELD();
} }
#endif #endif
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running. */ /* This is called to check that all the created tasks are still running. */
BaseType_t xAreIntegerMathsTaskStillRunning( void ) BaseType_t xAreIntegerMathsTaskStillRunning( void )
{ {
BaseType_t xReturn = pdTRUE; BaseType_t xReturn = pdTRUE;
short sTask; short sTask;
/* Check the maths tasks are still running by ensuring their check variables /* Check the maths tasks are still running by ensuring their check variables
are still being set to true. */ * are still being set to true. */
for( sTask = 0; sTask < intgNUMBER_OF_TASKS; sTask++ ) for( sTask = 0; sTask < intgNUMBER_OF_TASKS; sTask++ )
{ {
if( xTaskCheck[ sTask ] == pdFALSE ) if( xTaskCheck[ sTask ] == pdFALSE )
{ {
/* The check has not incremented so an error exists. */ /* The check has not incremented so an error exists. */
xReturn = pdFALSE; xReturn = pdFALSE;
} }
/* Reset the check variable so we can tell if it has been set by /* Reset the check variable so we can tell if it has been set by
the next time around. */ * the next time around. */
xTaskCheck[ sTask ] = pdFALSE; xTaskCheck[ sTask ] = pdFALSE;
} }
return xReturn; return xReturn;
} }

View file

@ -26,40 +26,40 @@
*/ */
/* /*
The tasks defined on this page demonstrate the use of recursive mutexes. * The tasks defined on this page demonstrate the use of recursive mutexes.
*
For recursive mutex functionality the created mutex should be created using * For recursive mutex functionality the created mutex should be created using
xSemaphoreCreateRecursiveMutex(), then be manipulated * xSemaphoreCreateRecursiveMutex(), then be manipulated
using the xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() API * using the xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() API
functions. * functions.
*
This demo creates three tasks all of which access the same recursive mutex: * This demo creates three tasks all of which access the same recursive mutex:
*
prvRecursiveMutexControllingTask() has the highest priority so executes * prvRecursiveMutexControllingTask() has the highest priority so executes
first and grabs the mutex. It then performs some recursive accesses - * first and grabs the mutex. It then performs some recursive accesses -
between each of which it sleeps for a short period to let the lower * between each of which it sleeps for a short period to let the lower
priority tasks execute. When it has completed its demo functionality * priority tasks execute. When it has completed its demo functionality
it gives the mutex back before suspending itself. * it gives the mutex back before suspending itself.
*
prvRecursiveMutexBlockingTask() attempts to access the mutex by performing * prvRecursiveMutexBlockingTask() attempts to access the mutex by performing
a blocking 'take'. The blocking task has a lower priority than the * a blocking 'take'. The blocking task has a lower priority than the
controlling task so by the time it executes the mutex has already been * controlling task so by the time it executes the mutex has already been
taken by the controlling task, causing the blocking task to block. It * taken by the controlling task, causing the blocking task to block. It
does not unblock until the controlling task has given the mutex back, * does not unblock until the controlling task has given the mutex back,
and it does not actually run until the controlling task has suspended * and it does not actually run until the controlling task has suspended
itself (due to the relative priorities). When it eventually does obtain * itself (due to the relative priorities). When it eventually does obtain
the mutex all it does is give the mutex back prior to also suspending * the mutex all it does is give the mutex back prior to also suspending
itself. At this point both the controlling task and the blocking task are * itself. At this point both the controlling task and the blocking task are
suspended. * suspended.
*
prvRecursiveMutexPollingTask() runs at the idle priority. It spins round * prvRecursiveMutexPollingTask() runs at the idle priority. It spins round
a tight loop attempting to obtain the mutex with a non-blocking call. As * a tight loop attempting to obtain the mutex with a non-blocking call. As
the lowest priority task it will not successfully obtain the mutex until * the lowest priority task it will not successfully obtain the mutex until
both the controlling and blocking tasks are suspended. Once it eventually * both the controlling and blocking tasks are suspended. Once it eventually
does obtain the mutex it first unsuspends both the controlling task and * does obtain the mutex it first unsuspends both the controlling task and
blocking task prior to giving the mutex back - resulting in the polling * blocking task prior to giving the mutex back - resulting in the polling
task temporarily inheriting the controlling tasks priority. * task temporarily inheriting the controlling tasks priority.
*/ */
/* Scheduler include files. */ /* Scheduler include files. */
#include "FreeRTOS.h" #include "FreeRTOS.h"
@ -70,29 +70,29 @@
#include "recmutex.h" #include "recmutex.h"
/* Priorities assigned to the three tasks. recmuCONTROLLING_TASK_PRIORITY can /* Priorities assigned to the three tasks. recmuCONTROLLING_TASK_PRIORITY can
be overridden by a definition in FreeRTOSConfig.h. */ * be overridden by a definition in FreeRTOSConfig.h. */
#ifndef recmuCONTROLLING_TASK_PRIORITY #ifndef recmuCONTROLLING_TASK_PRIORITY
#define recmuCONTROLLING_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 ) #define recmuCONTROLLING_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 )
#endif #endif
#define recmuBLOCKING_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 ) #define recmuBLOCKING_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )
#define recmuPOLLING_TASK_PRIORITY ( tskIDLE_PRIORITY + 0 ) #define recmuPOLLING_TASK_PRIORITY ( tskIDLE_PRIORITY + 0 )
/* The recursive call depth. */ /* The recursive call depth. */
#define recmuMAX_COUNT ( 10 ) #define recmuMAX_COUNT ( 10 )
/* Misc. */ /* Misc. */
#define recmuSHORT_DELAY ( pdMS_TO_TICKS( 20 ) ) #define recmuSHORT_DELAY ( pdMS_TO_TICKS( 20 ) )
#define recmuNO_DELAY ( ( TickType_t ) 0 ) #define recmuNO_DELAY ( ( TickType_t ) 0 )
#define recmu15ms_DELAY ( pdMS_TO_TICKS( 15 ) ) #define recmu15ms_DELAY ( pdMS_TO_TICKS( 15 ) )
#ifndef recmuRECURSIVE_MUTEX_TEST_TASK_STACK_SIZE #ifndef recmuRECURSIVE_MUTEX_TEST_TASK_STACK_SIZE
#define recmuRECURSIVE_MUTEX_TEST_TASK_STACK_SIZE configMINIMAL_STACK_SIZE #define recmuRECURSIVE_MUTEX_TEST_TASK_STACK_SIZE configMINIMAL_STACK_SIZE
#endif #endif
/* The three tasks as described at the top of this file. */ /* The three tasks as described at the top of this file. */
static void prvRecursiveMutexControllingTask( void *pvParameters ); static void prvRecursiveMutexControllingTask( void * pvParameters );
static void prvRecursiveMutexBlockingTask( void *pvParameters ); static void prvRecursiveMutexBlockingTask( void * pvParameters );
static void prvRecursiveMutexPollingTask( void *pvParameters ); static void prvRecursiveMutexPollingTask( void * pvParameters );
/* The mutex used by the demo. */ /* The mutex used by the demo. */
static SemaphoreHandle_t xMutex; static SemaphoreHandle_t xMutex;
@ -102,315 +102,311 @@ static volatile BaseType_t xErrorOccurred = pdFALSE, xControllingIsSuspended = p
static volatile UBaseType_t uxControllingCycles = 0, uxBlockingCycles = 0, uxPollingCycles = 0; static volatile UBaseType_t uxControllingCycles = 0, uxBlockingCycles = 0, uxPollingCycles = 0;
/* Handles of the two higher priority tasks, required so they can be resumed /* Handles of the two higher priority tasks, required so they can be resumed
(unsuspended). */ * (unsuspended). */
static TaskHandle_t xControllingTaskHandle, xBlockingTaskHandle; static TaskHandle_t xControllingTaskHandle, xBlockingTaskHandle;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vStartRecursiveMutexTasks( void ) void vStartRecursiveMutexTasks( void )
{ {
/* Just creates the mutex and the three tasks. */ /* Just creates the mutex and the three tasks. */
xMutex = xSemaphoreCreateRecursiveMutex(); xMutex = xSemaphoreCreateRecursiveMutex();
if( xMutex != NULL ) if( xMutex != NULL )
{ {
/* vQueueAddToRegistry() adds the mutex to the registry, if one is /* vQueueAddToRegistry() adds the mutex to the registry, if one is
in use. The registry is provided as a means for kernel aware * in use. The registry is provided as a means for kernel aware
debuggers to locate mutex and has no purpose if a kernel aware debugger * debuggers to locate mutex and has no purpose if a kernel aware debugger
is not being used. The call to vQueueAddToRegistry() will be removed * is not being used. The call to vQueueAddToRegistry() will be removed
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is * by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
defined to be less than 1. */ * defined to be less than 1. */
vQueueAddToRegistry( ( QueueHandle_t ) xMutex, "Recursive_Mutex" ); vQueueAddToRegistry( ( QueueHandle_t ) xMutex, "Recursive_Mutex" );
xTaskCreate( prvRecursiveMutexControllingTask, "Rec1", recmuRECURSIVE_MUTEX_TEST_TASK_STACK_SIZE, NULL, recmuCONTROLLING_TASK_PRIORITY, &xControllingTaskHandle ); xTaskCreate( prvRecursiveMutexControllingTask, "Rec1", recmuRECURSIVE_MUTEX_TEST_TASK_STACK_SIZE, NULL, recmuCONTROLLING_TASK_PRIORITY, &xControllingTaskHandle );
xTaskCreate( prvRecursiveMutexBlockingTask, "Rec2", recmuRECURSIVE_MUTEX_TEST_TASK_STACK_SIZE, NULL, recmuBLOCKING_TASK_PRIORITY, &xBlockingTaskHandle ); xTaskCreate( prvRecursiveMutexBlockingTask, "Rec2", recmuRECURSIVE_MUTEX_TEST_TASK_STACK_SIZE, NULL, recmuBLOCKING_TASK_PRIORITY, &xBlockingTaskHandle );
xTaskCreate( prvRecursiveMutexPollingTask, "Rec3", recmuRECURSIVE_MUTEX_TEST_TASK_STACK_SIZE, NULL, recmuPOLLING_TASK_PRIORITY, NULL ); xTaskCreate( prvRecursiveMutexPollingTask, "Rec3", recmuRECURSIVE_MUTEX_TEST_TASK_STACK_SIZE, NULL, recmuPOLLING_TASK_PRIORITY, NULL );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvRecursiveMutexControllingTask( void *pvParameters ) static void prvRecursiveMutexControllingTask( void * pvParameters )
{ {
UBaseType_t ux; UBaseType_t ux;
/* Just to remove compiler warning. */ /* Just to remove compiler warning. */
( void ) pvParameters; ( void ) pvParameters;
for( ;; ) for( ; ; )
{ {
/* Should not be able to 'give' the mutex, as we have not yet 'taken' /* Should not be able to 'give' the mutex, as we have not yet 'taken'
it. The first time through, the mutex will not have been used yet, * it. The first time through, the mutex will not have been used yet,
subsequent times through, at this point the mutex will be held by the * subsequent times through, at this point the mutex will be held by the
polling task. */ * polling task. */
if( xSemaphoreGiveRecursive( xMutex ) == pdPASS ) if( xSemaphoreGiveRecursive( xMutex ) == pdPASS )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
for( ux = 0; ux < recmuMAX_COUNT; ux++ ) for( ux = 0; ux < recmuMAX_COUNT; ux++ )
{ {
/* We should now be able to take the mutex as many times as /* We should now be able to take the mutex as many times as
we like. * we like.
*
* The first time through the mutex will be immediately available, on
* subsequent times through the mutex will be held by the polling task
* at this point and this Take will cause the polling task to inherit
* the priority of this task. In this case the block time must be
* long enough to ensure the polling task will execute again before the
* block time expires. If the block time does expire then the error
* flag will be set here. */
if( xSemaphoreTakeRecursive( xMutex, recmu15ms_DELAY ) != pdPASS )
{
xErrorOccurred = pdTRUE;
}
The first time through the mutex will be immediately available, on /* Ensure the other task attempting to access the mutex (and the
subsequent times through the mutex will be held by the polling task * other demo tasks) are able to execute to ensure they either block
at this point and this Take will cause the polling task to inherit * (where a block time is specified) or return an error (where no
the priority of this task. In this case the block time must be * block time is specified) as the mutex is held by this task. */
long enough to ensure the polling task will execute again before the vTaskDelay( recmuSHORT_DELAY );
block time expires. If the block time does expire then the error }
flag will be set here. */
if( xSemaphoreTakeRecursive( xMutex, recmu15ms_DELAY ) != pdPASS )
{
xErrorOccurred = pdTRUE;
}
/* Ensure the other task attempting to access the mutex (and the /* For each time we took the mutex, give it back. */
other demo tasks) are able to execute to ensure they either block for( ux = 0; ux < recmuMAX_COUNT; ux++ )
(where a block time is specified) or return an error (where no {
block time is specified) as the mutex is held by this task. */ /* Ensure the other task attempting to access the mutex (and the
vTaskDelay( recmuSHORT_DELAY ); * other demo tasks) are able to execute. */
} vTaskDelay( recmuSHORT_DELAY );
/* For each time we took the mutex, give it back. */ /* We should now be able to give the mutex as many times as we
for( ux = 0; ux < recmuMAX_COUNT; ux++ ) * took it. When the mutex is available again the Blocking task
{ * should be unblocked but not run because it has a lower priority
/* Ensure the other task attempting to access the mutex (and the * than this task. The polling task should also not run at this point
other demo tasks) are able to execute. */ * as it too has a lower priority than this task. */
vTaskDelay( recmuSHORT_DELAY ); if( xSemaphoreGiveRecursive( xMutex ) != pdPASS )
{
xErrorOccurred = pdTRUE;
}
/* We should now be able to give the mutex as many times as we #if ( configUSE_PREEMPTION == 0 )
took it. When the mutex is available again the Blocking task taskYIELD();
should be unblocked but not run because it has a lower priority #endif
than this task. The polling task should also not run at this point }
as it too has a lower priority than this task. */
if( xSemaphoreGiveRecursive( xMutex ) != pdPASS )
{
xErrorOccurred = pdTRUE;
}
#if( configUSE_PREEMPTION == 0 ) /* Having given it back the same number of times as it was taken, we
taskYIELD(); * should no longer be the mutex owner, so the next give should fail. */
#endif if( xSemaphoreGiveRecursive( xMutex ) == pdPASS )
} {
xErrorOccurred = pdTRUE;
}
/* Having given it back the same number of times as it was taken, we /* Keep count of the number of cycles this task has performed so a
should no longer be the mutex owner, so the next give should fail. */ * stall can be detected. */
if( xSemaphoreGiveRecursive( xMutex ) == pdPASS ) uxControllingCycles++;
{
xErrorOccurred = pdTRUE;
}
/* Keep count of the number of cycles this task has performed so a /* Suspend ourselves so the blocking task can execute. */
stall can be detected. */ xControllingIsSuspended = pdTRUE;
uxControllingCycles++; vTaskSuspend( NULL );
xControllingIsSuspended = pdFALSE;
/* Suspend ourselves so the blocking task can execute. */ }
xControllingIsSuspended = pdTRUE;
vTaskSuspend( NULL );
xControllingIsSuspended = pdFALSE;
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvRecursiveMutexBlockingTask( void *pvParameters ) static void prvRecursiveMutexBlockingTask( void * pvParameters )
{ {
/* Just to remove compiler warning. */ /* Just to remove compiler warning. */
( void ) pvParameters; ( void ) pvParameters;
for( ;; ) for( ; ; )
{ {
/* This task will run while the controlling task is blocked, and the /* This task will run while the controlling task is blocked, and the
controlling task will block only once it has the mutex - therefore * controlling task will block only once it has the mutex - therefore
this call should block until the controlling task has given up the * this call should block until the controlling task has given up the
mutex, and not actually execute past this call until the controlling * mutex, and not actually execute past this call until the controlling
task is suspended. portMAX_DELAY - 1 is used instead of portMAX_DELAY * task is suspended. portMAX_DELAY - 1 is used instead of portMAX_DELAY
to ensure the task's state is reported as Blocked and not Suspended in * to ensure the task's state is reported as Blocked and not Suspended in
a later call to configASSERT() (within the polling task). */ * a later call to configASSERT() (within the polling task). */
if( xSemaphoreTakeRecursive( xMutex, ( portMAX_DELAY - 1 ) ) == pdPASS ) if( xSemaphoreTakeRecursive( xMutex, ( portMAX_DELAY - 1 ) ) == pdPASS )
{ {
if( xControllingIsSuspended != pdTRUE ) if( xControllingIsSuspended != pdTRUE )
{ {
/* Did not expect to execute until the controlling task was /* Did not expect to execute until the controlling task was
suspended. */ * suspended. */
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
else else
{ {
/* Give the mutex back before suspending ourselves to allow /* Give the mutex back before suspending ourselves to allow
the polling task to obtain the mutex. */ * the polling task to obtain the mutex. */
if( xSemaphoreGiveRecursive( xMutex ) != pdPASS ) if( xSemaphoreGiveRecursive( xMutex ) != pdPASS )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
xBlockingIsSuspended = pdTRUE; xBlockingIsSuspended = pdTRUE;
vTaskSuspend( NULL ); vTaskSuspend( NULL );
xBlockingIsSuspended = pdFALSE; xBlockingIsSuspended = pdFALSE;
} }
} }
else else
{ {
/* We should not leave the xSemaphoreTakeRecursive() function /* We should not leave the xSemaphoreTakeRecursive() function
until the mutex was obtained. */ * until the mutex was obtained. */
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
/* The controlling and blocking tasks should be in lock step. */ /* The controlling and blocking tasks should be in lock step. */
if( uxControllingCycles != (UBaseType_t) ( uxBlockingCycles + 1 ) ) if( uxControllingCycles != ( UBaseType_t ) ( uxBlockingCycles + 1 ) )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
/* Keep count of the number of cycles this task has performed so a /* Keep count of the number of cycles this task has performed so a
stall can be detected. */ * stall can be detected. */
uxBlockingCycles++; uxBlockingCycles++;
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvRecursiveMutexPollingTask( void *pvParameters ) static void prvRecursiveMutexPollingTask( void * pvParameters )
{ {
/* Just to remove compiler warning. */ /* Just to remove compiler warning. */
( void ) pvParameters; ( void ) pvParameters;
for( ;; ) for( ; ; )
{ {
/* Keep attempting to obtain the mutex. It should only be obtained when /* Keep attempting to obtain the mutex. It should only be obtained when
the blocking task has suspended itself, which in turn should only * the blocking task has suspended itself, which in turn should only
happen when the controlling task is also suspended. */ * happen when the controlling task is also suspended. */
if( xSemaphoreTakeRecursive( xMutex, recmuNO_DELAY ) == pdPASS ) if( xSemaphoreTakeRecursive( xMutex, recmuNO_DELAY ) == pdPASS )
{ {
#if( INCLUDE_eTaskGetState == 1 ) #if ( INCLUDE_eTaskGetState == 1 )
{ {
configASSERT( eTaskGetState( xControllingTaskHandle ) == eSuspended ); configASSERT( eTaskGetState( xControllingTaskHandle ) == eSuspended );
configASSERT( eTaskGetState( xBlockingTaskHandle ) == eSuspended ); configASSERT( eTaskGetState( xBlockingTaskHandle ) == eSuspended );
} }
#endif /* INCLUDE_eTaskGetState */ #endif /* INCLUDE_eTaskGetState */
/* Is the blocking task suspended? */ /* Is the blocking task suspended? */
if( ( xBlockingIsSuspended != pdTRUE ) || ( xControllingIsSuspended != pdTRUE ) ) if( ( xBlockingIsSuspended != pdTRUE ) || ( xControllingIsSuspended != pdTRUE ) )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
else else
{ {
/* Keep count of the number of cycles this task has performed /* Keep count of the number of cycles this task has performed
so a stall can be detected. */ * so a stall can be detected. */
uxPollingCycles++; uxPollingCycles++;
/* We can resume the other tasks here even though they have a /* We can resume the other tasks here even though they have a
higher priority than the polling task. When they execute they * higher priority than the polling task. When they execute they
will attempt to obtain the mutex but fail because the polling * will attempt to obtain the mutex but fail because the polling
task is still the mutex holder. The polling task (this task) * task is still the mutex holder. The polling task (this task)
will then inherit the higher priority. The Blocking task will * will then inherit the higher priority. The Blocking task will
block indefinitely when it attempts to obtain the mutex, the * block indefinitely when it attempts to obtain the mutex, the
Controlling task will only block for a fixed period and an * Controlling task will only block for a fixed period and an
error will be latched if the polling task has not returned the * error will be latched if the polling task has not returned the
mutex by the time this fixed period has expired. */ * mutex by the time this fixed period has expired. */
vTaskResume( xBlockingTaskHandle ); vTaskResume( xBlockingTaskHandle );
#if( configUSE_PREEMPTION == 0 ) #if ( configUSE_PREEMPTION == 0 )
taskYIELD(); taskYIELD();
#endif #endif
vTaskResume( xControllingTaskHandle ); vTaskResume( xControllingTaskHandle );
#if( configUSE_PREEMPTION == 0 ) #if ( configUSE_PREEMPTION == 0 )
taskYIELD(); taskYIELD();
#endif #endif
/* The other two tasks should now have executed and no longer /* The other two tasks should now have executed and no longer
be suspended. */ * be suspended. */
if( ( xBlockingIsSuspended == pdTRUE ) || ( xControllingIsSuspended == pdTRUE ) ) if( ( xBlockingIsSuspended == pdTRUE ) || ( xControllingIsSuspended == pdTRUE ) )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
#if( INCLUDE_uxTaskPriorityGet == 1 ) #if ( INCLUDE_uxTaskPriorityGet == 1 )
{ {
/* Check priority inherited. */ /* Check priority inherited. */
configASSERT( uxTaskPriorityGet( NULL ) == recmuCONTROLLING_TASK_PRIORITY ); configASSERT( uxTaskPriorityGet( NULL ) == recmuCONTROLLING_TASK_PRIORITY );
} }
#endif /* INCLUDE_uxTaskPriorityGet */ #endif /* INCLUDE_uxTaskPriorityGet */
#if( INCLUDE_eTaskGetState == 1 ) #if ( INCLUDE_eTaskGetState == 1 )
{ {
configASSERT( eTaskGetState( xControllingTaskHandle ) == eBlocked ); configASSERT( eTaskGetState( xControllingTaskHandle ) == eBlocked );
configASSERT( eTaskGetState( xBlockingTaskHandle ) == eBlocked ); configASSERT( eTaskGetState( xBlockingTaskHandle ) == eBlocked );
} }
#endif /* INCLUDE_eTaskGetState */ #endif /* INCLUDE_eTaskGetState */
/* Release the mutex, disinheriting the higher priority again. */ /* Release the mutex, disinheriting the higher priority again. */
if( xSemaphoreGiveRecursive( xMutex ) != pdPASS ) if( xSemaphoreGiveRecursive( xMutex ) != pdPASS )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
#if( INCLUDE_uxTaskPriorityGet == 1 ) #if ( INCLUDE_uxTaskPriorityGet == 1 )
{ {
/* Check priority disinherited. */ /* Check priority disinherited. */
configASSERT( uxTaskPriorityGet( NULL ) == recmuPOLLING_TASK_PRIORITY ); configASSERT( uxTaskPriorityGet( NULL ) == recmuPOLLING_TASK_PRIORITY );
} }
#endif /* INCLUDE_uxTaskPriorityGet */ #endif /* INCLUDE_uxTaskPriorityGet */
} }
} }
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
{ {
taskYIELD(); taskYIELD();
} }
#endif #endif
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running. */ /* This is called to check that all the created tasks are still running. */
BaseType_t xAreRecursiveMutexTasksStillRunning( void ) BaseType_t xAreRecursiveMutexTasksStillRunning( void )
{ {
BaseType_t xReturn; BaseType_t xReturn;
static UBaseType_t uxLastControllingCycles = 0, uxLastBlockingCycles = 0, uxLastPollingCycles = 0; static UBaseType_t uxLastControllingCycles = 0, uxLastBlockingCycles = 0, uxLastPollingCycles = 0;
/* Is the controlling task still cycling? */ /* Is the controlling task still cycling? */
if( uxLastControllingCycles == uxControllingCycles ) if( uxLastControllingCycles == uxControllingCycles )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
else else
{ {
uxLastControllingCycles = uxControllingCycles; uxLastControllingCycles = uxControllingCycles;
} }
/* Is the blocking task still cycling? */ /* Is the blocking task still cycling? */
if( uxLastBlockingCycles == uxBlockingCycles ) if( uxLastBlockingCycles == uxBlockingCycles )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
else else
{ {
uxLastBlockingCycles = uxBlockingCycles; uxLastBlockingCycles = uxBlockingCycles;
} }
/* Is the polling task still cycling? */ /* Is the polling task still cycling? */
if( uxLastPollingCycles == uxPollingCycles ) if( uxLastPollingCycles == uxPollingCycles )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
else else
{ {
uxLastPollingCycles = uxPollingCycles; uxLastPollingCycles = uxPollingCycles;
} }
if( xErrorOccurred == pdTRUE ) if( xErrorOccurred == pdTRUE )
{ {
xReturn = pdFAIL; xReturn = pdFAIL;
} }
else else
{ {
xReturn = pdPASS; xReturn = pdPASS;
} }
return xReturn; return xReturn;
} }

View file

@ -60,14 +60,14 @@
#include "semtest.h" #include "semtest.h"
/* The value to which the shared variables are counted. */ /* The value to which the shared variables are counted. */
#define semtstBLOCKING_EXPECTED_VALUE ( ( uint32_t ) 0xfff ) #define semtstBLOCKING_EXPECTED_VALUE ( ( uint32_t ) 0xfff )
#define semtstNON_BLOCKING_EXPECTED_VALUE ( ( uint32_t ) 0xff ) #define semtstNON_BLOCKING_EXPECTED_VALUE ( ( uint32_t ) 0xff )
#define semtstSTACK_SIZE configMINIMAL_STACK_SIZE #define semtstSTACK_SIZE configMINIMAL_STACK_SIZE
#define semtstNUM_TASKS ( 4 ) #define semtstNUM_TASKS ( 4 )
#define semtstDELAY_FACTOR ( ( TickType_t ) 10 ) #define semtstDELAY_FACTOR ( ( TickType_t ) 10 )
/* The task function as described at the top of the file. */ /* The task function as described at the top of the file. */
static portTASK_FUNCTION_PROTO( prvSemaphoreTest, pvParameters ); static portTASK_FUNCTION_PROTO( prvSemaphoreTest, pvParameters );
@ -75,9 +75,9 @@ static portTASK_FUNCTION_PROTO( prvSemaphoreTest, pvParameters );
/* Structure used to pass parameters to each task. */ /* Structure used to pass parameters to each task. */
typedef struct SEMAPHORE_PARAMETERS typedef struct SEMAPHORE_PARAMETERS
{ {
SemaphoreHandle_t xSemaphore; SemaphoreHandle_t xSemaphore;
volatile uint32_t *pulSharedVariable; volatile uint32_t * pulSharedVariable;
TickType_t xBlockTime; TickType_t xBlockTime;
} xSemaphoreParameters; } xSemaphoreParameters;
/* Variables used to check that all the tasks are still running without errors. */ /* Variables used to check that all the tasks are still running without errors. */
@ -88,185 +88,185 @@ static volatile short sNextCheckVariable = 0;
void vStartSemaphoreTasks( UBaseType_t uxPriority ) void vStartSemaphoreTasks( UBaseType_t uxPriority )
{ {
xSemaphoreParameters *pxFirstSemaphoreParameters, *pxSecondSemaphoreParameters; xSemaphoreParameters * pxFirstSemaphoreParameters, * pxSecondSemaphoreParameters;
const TickType_t xBlockTime = ( TickType_t ) 100; const TickType_t xBlockTime = ( TickType_t ) 100;
/* Create the structure used to pass parameters to the first two tasks. */ /* Create the structure used to pass parameters to the first two tasks. */
pxFirstSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) ); pxFirstSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );
if( pxFirstSemaphoreParameters != NULL ) if( pxFirstSemaphoreParameters != NULL )
{ {
/* Create the semaphore used by the first two tasks. */ /* Create the semaphore used by the first two tasks. */
pxFirstSemaphoreParameters->xSemaphore = xSemaphoreCreateBinary(); pxFirstSemaphoreParameters->xSemaphore = xSemaphoreCreateBinary();
if( pxFirstSemaphoreParameters->xSemaphore != NULL ) if( pxFirstSemaphoreParameters->xSemaphore != NULL )
{ {
xSemaphoreGive( pxFirstSemaphoreParameters->xSemaphore ); xSemaphoreGive( pxFirstSemaphoreParameters->xSemaphore );
/* Create the variable which is to be shared by the first two tasks. */ /* Create the variable which is to be shared by the first two tasks. */
pxFirstSemaphoreParameters->pulSharedVariable = ( uint32_t * ) pvPortMalloc( sizeof( uint32_t ) ); pxFirstSemaphoreParameters->pulSharedVariable = ( uint32_t * ) pvPortMalloc( sizeof( uint32_t ) );
/* Initialise the share variable to the value the tasks expect. */ /* Initialise the share variable to the value the tasks expect. */
*( pxFirstSemaphoreParameters->pulSharedVariable ) = semtstNON_BLOCKING_EXPECTED_VALUE; *( pxFirstSemaphoreParameters->pulSharedVariable ) = semtstNON_BLOCKING_EXPECTED_VALUE;
/* The first two tasks do not block on semaphore calls. */ /* The first two tasks do not block on semaphore calls. */
pxFirstSemaphoreParameters->xBlockTime = ( TickType_t ) 0; pxFirstSemaphoreParameters->xBlockTime = ( TickType_t ) 0;
/* Spawn the first two tasks. As they poll they operate at the idle priority. */ /* Spawn the first two tasks. As they poll they operate at the idle priority. */
xTaskCreate( prvSemaphoreTest, "PolSEM1", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( TaskHandle_t * ) NULL ); xTaskCreate( prvSemaphoreTest, "PolSEM1", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( TaskHandle_t * ) NULL );
xTaskCreate( prvSemaphoreTest, "PolSEM2", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( TaskHandle_t * ) NULL ); xTaskCreate( prvSemaphoreTest, "PolSEM2", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( TaskHandle_t * ) NULL );
/* vQueueAddToRegistry() adds the semaphore to the registry, if one /* vQueueAddToRegistry() adds the semaphore to the registry, if one
is in use. The registry is provided as a means for kernel aware * is in use. The registry is provided as a means for kernel aware
debuggers to locate semaphores and has no purpose if a kernel aware * debuggers to locate semaphores and has no purpose if a kernel aware
debugger is not being used. The call to vQueueAddToRegistry() will * debugger is not being used. The call to vQueueAddToRegistry() will
be removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not * be removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not
defined or is defined to be less than 1. */ * defined or is defined to be less than 1. */
vQueueAddToRegistry( ( QueueHandle_t ) pxFirstSemaphoreParameters->xSemaphore, "Counting_Sem_1" ); vQueueAddToRegistry( ( QueueHandle_t ) pxFirstSemaphoreParameters->xSemaphore, "Counting_Sem_1" );
} }
} }
/* Do exactly the same to create the second set of tasks, only this time /* Do exactly the same to create the second set of tasks, only this time
provide a block time for the semaphore calls. */ * provide a block time for the semaphore calls. */
pxSecondSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) ); pxSecondSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );
if( pxSecondSemaphoreParameters != NULL )
{
pxSecondSemaphoreParameters->xSemaphore = xSemaphoreCreateBinary();
if( pxSecondSemaphoreParameters->xSemaphore != NULL ) if( pxSecondSemaphoreParameters != NULL )
{ {
xSemaphoreGive( pxSecondSemaphoreParameters->xSemaphore ); pxSecondSemaphoreParameters->xSemaphore = xSemaphoreCreateBinary();
pxSecondSemaphoreParameters->pulSharedVariable = ( uint32_t * ) pvPortMalloc( sizeof( uint32_t ) ); if( pxSecondSemaphoreParameters->xSemaphore != NULL )
*( pxSecondSemaphoreParameters->pulSharedVariable ) = semtstBLOCKING_EXPECTED_VALUE; {
pxSecondSemaphoreParameters->xBlockTime = xBlockTime / portTICK_PERIOD_MS; xSemaphoreGive( pxSecondSemaphoreParameters->xSemaphore );
xTaskCreate( prvSemaphoreTest, "BlkSEM1", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( TaskHandle_t * ) NULL ); pxSecondSemaphoreParameters->pulSharedVariable = ( uint32_t * ) pvPortMalloc( sizeof( uint32_t ) );
xTaskCreate( prvSemaphoreTest, "BlkSEM2", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( TaskHandle_t * ) NULL ); *( pxSecondSemaphoreParameters->pulSharedVariable ) = semtstBLOCKING_EXPECTED_VALUE;
pxSecondSemaphoreParameters->xBlockTime = xBlockTime / portTICK_PERIOD_MS;
/* vQueueAddToRegistry() adds the semaphore to the registry, if one xTaskCreate( prvSemaphoreTest, "BlkSEM1", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( TaskHandle_t * ) NULL );
is in use. The registry is provided as a means for kernel aware xTaskCreate( prvSemaphoreTest, "BlkSEM2", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( TaskHandle_t * ) NULL );
debuggers to locate semaphores and has no purpose if a kernel aware
debugger is not being used. The call to vQueueAddToRegistry() will /* vQueueAddToRegistry() adds the semaphore to the registry, if one
be removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not * is in use. The registry is provided as a means for kernel aware
defined or is defined to be less than 1. */ * debuggers to locate semaphores and has no purpose if a kernel aware
vQueueAddToRegistry( ( QueueHandle_t ) pxSecondSemaphoreParameters->xSemaphore, "Counting_Sem_2" ); * debugger is not being used. The call to vQueueAddToRegistry() will
} * be removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not
} * defined or is defined to be less than 1. */
vQueueAddToRegistry( ( QueueHandle_t ) pxSecondSemaphoreParameters->xSemaphore, "Counting_Sem_2" );
}
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static portTASK_FUNCTION( prvSemaphoreTest, pvParameters ) static portTASK_FUNCTION( prvSemaphoreTest, pvParameters )
{ {
xSemaphoreParameters *pxParameters; xSemaphoreParameters * pxParameters;
volatile uint32_t *pulSharedVariable, ulExpectedValue; volatile uint32_t * pulSharedVariable, ulExpectedValue;
uint32_t ulCounter; uint32_t ulCounter;
short sError = pdFALSE, sCheckVariableToUse; short sError = pdFALSE, sCheckVariableToUse;
/* See which check variable to use. sNextCheckVariable is not semaphore /* See which check variable to use. sNextCheckVariable is not semaphore
protected! */ * protected! */
portENTER_CRITICAL(); portENTER_CRITICAL();
sCheckVariableToUse = sNextCheckVariable; sCheckVariableToUse = sNextCheckVariable;
sNextCheckVariable++; sNextCheckVariable++;
portEXIT_CRITICAL(); portEXIT_CRITICAL();
/* A structure is passed in as the parameter. This contains the shared /* A structure is passed in as the parameter. This contains the shared
variable being guarded. */ * variable being guarded. */
pxParameters = ( xSemaphoreParameters * ) pvParameters; pxParameters = ( xSemaphoreParameters * ) pvParameters;
pulSharedVariable = pxParameters->pulSharedVariable; pulSharedVariable = pxParameters->pulSharedVariable;
/* If we are blocking we use a much higher count to ensure loads of context /* If we are blocking we use a much higher count to ensure loads of context
switches occur during the count. */ * switches occur during the count. */
if( pxParameters->xBlockTime > ( TickType_t ) 0 ) if( pxParameters->xBlockTime > ( TickType_t ) 0 )
{ {
ulExpectedValue = semtstBLOCKING_EXPECTED_VALUE; ulExpectedValue = semtstBLOCKING_EXPECTED_VALUE;
} }
else else
{ {
ulExpectedValue = semtstNON_BLOCKING_EXPECTED_VALUE; ulExpectedValue = semtstNON_BLOCKING_EXPECTED_VALUE;
} }
for( ;; ) for( ; ; )
{ {
/* Try to obtain the semaphore. */ /* Try to obtain the semaphore. */
if( xSemaphoreTake( pxParameters->xSemaphore, pxParameters->xBlockTime ) == pdPASS ) if( xSemaphoreTake( pxParameters->xSemaphore, pxParameters->xBlockTime ) == pdPASS )
{ {
/* We have the semaphore and so expect any other tasks using the /* We have the semaphore and so expect any other tasks using the
shared variable to have left it in the state we expect to find * shared variable to have left it in the state we expect to find
it. */ * it. */
if( *pulSharedVariable != ulExpectedValue ) if( *pulSharedVariable != ulExpectedValue )
{ {
sError = pdTRUE; sError = pdTRUE;
} }
/* Clear the variable, then count it back up to the expected value /* Clear the variable, then count it back up to the expected value
before releasing the semaphore. Would expect a context switch or * before releasing the semaphore. Would expect a context switch or
two during this time. */ * two during this time. */
for( ulCounter = ( uint32_t ) 0; ulCounter <= ulExpectedValue; ulCounter++ ) for( ulCounter = ( uint32_t ) 0; ulCounter <= ulExpectedValue; ulCounter++ )
{ {
*pulSharedVariable = ulCounter; *pulSharedVariable = ulCounter;
if( *pulSharedVariable != ulCounter )
{
sError = pdTRUE;
}
}
/* Release the semaphore, and if no errors have occurred increment the check if( *pulSharedVariable != ulCounter )
variable. */ {
if( xSemaphoreGive( pxParameters->xSemaphore ) == pdFALSE ) sError = pdTRUE;
{ }
sError = pdTRUE; }
}
if( sError == pdFALSE ) /* Release the semaphore, and if no errors have occurred increment the check
{ * variable. */
if( sCheckVariableToUse < semtstNUM_TASKS ) if( xSemaphoreGive( pxParameters->xSemaphore ) == pdFALSE )
{ {
( sCheckVariables[ sCheckVariableToUse ] )++; sError = pdTRUE;
} }
}
/* If we have a block time then we are running at a priority higher if( sError == pdFALSE )
than the idle priority. This task takes a long time to complete {
a cycle (deliberately so to test the guarding) so will be starving if( sCheckVariableToUse < semtstNUM_TASKS )
out lower priority tasks. Block for some time to allow give lower {
priority tasks some processor time. */ ( sCheckVariables[ sCheckVariableToUse ] )++;
if( pxParameters->xBlockTime != ( TickType_t ) 0 ) }
{ }
vTaskDelay( pxParameters->xBlockTime * semtstDELAY_FACTOR );
}
} /* If we have a block time then we are running at a priority higher
else * than the idle priority. This task takes a long time to complete
{ * a cycle (deliberately so to test the guarding) so will be starving
if( pxParameters->xBlockTime == ( TickType_t ) 0 ) * out lower priority tasks. Block for some time to allow give lower
{ * priority tasks some processor time. */
/* We have not got the semaphore yet, so no point using the if( pxParameters->xBlockTime != ( TickType_t ) 0 )
processor. We are not blocking when attempting to obtain the {
semaphore. */ vTaskDelay( pxParameters->xBlockTime * semtstDELAY_FACTOR );
taskYIELD(); }
} }
} else
} {
if( pxParameters->xBlockTime == ( TickType_t ) 0 )
{
/* We have not got the semaphore yet, so no point using the
* processor. We are not blocking when attempting to obtain the
* semaphore. */
taskYIELD();
}
}
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running. */ /* This is called to check that all the created tasks are still running. */
BaseType_t xAreSemaphoreTasksStillRunning( void ) BaseType_t xAreSemaphoreTasksStillRunning( void )
{ {
static short sLastCheckVariables[ semtstNUM_TASKS ] = { 0 }; static short sLastCheckVariables[ semtstNUM_TASKS ] = { 0 };
BaseType_t xTask, xReturn = pdTRUE; BaseType_t xTask, xReturn = pdTRUE;
for( xTask = 0; xTask < semtstNUM_TASKS; xTask++ ) for( xTask = 0; xTask < semtstNUM_TASKS; xTask++ )
{ {
if( sLastCheckVariables[ xTask ] == sCheckVariables[ xTask ] ) if( sLastCheckVariables[ xTask ] == sCheckVariables[ xTask ] )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
} }
sLastCheckVariables[ xTask ] = sCheckVariables[ xTask ]; sLastCheckVariables[ xTask ] = sCheckVariables[ xTask ];
} }
return xReturn; return xReturn;
} }

View file

@ -48,254 +48,255 @@
/* Demo program include files. */ /* Demo program include files. */
#include "flop.h" #include "flop.h"
#define mathSTACK_SIZE configMINIMAL_STACK_SIZE #define mathSTACK_SIZE configMINIMAL_STACK_SIZE
#define mathNUMBER_OF_TASKS ( 8 ) #define mathNUMBER_OF_TASKS ( 8 )
/* Four tasks, each of which performs a different floating point calculation. /* Four tasks, each of which performs a different floating point calculation.
Each of the four is created twice. */ * Each of the four is created twice. */
static portTASK_FUNCTION_PROTO( vCompetingMathTask1, pvParameters ); static portTASK_FUNCTION_PROTO( vCompetingMathTask1, pvParameters );
static portTASK_FUNCTION_PROTO( vCompetingMathTask2, pvParameters ); static portTASK_FUNCTION_PROTO( vCompetingMathTask2, pvParameters );
static portTASK_FUNCTION_PROTO( vCompetingMathTask3, pvParameters ); static portTASK_FUNCTION_PROTO( vCompetingMathTask3, pvParameters );
static portTASK_FUNCTION_PROTO( vCompetingMathTask4, pvParameters ); static portTASK_FUNCTION_PROTO( vCompetingMathTask4, pvParameters );
/* These variables are used to check that all the tasks are still running. If a /* These variables are used to check that all the tasks are still running. If a
task gets a calculation wrong it will * task gets a calculation wrong it will
stop incrementing its check variable. */ * stop incrementing its check variable. */
static volatile uint16_t usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( uint16_t ) 0 }; static volatile uint16_t usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( uint16_t ) 0 };
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vStartMathTasks( UBaseType_t uxPriority ) void vStartMathTasks( UBaseType_t uxPriority )
{ {
xTaskCreate( vCompetingMathTask1, "Math1", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL ); xTaskCreate( vCompetingMathTask1, "Math1", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask2, "Math2", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL ); xTaskCreate( vCompetingMathTask2, "Math2", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask3, "Math3", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL ); xTaskCreate( vCompetingMathTask3, "Math3", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask4, "Math4", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL ); xTaskCreate( vCompetingMathTask4, "Math4", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask1, "Math5", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 4 ] ), uxPriority, NULL ); xTaskCreate( vCompetingMathTask1, "Math5", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 4 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask2, "Math6", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 5 ] ), uxPriority, NULL ); xTaskCreate( vCompetingMathTask2, "Math6", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 5 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask3, "Math7", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 6 ] ), uxPriority, NULL ); xTaskCreate( vCompetingMathTask3, "Math7", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 6 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask4, "Math8", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 7 ] ), uxPriority, NULL ); xTaskCreate( vCompetingMathTask4, "Math8", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 7 ] ), uxPriority, NULL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static portTASK_FUNCTION( vCompetingMathTask1, pvParameters ) static portTASK_FUNCTION( vCompetingMathTask1, pvParameters )
{ {
volatile float f1, f2, f3, f4; volatile float f1, f2, f3, f4;
volatile uint16_t *pusTaskCheckVariable; volatile uint16_t * pusTaskCheckVariable;
volatile float fAnswer; volatile float fAnswer;
short sError = pdFALSE; short sError = pdFALSE;
f1 = 123.4567F; f1 = 123.4567F;
f2 = 2345.6789F; f2 = 2345.6789F;
f3 = -918.222F; f3 = -918.222F;
fAnswer = ( f1 + f2 ) * f3; fAnswer = ( f1 + f2 ) * f3;
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( uint16_t * ) pvParameters; pusTaskCheckVariable = ( uint16_t * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */ /* Keep performing a calculation and checking the result against a constant. */
for(;;) for( ; ; )
{ {
f1 = 123.4567F; f1 = 123.4567F;
f2 = 2345.6789F; f2 = 2345.6789F;
f3 = -918.222F; f3 = -918.222F;
f4 = ( f1 + f2 ) * f3; f4 = ( f1 + f2 ) * f3;
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
taskYIELD(); taskYIELD();
#endif #endif
/* If the calculation does not match the expected constant, stop the /* If the calculation does not match the expected constant, stop the
increment of the check variable. */ * increment of the check variable. */
if( fabs( f4 - fAnswer ) > 0.001F ) if( fabs( f4 - fAnswer ) > 0.001F )
{ {
sError = pdTRUE; sError = pdTRUE;
} }
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct, increment the check /* If the calculation has always been correct, increment the check
variable so we know this task is still running okay. */ * variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++; ( *pusTaskCheckVariable )++;
} }
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
taskYIELD(); taskYIELD();
#endif #endif
}
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static portTASK_FUNCTION( vCompetingMathTask2, pvParameters ) static portTASK_FUNCTION( vCompetingMathTask2, pvParameters )
{ {
volatile float f1, f2, f3, f4; volatile float f1, f2, f3, f4;
volatile uint16_t *pusTaskCheckVariable; volatile uint16_t * pusTaskCheckVariable;
volatile float fAnswer; volatile float fAnswer;
short sError = pdFALSE; short sError = pdFALSE;
f1 = -389.38F; f1 = -389.38F;
f2 = 32498.2F; f2 = 32498.2F;
f3 = -2.0001F; f3 = -2.0001F;
fAnswer = ( f1 / f2 ) * f3; fAnswer = ( f1 / f2 ) * f3;
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( uint16_t * ) pvParameters; pusTaskCheckVariable = ( uint16_t * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */ /* Keep performing a calculation and checking the result against a constant. */
for( ;; ) for( ; ; )
{ {
f1 = -389.38F; f1 = -389.38F;
f2 = 32498.2F; f2 = 32498.2F;
f3 = -2.0001F; f3 = -2.0001F;
f4 = ( f1 / f2 ) * f3; f4 = ( f1 / f2 ) * f3;
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
taskYIELD(); taskYIELD();
#endif #endif
/* If the calculation does not match the expected constant, stop the /* If the calculation does not match the expected constant, stop the
increment of the check variable. */ * increment of the check variable. */
if( fabs( f4 - fAnswer ) > 0.001F ) if( fabs( f4 - fAnswer ) > 0.001F )
{ {
sError = pdTRUE; sError = pdTRUE;
} }
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct, increment the check /* If the calculation has always been correct, increment the check
variable so we know * variable so we know
this task is still running okay. */ * this task is still running okay. */
( *pusTaskCheckVariable )++; ( *pusTaskCheckVariable )++;
} }
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
taskYIELD(); taskYIELD();
#endif #endif
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static portTASK_FUNCTION( vCompetingMathTask3, pvParameters ) static portTASK_FUNCTION( vCompetingMathTask3, pvParameters )
{ {
volatile float *pfArray, fTotal1, fTotal2, fDifference, fPosition; volatile float * pfArray, fTotal1, fTotal2, fDifference, fPosition;
volatile uint16_t *pusTaskCheckVariable; volatile uint16_t * pusTaskCheckVariable;
const size_t xArraySize = 10; const size_t xArraySize = 10;
size_t xPosition; size_t xPosition;
short sError = pdFALSE; short sError = pdFALSE;
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( uint16_t * ) pvParameters; pusTaskCheckVariable = ( uint16_t * ) pvParameters;
pfArray = ( float * ) pvPortMalloc( xArraySize * sizeof( float ) ); pfArray = ( float * ) pvPortMalloc( xArraySize * sizeof( float ) );
/* Keep filling an array, keeping a running total of the values placed in the /* Keep filling an array, keeping a running total of the values placed in the
array. Then run through the array adding up all the values. If the two totals * array. Then run through the array adding up all the values. If the two totals
do not match, stop the check variable from incrementing. */ * do not match, stop the check variable from incrementing. */
for( ;; ) for( ; ; )
{ {
fTotal1 = 0.0F; fTotal1 = 0.0F;
fTotal2 = 0.0F; fTotal2 = 0.0F;
fPosition = 0.0F; fPosition = 0.0F;
for( xPosition = 0; xPosition < xArraySize; xPosition++ ) for( xPosition = 0; xPosition < xArraySize; xPosition++ )
{ {
pfArray[ xPosition ] = fPosition + 5.5F; pfArray[ xPosition ] = fPosition + 5.5F;
fTotal1 += fPosition + 5.5F; fTotal1 += fPosition + 5.5F;
} }
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
taskYIELD(); taskYIELD();
#endif #endif
for( xPosition = 0; xPosition < xArraySize; xPosition++ ) for( xPosition = 0; xPosition < xArraySize; xPosition++ )
{ {
fTotal2 += pfArray[ xPosition ]; fTotal2 += pfArray[ xPosition ];
} }
fDifference = fTotal1 - fTotal2; fDifference = fTotal1 - fTotal2;
if( fabs( fDifference ) > 0.001F )
{
sError = pdTRUE;
}
#if configUSE_PREEMPTION == 0 if( fabs( fDifference ) > 0.001F )
taskYIELD(); {
#endif sError = pdTRUE;
}
if( sError == pdFALSE ) #if configUSE_PREEMPTION == 0
{ taskYIELD();
/* If the calculation has always been correct, increment the check #endif
variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++; if( sError == pdFALSE )
} {
} /* If the calculation has always been correct, increment the check
* variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++;
}
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static portTASK_FUNCTION( vCompetingMathTask4, pvParameters ) static portTASK_FUNCTION( vCompetingMathTask4, pvParameters )
{ {
volatile float *pfArray, fTotal1, fTotal2, fDifference, fPosition; volatile float * pfArray, fTotal1, fTotal2, fDifference, fPosition;
volatile uint16_t *pusTaskCheckVariable; volatile uint16_t * pusTaskCheckVariable;
const size_t xArraySize = 10; const size_t xArraySize = 10;
size_t xPosition; size_t xPosition;
short sError = pdFALSE; short sError = pdFALSE;
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( uint16_t * ) pvParameters; pusTaskCheckVariable = ( uint16_t * ) pvParameters;
pfArray = ( float * ) pvPortMalloc( xArraySize * sizeof( float ) ); pfArray = ( float * ) pvPortMalloc( xArraySize * sizeof( float ) );
/* Keep filling an array, keeping a running total of the values placed in the /* Keep filling an array, keeping a running total of the values placed in the
array. Then run through the array adding up all the values. If the two totals * array. Then run through the array adding up all the values. If the two totals
do not match, stop the check variable from incrementing. */ * do not match, stop the check variable from incrementing. */
for( ;; ) for( ; ; )
{ {
fTotal1 = 0.0F; fTotal1 = 0.0F;
fTotal2 = 0.0F; fTotal2 = 0.0F;
fPosition = 0.0F; fPosition = 0.0F;
for( xPosition = 0; xPosition < xArraySize; xPosition++ ) for( xPosition = 0; xPosition < xArraySize; xPosition++ )
{ {
pfArray[ xPosition ] = fPosition * 12.123F; pfArray[ xPosition ] = fPosition * 12.123F;
fTotal1 += fPosition * 12.123F; fTotal1 += fPosition * 12.123F;
} }
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
taskYIELD(); taskYIELD();
#endif #endif
for( xPosition = 0; xPosition < xArraySize; xPosition++ ) for( xPosition = 0; xPosition < xArraySize; xPosition++ )
{ {
fTotal2 += pfArray[ xPosition ]; fTotal2 += pfArray[ xPosition ];
} }
fDifference = fTotal1 - fTotal2; fDifference = fTotal1 - fTotal2;
if( fabs( fDifference ) > 0.001F )
{
sError = pdTRUE;
}
#if configUSE_PREEMPTION == 0 if( fabs( fDifference ) > 0.001F )
taskYIELD(); {
#endif sError = pdTRUE;
}
if( sError == pdFALSE ) #if configUSE_PREEMPTION == 0
{ taskYIELD();
/* If the calculation has always been correct, increment the check #endif
variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++; if( sError == pdFALSE )
} {
} /* If the calculation has always been correct, increment the check
* variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++;
}
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -303,25 +304,22 @@ short sError = pdFALSE;
BaseType_t xAreMathsTaskStillRunning( void ) BaseType_t xAreMathsTaskStillRunning( void )
{ {
/* Keep a history of the check variables so we know if they have been incremented /* Keep a history of the check variables so we know if they have been incremented
since the last call. */ * since the last call. */
static uint16_t usLastTaskCheck[ mathNUMBER_OF_TASKS ] = { ( uint16_t ) 0 }; static uint16_t usLastTaskCheck[ mathNUMBER_OF_TASKS ] = { ( uint16_t ) 0 };
BaseType_t xReturn = pdTRUE, xTask; BaseType_t xReturn = pdTRUE, xTask;
/* Check the maths tasks are still running by ensuring their check variables /* Check the maths tasks are still running by ensuring their check variables
are still incrementing. */ * are still incrementing. */
for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ ) for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ )
{ {
if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] ) if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] )
{ {
/* The check has not incremented so an error exists. */ /* The check has not incremented so an error exists. */
xReturn = pdFALSE; xReturn = pdFALSE;
} }
usLastTaskCheck[ xTask ] = usTaskCheck[ xTask ]; usLastTaskCheck[ xTask ] = usTaskCheck[ xTask ];
} }
return xReturn; return xReturn;
} }

View file

@ -32,5 +32,3 @@ void vCreateAbortDelayTasks( void );
BaseType_t xAreAbortDelayTestTasksStillRunning( void ); BaseType_t xAreAbortDelayTestTasksStillRunning( void );
#endif #endif

View file

@ -32,5 +32,3 @@ void vStartBlockingQueueTasks( UBaseType_t uxPriority );
BaseType_t xAreBlockingQueuesStillRunning( void ); BaseType_t xAreBlockingQueuesStillRunning( void );
#endif #endif

View file

@ -41,4 +41,3 @@ BaseType_t xAreEventGroupTasksStillRunning( void );
void vPeriodicEventGroupsProcessing( void ); void vPeriodicEventGroupsProcessing( void );
#endif /* EVENT_GROUPS_DEMO_H */ #endif /* EVENT_GROUPS_DEMO_H */

View file

@ -33,6 +33,3 @@ BaseType_t xAreGenericQueueTasksStillRunning( void );
void vMutexISRInteractionTest( void ); void vMutexISRInteractionTest( void );
#endif /* GEN_Q_TEST_H */ #endif /* GEN_Q_TEST_H */

View file

@ -34,9 +34,3 @@ BaseType_t xFirstTimerHandler( void );
BaseType_t xSecondTimerHandler( void ); BaseType_t xSecondTimerHandler( void );
#endif /* QUEUE_ACCESS_TEST */ #endif /* QUEUE_ACCESS_TEST */

View file

@ -33,6 +33,3 @@ BaseType_t xAreInterruptSemaphoreTasksStillRunning( void );
void vInterruptSemaphorePeriodicTest( void ); void vInterruptSemaphorePeriodicTest( void );
#endif /* INT_SEM_TEST_H */ #endif /* INT_SEM_TEST_H */

View file

@ -28,10 +28,7 @@
#ifndef MESSAGE_BUFFER_TEST_H #ifndef MESSAGE_BUFFER_TEST_H
#define MESSAGE_BUFFER_TEST_H #define MESSAGE_BUFFER_TEST_H
void vStartMessageBufferTasks( configSTACK_DEPTH_TYPE xStackSize ); void vStartMessageBufferTasks( configSTACK_DEPTH_TYPE xStackSize );
BaseType_t xAreMessageBufferTasksStillRunning( void ); BaseType_t xAreMessageBufferTasksStillRunning( void );
#endif /* MESSAGE_BUFFER_TEST_H */ #endif /* MESSAGE_BUFFER_TEST_H */

View file

@ -32,5 +32,3 @@ void vStartPolledQueueTasks( UBaseType_t uxPriority );
BaseType_t xArePollingQueuesStillRunning( void ); BaseType_t xArePollingQueuesStillRunning( void );
#endif #endif

View file

@ -32,6 +32,3 @@ void vStartQueuePeekTasks( void );
BaseType_t xAreQueuePeekTasksStillRunning( void ); BaseType_t xAreQueuePeekTasksStillRunning( void );
#endif /* Q_PEEK_TEST_H */ #endif /* Q_PEEK_TEST_H */

View file

@ -33,5 +33,3 @@ BaseType_t xIsQueueOverwriteTaskStillRunning( void );
void vQueueOverwritePeriodicISRDemo( void ); void vQueueOverwritePeriodicISRDemo( void );
#endif /* QUEUE_OVERWRITE_H */ #endif /* QUEUE_OVERWRITE_H */

View file

@ -33,5 +33,3 @@ BaseType_t xAreQueueSetTasksStillRunning( void );
void vQueueSetAccessQueueSetFromISR( void ); void vQueueSetAccessQueueSetFromISR( void );
#endif /* QUEUE_WAIT_MULTIPLE_H */ #endif /* QUEUE_WAIT_MULTIPLE_H */

View file

@ -33,5 +33,3 @@ BaseType_t xAreQueueSetPollTasksStillRunning( void );
void vQueueSetPollingInterruptAccess( void ); void vQueueSetPollingInterruptAccess( void );
#endif /* QUEUE_SET_POLLING_H */ #endif /* QUEUE_SET_POLLING_H */

View file

@ -28,10 +28,7 @@
#ifndef STATIC_ALLOCATION_H #ifndef STATIC_ALLOCATION_H
#define STATIC_ALLOCATION_H #define STATIC_ALLOCATION_H
void vStartStaticallyAllocatedTasks( void ); void vStartStaticallyAllocatedTasks( void );
BaseType_t xAreStaticAllocationTasksStillRunning( void ); BaseType_t xAreStaticAllocationTasksStillRunning( void );
#endif /* STATIC_ALLOCATION_H */ #endif /* STATIC_ALLOCATION_H */

View file

@ -33,6 +33,3 @@ BaseType_t xAreStreamBufferTasksStillRunning( void );
void vPeriodicStreamBufferProcessing( void ); void vPeriodicStreamBufferProcessing( void );
#endif /* STREAM_BUFFER_TEST_H */ #endif /* STREAM_BUFFER_TEST_H */

View file

@ -28,11 +28,8 @@
#ifndef TASK_NOTIFY_H #ifndef TASK_NOTIFY_H
#define TASK_NOTIFY_H #define TASK_NOTIFY_H
void vStartTaskNotifyTask( void ); void vStartTaskNotifyTask( void );
BaseType_t xAreTaskNotificationTasksStillRunning( void ); BaseType_t xAreTaskNotificationTasksStillRunning( void );
void xNotifyTaskFromISR( void ); void xNotifyTaskFromISR( void );
#endif /* TASK_NOTIFY_H */ #endif /* TASK_NOTIFY_H */

View file

@ -28,11 +28,8 @@
#ifndef TASK_NOTIFY_ARRAY_H #ifndef TASK_NOTIFY_ARRAY_H
#define TASK_NOTIFY_ARRAY_H #define TASK_NOTIFY_ARRAY_H
void vStartTaskNotifyArrayTask( void ); void vStartTaskNotifyArrayTask( void );
BaseType_t xAreTaskNotificationArrayTasksStillRunning( void ); BaseType_t xAreTaskNotificationArrayTasksStillRunning( void );
void xNotifyArrayTaskFromISR( void ); void xNotifyArrayTaskFromISR( void );
#endif /* TASK_NOTIFY_ARRAY_H */ #endif /* TASK_NOTIFY_ARRAY_H */

View file

@ -33,6 +33,3 @@ void vTimerPeriodicISRTests( void );
void vTimerDemoIncludeBacklogTests( BaseType_t includeBacklogTests ); void vTimerDemoIncludeBacklogTests( BaseType_t includeBacklogTests );
#endif /* TIMER_DEMO_H */ #endif /* TIMER_DEMO_H */

View file

@ -32,5 +32,3 @@ void vCreateBlockTimeTasks( void );
BaseType_t xAreBlockTimeTestTasksStillRunning( void ); BaseType_t xAreBlockTimeTestTasksStillRunning( void );
#endif #endif

View file

@ -28,10 +28,13 @@
#ifndef COMTEST_H #ifndef COMTEST_H
#define COMTEST_H #define COMTEST_H
void vAltStartComTestTasks( UBaseType_t uxPriority, uint32_t ulBaudRate, UBaseType_t uxLED ); void vAltStartComTestTasks( UBaseType_t uxPriority,
void vStartComTestTasks( UBaseType_t uxPriority, eCOMPort ePort, eBaud eBaudRate ); uint32_t ulBaudRate,
UBaseType_t uxLED );
void vStartComTestTasks( UBaseType_t uxPriority,
eCOMPort ePort,
eBaud eBaudRate );
BaseType_t xAreComTestTasksStillRunning( void ); BaseType_t xAreComTestTasksStillRunning( void );
void vComTestUnsuspendTask( void ); void vComTestUnsuspendTask( void );
#endif #endif /* ifndef COMTEST_H */

View file

@ -28,8 +28,9 @@
#ifndef COMTEST_H #ifndef COMTEST_H
#define COMTEST_H #define COMTEST_H
void vAltStartComTestTasks( UBaseType_t uxPriority, uint32_t ulBaudRate, UBaseType_t uxLED ); void vAltStartComTestTasks( UBaseType_t uxPriority,
uint32_t ulBaudRate,
UBaseType_t uxLED );
BaseType_t xAreComTestTasksStillRunning( void ); BaseType_t xAreComTestTasksStillRunning( void );
#endif #endif

View file

@ -28,8 +28,9 @@
#ifndef COMTEST_STRINGS_H #ifndef COMTEST_STRINGS_H
#define COMTEST_STRINGS_H #define COMTEST_STRINGS_H
void vStartComTestStringsTasks( UBaseType_t uxPriority, uint32_t ulBaudRate, UBaseType_t uxLED ); void vStartComTestStringsTasks( UBaseType_t uxPriority,
uint32_t ulBaudRate,
UBaseType_t uxLED );
BaseType_t xAreComTestTasksStillRunning( void ); BaseType_t xAreComTestTasksStillRunning( void );
#endif #endif

View file

@ -32,4 +32,3 @@ void vStartCountingSemaphoreTasks( void );
BaseType_t xAreCountingSemaphoreTasksStillRunning( void ); BaseType_t xAreCountingSemaphoreTasksStillRunning( void );
#endif #endif

View file

@ -44,4 +44,3 @@ void vStartFlashCoRoutines( UBaseType_t uxPriority );
BaseType_t xAreFlashCoRoutinesStillRunning( void ); BaseType_t xAreFlashCoRoutinesStillRunning( void );
#endif #endif

View file

@ -40,4 +40,3 @@ void vStartHookCoRoutines( void );
BaseType_t xAreHookCoRoutinesStillRunning( void ); BaseType_t xAreHookCoRoutinesStillRunning( void );
#endif #endif

View file

@ -32,5 +32,3 @@ void vCreateSuicidalTasks( UBaseType_t uxPriority );
BaseType_t xIsCreateTaskStillRunning( void ); BaseType_t xIsCreateTaskStillRunning( void );
#endif #endif

View file

@ -32,5 +32,3 @@ void vStartDynamicPriorityTasks( void );
BaseType_t xAreDynamicPriorityTasksStillRunning( void ); BaseType_t xAreDynamicPriorityTasksStillRunning( void );
#endif #endif

View file

@ -30,7 +30,7 @@
void vDisplayMessage( const char * const pcMessageToPrint ); void vDisplayMessage( const char * const pcMessageToPrint );
void vWriteMessageToDisk( const char * const pcMessage ); void vWriteMessageToDisk( const char * const pcMessage );
void vWriteBufferToDisk( const char * const pcBuffer, uint32_t ulBufferLength ); void vWriteBufferToDisk( const char * const pcBuffer,
uint32_t ulBufferLength );
#endif #endif

View file

@ -31,4 +31,3 @@
void vStartLEDFlashTasks( UBaseType_t uxPriority ); void vStartLEDFlashTasks( UBaseType_t uxPriority );
#endif #endif

View file

@ -30,7 +30,7 @@
/* /*
* Creates the LED flashing timers. xNumberOfLEDs specifies how many timers to * Creates the LED flashing timers. xNumberOfLEDs specifies how many timers to
* create, with each timer toggling a different LED. The first LED to be * create, with each timer toggling a different LED. The first LED to be
* toggled is LED 0, with subsequent LEDs following on in numerical order. Each * toggled is LED 0, with subsequent LEDs following on in numerical order. Each
* timer uses the exact same callback function, with the timer ID being used * timer uses the exact same callback function, with the timer ID being used
* within the callback function to determine which timer has actually expired * within the callback function to determine which timer has actually expired

View file

@ -32,5 +32,3 @@ void vStartMathTasks( UBaseType_t uxPriority );
BaseType_t xAreMathsTaskStillRunning( void ); BaseType_t xAreMathsTaskStillRunning( void );
#endif #endif

View file

@ -32,5 +32,3 @@ void vStartIntegerMathTasks( UBaseType_t uxPriority );
BaseType_t xAreIntegerMathsTaskStillRunning( void ); BaseType_t xAreIntegerMathsTaskStillRunning( void );
#endif #endif

View file

@ -32,5 +32,3 @@ void vStartMultiEventTasks( void );
BaseType_t xAreMultiEventTasksStillRunning( void ); BaseType_t xAreMultiEventTasksStillRunning( void );
#endif #endif

View file

@ -28,11 +28,11 @@
#ifndef PARTEST_H #ifndef PARTEST_H
#define PARTEST_H #define PARTEST_H
#define partstDEFAULT_PORT_ADDRESS ( ( uint16_t ) 0x378 ) #define partstDEFAULT_PORT_ADDRESS ( ( uint16_t ) 0x378 )
void vParTestInitialise( void ); void vParTestInitialise( void );
void vParTestSetLED( UBaseType_t uxLED, BaseType_t xValue ); void vParTestSetLED( UBaseType_t uxLED,
BaseType_t xValue );
void vParTestToggleLED( UBaseType_t uxLED ); void vParTestToggleLED( UBaseType_t uxLED );
#endif #endif

View file

@ -30,8 +30,6 @@
void vPrintInitialise( void ); void vPrintInitialise( void );
void vPrintDisplayMessage( const char * const * pcMessageToSend ); void vPrintDisplayMessage( const char * const * pcMessageToSend );
const char *pcPrintGetNextMessage( TickType_t xPrintRate ); const char * pcPrintGetNextMessage( TickType_t xPrintRate );
#endif #endif

View file

@ -32,4 +32,3 @@ void vStartRecursiveMutexTasks( void );
BaseType_t xAreRecursiveMutexTasksStillRunning( void ); BaseType_t xAreRecursiveMutexTasksStillRunning( void );
#endif #endif

View file

@ -32,4 +32,3 @@ void vStartSemaphoreTasks( UBaseType_t uxPriority );
BaseType_t xAreSemaphoreTasksStillRunning( void ); BaseType_t xAreSemaphoreTasksStillRunning( void );
#endif #endif

View file

@ -31,68 +31,79 @@
typedef void * xComPortHandle; typedef void * xComPortHandle;
typedef enum typedef enum
{ {
serCOM1, serCOM1,
serCOM2, serCOM2,
serCOM3, serCOM3,
serCOM4, serCOM4,
serCOM5, serCOM5,
serCOM6, serCOM6,
serCOM7, serCOM7,
serCOM8 serCOM8
} eCOMPort; } eCOMPort;
typedef enum typedef enum
{ {
serNO_PARITY, serNO_PARITY,
serODD_PARITY, serODD_PARITY,
serEVEN_PARITY, serEVEN_PARITY,
serMARK_PARITY, serMARK_PARITY,
serSPACE_PARITY serSPACE_PARITY
} eParity; } eParity;
typedef enum typedef enum
{ {
serSTOP_1, serSTOP_1,
serSTOP_2 serSTOP_2
} eStopBits; } eStopBits;
typedef enum typedef enum
{ {
serBITS_5, serBITS_5,
serBITS_6, serBITS_6,
serBITS_7, serBITS_7,
serBITS_8 serBITS_8
} eDataBits; } eDataBits;
typedef enum typedef enum
{ {
ser50, ser50,
ser75, ser75,
ser110, ser110,
ser134, ser134,
ser150, ser150,
ser200, ser200,
ser300, ser300,
ser600, ser600,
ser1200, ser1200,
ser1800, ser1800,
ser2400, ser2400,
ser4800, ser4800,
ser9600, ser9600,
ser19200, ser19200,
ser38400, ser38400,
ser57600, ser57600,
ser115200 ser115200
} eBaud; } eBaud;
xComPortHandle xSerialPortInitMinimal( unsigned long ulWantedBaud, unsigned portBASE_TYPE uxQueueLength ); xComPortHandle xSerialPortInitMinimal( unsigned long ulWantedBaud,
xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength ); unsigned portBASE_TYPE uxQueueLength );
void vSerialPutString( xComPortHandle pxPort, const signed char * const pcString, unsigned short usStringLength ); xComPortHandle xSerialPortInit( eCOMPort ePort,
signed portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, signed char *pcRxedChar, TickType_t xBlockTime ); eBaud eWantedBaud,
signed portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, signed char cOutChar, TickType_t xBlockTime ); eParity eWantedParity,
eDataBits eWantedDataBits,
eStopBits eWantedStopBits,
unsigned portBASE_TYPE uxBufferLength );
void vSerialPutString( xComPortHandle pxPort,
const signed char * const pcString,
unsigned short usStringLength );
signed portBASE_TYPE xSerialGetChar( xComPortHandle pxPort,
signed char * pcRxedChar,
TickType_t xBlockTime );
signed portBASE_TYPE xSerialPutChar( xComPortHandle pxPort,
signed char cOutChar,
TickType_t xBlockTime );
portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort ); portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort );
void vSerialClose( xComPortHandle xPort ); void vSerialClose( xComPortHandle xPort );
#endif #endif /* ifndef SERIAL_COMMS_H */

View file

@ -10,10 +10,10 @@ FreeRTOS port, and contains its own readme file.
See [FreeRTOS/SourceOrganization](http://www.freertos.org/a00017.html) for full details of the directory structure and information on locating the files you require. See [FreeRTOS/SourceOrganization](http://www.freertos.org/a00017.html) for full details of the directory structure and information on locating the files you require.
The easiest way to use FreeRTOS is to start with one of the pre-configured demo The easiest way to use FreeRTOS is to start with one of the pre-configured demo
application projects (found in the FreeRTOS/Demo directory). That way you will application projects (found in the FreeRTOS/Demo directory). That way you will
have the correct FreeRTOS source files included, and the correct include paths have the correct FreeRTOS source files included, and the correct include paths
configured. configured.
Once a demo application is building and executing you can remove Once a demo application is building and executing you can remove
the demo application file, and start to add in your own application source the demo application file, and start to add in your own application source
files. files.

View file

@ -1,3 +1,5 @@
eFrameProcessingResult_t publicProcessIPPacket( IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer ) { eFrameProcessingResult_t publicProcessIPPacket( IPPacket_t * const pxIPPacket,
prvProcessIPPacket(pxIPPacket, pxNetworkBuffer); NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
prvProcessIPPacket( pxIPPacket, pxNetworkBuffer );
} }

View file

@ -1,12 +1,20 @@
int32_t publicTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength ) { int32_t publicTCPPrepareSend( FreeRTOS_Socket_t * pxSocket,
prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength ); NetworkBufferDescriptor_t ** ppxNetworkBuffer,
UBaseType_t uxOptionsLength )
{
prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );
} }
BaseType_t publicTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer ) { BaseType_t publicTCPHandleState( FreeRTOS_Socket_t * pxSocket,
prvTCPHandleState(pxSocket, ppxNetworkBuffer); NetworkBufferDescriptor_t ** ppxNetworkBuffer )
{
prvTCPHandleState( pxSocket, ppxNetworkBuffer );
} }
void publicTCPReturnPacket( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer, void publicTCPReturnPacket( FreeRTOS_Socket_t * pxSocket,
uint32_t ulLen, BaseType_t xReleaseAfterSend ) { NetworkBufferDescriptor_t * pxNetworkBuffer,
prvTCPReturnPacket(pxSocket, pxNetworkBuffer, ulLen, xReleaseAfterSend ); uint32_t ulLen,
BaseType_t xReleaseAfterSend )
{
prvTCPReturnPacket( pxSocket, pxNetworkBuffer, ulLen, xReleaseAfterSend );
} }

View file

@ -18,12 +18,12 @@
#include "NetworkInterface.h" #include "NetworkInterface.h"
/* /*
* CBMC models a pointer as an object id and an offset into that * CBMC models a pointer as an object id and an offset into that
* object. The top bits of a pointer encode the object id and the * object. The top bits of a pointer encode the object id and the
* remaining bits encode the offset. This means there is a bound on * remaining bits encode the offset. This means there is a bound on
* the maximum offset into an object in CBMC, and hence a bound on the * the maximum offset into an object in CBMC, and hence a bound on the
* size of objects in CBMC. * size of objects in CBMC.
*/ */
#define CBMC_BITS 7 #define CBMC_BITS 7
#define CBMC_MAX_OBJECT_SIZE ( 0xFFFFFFFF >> ( CBMC_BITS + 1 ) ) #define CBMC_MAX_OBJECT_SIZE ( 0xFFFFFFFF >> ( CBMC_BITS + 1 ) )
@ -70,19 +70,19 @@ enum CBMC_LOOP_CONDITION
#define __CPROVER_printf2_ptr( str, exp ) { uint8_t * ValueOf_ ## str = ( uint8_t * ) ( exp ); } #define __CPROVER_printf2_ptr( str, exp ) { uint8_t * ValueOf_ ## str = ( uint8_t * ) ( exp ); }
/* /*
* An assertion that pvPortMalloc returns NULL when asked to allocate 0 bytes. * An assertion that pvPortMalloc returns NULL when asked to allocate 0 bytes.
* This assertion is used in some of the TaskPool proofs. * This assertion is used in some of the TaskPool proofs.
*/ */
#define __CPROVER_assert_zero_allocation() \ #define __CPROVER_assert_zero_allocation() \
__CPROVER_assert( pvPortMalloc( 0 ) == NULL, \ __CPROVER_assert( pvPortMalloc( 0 ) == NULL, \
"pvPortMalloc allows zero-allocated memory." ) "pvPortMalloc allows zero-allocated memory." )
/* /*
* A stub for pvPortMalloc that nondeterministically chooses to return * A stub for pvPortMalloc that nondeterministically chooses to return
* either NULL or an allocation of the requested space. The stub is * either NULL or an allocation of the requested space. The stub is
* guaranteed to return NULL when asked to allocate 0 bytes. * guaranteed to return NULL when asked to allocate 0 bytes.
* This stub is used in some of the TaskPool proofs. * This stub is used in some of the TaskPool proofs.
*/ */
void * pvPortMalloc( size_t xWantedSize ) void * pvPortMalloc( size_t xWantedSize )
{ {
if( xWantedSize == 0 ) if( xWantedSize == 0 )

Some files were not shown because too many files have changed in this diff Show more