initial commit

This commit is contained in:
2022-10-23 23:45:43 -07:00
commit e190fa5193
6450 changed files with 8626944 additions and 0 deletions
@@ -0,0 +1,37 @@
The FreeRTOS kernel is released under the MIT open source license, the text of
which is provided below.
This license covers the FreeRTOS kernel source files, which are located in the
/FreeRTOS/Source directory of the official FreeRTOS kernel download. It also
covers most of the source files in the demo application projects, which are
located in the /FreeRTOS/Demo directory of the official FreeRTOS download. The
demo projects may also include third party software that is not part of FreeRTOS
and is licensed separately to FreeRTOS. Examples of third party software
includes header files provided by chip or tools vendors, linker scripts,
peripheral drivers, etc. All the software in subdirectories of the /FreeRTOS
directory is either open source or distributed with permission, and is free for
use. For the avoidance of doubt, refer to the comments at the top of each
source file.
License text:
-------------
Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,353 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#include "FreeRTOS.h"
#include "task.h"
#include "croutine.h"
/* Remove the whole file is co-routines are not being used. */
#if( configUSE_CO_ROUTINES != 0 )
/*
* Some kernel aware debuggers require data to be viewed to be global, rather
* than file scope.
*/
#ifdef portREMOVE_STATIC_QUALIFIER
#define static
#endif
/* Lists for ready and blocked co-routines. --------------------*/
static List_t pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ]; /*< Prioritised ready co-routines. */
static List_t xDelayedCoRoutineList1; /*< Delayed co-routines. */
static List_t xDelayedCoRoutineList2; /*< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */
static List_t * pxDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used. */
static List_t * pxOverflowDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */
static List_t xPendingReadyCoRoutineList; /*< Holds co-routines that have been readied by an external event. They cannot be added directly to the ready lists as the ready lists cannot be accessed by interrupts. */
/* Other file private variables. --------------------------------*/
CRCB_t * pxCurrentCoRoutine = NULL;
static UBaseType_t uxTopCoRoutineReadyPriority = 0;
static TickType_t xCoRoutineTickCount = 0, xLastTickCount = 0, xPassedTicks = 0;
/* The initial state of the co-routine when it is created. */
#define corINITIAL_STATE ( 0 )
/*
* Place the co-routine represented by pxCRCB into the appropriate ready queue
* for the priority. It is inserted at the end of the list.
*
* This macro accesses the co-routine ready lists and therefore must not be
* used from within an ISR.
*/
#define prvAddCoRoutineToReadyQueue( pxCRCB ) \
{ \
if( pxCRCB->uxPriority > uxTopCoRoutineReadyPriority ) \
{ \
uxTopCoRoutineReadyPriority = pxCRCB->uxPriority; \
} \
vListInsertEnd( ( List_t * ) &( pxReadyCoRoutineLists[ pxCRCB->uxPriority ] ), &( pxCRCB->xGenericListItem ) ); \
}
/*
* Utility to ready all the lists used by the scheduler. This is called
* automatically upon the creation of the first co-routine.
*/
static void prvInitialiseCoRoutineLists( void );
/*
* Co-routines that are readied by an interrupt cannot be placed directly into
* the ready lists (there is no mutual exclusion). Instead they are placed in
* in the pending ready list in order that they can later be moved to the ready
* list by the co-routine scheduler.
*/
static void prvCheckPendingReadyList( void );
/*
* Macro that looks at the list of co-routines that are currently delayed to
* see if any require waking.
*
* Co-routines are stored in the queue in the order of their wake time -
* meaning once one co-routine has been found whose timer has not expired
* we need not look any further down the list.
*/
static void prvCheckDelayedList( void );
/*-----------------------------------------------------------*/
BaseType_t xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, UBaseType_t uxPriority, UBaseType_t uxIndex )
{
BaseType_t xReturn;
CRCB_t *pxCoRoutine;
/* Allocate the memory that will store the co-routine control block. */
pxCoRoutine = ( CRCB_t * ) pvPortMalloc( sizeof( CRCB_t ) );
if( pxCoRoutine )
{
/* If pxCurrentCoRoutine is NULL then this is the first co-routine to
be created and the co-routine data structures need initialising. */
if( pxCurrentCoRoutine == NULL )
{
pxCurrentCoRoutine = pxCoRoutine;
prvInitialiseCoRoutineLists();
}
/* Check the priority is within limits. */
if( uxPriority >= configMAX_CO_ROUTINE_PRIORITIES )
{
uxPriority = configMAX_CO_ROUTINE_PRIORITIES - 1;
}
/* Fill out the co-routine control block from the function parameters. */
pxCoRoutine->uxState = corINITIAL_STATE;
pxCoRoutine->uxPriority = uxPriority;
pxCoRoutine->uxIndex = uxIndex;
pxCoRoutine->pxCoRoutineFunction = pxCoRoutineCode;
/* Initialise all the other co-routine control block parameters. */
vListInitialiseItem( &( pxCoRoutine->xGenericListItem ) );
vListInitialiseItem( &( pxCoRoutine->xEventListItem ) );
/* Set the co-routine control block as a link back from the ListItem_t.
This is so we can get back to the containing CRCB from a generic item
in a list. */
listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xGenericListItem ), pxCoRoutine );
listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xEventListItem ), pxCoRoutine );
/* Event lists are always in priority order. */
listSET_LIST_ITEM_VALUE( &( pxCoRoutine->xEventListItem ), ( ( TickType_t ) configMAX_CO_ROUTINE_PRIORITIES - ( TickType_t ) uxPriority ) );
/* Now the co-routine has been initialised it can be added to the ready
list at the correct priority. */
prvAddCoRoutineToReadyQueue( pxCoRoutine );
xReturn = pdPASS;
}
else
{
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
}
return xReturn;
}
/*-----------------------------------------------------------*/
void vCoRoutineAddToDelayedList( TickType_t xTicksToDelay, List_t *pxEventList )
{
TickType_t xTimeToWake;
/* Calculate the time to wake - this may overflow but this is
not a problem. */
xTimeToWake = xCoRoutineTickCount + xTicksToDelay;
/* We must remove ourselves from the ready list before adding
ourselves to the blocked list as the same list item is used for
both lists. */
( void ) uxListRemove( ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) );
/* The list item will be inserted in wake time order. */
listSET_LIST_ITEM_VALUE( &( pxCurrentCoRoutine->xGenericListItem ), xTimeToWake );
if( xTimeToWake < xCoRoutineTickCount )
{
/* Wake time has overflowed. Place this item in the
overflow list. */
vListInsert( ( List_t * ) pxOverflowDelayedCoRoutineList, ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) );
}
else
{
/* The wake time has not overflowed, so we can use the
current block list. */
vListInsert( ( List_t * ) pxDelayedCoRoutineList, ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) );
}
if( pxEventList )
{
/* Also add the co-routine to an event list. If this is done then the
function must be called with interrupts disabled. */
vListInsert( pxEventList, &( pxCurrentCoRoutine->xEventListItem ) );
}
}
/*-----------------------------------------------------------*/
static void prvCheckPendingReadyList( void )
{
/* Are there any co-routines waiting to get moved to the ready list? These
are co-routines that have been readied by an ISR. The ISR cannot access
the ready lists itself. */
while( listLIST_IS_EMPTY( &xPendingReadyCoRoutineList ) == pdFALSE )
{
CRCB_t *pxUnblockedCRCB;
/* The pending ready list can be accessed by an ISR. */
portDISABLE_INTERRUPTS();
{
pxUnblockedCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( (&xPendingReadyCoRoutineList) );
( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) );
}
portENABLE_INTERRUPTS();
( void ) uxListRemove( &( pxUnblockedCRCB->xGenericListItem ) );
prvAddCoRoutineToReadyQueue( pxUnblockedCRCB );
}
}
/*-----------------------------------------------------------*/
static void prvCheckDelayedList( void )
{
CRCB_t *pxCRCB;
xPassedTicks = xTaskGetTickCount() - xLastTickCount;
while( xPassedTicks )
{
xCoRoutineTickCount++;
xPassedTicks--;
/* If the tick count has overflowed we need to swap the ready lists. */
if( xCoRoutineTickCount == 0 )
{
List_t * pxTemp;
/* Tick count has overflowed so we need to swap the delay lists. If there are
any items in pxDelayedCoRoutineList here then there is an error! */
pxTemp = pxDelayedCoRoutineList;
pxDelayedCoRoutineList = pxOverflowDelayedCoRoutineList;
pxOverflowDelayedCoRoutineList = pxTemp;
}
/* See if this tick has made a timeout expire. */
while( listLIST_IS_EMPTY( pxDelayedCoRoutineList ) == pdFALSE )
{
pxCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList );
if( xCoRoutineTickCount < listGET_LIST_ITEM_VALUE( &( pxCRCB->xGenericListItem ) ) )
{
/* Timeout not yet expired. */
break;
}
portDISABLE_INTERRUPTS();
{
/* The event could have occurred just before this critical
section. If this is the case then the generic list item will
have been moved to the pending ready list and the following
line is still valid. Also the pvContainer parameter will have
been set to NULL so the following lines are also valid. */
( void ) uxListRemove( &( pxCRCB->xGenericListItem ) );
/* Is the co-routine waiting on an event also? */
if( pxCRCB->xEventListItem.pxContainer )
{
( void ) uxListRemove( &( pxCRCB->xEventListItem ) );
}
}
portENABLE_INTERRUPTS();
prvAddCoRoutineToReadyQueue( pxCRCB );
}
}
xLastTickCount = xCoRoutineTickCount;
}
/*-----------------------------------------------------------*/
void vCoRoutineSchedule( void )
{
/* See if any co-routines readied by events need moving to the ready lists. */
prvCheckPendingReadyList();
/* See if any delayed co-routines have timed out. */
prvCheckDelayedList();
/* Find the highest priority queue that contains ready co-routines. */
while( listLIST_IS_EMPTY( &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ) )
{
if( uxTopCoRoutineReadyPriority == 0 )
{
/* No more co-routines to check. */
return;
}
--uxTopCoRoutineReadyPriority;
}
/* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the co-routines
of the same priority get an equal share of the processor time. */
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentCoRoutine, &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) );
/* Call the co-routine. */
( pxCurrentCoRoutine->pxCoRoutineFunction )( pxCurrentCoRoutine, pxCurrentCoRoutine->uxIndex );
return;
}
/*-----------------------------------------------------------*/
static void prvInitialiseCoRoutineLists( void )
{
UBaseType_t uxPriority;
for( uxPriority = 0; uxPriority < configMAX_CO_ROUTINE_PRIORITIES; uxPriority++ )
{
vListInitialise( ( List_t * ) &( pxReadyCoRoutineLists[ uxPriority ] ) );
}
vListInitialise( ( List_t * ) &xDelayedCoRoutineList1 );
vListInitialise( ( List_t * ) &xDelayedCoRoutineList2 );
vListInitialise( ( List_t * ) &xPendingReadyCoRoutineList );
/* Start with pxDelayedCoRoutineList using list1 and the
pxOverflowDelayedCoRoutineList using list2. */
pxDelayedCoRoutineList = &xDelayedCoRoutineList1;
pxOverflowDelayedCoRoutineList = &xDelayedCoRoutineList2;
}
/*-----------------------------------------------------------*/
BaseType_t xCoRoutineRemoveFromEventList( const List_t *pxEventList )
{
CRCB_t *pxUnblockedCRCB;
BaseType_t xReturn;
/* This function is called from within an interrupt. It can only access
event lists and the pending ready list. This function assumes that a
check has already been made to ensure pxEventList is not empty. */
pxUnblockedCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) );
vListInsertEnd( ( List_t * ) &( xPendingReadyCoRoutineList ), &( pxUnblockedCRCB->xEventListItem ) );
if( pxUnblockedCRCB->uxPriority >= pxCurrentCoRoutine->uxPriority )
{
xReturn = pdTRUE;
}
else
{
xReturn = pdFALSE;
}
return xReturn;
}
#endif /* configUSE_CO_ROUTINES == 0 */
@@ -0,0 +1,753 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/* Standard includes. */
#include <stdlib.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
all the API functions to use the MPU wrappers. That should only be done when
task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "event_groups.h"
/* Lint e961, e750 and e9021 are suppressed as a MISRA exception justified
because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined
for the header files above, but not in this file, in order to generate the
correct privileged Vs unprivileged linkage and placement. */
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021 See comment above. */
/* The following bit fields convey control information in a task's event list
item value. It is important they don't clash with the
taskEVENT_LIST_ITEM_VALUE_IN_USE definition. */
#if configUSE_16_BIT_TICKS == 1
#define eventCLEAR_EVENTS_ON_EXIT_BIT 0x0100U
#define eventUNBLOCKED_DUE_TO_BIT_SET 0x0200U
#define eventWAIT_FOR_ALL_BITS 0x0400U
#define eventEVENT_BITS_CONTROL_BYTES 0xff00U
#else
#define eventCLEAR_EVENTS_ON_EXIT_BIT 0x01000000UL
#define eventUNBLOCKED_DUE_TO_BIT_SET 0x02000000UL
#define eventWAIT_FOR_ALL_BITS 0x04000000UL
#define eventEVENT_BITS_CONTROL_BYTES 0xff000000UL
#endif
typedef struct EventGroupDef_t
{
EventBits_t uxEventBits;
List_t xTasksWaitingForBits; /*< List of tasks waiting for a bit to be set. */
#if( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxEventGroupNumber;
#endif
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the event group is statically allocated to ensure no attempt is made to free the memory. */
#endif
} EventGroup_t;
/*-----------------------------------------------------------*/
/*
* Test the bits set in uxCurrentEventBits to see if the wait condition is met.
* The wait condition is defined by xWaitForAllBits. If xWaitForAllBits is
* pdTRUE then the wait condition is met if all the bits set in uxBitsToWaitFor
* are also set in uxCurrentEventBits. If xWaitForAllBits is pdFALSE then the
* wait condition is met if any of the bits set in uxBitsToWait for are also set
* in uxCurrentEventBits.
*/
static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits ) PRIVILEGED_FUNCTION;
/*-----------------------------------------------------------*/
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer )
{
EventGroup_t *pxEventBits;
/* A StaticEventGroup_t object must be provided. */
configASSERT( pxEventGroupBuffer );
#if( configASSERT_DEFINED == 1 )
{
/* Sanity check that the size of the structure used to declare a
variable of type StaticEventGroup_t equals the size of the real
event group structure. */
volatile size_t xSize = sizeof( StaticEventGroup_t );
configASSERT( xSize == sizeof( EventGroup_t ) );
} /*lint !e529 xSize is referenced if configASSERT() is defined. */
#endif /* configASSERT_DEFINED */
/* The user has provided a statically allocated event group - use it. */
pxEventBits = ( EventGroup_t * ) pxEventGroupBuffer; /*lint !e740 !e9087 EventGroup_t and StaticEventGroup_t are deliberately aliased for data hiding purposes and guaranteed to have the same size and alignment requirement - checked by configASSERT(). */
if( pxEventBits != NULL )
{
pxEventBits->uxEventBits = 0;
vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{
/* Both static and dynamic allocation can be used, so note that
this event group was created statically in case the event group
is later deleted. */
pxEventBits->ucStaticallyAllocated = pdTRUE;
}
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
traceEVENT_GROUP_CREATE( pxEventBits );
}
else
{
/* xEventGroupCreateStatic should only ever be called with
pxEventGroupBuffer pointing to a pre-allocated (compile time
allocated) StaticEventGroup_t variable. */
traceEVENT_GROUP_CREATE_FAILED();
}
return pxEventBits;
}
#endif /* configSUPPORT_STATIC_ALLOCATION */
/*-----------------------------------------------------------*/
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
EventGroupHandle_t xEventGroupCreate( void )
{
EventGroup_t *pxEventBits;
/* Allocate the event group. Justification for MISRA deviation as
follows: pvPortMalloc() always ensures returned memory blocks are
aligned per the requirements of the MCU stack. In this case
pvPortMalloc() must return a pointer that is guaranteed to meet the
alignment requirements of the EventGroup_t structure - which (if you
follow it through) is the alignment requirements of the TickType_t type
(EventBits_t being of TickType_t itself). Therefore, whenever the
stack alignment requirements are greater than or equal to the
TickType_t alignment requirements the cast is safe. In other cases,
where the natural word size of the architecture is less than
sizeof( TickType_t ), the TickType_t variables will be accessed in two
or more reads operations, and the alignment requirements is only that
of each individual read. */
pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) ); /*lint !e9087 !e9079 see comment above. */
if( pxEventBits != NULL )
{
pxEventBits->uxEventBits = 0;
vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
{
/* Both static and dynamic allocation can be used, so note this
event group was allocated statically in case the event group is
later deleted. */
pxEventBits->ucStaticallyAllocated = pdFALSE;
}
#endif /* configSUPPORT_STATIC_ALLOCATION */
traceEVENT_GROUP_CREATE( pxEventBits );
}
else
{
traceEVENT_GROUP_CREATE_FAILED(); /*lint !e9063 Else branch only exists to allow tracing and does not generate code if trace macros are not defined. */
}
return pxEventBits;
}
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
/*-----------------------------------------------------------*/
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait )
{
EventBits_t uxOriginalBitValue, uxReturn;
EventGroup_t *pxEventBits = xEventGroup;
BaseType_t xAlreadyYielded;
BaseType_t xTimeoutOccurred = pdFALSE;
configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
configASSERT( uxBitsToWaitFor != 0 );
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
{
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
}
#endif
vTaskSuspendAll();
{
uxOriginalBitValue = pxEventBits->uxEventBits;
( void ) xEventGroupSetBits( xEventGroup, uxBitsToSet );
if( ( ( uxOriginalBitValue | uxBitsToSet ) & uxBitsToWaitFor ) == uxBitsToWaitFor )
{
/* All the rendezvous bits are now set - no need to block. */
uxReturn = ( uxOriginalBitValue | uxBitsToSet );
/* Rendezvous always clear the bits. They will have been cleared
already unless this is the only task in the rendezvous. */
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
xTicksToWait = 0;
}
else
{
if( xTicksToWait != ( TickType_t ) 0 )
{
traceEVENT_GROUP_SYNC_BLOCK( xEventGroup, uxBitsToSet, uxBitsToWaitFor );
/* Store the bits that the calling task is waiting for in the
task's event list item so the kernel knows when a match is
found. Then enter the blocked state. */
vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | eventCLEAR_EVENTS_ON_EXIT_BIT | eventWAIT_FOR_ALL_BITS ), xTicksToWait );
/* This assignment is obsolete as uxReturn will get set after
the task unblocks, but some compilers mistakenly generate a
warning about uxReturn being returned without being set if the
assignment is omitted. */
uxReturn = 0;
}
else
{
/* The rendezvous bits were not set, but no block time was
specified - just return the current event bit value. */
uxReturn = pxEventBits->uxEventBits;
xTimeoutOccurred = pdTRUE;
}
}
}
xAlreadyYielded = xTaskResumeAll();
if( xTicksToWait != ( TickType_t ) 0 )
{
if( xAlreadyYielded == pdFALSE )
{
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* The task blocked to wait for its required bits to be set - at this
point either the required bits were set or the block time expired. If
the required bits were set they will have been stored in the task's
event list item, and they should now be retrieved then cleared. */
uxReturn = uxTaskResetEventItemValue();
if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )
{
/* The task timed out, just return the current event bit value. */
taskENTER_CRITICAL();
{
uxReturn = pxEventBits->uxEventBits;
/* Although the task got here because it timed out before the
bits it was waiting for were set, it is possible that since it
unblocked another task has set the bits. If this is the case
then it needs to clear the bits before exiting. */
if( ( uxReturn & uxBitsToWaitFor ) == uxBitsToWaitFor )
{
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
taskEXIT_CRITICAL();
xTimeoutOccurred = pdTRUE;
}
else
{
/* The task unblocked because the bits were set. */
}
/* Control bits might be set as the task had blocked should not be
returned. */
uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;
}
traceEVENT_GROUP_SYNC_END( xEventGroup, uxBitsToSet, uxBitsToWaitFor, xTimeoutOccurred );
/* Prevent compiler warnings when trace macros are not used. */
( void ) xTimeoutOccurred;
return uxReturn;
}
/*-----------------------------------------------------------*/
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait )
{
EventGroup_t *pxEventBits = xEventGroup;
EventBits_t uxReturn, uxControlBits = 0;
BaseType_t xWaitConditionMet, xAlreadyYielded;
BaseType_t xTimeoutOccurred = pdFALSE;
/* Check the user is not attempting to wait on the bits used by the kernel
itself, and that at least one bit is being requested. */
configASSERT( xEventGroup );
configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
configASSERT( uxBitsToWaitFor != 0 );
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
{
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
}
#endif
vTaskSuspendAll();
{
const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits;
/* Check to see if the wait condition is already met or not. */
xWaitConditionMet = prvTestWaitCondition( uxCurrentEventBits, uxBitsToWaitFor, xWaitForAllBits );
if( xWaitConditionMet != pdFALSE )
{
/* The wait condition has already been met so there is no need to
block. */
uxReturn = uxCurrentEventBits;
xTicksToWait = ( TickType_t ) 0;
/* Clear the wait bits if requested to do so. */
if( xClearOnExit != pdFALSE )
{
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else if( xTicksToWait == ( TickType_t ) 0 )
{
/* The wait condition has not been met, but no block time was
specified, so just return the current value. */
uxReturn = uxCurrentEventBits;
xTimeoutOccurred = pdTRUE;
}
else
{
/* The task is going to block to wait for its required bits to be
set. uxControlBits are used to remember the specified behaviour of
this call to xEventGroupWaitBits() - for use when the event bits
unblock the task. */
if( xClearOnExit != pdFALSE )
{
uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
if( xWaitForAllBits != pdFALSE )
{
uxControlBits |= eventWAIT_FOR_ALL_BITS;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* Store the bits that the calling task is waiting for in the
task's event list item so the kernel knows when a match is
found. Then enter the blocked state. */
vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait );
/* This is obsolete as it will get set after the task unblocks, but
some compilers mistakenly generate a warning about the variable
being returned without being set if it is not done. */
uxReturn = 0;
traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor );
}
}
xAlreadyYielded = xTaskResumeAll();
if( xTicksToWait != ( TickType_t ) 0 )
{
if( xAlreadyYielded == pdFALSE )
{
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* The task blocked to wait for its required bits to be set - at this
point either the required bits were set or the block time expired. If
the required bits were set they will have been stored in the task's
event list item, and they should now be retrieved then cleared. */
uxReturn = uxTaskResetEventItemValue();
if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )
{
taskENTER_CRITICAL();
{
/* The task timed out, just return the current event bit value. */
uxReturn = pxEventBits->uxEventBits;
/* It is possible that the event bits were updated between this
task leaving the Blocked state and running again. */
if( prvTestWaitCondition( uxReturn, uxBitsToWaitFor, xWaitForAllBits ) != pdFALSE )
{
if( xClearOnExit != pdFALSE )
{
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
xTimeoutOccurred = pdTRUE;
}
taskEXIT_CRITICAL();
}
else
{
/* The task unblocked because the bits were set. */
}
/* The task blocked so control bits may have been set. */
uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;
}
traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred );
/* Prevent compiler warnings when trace macros are not used. */
( void ) xTimeoutOccurred;
return uxReturn;
}
/*-----------------------------------------------------------*/
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
{
EventGroup_t *pxEventBits = xEventGroup;
EventBits_t uxReturn;
/* Check the user is not attempting to clear the bits used by the kernel
itself. */
configASSERT( xEventGroup );
configASSERT( ( uxBitsToClear & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
taskENTER_CRITICAL();
{
traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear );
/* The value returned is the event group value prior to the bits being
cleared. */
uxReturn = pxEventBits->uxEventBits;
/* Clear the bits. */
pxEventBits->uxEventBits &= ~uxBitsToClear;
}
taskEXIT_CRITICAL();
return uxReturn;
}
/*-----------------------------------------------------------*/
#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
{
BaseType_t xReturn;
traceEVENT_GROUP_CLEAR_BITS_FROM_ISR( xEventGroup, uxBitsToClear );
xReturn = xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL ); /*lint !e9087 Can't avoid cast to void* as a generic callback function not specific to this use case. Callback casts back to original type so safe. */
return xReturn;
}
#endif
/*-----------------------------------------------------------*/
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup )
{
UBaseType_t uxSavedInterruptStatus;
EventGroup_t const * const pxEventBits = xEventGroup;
EventBits_t uxReturn;
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
{
uxReturn = pxEventBits->uxEventBits;
}
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
return uxReturn;
} /*lint !e818 EventGroupHandle_t is a typedef used in other functions to so can't be pointer to const. */
/*-----------------------------------------------------------*/
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )
{
ListItem_t *pxListItem, *pxNext;
ListItem_t const *pxListEnd;
List_t const * pxList;
EventBits_t uxBitsToClear = 0, uxBitsWaitedFor, uxControlBits;
EventGroup_t *pxEventBits = xEventGroup;
BaseType_t xMatchFound = pdFALSE;
/* Check the user is not attempting to set the bits used by the kernel
itself. */
configASSERT( xEventGroup );
configASSERT( ( uxBitsToSet & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
pxList = &( pxEventBits->xTasksWaitingForBits );
pxListEnd = listGET_END_MARKER( pxList ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */
vTaskSuspendAll();
{
traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet );
pxListItem = listGET_HEAD_ENTRY( pxList );
/* Set the bits. */
pxEventBits->uxEventBits |= uxBitsToSet;
/* See if the new bit value should unblock any tasks. */
while( pxListItem != pxListEnd )
{
pxNext = listGET_NEXT( pxListItem );
uxBitsWaitedFor = listGET_LIST_ITEM_VALUE( pxListItem );
xMatchFound = pdFALSE;
/* Split the bits waited for from the control bits. */
uxControlBits = uxBitsWaitedFor & eventEVENT_BITS_CONTROL_BYTES;
uxBitsWaitedFor &= ~eventEVENT_BITS_CONTROL_BYTES;
if( ( uxControlBits & eventWAIT_FOR_ALL_BITS ) == ( EventBits_t ) 0 )
{
/* Just looking for single bit being set. */
if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) != ( EventBits_t ) 0 )
{
xMatchFound = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) == uxBitsWaitedFor )
{
/* All bits are set. */
xMatchFound = pdTRUE;
}
else
{
/* Need all bits to be set, but not all the bits were set. */
}
if( xMatchFound != pdFALSE )
{
/* The bits match. Should the bits be cleared on exit? */
if( ( uxControlBits & eventCLEAR_EVENTS_ON_EXIT_BIT ) != ( EventBits_t ) 0 )
{
uxBitsToClear |= uxBitsWaitedFor;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* Store the actual event flag value in the task's event list
item before removing the task from the event list. The
eventUNBLOCKED_DUE_TO_BIT_SET bit is set so the task knows
that is was unblocked due to its required bits matching, rather
than because it timed out. */
vTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET );
}
/* Move onto the next list item. Note pxListItem->pxNext is not
used here as the list item may have been removed from the event list
and inserted into the ready/pending reading list. */
pxListItem = pxNext;
}
/* Clear any bits that matched when the eventCLEAR_EVENTS_ON_EXIT_BIT
bit was set in the control word. */
pxEventBits->uxEventBits &= ~uxBitsToClear;
}
( void ) xTaskResumeAll();
return pxEventBits->uxEventBits;
}
/*-----------------------------------------------------------*/
void vEventGroupDelete( EventGroupHandle_t xEventGroup )
{
EventGroup_t *pxEventBits = xEventGroup;
const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits );
vTaskSuspendAll();
{
traceEVENT_GROUP_DELETE( xEventGroup );
while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( UBaseType_t ) 0 )
{
/* Unblock the task, returning 0 as the event list is being deleted
and cannot therefore have any bits set. */
configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( const ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) );
vTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET );
}
#if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) )
{
/* The event group can only have been allocated dynamically - free
it again. */
vPortFree( pxEventBits );
}
#elif( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
{
/* The event group could have been allocated statically or
dynamically, so check before attempting to free the memory. */
if( pxEventBits->ucStaticallyAllocated == ( uint8_t ) pdFALSE )
{
vPortFree( pxEventBits );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
}
( void ) xTaskResumeAll();
}
/*-----------------------------------------------------------*/
/* For internal use only - execute a 'set bits' command that was pended from
an interrupt. */
void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet )
{
( void ) xEventGroupSetBits( pvEventGroup, ( EventBits_t ) ulBitsToSet ); /*lint !e9079 Can't avoid cast to void* as a generic timer callback prototype. Callback casts back to original type so safe. */
}
/*-----------------------------------------------------------*/
/* For internal use only - execute a 'clear bits' command that was pended from
an interrupt. */
void vEventGroupClearBitsCallback( void *pvEventGroup, const uint32_t ulBitsToClear )
{
( void ) xEventGroupClearBits( pvEventGroup, ( EventBits_t ) ulBitsToClear ); /*lint !e9079 Can't avoid cast to void* as a generic timer callback prototype. Callback casts back to original type so safe. */
}
/*-----------------------------------------------------------*/
static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits )
{
BaseType_t xWaitConditionMet = pdFALSE;
if( xWaitForAllBits == pdFALSE )
{
/* Task only has to wait for one bit within uxBitsToWaitFor to be
set. Is one already set? */
if( ( uxCurrentEventBits & uxBitsToWaitFor ) != ( EventBits_t ) 0 )
{
xWaitConditionMet = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
/* Task has to wait for all the bits in uxBitsToWaitFor to be set.
Are they set already? */
if( ( uxCurrentEventBits & uxBitsToWaitFor ) == uxBitsToWaitFor )
{
xWaitConditionMet = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
return xWaitConditionMet;
}
/*-----------------------------------------------------------*/
#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken )
{
BaseType_t xReturn;
traceEVENT_GROUP_SET_BITS_FROM_ISR( xEventGroup, uxBitsToSet );
xReturn = xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken ); /*lint !e9087 Can't avoid cast to void* as a generic callback function not specific to this use case. Callback casts back to original type so safe. */
return xReturn;
}
#endif
/*-----------------------------------------------------------*/
#if (configUSE_TRACE_FACILITY == 1)
UBaseType_t uxEventGroupGetNumber( void* xEventGroup )
{
UBaseType_t xReturn;
EventGroup_t const *pxEventBits = ( EventGroup_t * ) xEventGroup; /*lint !e9087 !e9079 EventGroupHandle_t is a pointer to an EventGroup_t, but EventGroupHandle_t is kept opaque outside of this file for data hiding purposes. */
if( xEventGroup == NULL )
{
xReturn = 0;
}
else
{
xReturn = pxEventBits->uxEventGroupNumber;
}
return xReturn;
}
#endif /* configUSE_TRACE_FACILITY */
/*-----------------------------------------------------------*/
#if ( configUSE_TRACE_FACILITY == 1 )
void vEventGroupSetNumber( void * xEventGroup, UBaseType_t uxEventGroupNumber )
{
( ( EventGroup_t * ) xEventGroup )->uxEventGroupNumber = uxEventGroupNumber; /*lint !e9087 !e9079 EventGroupHandle_t is a pointer to an EventGroup_t, but EventGroupHandle_t is kept opaque outside of this file for data hiding purposes. */
}
#endif /* configUSE_TRACE_FACILITY */
/*-----------------------------------------------------------*/
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,133 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef STACK_MACROS_H
#define STACK_MACROS_H
#ifndef _MSC_VER /* Visual Studio doesn't support #warning. */
#warning The name of this file has changed to stack_macros.h. Please update your code accordingly. This source file (which has the original name) will be removed in future released.
#endif
/*
* Call the stack overflow hook function if the stack of the task being swapped
* out is currently overflowed, or looks like it might have overflowed in the
* past.
*
* Setting configCHECK_FOR_STACK_OVERFLOW to 1 will cause the macro to check
* the current stack state only - comparing the current top of stack value to
* the stack limit. Setting configCHECK_FOR_STACK_OVERFLOW to greater than 1
* will also cause the last few stack bytes to be checked to ensure the value
* to which the bytes were set when the task was created have not been
* overwritten. Note this second test does not guarantee that an overflowed
* stack will always be recognised.
*/
/*-----------------------------------------------------------*/
#if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH < 0 ) )
/* Only the current stack state is to be checked. */
#define taskCHECK_FOR_STACK_OVERFLOW() \
{ \
/* Is the currently saved stack pointer within the stack limit? */ \
if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack ) \
{ \
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
} \
}
#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */
/*-----------------------------------------------------------*/
#if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH > 0 ) )
/* Only the current stack state is to be checked. */
#define taskCHECK_FOR_STACK_OVERFLOW() \
{ \
\
/* Is the currently saved stack pointer within the stack limit? */ \
if( pxCurrentTCB->pxTopOfStack >= pxCurrentTCB->pxEndOfStack ) \
{ \
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
} \
}
#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */
/*-----------------------------------------------------------*/
#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH < 0 ) )
#define taskCHECK_FOR_STACK_OVERFLOW() \
{ \
const uint32_t * const pulStack = ( uint32_t * ) pxCurrentTCB->pxStack; \
const uint32_t ulCheckValue = ( uint32_t ) 0xa5a5a5a5; \
\
if( ( pulStack[ 0 ] != ulCheckValue ) || \
( pulStack[ 1 ] != ulCheckValue ) || \
( pulStack[ 2 ] != ulCheckValue ) || \
( pulStack[ 3 ] != ulCheckValue ) ) \
{ \
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
} \
}
#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */
/*-----------------------------------------------------------*/
#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH > 0 ) )
#define taskCHECK_FOR_STACK_OVERFLOW() \
{ \
int8_t *pcEndOfStack = ( int8_t * ) pxCurrentTCB->pxEndOfStack; \
static const uint8_t ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \
\
\
pcEndOfStack -= sizeof( ucExpectedStackBytes ); \
\
/* Has the extremity of the task stack ever been written over? */ \
if( memcmp( ( void * ) pcEndOfStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \
{ \
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
} \
}
#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */
/*-----------------------------------------------------------*/
/* Remove stack overflow macro if not being used. */
#ifndef taskCHECK_FOR_STACK_OVERFLOW
#define taskCHECK_FOR_STACK_OVERFLOW()
#endif
#endif /* STACK_MACROS_H */
@@ -0,0 +1,720 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef CO_ROUTINE_H
#define CO_ROUTINE_H
#ifndef INC_FREERTOS_H
#error "include FreeRTOS.h must appear in source files before include croutine.h"
#endif
#include "list.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Used to hide the implementation of the co-routine control block. The
control block structure however has to be included in the header due to
the macro implementation of the co-routine functionality. */
typedef void * CoRoutineHandle_t;
/* Defines the prototype to which co-routine functions must conform. */
typedef void (*crCOROUTINE_CODE)( CoRoutineHandle_t, UBaseType_t );
typedef struct corCoRoutineControlBlock
{
crCOROUTINE_CODE pxCoRoutineFunction;
ListItem_t xGenericListItem; /*< List item used to place the CRCB in ready and blocked queues. */
ListItem_t xEventListItem; /*< List item used to place the CRCB in event lists. */
UBaseType_t uxPriority; /*< The priority of the co-routine in relation to other co-routines. */
UBaseType_t uxIndex; /*< Used to distinguish between co-routines when multiple co-routines use the same co-routine function. */
uint16_t uxState; /*< Used internally by the co-routine implementation. */
} CRCB_t; /* Co-routine control block. Note must be identical in size down to uxPriority with TCB_t. */
/**
* croutine. h
*<pre>
BaseType_t xCoRoutineCreate(
crCOROUTINE_CODE pxCoRoutineCode,
UBaseType_t uxPriority,
UBaseType_t uxIndex
);</pre>
*
* Create a new co-routine and add it to the list of co-routines that are
* ready to run.
*
* @param pxCoRoutineCode Pointer to the co-routine function. Co-routine
* functions require special syntax - see the co-routine section of the WEB
* documentation for more information.
*
* @param uxPriority The priority with respect to other co-routines at which
* the co-routine will run.
*
* @param uxIndex Used to distinguish between different co-routines that
* execute the same function. See the example below and the co-routine section
* of the WEB documentation for further information.
*
* @return pdPASS if the co-routine was successfully created and added to a ready
* list, otherwise an error code defined with ProjDefs.h.
*
* Example usage:
<pre>
// Co-routine to be created.
void vFlashCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
{
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
// This may not be necessary for const variables.
static const char cLedToFlash[ 2 ] = { 5, 6 };
static const TickType_t uxFlashRates[ 2 ] = { 200, 400 };
// Must start every co-routine with a call to crSTART();
crSTART( xHandle );
for( ;; )
{
// This co-routine just delays for a fixed period, then toggles
// an LED. Two co-routines are created using this function, so
// the uxIndex parameter is used to tell the co-routine which
// LED to flash and how int32_t to delay. This assumes xQueue has
// already been created.
vParTestToggleLED( cLedToFlash[ uxIndex ] );
crDELAY( xHandle, uxFlashRates[ uxIndex ] );
}
// Must end every co-routine with a call to crEND();
crEND();
}
// Function that creates two co-routines.
void vOtherFunction( void )
{
uint8_t ucParameterToPass;
TaskHandle_t xHandle;
// Create two co-routines at priority 0. The first is given index 0
// so (from the code above) toggles LED 5 every 200 ticks. The second
// is given index 1 so toggles LED 6 every 400 ticks.
for( uxIndex = 0; uxIndex < 2; uxIndex++ )
{
xCoRoutineCreate( vFlashCoRoutine, 0, uxIndex );
}
}
</pre>
* \defgroup xCoRoutineCreate xCoRoutineCreate
* \ingroup Tasks
*/
BaseType_t xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, UBaseType_t uxPriority, UBaseType_t uxIndex );
/**
* croutine. h
*<pre>
void vCoRoutineSchedule( void );</pre>
*
* Run a co-routine.
*
* vCoRoutineSchedule() executes the highest priority co-routine that is able
* to run. The co-routine will execute until it either blocks, yields or is
* preempted by a task. Co-routines execute cooperatively so one
* co-routine cannot be preempted by another, but can be preempted by a task.
*
* If an application comprises of both tasks and co-routines then
* vCoRoutineSchedule should be called from the idle task (in an idle task
* hook).
*
* Example usage:
<pre>
// This idle task hook will schedule a co-routine each time it is called.
// The rest of the idle task will execute between co-routine calls.
void vApplicationIdleHook( void )
{
vCoRoutineSchedule();
}
// Alternatively, if you do not require any other part of the idle task to
// execute, the idle task hook can call vCoRoutineScheduler() within an
// infinite loop.
void vApplicationIdleHook( void )
{
for( ;; )
{
vCoRoutineSchedule();
}
}
</pre>
* \defgroup vCoRoutineSchedule vCoRoutineSchedule
* \ingroup Tasks
*/
void vCoRoutineSchedule( void );
/**
* croutine. h
* <pre>
crSTART( CoRoutineHandle_t xHandle );</pre>
*
* This macro MUST always be called at the start of a co-routine function.
*
* Example usage:
<pre>
// Co-routine to be created.
void vACoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
{
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
static int32_t ulAVariable;
// Must start every co-routine with a call to crSTART();
crSTART( xHandle );
for( ;; )
{
// Co-routine functionality goes here.
}
// Must end every co-routine with a call to crEND();
crEND();
}</pre>
* \defgroup crSTART crSTART
* \ingroup Tasks
*/
#define crSTART( pxCRCB ) switch( ( ( CRCB_t * )( pxCRCB ) )->uxState ) { case 0:
/**
* croutine. h
* <pre>
crEND();</pre>
*
* This macro MUST always be called at the end of a co-routine function.
*
* Example usage:
<pre>
// Co-routine to be created.
void vACoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
{
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
static int32_t ulAVariable;
// Must start every co-routine with a call to crSTART();
crSTART( xHandle );
for( ;; )
{
// Co-routine functionality goes here.
}
// Must end every co-routine with a call to crEND();
crEND();
}</pre>
* \defgroup crSTART crSTART
* \ingroup Tasks
*/
#define crEND() }
/*
* These macros are intended for internal use by the co-routine implementation
* only. The macros should not be used directly by application writers.
*/
#define crSET_STATE0( xHandle ) ( ( CRCB_t * )( xHandle ) )->uxState = (__LINE__ * 2); return; case (__LINE__ * 2):
#define crSET_STATE1( xHandle ) ( ( CRCB_t * )( xHandle ) )->uxState = ((__LINE__ * 2)+1); return; case ((__LINE__ * 2)+1):
/**
* croutine. h
*<pre>
crDELAY( CoRoutineHandle_t xHandle, TickType_t xTicksToDelay );</pre>
*
* Delay a co-routine for a fixed period of time.
*
* crDELAY can only be called from the co-routine function itself - not
* from within a function called by the co-routine function. This is because
* co-routines do not maintain their own stack.
*
* @param xHandle The handle of the co-routine to delay. This is the xHandle
* parameter of the co-routine function.
*
* @param xTickToDelay The number of ticks that the co-routine should delay
* for. The actual amount of time this equates to is defined by
* configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant portTICK_PERIOD_MS
* can be used to convert ticks to milliseconds.
*
* Example usage:
<pre>
// Co-routine to be created.
void vACoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
{
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
// This may not be necessary for const variables.
// We are to delay for 200ms.
static const xTickType xDelayTime = 200 / portTICK_PERIOD_MS;
// Must start every co-routine with a call to crSTART();
crSTART( xHandle );
for( ;; )
{
// Delay for 200ms.
crDELAY( xHandle, xDelayTime );
// Do something here.
}
// Must end every co-routine with a call to crEND();
crEND();
}</pre>
* \defgroup crDELAY crDELAY
* \ingroup Tasks
*/
#define crDELAY( xHandle, xTicksToDelay ) \
if( ( xTicksToDelay ) > 0 ) \
{ \
vCoRoutineAddToDelayedList( ( xTicksToDelay ), NULL ); \
} \
crSET_STATE0( ( xHandle ) );
/**
* <pre>
crQUEUE_SEND(
CoRoutineHandle_t xHandle,
QueueHandle_t pxQueue,
void *pvItemToQueue,
TickType_t xTicksToWait,
BaseType_t *pxResult
)</pre>
*
* The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine
* equivalent to the xQueueSend() and xQueueReceive() functions used by tasks.
*
* crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas
* xQueueSend() and xQueueReceive() can only be used from tasks.
*
* crQUEUE_SEND can only be called from the co-routine function itself - not
* from within a function called by the co-routine function. This is because
* co-routines do not maintain their own stack.
*
* See the co-routine section of the WEB documentation for information on
* passing data between tasks and co-routines and between ISR's and
* co-routines.
*
* @param xHandle The handle of the calling co-routine. This is the xHandle
* parameter of the co-routine function.
*
* @param pxQueue The handle of the queue on which the data will be posted.
* The handle is obtained as the return value when the queue is created using
* the xQueueCreate() API function.
*
* @param pvItemToQueue A pointer to the data being posted onto the queue.
* The number of bytes of each queued item is specified when the queue is
* created. This number of bytes is copied from pvItemToQueue into the queue
* itself.
*
* @param xTickToDelay The number of ticks that the co-routine should block
* to wait for space to become available on the queue, should space not be
* available immediately. The actual amount of time this equates to is defined
* by configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant
* portTICK_PERIOD_MS can be used to convert ticks to milliseconds (see example
* below).
*
* @param pxResult The variable pointed to by pxResult will be set to pdPASS if
* data was successfully posted onto the queue, otherwise it will be set to an
* error defined within ProjDefs.h.
*
* Example usage:
<pre>
// Co-routine function that blocks for a fixed period then posts a number onto
// a queue.
static void prvCoRoutineFlashTask( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
{
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
static BaseType_t xNumberToPost = 0;
static BaseType_t xResult;
// Co-routines must begin with a call to crSTART().
crSTART( xHandle );
for( ;; )
{
// This assumes the queue has already been created.
crQUEUE_SEND( xHandle, xCoRoutineQueue, &xNumberToPost, NO_DELAY, &xResult );
if( xResult != pdPASS )
{
// The message was not posted!
}
// Increment the number to be posted onto the queue.
xNumberToPost++;
// Delay for 100 ticks.
crDELAY( xHandle, 100 );
}
// Co-routines must end with a call to crEND().
crEND();
}</pre>
* \defgroup crQUEUE_SEND crQUEUE_SEND
* \ingroup Tasks
*/
#define crQUEUE_SEND( xHandle, pxQueue, pvItemToQueue, xTicksToWait, pxResult ) \
{ \
*( pxResult ) = xQueueCRSend( ( pxQueue) , ( pvItemToQueue) , ( xTicksToWait ) ); \
if( *( pxResult ) == errQUEUE_BLOCKED ) \
{ \
crSET_STATE0( ( xHandle ) ); \
*pxResult = xQueueCRSend( ( pxQueue ), ( pvItemToQueue ), 0 ); \
} \
if( *pxResult == errQUEUE_YIELD ) \
{ \
crSET_STATE1( ( xHandle ) ); \
*pxResult = pdPASS; \
} \
}
/**
* croutine. h
* <pre>
crQUEUE_RECEIVE(
CoRoutineHandle_t xHandle,
QueueHandle_t pxQueue,
void *pvBuffer,
TickType_t xTicksToWait,
BaseType_t *pxResult
)</pre>
*
* The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine
* equivalent to the xQueueSend() and xQueueReceive() functions used by tasks.
*
* crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas
* xQueueSend() and xQueueReceive() can only be used from tasks.
*
* crQUEUE_RECEIVE can only be called from the co-routine function itself - not
* from within a function called by the co-routine function. This is because
* co-routines do not maintain their own stack.
*
* See the co-routine section of the WEB documentation for information on
* passing data between tasks and co-routines and between ISR's and
* co-routines.
*
* @param xHandle The handle of the calling co-routine. This is the xHandle
* parameter of the co-routine function.
*
* @param pxQueue The handle of the queue from which the data will be received.
* The handle is obtained as the return value when the queue is created using
* the xQueueCreate() API function.
*
* @param pvBuffer The buffer into which the received item is to be copied.
* The number of bytes of each queued item is specified when the queue is
* created. This number of bytes is copied into pvBuffer.
*
* @param xTickToDelay The number of ticks that the co-routine should block
* to wait for data to become available from the queue, should data not be
* available immediately. The actual amount of time this equates to is defined
* by configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant
* portTICK_PERIOD_MS can be used to convert ticks to milliseconds (see the
* crQUEUE_SEND example).
*
* @param pxResult The variable pointed to by pxResult will be set to pdPASS if
* data was successfully retrieved from the queue, otherwise it will be set to
* an error code as defined within ProjDefs.h.
*
* Example usage:
<pre>
// A co-routine receives the number of an LED to flash from a queue. It
// blocks on the queue until the number is received.
static void prvCoRoutineFlashWorkTask( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
{
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
static BaseType_t xResult;
static UBaseType_t uxLEDToFlash;
// All co-routines must start with a call to crSTART().
crSTART( xHandle );
for( ;; )
{
// Wait for data to become available on the queue.
crQUEUE_RECEIVE( xHandle, xCoRoutineQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
if( xResult == pdPASS )
{
// We received the LED to flash - flash it!
vParTestToggleLED( uxLEDToFlash );
}
}
crEND();
}</pre>
* \defgroup crQUEUE_RECEIVE crQUEUE_RECEIVE
* \ingroup Tasks
*/
#define crQUEUE_RECEIVE( xHandle, pxQueue, pvBuffer, xTicksToWait, pxResult ) \
{ \
*( pxResult ) = xQueueCRReceive( ( pxQueue) , ( pvBuffer ), ( xTicksToWait ) ); \
if( *( pxResult ) == errQUEUE_BLOCKED ) \
{ \
crSET_STATE0( ( xHandle ) ); \
*( pxResult ) = xQueueCRReceive( ( pxQueue) , ( pvBuffer ), 0 ); \
} \
if( *( pxResult ) == errQUEUE_YIELD ) \
{ \
crSET_STATE1( ( xHandle ) ); \
*( pxResult ) = pdPASS; \
} \
}
/**
* croutine. h
* <pre>
crQUEUE_SEND_FROM_ISR(
QueueHandle_t pxQueue,
void *pvItemToQueue,
BaseType_t xCoRoutinePreviouslyWoken
)</pre>
*
* The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the
* co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR()
* functions used by tasks.
*
* crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to
* pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and
* xQueueReceiveFromISR() can only be used to pass data between a task and and
* ISR.
*
* crQUEUE_SEND_FROM_ISR can only be called from an ISR to send data to a queue
* that is being used from within a co-routine.
*
* See the co-routine section of the WEB documentation for information on
* passing data between tasks and co-routines and between ISR's and
* co-routines.
*
* @param xQueue The handle to the queue on which the item is to be posted.
*
* @param pvItemToQueue A pointer to the item that is to be placed on the
* queue. The size of the items the queue will hold was defined when the
* queue was created, so this many bytes will be copied from pvItemToQueue
* into the queue storage area.
*
* @param xCoRoutinePreviouslyWoken This is included so an ISR can post onto
* the same queue multiple times from a single interrupt. The first call
* should always pass in pdFALSE. Subsequent calls should pass in
* the value returned from the previous call.
*
* @return pdTRUE if a co-routine was woken by posting onto the queue. This is
* used by the ISR to determine if a context switch may be required following
* the ISR.
*
* Example usage:
<pre>
// A co-routine that blocks on a queue waiting for characters to be received.
static void vReceivingCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
{
char cRxedChar;
BaseType_t xResult;
// All co-routines must start with a call to crSTART().
crSTART( xHandle );
for( ;; )
{
// Wait for data to become available on the queue. This assumes the
// queue xCommsRxQueue has already been created!
crQUEUE_RECEIVE( xHandle, xCommsRxQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
// Was a character received?
if( xResult == pdPASS )
{
// Process the character here.
}
}
// All co-routines must end with a call to crEND().
crEND();
}
// An ISR that uses a queue to send characters received on a serial port to
// a co-routine.
void vUART_ISR( void )
{
char cRxedChar;
BaseType_t xCRWokenByPost = pdFALSE;
// We loop around reading characters until there are none left in the UART.
while( UART_RX_REG_NOT_EMPTY() )
{
// Obtain the character from the UART.
cRxedChar = UART_RX_REG;
// Post the character onto a queue. xCRWokenByPost will be pdFALSE
// the first time around the loop. If the post causes a co-routine
// to be woken (unblocked) then xCRWokenByPost will be set to pdTRUE.
// In this manner we can ensure that if more than one co-routine is
// blocked on the queue only one is woken by this ISR no matter how
// many characters are posted to the queue.
xCRWokenByPost = crQUEUE_SEND_FROM_ISR( xCommsRxQueue, &cRxedChar, xCRWokenByPost );
}
}</pre>
* \defgroup crQUEUE_SEND_FROM_ISR crQUEUE_SEND_FROM_ISR
* \ingroup Tasks
*/
#define crQUEUE_SEND_FROM_ISR( pxQueue, pvItemToQueue, xCoRoutinePreviouslyWoken ) xQueueCRSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( xCoRoutinePreviouslyWoken ) )
/**
* croutine. h
* <pre>
crQUEUE_SEND_FROM_ISR(
QueueHandle_t pxQueue,
void *pvBuffer,
BaseType_t * pxCoRoutineWoken
)</pre>
*
* The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the
* co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR()
* functions used by tasks.
*
* crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to
* pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and
* xQueueReceiveFromISR() can only be used to pass data between a task and and
* ISR.
*
* crQUEUE_RECEIVE_FROM_ISR can only be called from an ISR to receive data
* from a queue that is being used from within a co-routine (a co-routine
* posted to the queue).
*
* See the co-routine section of the WEB documentation for information on
* passing data between tasks and co-routines and between ISR's and
* co-routines.
*
* @param xQueue The handle to the queue on which the item is to be posted.
*
* @param pvBuffer A pointer to a buffer into which the received item will be
* placed. The size of the items the queue will hold was defined when the
* queue was created, so this many bytes will be copied from the queue into
* pvBuffer.
*
* @param pxCoRoutineWoken A co-routine may be blocked waiting for space to become
* available on the queue. If crQUEUE_RECEIVE_FROM_ISR causes such a
* co-routine to unblock *pxCoRoutineWoken will get set to pdTRUE, otherwise
* *pxCoRoutineWoken will remain unchanged.
*
* @return pdTRUE an item was successfully received from the queue, otherwise
* pdFALSE.
*
* Example usage:
<pre>
// A co-routine that posts a character to a queue then blocks for a fixed
// period. The character is incremented each time.
static void vSendingCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
{
// cChar holds its value while this co-routine is blocked and must therefore
// be declared static.
static char cCharToTx = 'a';
BaseType_t xResult;
// All co-routines must start with a call to crSTART().
crSTART( xHandle );
for( ;; )
{
// Send the next character to the queue.
crQUEUE_SEND( xHandle, xCoRoutineQueue, &cCharToTx, NO_DELAY, &xResult );
if( xResult == pdPASS )
{
// The character was successfully posted to the queue.
}
else
{
// Could not post the character to the queue.
}
// Enable the UART Tx interrupt to cause an interrupt in this
// hypothetical UART. The interrupt will obtain the character
// from the queue and send it.
ENABLE_RX_INTERRUPT();
// Increment to the next character then block for a fixed period.
// cCharToTx will maintain its value across the delay as it is
// declared static.
cCharToTx++;
if( cCharToTx > 'x' )
{
cCharToTx = 'a';
}
crDELAY( 100 );
}
// All co-routines must end with a call to crEND().
crEND();
}
// An ISR that uses a queue to receive characters to send on a UART.
void vUART_ISR( void )
{
char cCharToTx;
BaseType_t xCRWokenByPost = pdFALSE;
while( UART_TX_REG_EMPTY() )
{
// Are there any characters in the queue waiting to be sent?
// xCRWokenByPost will automatically be set to pdTRUE if a co-routine
// is woken by the post - ensuring that only a single co-routine is
// woken no matter how many times we go around this loop.
if( crQUEUE_RECEIVE_FROM_ISR( pxQueue, &cCharToTx, &xCRWokenByPost ) )
{
SEND_CHARACTER( cCharToTx );
}
}
}</pre>
* \defgroup crQUEUE_RECEIVE_FROM_ISR crQUEUE_RECEIVE_FROM_ISR
* \ingroup Tasks
*/
#define crQUEUE_RECEIVE_FROM_ISR( pxQueue, pvBuffer, pxCoRoutineWoken ) xQueueCRReceiveFromISR( ( pxQueue ), ( pvBuffer ), ( pxCoRoutineWoken ) )
/*
* This function is intended for internal use by the co-routine macros only.
* The macro nature of the co-routine implementation requires that the
* prototype appears here. The function should not be used by application
* writers.
*
* Removes the current co-routine from its ready list and places it in the
* appropriate delayed list.
*/
void vCoRoutineAddToDelayedList( TickType_t xTicksToDelay, List_t *pxEventList );
/*
* This function is intended for internal use by the queue implementation only.
* The function should not be used by application writers.
*
* Removes the highest priority co-routine from the event list and places it in
* the pending ready list.
*/
BaseType_t xCoRoutineRemoveFromEventList( const List_t *pxEventList );
#ifdef __cplusplus
}
#endif
#endif /* CO_ROUTINE_H */
@@ -0,0 +1,279 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef DEPRECATED_DEFINITIONS_H
#define DEPRECATED_DEFINITIONS_H
/* Each FreeRTOS port has a unique portmacro.h header file. Originally a
pre-processor definition was used to ensure the pre-processor found the correct
portmacro.h file for the port being used. That scheme was deprecated in favour
of setting the compiler's include path such that it found the correct
portmacro.h file - removing the need for the constant and allowing the
portmacro.h file to be located anywhere in relation to the port being used. The
definitions below remain in the code for backward compatibility only. New
projects should not use them. */
#ifdef OPEN_WATCOM_INDUSTRIAL_PC_PORT
#include "..\..\Source\portable\owatcom\16bitdos\pc\portmacro.h"
typedef void ( __interrupt __far *pxISR )();
#endif
#ifdef OPEN_WATCOM_FLASH_LITE_186_PORT
#include "..\..\Source\portable\owatcom\16bitdos\flsh186\portmacro.h"
typedef void ( __interrupt __far *pxISR )();
#endif
#ifdef GCC_MEGA_AVR
#include "../portable/GCC/ATMega323/portmacro.h"
#endif
#ifdef IAR_MEGA_AVR
#include "../portable/IAR/ATMega323/portmacro.h"
#endif
#ifdef MPLAB_PIC24_PORT
#include "../../Source/portable/MPLAB/PIC24_dsPIC/portmacro.h"
#endif
#ifdef MPLAB_DSPIC_PORT
#include "../../Source/portable/MPLAB/PIC24_dsPIC/portmacro.h"
#endif
#ifdef MPLAB_PIC18F_PORT
#include "../../Source/portable/MPLAB/PIC18F/portmacro.h"
#endif
#ifdef MPLAB_PIC32MX_PORT
#include "../../Source/portable/MPLAB/PIC32MX/portmacro.h"
#endif
#ifdef _FEDPICC
#include "libFreeRTOS/Include/portmacro.h"
#endif
#ifdef SDCC_CYGNAL
#include "../../Source/portable/SDCC/Cygnal/portmacro.h"
#endif
#ifdef GCC_ARM7
#include "../../Source/portable/GCC/ARM7_LPC2000/portmacro.h"
#endif
#ifdef GCC_ARM7_ECLIPSE
#include "portmacro.h"
#endif
#ifdef ROWLEY_LPC23xx
#include "../../Source/portable/GCC/ARM7_LPC23xx/portmacro.h"
#endif
#ifdef IAR_MSP430
#include "..\..\Source\portable\IAR\MSP430\portmacro.h"
#endif
#ifdef GCC_MSP430
#include "../../Source/portable/GCC/MSP430F449/portmacro.h"
#endif
#ifdef ROWLEY_MSP430
#include "../../Source/portable/Rowley/MSP430F449/portmacro.h"
#endif
#ifdef ARM7_LPC21xx_KEIL_RVDS
#include "..\..\Source\portable\RVDS\ARM7_LPC21xx\portmacro.h"
#endif
#ifdef SAM7_GCC
#include "../../Source/portable/GCC/ARM7_AT91SAM7S/portmacro.h"
#endif
#ifdef SAM7_IAR
#include "..\..\Source\portable\IAR\AtmelSAM7S64\portmacro.h"
#endif
#ifdef SAM9XE_IAR
#include "..\..\Source\portable\IAR\AtmelSAM9XE\portmacro.h"
#endif
#ifdef LPC2000_IAR
#include "..\..\Source\portable\IAR\LPC2000\portmacro.h"
#endif
#ifdef STR71X_IAR
#include "..\..\Source\portable\IAR\STR71x\portmacro.h"
#endif
#ifdef STR75X_IAR
#include "..\..\Source\portable\IAR\STR75x\portmacro.h"
#endif
#ifdef STR75X_GCC
#include "..\..\Source\portable\GCC\STR75x\portmacro.h"
#endif
#ifdef STR91X_IAR
#include "..\..\Source\portable\IAR\STR91x\portmacro.h"
#endif
#ifdef GCC_H8S
#include "../../Source/portable/GCC/H8S2329/portmacro.h"
#endif
#ifdef GCC_AT91FR40008
#include "../../Source/portable/GCC/ARM7_AT91FR40008/portmacro.h"
#endif
#ifdef RVDS_ARMCM3_LM3S102
#include "../../Source/portable/RVDS/ARM_CM3/portmacro.h"
#endif
#ifdef GCC_ARMCM3_LM3S102
#include "../../Source/portable/GCC/ARM_CM3/portmacro.h"
#endif
#ifdef GCC_ARMCM3
#include "../../Source/portable/GCC/ARM_CM3/portmacro.h"
#endif
#ifdef IAR_ARM_CM3
#include "../../Source/portable/IAR/ARM_CM3/portmacro.h"
#endif
#ifdef IAR_ARMCM3_LM
#include "../../Source/portable/IAR/ARM_CM3/portmacro.h"
#endif
#ifdef HCS12_CODE_WARRIOR
#include "../../Source/portable/CodeWarrior/HCS12/portmacro.h"
#endif
#ifdef MICROBLAZE_GCC
#include "../../Source/portable/GCC/MicroBlaze/portmacro.h"
#endif
#ifdef TERN_EE
#include "..\..\Source\portable\Paradigm\Tern_EE\small\portmacro.h"
#endif
#ifdef GCC_HCS12
#include "../../Source/portable/GCC/HCS12/portmacro.h"
#endif
#ifdef GCC_MCF5235
#include "../../Source/portable/GCC/MCF5235/portmacro.h"
#endif
#ifdef COLDFIRE_V2_GCC
#include "../../../Source/portable/GCC/ColdFire_V2/portmacro.h"
#endif
#ifdef COLDFIRE_V2_CODEWARRIOR
#include "../../Source/portable/CodeWarrior/ColdFire_V2/portmacro.h"
#endif
#ifdef GCC_PPC405
#include "../../Source/portable/GCC/PPC405_Xilinx/portmacro.h"
#endif
#ifdef GCC_PPC440
#include "../../Source/portable/GCC/PPC440_Xilinx/portmacro.h"
#endif
#ifdef _16FX_SOFTUNE
#include "..\..\Source\portable\Softune\MB96340\portmacro.h"
#endif
#ifdef BCC_INDUSTRIAL_PC_PORT
/* A short file name has to be used in place of the normal
FreeRTOSConfig.h when using the Borland compiler. */
#include "frconfig.h"
#include "..\portable\BCC\16BitDOS\PC\prtmacro.h"
typedef void ( __interrupt __far *pxISR )();
#endif
#ifdef BCC_FLASH_LITE_186_PORT
/* A short file name has to be used in place of the normal
FreeRTOSConfig.h when using the Borland compiler. */
#include "frconfig.h"
#include "..\portable\BCC\16BitDOS\flsh186\prtmacro.h"
typedef void ( __interrupt __far *pxISR )();
#endif
#ifdef __GNUC__
#ifdef __AVR32_AVR32A__
#include "portmacro.h"
#endif
#endif
#ifdef __ICCAVR32__
#ifdef __CORE__
#if __CORE__ == __AVR32A__
#include "portmacro.h"
#endif
#endif
#endif
#ifdef __91467D
#include "portmacro.h"
#endif
#ifdef __96340
#include "portmacro.h"
#endif
#ifdef __IAR_V850ES_Fx3__
#include "../../Source/portable/IAR/V850ES/portmacro.h"
#endif
#ifdef __IAR_V850ES_Jx3__
#include "../../Source/portable/IAR/V850ES/portmacro.h"
#endif
#ifdef __IAR_V850ES_Jx3_L__
#include "../../Source/portable/IAR/V850ES/portmacro.h"
#endif
#ifdef __IAR_V850ES_Jx2__
#include "../../Source/portable/IAR/V850ES/portmacro.h"
#endif
#ifdef __IAR_V850ES_Hx2__
#include "../../Source/portable/IAR/V850ES/portmacro.h"
#endif
#ifdef __IAR_78K0R_Kx3__
#include "../../Source/portable/IAR/78K0R/portmacro.h"
#endif
#ifdef __IAR_78K0R_Kx3L__
#include "../../Source/portable/IAR/78K0R/portmacro.h"
#endif
#endif /* DEPRECATED_DEFINITIONS_H */
@@ -0,0 +1,757 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef EVENT_GROUPS_H
#define EVENT_GROUPS_H
#ifndef INC_FREERTOS_H
#error "include FreeRTOS.h" must appear in source files before "include event_groups.h"
#endif
/* FreeRTOS includes. */
#include "timers.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* An event group is a collection of bits to which an application can assign a
* meaning. For example, an application may create an event group to convey
* the status of various CAN bus related events in which bit 0 might mean "A CAN
* message has been received and is ready for processing", bit 1 might mean "The
* application has queued a message that is ready for sending onto the CAN
* network", and bit 2 might mean "It is time to send a SYNC message onto the
* CAN network" etc. A task can then test the bit values to see which events
* are active, and optionally enter the Blocked state to wait for a specified
* bit or a group of specified bits to be active. To continue the CAN bus
* example, a CAN controlling task can enter the Blocked state (and therefore
* not consume any processing time) until either bit 0, bit 1 or bit 2 are
* active, at which time the bit that was actually active would inform the task
* which action it had to take (process a received message, send a message, or
* send a SYNC).
*
* The event groups implementation contains intelligence to avoid race
* conditions that would otherwise occur were an application to use a simple
* variable for the same purpose. This is particularly important with respect
* to when a bit within an event group is to be cleared, and when bits have to
* be set and then tested atomically - as is the case where event groups are
* used to create a synchronisation point between multiple tasks (a
* 'rendezvous').
*
* \defgroup EventGroup
*/
/**
* event_groups.h
*
* Type by which event groups are referenced. For example, a call to
* xEventGroupCreate() returns an EventGroupHandle_t variable that can then
* be used as a parameter to other event group functions.
*
* \defgroup EventGroupHandle_t EventGroupHandle_t
* \ingroup EventGroup
*/
struct EventGroupDef_t;
typedef struct EventGroupDef_t * EventGroupHandle_t;
/*
* The type that holds event bits always matches TickType_t - therefore the
* number of bits it holds is set by configUSE_16_BIT_TICKS (16 bits if set to 1,
* 32 bits if set to 0.
*
* \defgroup EventBits_t EventBits_t
* \ingroup EventGroup
*/
typedef TickType_t EventBits_t;
/**
* event_groups.h
*<pre>
EventGroupHandle_t xEventGroupCreate( void );
</pre>
*
* Create a new event group.
*
* Internally, within the FreeRTOS implementation, event groups use a [small]
* block of memory, in which the event group's structure is stored. If an event
* groups is created using xEventGropuCreate() then the required memory is
* automatically dynamically allocated inside the xEventGroupCreate() function.
* (see http://www.freertos.org/a00111.html). If an event group is created
* using xEventGropuCreateStatic() then the application writer must instead
* provide the memory that will get used by the event group.
* xEventGroupCreateStatic() therefore allows an event group to be created
* without using any dynamic memory allocation.
*
* Although event groups are not related to ticks, for internal implementation
* reasons the number of bits available for use in an event group is dependent
* on the configUSE_16_BIT_TICKS setting in FreeRTOSConfig.h. If
* configUSE_16_BIT_TICKS is 1 then each event group contains 8 usable bits (bit
* 0 to bit 7). If configUSE_16_BIT_TICKS is set to 0 then each event group has
* 24 usable bits (bit 0 to bit 23). The EventBits_t type is used to store
* event bits within an event group.
*
* @return If the event group was created then a handle to the event group is
* returned. If there was insufficient FreeRTOS heap available to create the
* event group then NULL is returned. See http://www.freertos.org/a00111.html
*
* Example usage:
<pre>
// Declare a variable to hold the created event group.
EventGroupHandle_t xCreatedEventGroup;
// Attempt to create the event group.
xCreatedEventGroup = xEventGroupCreate();
// Was the event group created successfully?
if( xCreatedEventGroup == NULL )
{
// The event group was not created because there was insufficient
// FreeRTOS heap available.
}
else
{
// The event group was created.
}
</pre>
* \defgroup xEventGroupCreate xEventGroupCreate
* \ingroup EventGroup
*/
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
EventGroupHandle_t xEventGroupCreate( void ) PRIVILEGED_FUNCTION;
#endif
/**
* event_groups.h
*<pre>
EventGroupHandle_t xEventGroupCreateStatic( EventGroupHandle_t * pxEventGroupBuffer );
</pre>
*
* Create a new event group.
*
* Internally, within the FreeRTOS implementation, event groups use a [small]
* block of memory, in which the event group's structure is stored. If an event
* groups is created using xEventGropuCreate() then the required memory is
* automatically dynamically allocated inside the xEventGroupCreate() function.
* (see http://www.freertos.org/a00111.html). If an event group is created
* using xEventGropuCreateStatic() then the application writer must instead
* provide the memory that will get used by the event group.
* xEventGroupCreateStatic() therefore allows an event group to be created
* without using any dynamic memory allocation.
*
* Although event groups are not related to ticks, for internal implementation
* reasons the number of bits available for use in an event group is dependent
* on the configUSE_16_BIT_TICKS setting in FreeRTOSConfig.h. If
* configUSE_16_BIT_TICKS is 1 then each event group contains 8 usable bits (bit
* 0 to bit 7). If configUSE_16_BIT_TICKS is set to 0 then each event group has
* 24 usable bits (bit 0 to bit 23). The EventBits_t type is used to store
* event bits within an event group.
*
* @param pxEventGroupBuffer pxEventGroupBuffer must point to a variable of type
* StaticEventGroup_t, which will be then be used to hold the event group's data
* structures, removing the need for the memory to be allocated dynamically.
*
* @return If the event group was created then a handle to the event group is
* returned. If pxEventGroupBuffer was NULL then NULL is returned.
*
* Example usage:
<pre>
// StaticEventGroup_t is a publicly accessible structure that has the same
// size and alignment requirements as the real event group structure. It is
// provided as a mechanism for applications to know the size of the event
// group (which is dependent on the architecture and configuration file
// settings) without breaking the strict data hiding policy by exposing the
// real event group internals. This StaticEventGroup_t variable is passed
// into the xSemaphoreCreateEventGroupStatic() function and is used to store
// the event group's data structures
StaticEventGroup_t xEventGroupBuffer;
// Create the event group without dynamically allocating any memory.
xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer );
</pre>
*/
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer ) PRIVILEGED_FUNCTION;
#endif
/**
* event_groups.h
*<pre>
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
const TickType_t xTicksToWait );
</pre>
*
* [Potentially] block to wait for one or more bits to be set within a
* previously created event group.
*
* This function cannot be called from an interrupt.
*
* @param xEventGroup The event group in which the bits are being tested. The
* event group must have previously been created using a call to
* xEventGroupCreate().
*
* @param uxBitsToWaitFor A bitwise value that indicates the bit or bits to test
* inside the event group. For example, to wait for bit 0 and/or bit 2 set
* uxBitsToWaitFor to 0x05. To wait for bits 0 and/or bit 1 and/or bit 2 set
* uxBitsToWaitFor to 0x07. Etc.
*
* @param xClearOnExit If xClearOnExit is set to pdTRUE then any bits within
* uxBitsToWaitFor that are set within the event group will be cleared before
* xEventGroupWaitBits() returns if the wait condition was met (if the function
* returns for a reason other than a timeout). If xClearOnExit is set to
* pdFALSE then the bits set in the event group are not altered when the call to
* xEventGroupWaitBits() returns.
*
* @param xWaitForAllBits If xWaitForAllBits is set to pdTRUE then
* xEventGroupWaitBits() will return when either all the bits in uxBitsToWaitFor
* are set or the specified block time expires. If xWaitForAllBits is set to
* pdFALSE then xEventGroupWaitBits() will return when any one of the bits set
* in uxBitsToWaitFor is set or the specified block time expires. The block
* time is specified by the xTicksToWait parameter.
*
* @param xTicksToWait The maximum amount of time (specified in 'ticks') to wait
* for one/all (depending on the xWaitForAllBits value) of the bits specified by
* uxBitsToWaitFor to become set.
*
* @return The value of the event group at the time either the bits being waited
* for became set, or the block time expired. Test the return value to know
* which bits were set. If xEventGroupWaitBits() returned because its timeout
* expired then not all the bits being waited for will be set. If
* xEventGroupWaitBits() returned because the bits it was waiting for were set
* then the returned value is the event group value before any bits were
* automatically cleared in the case that xClearOnExit parameter was set to
* pdTRUE.
*
* Example usage:
<pre>
#define BIT_0 ( 1 << 0 )
#define BIT_4 ( 1 << 4 )
void aFunction( EventGroupHandle_t xEventGroup )
{
EventBits_t uxBits;
const TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;
// Wait a maximum of 100ms for either bit 0 or bit 4 to be set within
// the event group. Clear the bits before exiting.
uxBits = xEventGroupWaitBits(
xEventGroup, // The event group being tested.
BIT_0 | BIT_4, // The bits within the event group to wait for.
pdTRUE, // BIT_0 and BIT_4 should be cleared before returning.
pdFALSE, // Don't wait for both bits, either bit will do.
xTicksToWait ); // Wait a maximum of 100ms for either bit to be set.
if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
{
// xEventGroupWaitBits() returned because both bits were set.
}
else if( ( uxBits & BIT_0 ) != 0 )
{
// xEventGroupWaitBits() returned because just BIT_0 was set.
}
else if( ( uxBits & BIT_4 ) != 0 )
{
// xEventGroupWaitBits() returned because just BIT_4 was set.
}
else
{
// xEventGroupWaitBits() returned because xTicksToWait ticks passed
// without either BIT_0 or BIT_4 becoming set.
}
}
</pre>
* \defgroup xEventGroupWaitBits xEventGroupWaitBits
* \ingroup EventGroup
*/
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
/**
* event_groups.h
*<pre>
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear );
</pre>
*
* Clear bits within an event group. This function cannot be called from an
* interrupt.
*
* @param xEventGroup The event group in which the bits are to be cleared.
*
* @param uxBitsToClear A bitwise value that indicates the bit or bits to clear
* in the event group. For example, to clear bit 3 only, set uxBitsToClear to
* 0x08. To clear bit 3 and bit 0 set uxBitsToClear to 0x09.
*
* @return The value of the event group before the specified bits were cleared.
*
* Example usage:
<pre>
#define BIT_0 ( 1 << 0 )
#define BIT_4 ( 1 << 4 )
void aFunction( EventGroupHandle_t xEventGroup )
{
EventBits_t uxBits;
// Clear bit 0 and bit 4 in xEventGroup.
uxBits = xEventGroupClearBits(
xEventGroup, // The event group being updated.
BIT_0 | BIT_4 );// The bits being cleared.
if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
{
// Both bit 0 and bit 4 were set before xEventGroupClearBits() was
// called. Both will now be clear (not set).
}
else if( ( uxBits & BIT_0 ) != 0 )
{
// Bit 0 was set before xEventGroupClearBits() was called. It will
// now be clear.
}
else if( ( uxBits & BIT_4 ) != 0 )
{
// Bit 4 was set before xEventGroupClearBits() was called. It will
// now be clear.
}
else
{
// Neither bit 0 nor bit 4 were set in the first place.
}
}
</pre>
* \defgroup xEventGroupClearBits xEventGroupClearBits
* \ingroup EventGroup
*/
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) PRIVILEGED_FUNCTION;
/**
* event_groups.h
*<pre>
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
</pre>
*
* A version of xEventGroupClearBits() that can be called from an interrupt.
*
* Setting bits in an event group is not a deterministic operation because there
* are an unknown number of tasks that may be waiting for the bit or bits being
* set. FreeRTOS does not allow nondeterministic operations to be performed
* while interrupts are disabled, so protects event groups that are accessed
* from tasks by suspending the scheduler rather than disabling interrupts. As
* a result event groups cannot be accessed directly from an interrupt service
* routine. Therefore xEventGroupClearBitsFromISR() sends a message to the
* timer task to have the clear operation performed in the context of the timer
* task.
*
* @param xEventGroup The event group in which the bits are to be cleared.
*
* @param uxBitsToClear A bitwise value that indicates the bit or bits to clear.
* For example, to clear bit 3 only, set uxBitsToClear to 0x08. To clear bit 3
* and bit 0 set uxBitsToClear to 0x09.
*
* @return If the request to execute the function was posted successfully then
* pdPASS is returned, otherwise pdFALSE is returned. pdFALSE will be returned
* if the timer service queue was full.
*
* Example usage:
<pre>
#define BIT_0 ( 1 << 0 )
#define BIT_4 ( 1 << 4 )
// An event group which it is assumed has already been created by a call to
// xEventGroupCreate().
EventGroupHandle_t xEventGroup;
void anInterruptHandler( void )
{
// Clear bit 0 and bit 4 in xEventGroup.
xResult = xEventGroupClearBitsFromISR(
xEventGroup, // The event group being updated.
BIT_0 | BIT_4 ); // The bits being set.
if( xResult == pdPASS )
{
// The message was posted successfully.
}
}
</pre>
* \defgroup xEventGroupClearBitsFromISR xEventGroupClearBitsFromISR
* \ingroup EventGroup
*/
#if( configUSE_TRACE_FACILITY == 1 )
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) PRIVILEGED_FUNCTION;
#else
#define xEventGroupClearBitsFromISR( xEventGroup, uxBitsToClear ) xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL )
#endif
/**
* event_groups.h
*<pre>
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
</pre>
*
* Set bits within an event group.
* This function cannot be called from an interrupt. xEventGroupSetBitsFromISR()
* is a version that can be called from an interrupt.
*
* Setting bits in an event group will automatically unblock tasks that are
* blocked waiting for the bits.
*
* @param xEventGroup The event group in which the bits are to be set.
*
* @param uxBitsToSet A bitwise value that indicates the bit or bits to set.
* For example, to set bit 3 only, set uxBitsToSet to 0x08. To set bit 3
* and bit 0 set uxBitsToSet to 0x09.
*
* @return The value of the event group at the time the call to
* xEventGroupSetBits() returns. There are two reasons why the returned value
* might have the bits specified by the uxBitsToSet parameter cleared. First,
* if setting a bit results in a task that was waiting for the bit leaving the
* blocked state then it is possible the bit will be cleared automatically
* (see the xClearBitOnExit parameter of xEventGroupWaitBits()). Second, any
* unblocked (or otherwise Ready state) task that has a priority above that of
* the task that called xEventGroupSetBits() will execute and may change the
* event group value before the call to xEventGroupSetBits() returns.
*
* Example usage:
<pre>
#define BIT_0 ( 1 << 0 )
#define BIT_4 ( 1 << 4 )
void aFunction( EventGroupHandle_t xEventGroup )
{
EventBits_t uxBits;
// Set bit 0 and bit 4 in xEventGroup.
uxBits = xEventGroupSetBits(
xEventGroup, // The event group being updated.
BIT_0 | BIT_4 );// The bits being set.
if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
{
// Both bit 0 and bit 4 remained set when the function returned.
}
else if( ( uxBits & BIT_0 ) != 0 )
{
// Bit 0 remained set when the function returned, but bit 4 was
// cleared. It might be that bit 4 was cleared automatically as a
// task that was waiting for bit 4 was removed from the Blocked
// state.
}
else if( ( uxBits & BIT_4 ) != 0 )
{
// Bit 4 remained set when the function returned, but bit 0 was
// cleared. It might be that bit 0 was cleared automatically as a
// task that was waiting for bit 0 was removed from the Blocked
// state.
}
else
{
// Neither bit 0 nor bit 4 remained set. It might be that a task
// was waiting for both of the bits to be set, and the bits were
// cleared as the task left the Blocked state.
}
}
</pre>
* \defgroup xEventGroupSetBits xEventGroupSetBits
* \ingroup EventGroup
*/
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ) PRIVILEGED_FUNCTION;
/**
* event_groups.h
*<pre>
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken );
</pre>
*
* A version of xEventGroupSetBits() that can be called from an interrupt.
*
* Setting bits in an event group is not a deterministic operation because there
* are an unknown number of tasks that may be waiting for the bit or bits being
* set. FreeRTOS does not allow nondeterministic operations to be performed in
* interrupts or from critical sections. Therefore xEventGroupSetBitsFromISR()
* sends a message to the timer task to have the set operation performed in the
* context of the timer task - where a scheduler lock is used in place of a
* critical section.
*
* @param xEventGroup The event group in which the bits are to be set.
*
* @param uxBitsToSet A bitwise value that indicates the bit or bits to set.
* For example, to set bit 3 only, set uxBitsToSet to 0x08. To set bit 3
* and bit 0 set uxBitsToSet to 0x09.
*
* @param pxHigherPriorityTaskWoken As mentioned above, calling this function
* will result in a message being sent to the timer daemon task. If the
* priority of the timer daemon task is higher than the priority of the
* currently running task (the task the interrupt interrupted) then
* *pxHigherPriorityTaskWoken will be set to pdTRUE by
* xEventGroupSetBitsFromISR(), indicating that a context switch should be
* requested before the interrupt exits. For that reason
* *pxHigherPriorityTaskWoken must be initialised to pdFALSE. See the
* example code below.
*
* @return If the request to execute the function was posted successfully then
* pdPASS is returned, otherwise pdFALSE is returned. pdFALSE will be returned
* if the timer service queue was full.
*
* Example usage:
<pre>
#define BIT_0 ( 1 << 0 )
#define BIT_4 ( 1 << 4 )
// An event group which it is assumed has already been created by a call to
// xEventGroupCreate().
EventGroupHandle_t xEventGroup;
void anInterruptHandler( void )
{
BaseType_t xHigherPriorityTaskWoken, xResult;
// xHigherPriorityTaskWoken must be initialised to pdFALSE.
xHigherPriorityTaskWoken = pdFALSE;
// Set bit 0 and bit 4 in xEventGroup.
xResult = xEventGroupSetBitsFromISR(
xEventGroup, // The event group being updated.
BIT_0 | BIT_4 // The bits being set.
&xHigherPriorityTaskWoken );
// Was the message posted successfully?
if( xResult == pdPASS )
{
// If xHigherPriorityTaskWoken is now set to pdTRUE then a context
// switch should be requested. The macro used is port specific and
// will be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() -
// refer to the documentation page for the port being used.
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
}
</pre>
* \defgroup xEventGroupSetBitsFromISR xEventGroupSetBitsFromISR
* \ingroup EventGroup
*/
#if( configUSE_TRACE_FACILITY == 1 )
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
#else
#define xEventGroupSetBitsFromISR( xEventGroup, uxBitsToSet, pxHigherPriorityTaskWoken ) xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken )
#endif
/**
* event_groups.h
*<pre>
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
const EventBits_t uxBitsToWaitFor,
TickType_t xTicksToWait );
</pre>
*
* Atomically set bits within an event group, then wait for a combination of
* bits to be set within the same event group. This functionality is typically
* used to synchronise multiple tasks, where each task has to wait for the other
* tasks to reach a synchronisation point before proceeding.
*
* This function cannot be used from an interrupt.
*
* The function will return before its block time expires if the bits specified
* by the uxBitsToWait parameter are set, or become set within that time. In
* this case all the bits specified by uxBitsToWait will be automatically
* cleared before the function returns.
*
* @param xEventGroup The event group in which the bits are being tested. The
* event group must have previously been created using a call to
* xEventGroupCreate().
*
* @param uxBitsToSet The bits to set in the event group before determining
* if, and possibly waiting for, all the bits specified by the uxBitsToWait
* parameter are set.
*
* @param uxBitsToWaitFor A bitwise value that indicates the bit or bits to test
* inside the event group. For example, to wait for bit 0 and bit 2 set
* uxBitsToWaitFor to 0x05. To wait for bits 0 and bit 1 and bit 2 set
* uxBitsToWaitFor to 0x07. Etc.
*
* @param xTicksToWait The maximum amount of time (specified in 'ticks') to wait
* for all of the bits specified by uxBitsToWaitFor to become set.
*
* @return The value of the event group at the time either the bits being waited
* for became set, or the block time expired. Test the return value to know
* which bits were set. If xEventGroupSync() returned because its timeout
* expired then not all the bits being waited for will be set. If
* xEventGroupSync() returned because all the bits it was waiting for were
* set then the returned value is the event group value before any bits were
* automatically cleared.
*
* Example usage:
<pre>
// Bits used by the three tasks.
#define TASK_0_BIT ( 1 << 0 )
#define TASK_1_BIT ( 1 << 1 )
#define TASK_2_BIT ( 1 << 2 )
#define ALL_SYNC_BITS ( TASK_0_BIT | TASK_1_BIT | TASK_2_BIT )
// Use an event group to synchronise three tasks. It is assumed this event
// group has already been created elsewhere.
EventGroupHandle_t xEventBits;
void vTask0( void *pvParameters )
{
EventBits_t uxReturn;
TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;
for( ;; )
{
// Perform task functionality here.
// Set bit 0 in the event flag to note this task has reached the
// sync point. The other two tasks will set the other two bits defined
// by ALL_SYNC_BITS. All three tasks have reached the synchronisation
// point when all the ALL_SYNC_BITS are set. Wait a maximum of 100ms
// for this to happen.
uxReturn = xEventGroupSync( xEventBits, TASK_0_BIT, ALL_SYNC_BITS, xTicksToWait );
if( ( uxReturn & ALL_SYNC_BITS ) == ALL_SYNC_BITS )
{
// All three tasks reached the synchronisation point before the call
// to xEventGroupSync() timed out.
}
}
}
void vTask1( void *pvParameters )
{
for( ;; )
{
// Perform task functionality here.
// Set bit 1 in the event flag to note this task has reached the
// synchronisation point. The other two tasks will set the other two
// bits defined by ALL_SYNC_BITS. All three tasks have reached the
// synchronisation point when all the ALL_SYNC_BITS are set. Wait
// indefinitely for this to happen.
xEventGroupSync( xEventBits, TASK_1_BIT, ALL_SYNC_BITS, portMAX_DELAY );
// xEventGroupSync() was called with an indefinite block time, so
// this task will only reach here if the syncrhonisation was made by all
// three tasks, so there is no need to test the return value.
}
}
void vTask2( void *pvParameters )
{
for( ;; )
{
// Perform task functionality here.
// Set bit 2 in the event flag to note this task has reached the
// synchronisation point. The other two tasks will set the other two
// bits defined by ALL_SYNC_BITS. All three tasks have reached the
// synchronisation point when all the ALL_SYNC_BITS are set. Wait
// indefinitely for this to happen.
xEventGroupSync( xEventBits, TASK_2_BIT, ALL_SYNC_BITS, portMAX_DELAY );
// xEventGroupSync() was called with an indefinite block time, so
// this task will only reach here if the syncrhonisation was made by all
// three tasks, so there is no need to test the return value.
}
}
</pre>
* \defgroup xEventGroupSync xEventGroupSync
* \ingroup EventGroup
*/
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
/**
* event_groups.h
*<pre>
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup );
</pre>
*
* Returns the current value of the bits in an event group. This function
* cannot be used from an interrupt.
*
* @param xEventGroup The event group being queried.
*
* @return The event group bits at the time xEventGroupGetBits() was called.
*
* \defgroup xEventGroupGetBits xEventGroupGetBits
* \ingroup EventGroup
*/
#define xEventGroupGetBits( xEventGroup ) xEventGroupClearBits( xEventGroup, 0 )
/**
* event_groups.h
*<pre>
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup );
</pre>
*
* A version of xEventGroupGetBits() that can be called from an ISR.
*
* @param xEventGroup The event group being queried.
*
* @return The event group bits at the time xEventGroupGetBitsFromISR() was called.
*
* \defgroup xEventGroupGetBitsFromISR xEventGroupGetBitsFromISR
* \ingroup EventGroup
*/
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ) PRIVILEGED_FUNCTION;
/**
* event_groups.h
*<pre>
void xEventGroupDelete( EventGroupHandle_t xEventGroup );
</pre>
*
* Delete an event group that was previously created by a call to
* xEventGroupCreate(). Tasks that are blocked on the event group will be
* unblocked and obtain 0 as the event group's value.
*
* @param xEventGroup The event group being deleted.
*/
void vEventGroupDelete( EventGroupHandle_t xEventGroup ) PRIVILEGED_FUNCTION;
/* For internal use only. */
void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet ) PRIVILEGED_FUNCTION;
void vEventGroupClearBitsCallback( void *pvEventGroup, const uint32_t ulBitsToClear ) PRIVILEGED_FUNCTION;
#if (configUSE_TRACE_FACILITY == 1)
UBaseType_t uxEventGroupGetNumber( void* xEventGroup ) PRIVILEGED_FUNCTION;
void vEventGroupSetNumber( void* xEventGroup, UBaseType_t uxEventGroupNumber ) PRIVILEGED_FUNCTION;
#endif
#ifdef __cplusplus
}
#endif
#endif /* EVENT_GROUPS_H */
@@ -0,0 +1,412 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/*
* This is the list implementation used by the scheduler. While it is tailored
* heavily for the schedulers needs, it is also available for use by
* application code.
*
* list_ts can only store pointers to list_item_ts. Each ListItem_t contains a
* numeric value (xItemValue). Most of the time the lists are sorted in
* descending item value order.
*
* Lists are created already containing one list item. The value of this
* item is the maximum possible that can be stored, it is therefore always at
* the end of the list and acts as a marker. The list member pxHead always
* points to this marker - even though it is at the tail of the list. This
* is because the tail contains a wrap back pointer to the true head of
* the list.
*
* In addition to it's value, each list item contains a pointer to the next
* item in the list (pxNext), a pointer to the list it is in (pxContainer)
* and a pointer to back to the object that contains it. These later two
* pointers are included for efficiency of list manipulation. There is
* effectively a two way link between the object containing the list item and
* the list item itself.
*
*
* \page ListIntroduction List Implementation
* \ingroup FreeRTOSIntro
*/
#ifndef INC_FREERTOS_H
#error FreeRTOS.h must be included before list.h
#endif
#ifndef LIST_H
#define LIST_H
/*
* The list structure members are modified from within interrupts, and therefore
* by rights should be declared volatile. However, they are only modified in a
* functionally atomic way (within critical sections of with the scheduler
* suspended) and are either passed by reference into a function or indexed via
* a volatile variable. Therefore, in all use cases tested so far, the volatile
* qualifier can be omitted in order to provide a moderate performance
* improvement without adversely affecting functional behaviour. The assembly
* instructions generated by the IAR, ARM and GCC compilers when the respective
* compiler's options were set for maximum optimisation has been inspected and
* deemed to be as intended. That said, as compiler technology advances, and
* especially if aggressive cross module optimisation is used (a use case that
* has not been exercised to any great extend) then it is feasible that the
* volatile qualifier will be needed for correct optimisation. It is expected
* that a compiler removing essential code because, without the volatile
* qualifier on the list structure members and with aggressive cross module
* optimisation, the compiler deemed the code unnecessary will result in
* complete and obvious failure of the scheduler. If this is ever experienced
* then the volatile qualifier can be inserted in the relevant places within the
* list structures by simply defining configLIST_VOLATILE to volatile in
* FreeRTOSConfig.h (as per the example at the bottom of this comment block).
* If configLIST_VOLATILE is not defined then the preprocessor directives below
* will simply #define configLIST_VOLATILE away completely.
*
* To use volatile list structure members then add the following line to
* FreeRTOSConfig.h (without the quotes):
* "#define configLIST_VOLATILE volatile"
*/
#ifndef configLIST_VOLATILE
#define configLIST_VOLATILE
#endif /* configSUPPORT_CROSS_MODULE_OPTIMISATION */
#ifdef __cplusplus
extern "C" {
#endif
/* Macros that can be used to place known values within the list structures,
then check that the known values do not get corrupted during the execution of
the application. These may catch the list data structures being overwritten in
memory. They will not catch data errors caused by incorrect configuration or
use of FreeRTOS.*/
#if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 )
/* Define the macros to do nothing. */
#define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
#define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
#define listFIRST_LIST_INTEGRITY_CHECK_VALUE
#define listSECOND_LIST_INTEGRITY_CHECK_VALUE
#define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )
#define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )
#define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList )
#define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList )
#define listTEST_LIST_ITEM_INTEGRITY( pxItem )
#define listTEST_LIST_INTEGRITY( pxList )
#else
/* Define macros that add new members into the list structures. */
#define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue1;
#define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue2;
#define listFIRST_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue1;
#define listSECOND_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue2;
/* Define macros that set the new structure members to known values. */
#define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) ( pxItem )->xListItemIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
#define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) ( pxItem )->xListItemIntegrityValue2 = pdINTEGRITY_CHECK_VALUE
#define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ) ( pxList )->xListIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
#define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ) ( pxList )->xListIntegrityValue2 = pdINTEGRITY_CHECK_VALUE
/* Define macros that will assert if one of the structure members does not
contain its expected value. */
#define listTEST_LIST_ITEM_INTEGRITY( pxItem ) configASSERT( ( ( pxItem )->xListItemIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxItem )->xListItemIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
#define listTEST_LIST_INTEGRITY( pxList ) configASSERT( ( ( pxList )->xListIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxList )->xListIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
#endif /* configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES */
/*
* Definition of the only type of object that a list can contain.
*/
struct xLIST;
struct xLIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
configLIST_VOLATILE TickType_t xItemValue; /*< The value being listed. In most cases this is used to sort the list in descending order. */
struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*< Pointer to the next ListItem_t in the list. */
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*< Pointer to the previous ListItem_t in the list. */
void * pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */
struct xLIST * configLIST_VOLATILE pxContainer; /*< Pointer to the list in which this list item is placed (if any). */
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
};
typedef struct xLIST_ITEM ListItem_t; /* For some reason lint wants this as two separate definitions. */
struct xMINI_LIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
configLIST_VOLATILE TickType_t xItemValue;
struct xLIST_ITEM * configLIST_VOLATILE pxNext;
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;
/*
* Definition of the type of queue used by the scheduler.
*/
typedef struct xLIST
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
volatile UBaseType_t uxNumberOfItems;
ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */
MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
} List_t;
/*
* Access macro to set the owner of a list item. The owner of a list item
* is the object (usually a TCB) that contains the list item.
*
* \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER
* \ingroup LinkedList
*/
#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
/*
* Access macro to get the owner of a list item. The owner of a list item
* is the object (usually a TCB) that contains the list item.
*
* \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER
* \ingroup LinkedList
*/
#define listGET_LIST_ITEM_OWNER( pxListItem ) ( ( pxListItem )->pvOwner )
/*
* Access macro to set the value of the list item. In most cases the value is
* used to sort the list in descending order.
*
* \page listSET_LIST_ITEM_VALUE listSET_LIST_ITEM_VALUE
* \ingroup LinkedList
*/
#define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) ( ( pxListItem )->xItemValue = ( xValue ) )
/*
* Access macro to retrieve the value of the list item. The value can
* represent anything - for example the priority of a task, or the time at
* which a task should be unblocked.
*
* \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE
* \ingroup LinkedList
*/
#define listGET_LIST_ITEM_VALUE( pxListItem ) ( ( pxListItem )->xItemValue )
/*
* Access macro to retrieve the value of the list item at the head of a given
* list.
*
* \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE
* \ingroup LinkedList
*/
#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext->xItemValue )
/*
* Return the list item at the head of the list.
*
* \page listGET_HEAD_ENTRY listGET_HEAD_ENTRY
* \ingroup LinkedList
*/
#define listGET_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext )
/*
* Return the list item at the head of the list.
*
* \page listGET_NEXT listGET_NEXT
* \ingroup LinkedList
*/
#define listGET_NEXT( pxListItem ) ( ( pxListItem )->pxNext )
/*
* Return the list item that marks the end of the list
*
* \page listGET_END_MARKER listGET_END_MARKER
* \ingroup LinkedList
*/
#define listGET_END_MARKER( pxList ) ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )
/*
* Access macro to determine if a list contains any items. The macro will
* only have the value true if the list is empty.
*
* \page listLIST_IS_EMPTY listLIST_IS_EMPTY
* \ingroup LinkedList
*/
#define listLIST_IS_EMPTY( pxList ) ( ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ? pdTRUE : pdFALSE )
/*
* Access macro to return the number of items in the list.
*/
#define listCURRENT_LIST_LENGTH( pxList ) ( ( pxList )->uxNumberOfItems )
/*
* Access function to obtain the owner of the next entry in a list.
*
* The list member pxIndex is used to walk through a list. Calling
* listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list
* and returns that entry's pxOwner parameter. Using multiple calls to this
* function it is therefore possible to move through every item contained in
* a list.
*
* The pxOwner parameter of a list item is a pointer to the object that owns
* the list item. In the scheduler this is normally a task control block.
* The pxOwner parameter effectively creates a two way link between the list
* item and its owner.
*
* @param pxTCB pxTCB is set to the address of the owner of the next list item.
* @param pxList The list from which the next item owner is to be returned.
*
* \page listGET_OWNER_OF_NEXT_ENTRY listGET_OWNER_OF_NEXT_ENTRY
* \ingroup LinkedList
*/
#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) \
{ \
List_t * const pxConstList = ( pxList ); \
/* Increment the index to the next item and return the item, ensuring */ \
/* we don't return the marker used at the end of the list. */ \
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \
{ \
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
} \
( pxTCB ) = ( pxConstList )->pxIndex->pvOwner; \
}
/*
* Access function to obtain the owner of the first entry in a list. Lists
* are normally sorted in ascending item value order.
*
* This function returns the pxOwner member of the first item in the list.
* The pxOwner parameter of a list item is a pointer to the object that owns
* the list item. In the scheduler this is normally a task control block.
* The pxOwner parameter effectively creates a two way link between the list
* item and its owner.
*
* @param pxList The list from which the owner of the head item is to be
* returned.
*
* \page listGET_OWNER_OF_HEAD_ENTRY listGET_OWNER_OF_HEAD_ENTRY
* \ingroup LinkedList
*/
#define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( (&( ( pxList )->xListEnd ))->pxNext->pvOwner )
/*
* Check to see if a list item is within a list. The list item maintains a
* "container" pointer that points to the list it is in. All this macro does
* is check to see if the container and the list match.
*
* @param pxList The list we want to know if the list item is within.
* @param pxListItem The list item we want to know if is in the list.
* @return pdTRUE if the list item is in the list, otherwise pdFALSE.
*/
#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( ( pxListItem )->pxContainer == ( pxList ) ) ? ( pdTRUE ) : ( pdFALSE ) )
/*
* Return the list a list item is contained within (referenced from).
*
* @param pxListItem The list item being queried.
* @return A pointer to the List_t object that references the pxListItem
*/
#define listLIST_ITEM_CONTAINER( pxListItem ) ( ( pxListItem )->pxContainer )
/*
* This provides a crude means of knowing if a list has been initialised, as
* pxList->xListEnd.xItemValue is set to portMAX_DELAY by the vListInitialise()
* function.
*/
#define listLIST_IS_INITIALISED( pxList ) ( ( pxList )->xListEnd.xItemValue == portMAX_DELAY )
/*
* Must be called before a list is used! This initialises all the members
* of the list structure and inserts the xListEnd item into the list as a
* marker to the back of the list.
*
* @param pxList Pointer to the list being initialised.
*
* \page vListInitialise vListInitialise
* \ingroup LinkedList
*/
void vListInitialise( List_t * const pxList ) PRIVILEGED_FUNCTION;
/*
* Must be called before a list item is used. This sets the list container to
* null so the item does not think that it is already contained in a list.
*
* @param pxItem Pointer to the list item being initialised.
*
* \page vListInitialiseItem vListInitialiseItem
* \ingroup LinkedList
*/
void vListInitialiseItem( ListItem_t * const pxItem ) PRIVILEGED_FUNCTION;
/*
* Insert a list item into a list. The item will be inserted into the list in
* a position determined by its item value (descending item value order).
*
* @param pxList The list into which the item is to be inserted.
*
* @param pxNewListItem The item that is to be placed in the list.
*
* \page vListInsert vListInsert
* \ingroup LinkedList
*/
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION;
/*
* Insert a list item into a list. The item will be inserted in a position
* such that it will be the last item within the list returned by multiple
* calls to listGET_OWNER_OF_NEXT_ENTRY.
*
* The list member pxIndex is used to walk through a list. Calling
* listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list.
* Placing an item in a list using vListInsertEnd effectively places the item
* in the list position pointed to by pxIndex. This means that every other
* item within the list will be returned by listGET_OWNER_OF_NEXT_ENTRY before
* the pxIndex parameter again points to the item being inserted.
*
* @param pxList The list into which the item is to be inserted.
*
* @param pxNewListItem The list item to be inserted into the list.
*
* \page vListInsertEnd vListInsertEnd
* \ingroup LinkedList
*/
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION;
/*
* Remove an item from a list. The list item has a pointer to the list that
* it is in, so only the list item need be passed into the function.
*
* @param uxListRemove The item to be removed. The item will remove itself from
* the list pointed to by it's pxContainer parameter.
*
* @return The number of items that remain in the list after the list item has
* been removed.
*
* \page uxListRemove uxListRemove
* \ingroup LinkedList
*/
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ) PRIVILEGED_FUNCTION;
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,798 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/*
* Message buffers build functionality on top of FreeRTOS stream buffers.
* Whereas stream buffers are used to send a continuous stream of data from one
* task or interrupt to another, message buffers are used to send variable
* length discrete messages from one task or interrupt to another. Their
* implementation is light weight, making them particularly suited for interrupt
* to task and core to core communication scenarios.
*
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
* implementation (so also the message buffer implementation, as message buffers
* are built on top of stream buffers) assumes there is only one task or
* interrupt that will write to the buffer (the writer), and only one task or
* interrupt that will read from the buffer (the reader). It is safe for the
* writer and reader to be different tasks or interrupts, but, unlike other
* FreeRTOS objects, it is not safe to have multiple different writers or
* multiple different readers. If there are to be multiple different writers
* then the application writer must place each call to a writing API function
* (such as xMessageBufferSend()) inside a critical section and set the send
* block time to 0. Likewise, if there are to be multiple different readers
* then the application writer must place each call to a reading API function
* (such as xMessageBufferRead()) inside a critical section and set the receive
* timeout to 0.
*
* Message buffers hold variable length messages. To enable that, when a
* message is written to the message buffer an additional sizeof( size_t ) bytes
* are also written to store the message's length (that happens internally, with
* the API function). sizeof( size_t ) is typically 4 bytes on a 32-bit
* architecture, so writing a 10 byte message to a message buffer on a 32-bit
* architecture will actually reduce the available space in the message buffer
* by 14 bytes (10 byte are used by the message, and 4 bytes to hold the length
* of the message).
*/
#ifndef FREERTOS_MESSAGE_BUFFER_H
#define FREERTOS_MESSAGE_BUFFER_H
/* Message buffers are built onto of stream buffers. */
#include "stream_buffer.h"
#if defined( __cplusplus )
extern "C" {
#endif
/**
* Type by which message buffers are referenced. For example, a call to
* xMessageBufferCreate() returns an MessageBufferHandle_t variable that can
* then be used as a parameter to xMessageBufferSend(), xMessageBufferReceive(),
* etc.
*/
typedef void * MessageBufferHandle_t;
/*-----------------------------------------------------------*/
/**
* message_buffer.h
*
<pre>
MessageBufferHandle_t xMessageBufferCreate( size_t xBufferSizeBytes );
</pre>
*
* Creates a new message buffer using dynamically allocated memory. See
* xMessageBufferCreateStatic() for a version that uses statically allocated
* memory (memory that is allocated at compile time).
*
* configSUPPORT_DYNAMIC_ALLOCATION must be set to 1 or left undefined in
* FreeRTOSConfig.h for xMessageBufferCreate() to be available.
*
* @param xBufferSizeBytes The total number of bytes (not messages) the message
* buffer will be able to hold at any one time. When a message is written to
* the message buffer an additional sizeof( size_t ) bytes are also written to
* store the message's length. sizeof( size_t ) is typically 4 bytes on a
* 32-bit architecture, so on most 32-bit architectures a 10 byte message will
* take up 14 bytes of message buffer space.
*
* @return If NULL is returned, then the message buffer cannot be created
* because there is insufficient heap memory available for FreeRTOS to allocate
* the message buffer data structures and storage area. A non-NULL value being
* returned indicates that the message buffer has been created successfully -
* the returned value should be stored as the handle to the created message
* buffer.
*
* Example use:
<pre>
void vAFunction( void )
{
MessageBufferHandle_t xMessageBuffer;
const size_t xMessageBufferSizeBytes = 100;
// Create a message buffer that can hold 100 bytes. The memory used to hold
// both the message buffer structure and the messages themselves is allocated
// dynamically. Each message added to the buffer consumes an additional 4
// bytes which are used to hold the lengh of the message.
xMessageBuffer = xMessageBufferCreate( xMessageBufferSizeBytes );
if( xMessageBuffer == NULL )
{
// There was not enough heap memory space available to create the
// message buffer.
}
else
{
// The message buffer was created successfully and can now be used.
}
</pre>
* \defgroup xMessageBufferCreate xMessageBufferCreate
* \ingroup MessageBufferManagement
*/
#define xMessageBufferCreate( xBufferSizeBytes ) ( MessageBufferHandle_t ) xStreamBufferGenericCreate( xBufferSizeBytes, ( size_t ) 0, pdTRUE )
/**
* message_buffer.h
*
<pre>
MessageBufferHandle_t xMessageBufferCreateStatic( size_t xBufferSizeBytes,
uint8_t *pucMessageBufferStorageArea,
StaticMessageBuffer_t *pxStaticMessageBuffer );
</pre>
* Creates a new message buffer using statically allocated memory. See
* xMessageBufferCreate() for a version that uses dynamically allocated memory.
*
* @param xBufferSizeBytes The size, in bytes, of the buffer pointed to by the
* pucMessageBufferStorageArea parameter. When a message is written to the
* message buffer an additional sizeof( size_t ) bytes are also written to store
* the message's length. sizeof( size_t ) is typically 4 bytes on a 32-bit
* architecture, so on most 32-bit architecture a 10 byte message will take up
* 14 bytes of message buffer space. The maximum number of bytes that can be
* stored in the message buffer is actually (xBufferSizeBytes - 1).
*
* @param pucMessageBufferStorageArea Must point to a uint8_t array that is at
* least xBufferSizeBytes + 1 big. This is the array to which messages are
* copied when they are written to the message buffer.
*
* @param pxStaticMessageBuffer Must point to a variable of type
* StaticMessageBuffer_t, which will be used to hold the message buffer's data
* structure.
*
* @return If the message buffer is created successfully then a handle to the
* created message buffer is returned. If either pucMessageBufferStorageArea or
* pxStaticmessageBuffer are NULL then NULL is returned.
*
* Example use:
<pre>
// Used to dimension the array used to hold the messages. The available space
// will actually be one less than this, so 999.
#define STORAGE_SIZE_BYTES 1000
// Defines the memory that will actually hold the messages within the message
// buffer.
static uint8_t ucStorageBuffer[ STORAGE_SIZE_BYTES ];
// The variable used to hold the message buffer structure.
StaticMessageBuffer_t xMessageBufferStruct;
void MyFunction( void )
{
MessageBufferHandle_t xMessageBuffer;
xMessageBuffer = xMessageBufferCreateStatic( sizeof( ucBufferStorage ),
ucBufferStorage,
&xMessageBufferStruct );
// As neither the pucMessageBufferStorageArea or pxStaticMessageBuffer
// parameters were NULL, xMessageBuffer will not be NULL, and can be used to
// reference the created message buffer in other message buffer API calls.
// Other code that uses the message buffer can go here.
}
</pre>
* \defgroup xMessageBufferCreateStatic xMessageBufferCreateStatic
* \ingroup MessageBufferManagement
*/
#define xMessageBufferCreateStatic( xBufferSizeBytes, pucMessageBufferStorageArea, pxStaticMessageBuffer ) ( MessageBufferHandle_t ) xStreamBufferGenericCreateStatic( xBufferSizeBytes, 0, pdTRUE, pucMessageBufferStorageArea, pxStaticMessageBuffer )
/**
* message_buffer.h
*
<pre>
size_t xMessageBufferSend( MessageBufferHandle_t xMessageBuffer,
const void *pvTxData,
size_t xDataLengthBytes,
TickType_t xTicksToWait );
<pre>
*
* Sends a discrete message to the message buffer. The message can be any
* length that fits within the buffer's free space, and is copied into the
* buffer.
*
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
* implementation (so also the message buffer implementation, as message buffers
* are built on top of stream buffers) assumes there is only one task or
* interrupt that will write to the buffer (the writer), and only one task or
* interrupt that will read from the buffer (the reader). It is safe for the
* writer and reader to be different tasks or interrupts, but, unlike other
* FreeRTOS objects, it is not safe to have multiple different writers or
* multiple different readers. If there are to be multiple different writers
* then the application writer must place each call to a writing API function
* (such as xMessageBufferSend()) inside a critical section and set the send
* block time to 0. Likewise, if there are to be multiple different readers
* then the application writer must place each call to a reading API function
* (such as xMessageBufferRead()) inside a critical section and set the receive
* block time to 0.
*
* Use xMessageBufferSend() to write to a message buffer from a task. Use
* xMessageBufferSendFromISR() to write to a message buffer from an interrupt
* service routine (ISR).
*
* @param xMessageBuffer The handle of the message buffer to which a message is
* being sent.
*
* @param pvTxData A pointer to the message that is to be copied into the
* message buffer.
*
* @param xDataLengthBytes The length of the message. That is, the number of
* bytes to copy from pvTxData into the message buffer. When a message is
* written to the message buffer an additional sizeof( size_t ) bytes are also
* written to store the message's length. sizeof( size_t ) is typically 4 bytes
* on a 32-bit architecture, so on most 32-bit architecture setting
* xDataLengthBytes to 20 will reduce the free space in the message buffer by 24
* bytes (20 bytes of message data and 4 bytes to hold the message length).
*
* @param xTicksToWait The maximum amount of time the calling task should remain
* in the Blocked state to wait for enough space to become available in the
* message buffer, should the message buffer have insufficient space when
* xMessageBufferSend() is called. The calling task will never block if
* xTicksToWait is zero. The block time is specified in tick periods, so the
* absolute time it represents is dependent on the tick frequency. The macro
* pdMS_TO_TICKS() can be used to convert a time specified in milliseconds into
* a time specified in ticks. Setting xTicksToWait to portMAX_DELAY will cause
* the task to wait indefinitely (without timing out), provided
* INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h. Tasks do not use any
* CPU time when they are in the Blocked state.
*
* @return The number of bytes written to the message buffer. If the call to
* xMessageBufferSend() times out before there was enough space to write the
* message into the message buffer then zero is returned. If the call did not
* time out then xDataLengthBytes is returned.
*
* Example use:
<pre>
void vAFunction( MessageBufferHandle_t xMessageBuffer )
{
size_t xBytesSent;
uint8_t ucArrayToSend[] = { 0, 1, 2, 3 };
char *pcStringToSend = "String to send";
const TickType_t x100ms = pdMS_TO_TICKS( 100 );
// Send an array to the message buffer, blocking for a maximum of 100ms to
// wait for enough space to be available in the message buffer.
xBytesSent = xMessageBufferSend( xMessageBuffer, ( void * ) ucArrayToSend, sizeof( ucArrayToSend ), x100ms );
if( xBytesSent != sizeof( ucArrayToSend ) )
{
// The call to xMessageBufferSend() times out before there was enough
// space in the buffer for the data to be written.
}
// Send the string to the message buffer. Return immediately if there is
// not enough space in the buffer.
xBytesSent = xMessageBufferSend( xMessageBuffer, ( void * ) pcStringToSend, strlen( pcStringToSend ), 0 );
if( xBytesSent != strlen( pcStringToSend ) )
{
// The string could not be added to the message buffer because there was
// not enough free space in the buffer.
}
}
</pre>
* \defgroup xMessageBufferSend xMessageBufferSend
* \ingroup MessageBufferManagement
*/
#define xMessageBufferSend( xMessageBuffer, pvTxData, xDataLengthBytes, xTicksToWait ) xStreamBufferSend( ( StreamBufferHandle_t ) xMessageBuffer, pvTxData, xDataLengthBytes, xTicksToWait )
/**
* message_buffer.h
*
<pre>
size_t xMessageBufferSendFromISR( MessageBufferHandle_t xMessageBuffer,
const void *pvTxData,
size_t xDataLengthBytes,
BaseType_t *pxHigherPriorityTaskWoken );
<pre>
*
* Interrupt safe version of the API function that sends a discrete message to
* the message buffer. The message can be any length that fits within the
* buffer's free space, and is copied into the buffer.
*
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
* implementation (so also the message buffer implementation, as message buffers
* are built on top of stream buffers) assumes there is only one task or
* interrupt that will write to the buffer (the writer), and only one task or
* interrupt that will read from the buffer (the reader). It is safe for the
* writer and reader to be different tasks or interrupts, but, unlike other
* FreeRTOS objects, it is not safe to have multiple different writers or
* multiple different readers. If there are to be multiple different writers
* then the application writer must place each call to a writing API function
* (such as xMessageBufferSend()) inside a critical section and set the send
* block time to 0. Likewise, if there are to be multiple different readers
* then the application writer must place each call to a reading API function
* (such as xMessageBufferRead()) inside a critical section and set the receive
* block time to 0.
*
* Use xMessageBufferSend() to write to a message buffer from a task. Use
* xMessageBufferSendFromISR() to write to a message buffer from an interrupt
* service routine (ISR).
*
* @param xMessageBuffer The handle of the message buffer to which a message is
* being sent.
*
* @param pvTxData A pointer to the message that is to be copied into the
* message buffer.
*
* @param xDataLengthBytes The length of the message. That is, the number of
* bytes to copy from pvTxData into the message buffer. When a message is
* written to the message buffer an additional sizeof( size_t ) bytes are also
* written to store the message's length. sizeof( size_t ) is typically 4 bytes
* on a 32-bit architecture, so on most 32-bit architecture setting
* xDataLengthBytes to 20 will reduce the free space in the message buffer by 24
* bytes (20 bytes of message data and 4 bytes to hold the message length).
*
* @param pxHigherPriorityTaskWoken It is possible that a message buffer will
* have a task blocked on it waiting for data. Calling
* xMessageBufferSendFromISR() can make data available, and so cause a task that
* was waiting for data to leave the Blocked state. If calling
* xMessageBufferSendFromISR() causes a task to leave the Blocked state, and the
* unblocked task has a priority higher than the currently executing task (the
* task that was interrupted), then, internally, xMessageBufferSendFromISR()
* will set *pxHigherPriorityTaskWoken to pdTRUE. If
* xMessageBufferSendFromISR() sets this value to pdTRUE, then normally a
* context switch should be performed before the interrupt is exited. This will
* ensure that the interrupt returns directly to the highest priority Ready
* state task. *pxHigherPriorityTaskWoken should be set to pdFALSE before it
* is passed into the function. See the code example below for an example.
*
* @return The number of bytes actually written to the message buffer. If the
* message buffer didn't have enough free space for the message to be stored
* then 0 is returned, otherwise xDataLengthBytes is returned.
*
* Example use:
<pre>
// A message buffer that has already been created.
MessageBufferHandle_t xMessageBuffer;
void vAnInterruptServiceRoutine( void )
{
size_t xBytesSent;
char *pcStringToSend = "String to send";
BaseType_t xHigherPriorityTaskWoken = pdFALSE; // Initialised to pdFALSE.
// Attempt to send the string to the message buffer.
xBytesSent = xMessageBufferSendFromISR( xMessageBuffer,
( void * ) pcStringToSend,
strlen( pcStringToSend ),
&xHigherPriorityTaskWoken );
if( xBytesSent != strlen( pcStringToSend ) )
{
// The string could not be added to the message buffer because there was
// not enough free space in the buffer.
}
// If xHigherPriorityTaskWoken was set to pdTRUE inside
// xMessageBufferSendFromISR() then a task that has a priority above the
// priority of the currently executing task was unblocked and a context
// switch should be performed to ensure the ISR returns to the unblocked
// task. In most FreeRTOS ports this is done by simply passing
// xHigherPriorityTaskWoken into taskYIELD_FROM_ISR(), which will test the
// variables value, and perform the context switch if necessary. Check the
// documentation for the port in use for port specific instructions.
taskYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
</pre>
* \defgroup xMessageBufferSendFromISR xMessageBufferSendFromISR
* \ingroup MessageBufferManagement
*/
#define xMessageBufferSendFromISR( xMessageBuffer, pvTxData, xDataLengthBytes, pxHigherPriorityTaskWoken ) xStreamBufferSendFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pvTxData, xDataLengthBytes, pxHigherPriorityTaskWoken )
/**
* message_buffer.h
*
<pre>
size_t xMessageBufferReceive( MessageBufferHandle_t xMessageBuffer,
void *pvRxData,
size_t xBufferLengthBytes,
TickType_t xTicksToWait );
</pre>
*
* Receives a discrete message from a message buffer. Messages can be of
* variable length and are copied out of the buffer.
*
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
* implementation (so also the message buffer implementation, as message buffers
* are built on top of stream buffers) assumes there is only one task or
* interrupt that will write to the buffer (the writer), and only one task or
* interrupt that will read from the buffer (the reader). It is safe for the
* writer and reader to be different tasks or interrupts, but, unlike other
* FreeRTOS objects, it is not safe to have multiple different writers or
* multiple different readers. If there are to be multiple different writers
* then the application writer must place each call to a writing API function
* (such as xMessageBufferSend()) inside a critical section and set the send
* block time to 0. Likewise, if there are to be multiple different readers
* then the application writer must place each call to a reading API function
* (such as xMessageBufferRead()) inside a critical section and set the receive
* block time to 0.
*
* Use xMessageBufferReceive() to read from a message buffer from a task. Use
* xMessageBufferReceiveFromISR() to read from a message buffer from an
* interrupt service routine (ISR).
*
* @param xMessageBuffer The handle of the message buffer from which a message
* is being received.
*
* @param pvRxData A pointer to the buffer into which the received message is
* to be copied.
*
* @param xBufferLengthBytes The length of the buffer pointed to by the pvRxData
* parameter. This sets the maximum length of the message that can be received.
* If xBufferLengthBytes is too small to hold the next message then the message
* will be left in the message buffer and 0 will be returned.
*
* @param xTicksToWait The maximum amount of time the task should remain in the
* Blocked state to wait for a message, should the message buffer be empty.
* xMessageBufferReceive() will return immediately if xTicksToWait is zero and
* the message buffer is empty. The block time is specified in tick periods, so
* the absolute time it represents is dependent on the tick frequency. The
* macro pdMS_TO_TICKS() can be used to convert a time specified in milliseconds
* into a time specified in ticks. Setting xTicksToWait to portMAX_DELAY will
* cause the task to wait indefinitely (without timing out), provided
* INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h. Tasks do not use any
* CPU time when they are in the Blocked state.
*
* @return The length, in bytes, of the message read from the message buffer, if
* any. If xMessageBufferReceive() times out before a message became available
* then zero is returned. If the length of the message is greater than
* xBufferLengthBytes then the message will be left in the message buffer and
* zero is returned.
*
* Example use:
<pre>
void vAFunction( MessageBuffer_t xMessageBuffer )
{
uint8_t ucRxData[ 20 ];
size_t xReceivedBytes;
const TickType_t xBlockTime = pdMS_TO_TICKS( 20 );
// Receive the next message from the message buffer. Wait in the Blocked
// state (so not using any CPU processing time) for a maximum of 100ms for
// a message to become available.
xReceivedBytes = xMessageBufferReceive( xMessageBuffer,
( void * ) ucRxData,
sizeof( ucRxData ),
xBlockTime );
if( xReceivedBytes > 0 )
{
// A ucRxData contains a message that is xReceivedBytes long. Process
// the message here....
}
}
</pre>
* \defgroup xMessageBufferReceive xMessageBufferReceive
* \ingroup MessageBufferManagement
*/
#define xMessageBufferReceive( xMessageBuffer, pvRxData, xBufferLengthBytes, xTicksToWait ) xStreamBufferReceive( ( StreamBufferHandle_t ) xMessageBuffer, pvRxData, xBufferLengthBytes, xTicksToWait )
/**
* message_buffer.h
*
<pre>
size_t xMessageBufferReceiveFromISR( MessageBufferHandle_t xMessageBuffer,
void *pvRxData,
size_t xBufferLengthBytes,
BaseType_t *pxHigherPriorityTaskWoken );
</pre>
*
* An interrupt safe version of the API function that receives a discrete
* message from a message buffer. Messages can be of variable length and are
* copied out of the buffer.
*
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
* implementation (so also the message buffer implementation, as message buffers
* are built on top of stream buffers) assumes there is only one task or
* interrupt that will write to the buffer (the writer), and only one task or
* interrupt that will read from the buffer (the reader). It is safe for the
* writer and reader to be different tasks or interrupts, but, unlike other
* FreeRTOS objects, it is not safe to have multiple different writers or
* multiple different readers. If there are to be multiple different writers
* then the application writer must place each call to a writing API function
* (such as xMessageBufferSend()) inside a critical section and set the send
* block time to 0. Likewise, if there are to be multiple different readers
* then the application writer must place each call to a reading API function
* (such as xMessageBufferRead()) inside a critical section and set the receive
* block time to 0.
*
* Use xMessageBufferReceive() to read from a message buffer from a task. Use
* xMessageBufferReceiveFromISR() to read from a message buffer from an
* interrupt service routine (ISR).
*
* @param xMessageBuffer The handle of the message buffer from which a message
* is being received.
*
* @param pvRxData A pointer to the buffer into which the received message is
* to be copied.
*
* @param xBufferLengthBytes The length of the buffer pointed to by the pvRxData
* parameter. This sets the maximum length of the message that can be received.
* If xBufferLengthBytes is too small to hold the next message then the message
* will be left in the message buffer and 0 will be returned.
*
* @param pxHigherPriorityTaskWoken It is possible that a message buffer will
* have a task blocked on it waiting for space to become available. Calling
* xMessageBufferReceiveFromISR() can make space available, and so cause a task
* that is waiting for space to leave the Blocked state. If calling
* xMessageBufferReceiveFromISR() causes a task to leave the Blocked state, and
* the unblocked task has a priority higher than the currently executing task
* (the task that was interrupted), then, internally,
* xMessageBufferReceiveFromISR() will set *pxHigherPriorityTaskWoken to pdTRUE.
* If xMessageBufferReceiveFromISR() sets this value to pdTRUE, then normally a
* context switch should be performed before the interrupt is exited. That will
* ensure the interrupt returns directly to the highest priority Ready state
* task. *pxHigherPriorityTaskWoken should be set to pdFALSE before it is
* passed into the function. See the code example below for an example.
*
* @return The length, in bytes, of the message read from the message buffer, if
* any.
*
* Example use:
<pre>
// A message buffer that has already been created.
MessageBuffer_t xMessageBuffer;
void vAnInterruptServiceRoutine( void )
{
uint8_t ucRxData[ 20 ];
size_t xReceivedBytes;
BaseType_t xHigherPriorityTaskWoken = pdFALSE; // Initialised to pdFALSE.
// Receive the next message from the message buffer.
xReceivedBytes = xMessageBufferReceiveFromISR( xMessageBuffer,
( void * ) ucRxData,
sizeof( ucRxData ),
&xHigherPriorityTaskWoken );
if( xReceivedBytes > 0 )
{
// A ucRxData contains a message that is xReceivedBytes long. Process
// the message here....
}
// If xHigherPriorityTaskWoken was set to pdTRUE inside
// xMessageBufferReceiveFromISR() then a task that has a priority above the
// priority of the currently executing task was unblocked and a context
// switch should be performed to ensure the ISR returns to the unblocked
// task. In most FreeRTOS ports this is done by simply passing
// xHigherPriorityTaskWoken into taskYIELD_FROM_ISR(), which will test the
// variables value, and perform the context switch if necessary. Check the
// documentation for the port in use for port specific instructions.
taskYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
</pre>
* \defgroup xMessageBufferReceiveFromISR xMessageBufferReceiveFromISR
* \ingroup MessageBufferManagement
*/
#define xMessageBufferReceiveFromISR( xMessageBuffer, pvRxData, xBufferLengthBytes, pxHigherPriorityTaskWoken ) xStreamBufferReceiveFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pvRxData, xBufferLengthBytes, pxHigherPriorityTaskWoken )
/**
* message_buffer.h
*
<pre>
void vMessageBufferDelete( MessageBufferHandle_t xMessageBuffer );
</pre>
*
* Deletes a message buffer that was previously created using a call to
* xMessageBufferCreate() or xMessageBufferCreateStatic(). If the message
* buffer was created using dynamic memory (that is, by xMessageBufferCreate()),
* then the allocated memory is freed.
*
* A message buffer handle must not be used after the message buffer has been
* deleted.
*
* @param xMessageBuffer The handle of the message buffer to be deleted.
*
*/
#define vMessageBufferDelete( xMessageBuffer ) vStreamBufferDelete( ( StreamBufferHandle_t ) xMessageBuffer )
/**
* message_buffer.h
<pre>
BaseType_t xMessageBufferIsFull( MessageBufferHandle_t xMessageBuffer ) );
</pre>
*
* Tests to see if a message buffer is full. A message buffer is full if it
* cannot accept any more messages, of any size, until space is made available
* by a message being removed from the message buffer.
*
* @param xMessageBuffer The handle of the message buffer being queried.
*
* @return If the message buffer referenced by xMessageBuffer is full then
* pdTRUE is returned. Otherwise pdFALSE is returned.
*/
#define xMessageBufferIsFull( xMessageBuffer ) xStreamBufferIsFull( ( StreamBufferHandle_t ) xMessageBuffer )
/**
* message_buffer.h
<pre>
BaseType_t xMessageBufferIsEmpty( MessageBufferHandle_t xMessageBuffer ) );
</pre>
*
* Tests to see if a message buffer is empty (does not contain any messages).
*
* @param xMessageBuffer The handle of the message buffer being queried.
*
* @return If the message buffer referenced by xMessageBuffer is empty then
* pdTRUE is returned. Otherwise pdFALSE is returned.
*
*/
#define xMessageBufferIsEmpty( xMessageBuffer ) xStreamBufferIsEmpty( ( StreamBufferHandle_t ) xMessageBuffer )
/**
* message_buffer.h
<pre>
BaseType_t xMessageBufferReset( MessageBufferHandle_t xMessageBuffer );
</pre>
*
* Resets a message buffer to its initial empty state, discarding any message it
* contained.
*
* A message buffer can only be reset if there are no tasks blocked on it.
*
* @param xMessageBuffer The handle of the message buffer being reset.
*
* @return If the message buffer was reset then pdPASS is returned. If the
* message buffer could not be reset because either there was a task blocked on
* the message queue to wait for space to become available, or to wait for a
* a message to be available, then pdFAIL is returned.
*
* \defgroup xMessageBufferReset xMessageBufferReset
* \ingroup MessageBufferManagement
*/
#define xMessageBufferReset( xMessageBuffer ) xStreamBufferReset( ( StreamBufferHandle_t ) xMessageBuffer )
/**
* message_buffer.h
<pre>
size_t xMessageBufferSpaceAvailable( MessageBufferHandle_t xMessageBuffer ) );
</pre>
* Returns the number of bytes of free space in the message buffer.
*
* @param xMessageBuffer The handle of the message buffer being queried.
*
* @return The number of bytes that can be written to the message buffer before
* the message buffer would be full. When a message is written to the message
* buffer an additional sizeof( size_t ) bytes are also written to store the
* message's length. sizeof( size_t ) is typically 4 bytes on a 32-bit
* architecture, so if xMessageBufferSpacesAvailable() returns 10, then the size
* of the largest message that can be written to the message buffer is 6 bytes.
*
* \defgroup xMessageBufferSpaceAvailable xMessageBufferSpaceAvailable
* \ingroup MessageBufferManagement
*/
#define xMessageBufferSpaceAvailable( xMessageBuffer ) xStreamBufferSpacesAvailable( ( StreamBufferHandle_t ) xMessageBuffer )
/**
* message_buffer.h
<pre>
size_t xMessageBufferNextLengthBytes( MessageBufferHandle_t xMessageBuffer ) );
</pre>
* Returns the length (in bytes) of the next message in a message buffer.
* Useful if xMessageBufferReceive() returned 0 because the size of the buffer
* passed into xMessageBufferReceive() was too small to hold the next message.
*
* @param xMessageBuffer The handle of the message buffer being queried.
*
* @return The length (in bytes) of the next message in the message buffer, or 0
* if the message buffer is empty.
*
* \defgroup xMessageBufferNextLengthBytes xMessageBufferNextLengthBytes
* \ingroup MessageBufferManagement
*/
#define xMessageBufferNextLengthBytes( xMessageBuffer ) xStreamBufferNextMessageLengthBytes( ( StreamBufferHandle_t ) xMessageBuffer ) PRIVILEGED_FUNCTION;
/**
* message_buffer.h
*
<pre>
BaseType_t xMessageBufferSendCompletedFromISR( MessageBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken );
</pre>
*
* For advanced users only.
*
* The sbSEND_COMPLETED() macro is called from within the FreeRTOS APIs when
* data is sent to a message buffer or stream buffer. If there was a task that
* was blocked on the message or stream buffer waiting for data to arrive then
* the sbSEND_COMPLETED() macro sends a notification to the task to remove it
* from the Blocked state. xMessageBufferSendCompletedFromISR() does the same
* thing. It is provided to enable application writers to implement their own
* version of sbSEND_COMPLETED(), and MUST NOT BE USED AT ANY OTHER TIME.
*
* See the example implemented in FreeRTOS/Demo/Minimal/MessageBufferAMP.c for
* additional information.
*
* @param xStreamBuffer The handle of the stream buffer to which data was
* written.
*
* @param pxHigherPriorityTaskWoken *pxHigherPriorityTaskWoken should be
* initialised to pdFALSE before it is passed into
* xMessageBufferSendCompletedFromISR(). If calling
* xMessageBufferSendCompletedFromISR() removes a task from the Blocked state,
* and the task has a priority above the priority of the currently running task,
* then *pxHigherPriorityTaskWoken will get set to pdTRUE indicating that a
* context switch should be performed before exiting the ISR.
*
* @return If a task was removed from the Blocked state then pdTRUE is returned.
* Otherwise pdFALSE is returned.
*
* \defgroup xMessageBufferSendCompletedFromISR xMessageBufferSendCompletedFromISR
* \ingroup StreamBufferManagement
*/
#define xMessageBufferSendCompletedFromISR( xMessageBuffer, pxHigherPriorityTaskWoken ) xStreamBufferSendCompletedFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pxHigherPriorityTaskWoken )
/**
* message_buffer.h
*
<pre>
BaseType_t xMessageBufferReceiveCompletedFromISR( MessageBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken );
</pre>
*
* For advanced users only.
*
* The sbRECEIVE_COMPLETED() macro is called from within the FreeRTOS APIs when
* data is read out of a message buffer or stream buffer. If there was a task
* that was blocked on the message or stream buffer waiting for data to arrive
* then the sbRECEIVE_COMPLETED() macro sends a notification to the task to
* remove it from the Blocked state. xMessageBufferReceiveCompletedFromISR()
* does the same thing. It is provided to enable application writers to
* implement their own version of sbRECEIVE_COMPLETED(), and MUST NOT BE USED AT
* ANY OTHER TIME.
*
* See the example implemented in FreeRTOS/Demo/Minimal/MessageBufferAMP.c for
* additional information.
*
* @param xStreamBuffer The handle of the stream buffer from which data was
* read.
*
* @param pxHigherPriorityTaskWoken *pxHigherPriorityTaskWoken should be
* initialised to pdFALSE before it is passed into
* xMessageBufferReceiveCompletedFromISR(). If calling
* xMessageBufferReceiveCompletedFromISR() removes a task from the Blocked state,
* and the task has a priority above the priority of the currently running task,
* then *pxHigherPriorityTaskWoken will get set to pdTRUE indicating that a
* context switch should be performed before exiting the ISR.
*
* @return If a task was removed from the Blocked state then pdTRUE is returned.
* Otherwise pdFALSE is returned.
*
* \defgroup xMessageBufferReceiveCompletedFromISR xMessageBufferReceiveCompletedFromISR
* \ingroup StreamBufferManagement
*/
#define xMessageBufferReceiveCompletedFromISR( xMessageBuffer, pxHigherPriorityTaskWoken ) xStreamBufferReceiveCompletedFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pxHigherPriorityTaskWoken )
#if defined( __cplusplus )
} /* extern "C" */
#endif
#endif /* !defined( FREERTOS_MESSAGE_BUFFER_H ) */
@@ -0,0 +1,156 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/*
* When the MPU is used the standard (non MPU) API functions are mapped to
* equivalents that start "MPU_", the prototypes for which are defined in this
* header files. This will cause the application code to call the MPU_ version
* which wraps the non-MPU version with privilege promoting then demoting code,
* so the kernel code always runs will full privileges.
*/
#ifndef MPU_PROTOTYPES_H
#define MPU_PROTOTYPES_H
/* MPU versions of tasks.h API functions. */
BaseType_t MPU_xTaskCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask );
TaskHandle_t MPU_xTaskCreateStatic( TaskFunction_t pxTaskCode, const char * const pcName, const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, StackType_t * const puxStackBuffer, StaticTask_t * const pxTaskBuffer );
BaseType_t MPU_xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask );
BaseType_t MPU_xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask );
void MPU_vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions );
void MPU_vTaskDelete( TaskHandle_t xTaskToDelete );
void MPU_vTaskDelay( const TickType_t xTicksToDelay );
void MPU_vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement );
BaseType_t MPU_xTaskAbortDelay( TaskHandle_t xTask );
UBaseType_t MPU_uxTaskPriorityGet( const TaskHandle_t xTask );
eTaskState MPU_eTaskGetState( TaskHandle_t xTask );
void MPU_vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState );
void MPU_vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority );
void MPU_vTaskSuspend( TaskHandle_t xTaskToSuspend );
void MPU_vTaskResume( TaskHandle_t xTaskToResume );
void MPU_vTaskStartScheduler( void );
void MPU_vTaskSuspendAll( void );
BaseType_t MPU_xTaskResumeAll( void );
TickType_t MPU_xTaskGetTickCount( void );
UBaseType_t MPU_uxTaskGetNumberOfTasks( void );
char * MPU_pcTaskGetName( TaskHandle_t xTaskToQuery );
TaskHandle_t MPU_xTaskGetHandle( const char *pcNameToQuery );
UBaseType_t MPU_uxTaskGetStackHighWaterMark( TaskHandle_t xTask );
void MPU_vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction );
TaskHookFunction_t MPU_xTaskGetApplicationTaskTag( TaskHandle_t xTask );
void MPU_vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue );
void * MPU_pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex );
BaseType_t MPU_xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter );
TaskHandle_t MPU_xTaskGetIdleTaskHandle( void );
UBaseType_t MPU_uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime );
void MPU_vTaskList( char * pcWriteBuffer );
void MPU_vTaskGetRunTimeStats( char *pcWriteBuffer );
BaseType_t MPU_xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue );
BaseType_t MPU_xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait );
uint32_t MPU_ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );
BaseType_t MPU_xTaskNotifyStateClear( TaskHandle_t xTask );
BaseType_t MPU_xTaskIncrementTick( void );
TaskHandle_t MPU_xTaskGetCurrentTaskHandle( void );
void MPU_vTaskSetTimeOutState( TimeOut_t * const pxTimeOut );
BaseType_t MPU_xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait );
void MPU_vTaskMissedYield( void );
BaseType_t MPU_xTaskGetSchedulerState( void );
/* MPU versions of queue.h API functions. */
BaseType_t MPU_xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition );
BaseType_t MPU_xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait );
BaseType_t MPU_xQueuePeek( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait );
BaseType_t MPU_xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait );
UBaseType_t MPU_uxQueueMessagesWaiting( const QueueHandle_t xQueue );
UBaseType_t MPU_uxQueueSpacesAvailable( const QueueHandle_t xQueue );
void MPU_vQueueDelete( QueueHandle_t xQueue );
QueueHandle_t MPU_xQueueCreateMutex( const uint8_t ucQueueType );
QueueHandle_t MPU_xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue );
QueueHandle_t MPU_xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount );
QueueHandle_t MPU_xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue );
TaskHandle_t MPU_xQueueGetMutexHolder( QueueHandle_t xSemaphore );
BaseType_t MPU_xQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_t xTicksToWait );
BaseType_t MPU_xQueueGiveMutexRecursive( QueueHandle_t pxMutex );
void MPU_vQueueAddToRegistry( QueueHandle_t xQueue, const char *pcName );
void MPU_vQueueUnregisterQueue( QueueHandle_t xQueue );
const char * MPU_pcQueueGetName( QueueHandle_t xQueue );
QueueHandle_t MPU_xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType );
QueueHandle_t MPU_xQueueGenericCreateStatic( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType );
QueueSetHandle_t MPU_xQueueCreateSet( const UBaseType_t uxEventQueueLength );
BaseType_t MPU_xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet );
BaseType_t MPU_xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet );
QueueSetMemberHandle_t MPU_xQueueSelectFromSet( QueueSetHandle_t xQueueSet, const TickType_t xTicksToWait );
BaseType_t MPU_xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue );
void MPU_vQueueSetQueueNumber( QueueHandle_t xQueue, UBaseType_t uxQueueNumber );
UBaseType_t MPU_uxQueueGetQueueNumber( QueueHandle_t xQueue );
uint8_t MPU_ucQueueGetQueueType( QueueHandle_t xQueue );
/* MPU versions of timers.h API functions. */
TimerHandle_t MPU_xTimerCreate( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction );
TimerHandle_t MPU_xTimerCreateStatic( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction, StaticTimer_t *pxTimerBuffer );
void * MPU_pvTimerGetTimerID( const TimerHandle_t xTimer );
void MPU_vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID );
BaseType_t MPU_xTimerIsTimerActive( TimerHandle_t xTimer );
TaskHandle_t MPU_xTimerGetTimerDaemonTaskHandle( void );
BaseType_t MPU_xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, TickType_t xTicksToWait );
const char * MPU_pcTimerGetName( TimerHandle_t xTimer );
TickType_t MPU_xTimerGetPeriod( TimerHandle_t xTimer );
TickType_t MPU_xTimerGetExpiryTime( TimerHandle_t xTimer );
BaseType_t MPU_xTimerCreateTimerTask( void );
BaseType_t MPU_xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait );
/* MPU versions of event_group.h API functions. */
EventGroupHandle_t MPU_xEventGroupCreate( void );
EventGroupHandle_t MPU_xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer );
EventBits_t MPU_xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait );
EventBits_t MPU_xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear );
EventBits_t MPU_xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
EventBits_t MPU_xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait );
void MPU_vEventGroupDelete( EventGroupHandle_t xEventGroup );
UBaseType_t MPU_uxEventGroupGetNumber( void* xEventGroup );
/* MPU versions of message/stream_buffer.h API functions. */
size_t MPU_xStreamBufferSend( StreamBufferHandle_t xStreamBuffer, const void *pvTxData, size_t xDataLengthBytes, TickType_t xTicksToWait );
size_t MPU_xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer, const void *pvTxData, size_t xDataLengthBytes, BaseType_t * const pxHigherPriorityTaskWoken );
size_t MPU_xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer, void *pvRxData, size_t xBufferLengthBytes, TickType_t xTicksToWait );
size_t MPU_xStreamBufferNextMessageLengthBytes( StreamBufferHandle_t xStreamBuffer );
size_t MPU_xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer, void *pvRxData, size_t xBufferLengthBytes, BaseType_t * const pxHigherPriorityTaskWoken );
void MPU_vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer );
BaseType_t MPU_xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer );
BaseType_t MPU_xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer );
BaseType_t MPU_xStreamBufferReset( StreamBufferHandle_t xStreamBuffer );
size_t MPU_xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer );
size_t MPU_xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer );
BaseType_t MPU_xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, size_t xTriggerLevel );
StreamBufferHandle_t MPU_xStreamBufferGenericCreate( size_t xBufferSizeBytes, size_t xTriggerLevelBytes, BaseType_t xIsMessageBuffer );
StreamBufferHandle_t MPU_xStreamBufferGenericCreateStatic( size_t xBufferSizeBytes, size_t xTriggerLevelBytes, BaseType_t xIsMessageBuffer, uint8_t * const pucStreamBufferStorageArea, StaticStreamBuffer_t * const pxStaticStreamBuffer );
#endif /* MPU_PROTOTYPES_H */
@@ -0,0 +1,182 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef MPU_WRAPPERS_H
#define MPU_WRAPPERS_H
/* This file redefines API functions to be called through a wrapper macro, but
only for ports that are using the MPU. */
#ifdef portUSING_MPU_WRAPPERS
/* MPU_WRAPPERS_INCLUDED_FROM_API_FILE will be defined when this file is
included from queue.c or task.c to prevent it from having an effect within
those files. */
#ifndef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
/*
* Map standard (non MPU) API functions to equivalents that start
* "MPU_". This will cause the application code to call the MPU_
* version, which wraps the non-MPU version with privilege promoting
* then demoting code, so the kernel code always runs will full
* privileges.
*/
/* Map standard tasks.h API functions to the MPU equivalents. */
#define xTaskCreate MPU_xTaskCreate
#define xTaskCreateStatic MPU_xTaskCreateStatic
#define xTaskCreateRestricted MPU_xTaskCreateRestricted
#define vTaskAllocateMPURegions MPU_vTaskAllocateMPURegions
#define vTaskDelete MPU_vTaskDelete
#define vTaskDelay MPU_vTaskDelay
#define vTaskDelayUntil MPU_vTaskDelayUntil
#define xTaskAbortDelay MPU_xTaskAbortDelay
#define uxTaskPriorityGet MPU_uxTaskPriorityGet
#define eTaskGetState MPU_eTaskGetState
#define vTaskGetInfo MPU_vTaskGetInfo
#define vTaskPrioritySet MPU_vTaskPrioritySet
#define vTaskSuspend MPU_vTaskSuspend
#define vTaskResume MPU_vTaskResume
#define vTaskSuspendAll MPU_vTaskSuspendAll
#define xTaskResumeAll MPU_xTaskResumeAll
#define xTaskGetTickCount MPU_xTaskGetTickCount
#define uxTaskGetNumberOfTasks MPU_uxTaskGetNumberOfTasks
#define pcTaskGetName MPU_pcTaskGetName
#define xTaskGetHandle MPU_xTaskGetHandle
#define uxTaskGetStackHighWaterMark MPU_uxTaskGetStackHighWaterMark
#define vTaskSetApplicationTaskTag MPU_vTaskSetApplicationTaskTag
#define xTaskGetApplicationTaskTag MPU_xTaskGetApplicationTaskTag
#define vTaskSetThreadLocalStoragePointer MPU_vTaskSetThreadLocalStoragePointer
#define pvTaskGetThreadLocalStoragePointer MPU_pvTaskGetThreadLocalStoragePointer
#define xTaskCallApplicationTaskHook MPU_xTaskCallApplicationTaskHook
#define xTaskGetIdleTaskHandle MPU_xTaskGetIdleTaskHandle
#define uxTaskGetSystemState MPU_uxTaskGetSystemState
#define vTaskList MPU_vTaskList
#define vTaskGetRunTimeStats MPU_vTaskGetRunTimeStats
#define xTaskGenericNotify MPU_xTaskGenericNotify
#define xTaskNotifyWait MPU_xTaskNotifyWait
#define ulTaskNotifyTake MPU_ulTaskNotifyTake
#define xTaskNotifyStateClear MPU_xTaskNotifyStateClear
#define xTaskGetCurrentTaskHandle MPU_xTaskGetCurrentTaskHandle
#define vTaskSetTimeOutState MPU_vTaskSetTimeOutState
#define xTaskCheckForTimeOut MPU_xTaskCheckForTimeOut
#define xTaskGetSchedulerState MPU_xTaskGetSchedulerState
/* Map standard queue.h API functions to the MPU equivalents. */
#define xQueueGenericSend MPU_xQueueGenericSend
#define xQueueReceive MPU_xQueueReceive
#define xQueuePeek MPU_xQueuePeek
#define xQueueSemaphoreTake MPU_xQueueSemaphoreTake
#define uxQueueMessagesWaiting MPU_uxQueueMessagesWaiting
#define uxQueueSpacesAvailable MPU_uxQueueSpacesAvailable
#define vQueueDelete MPU_vQueueDelete
#define xQueueCreateMutex MPU_xQueueCreateMutex
#define xQueueCreateMutexStatic MPU_xQueueCreateMutexStatic
#define xQueueCreateCountingSemaphore MPU_xQueueCreateCountingSemaphore
#define xQueueCreateCountingSemaphoreStatic MPU_xQueueCreateCountingSemaphoreStatic
#define xQueueGetMutexHolder MPU_xQueueGetMutexHolder
#define xQueueTakeMutexRecursive MPU_xQueueTakeMutexRecursive
#define xQueueGiveMutexRecursive MPU_xQueueGiveMutexRecursive
#define xQueueGenericCreate MPU_xQueueGenericCreate
#define xQueueGenericCreateStatic MPU_xQueueGenericCreateStatic
#define xQueueCreateSet MPU_xQueueCreateSet
#define xQueueAddToSet MPU_xQueueAddToSet
#define xQueueRemoveFromSet MPU_xQueueRemoveFromSet
#define xQueueSelectFromSet MPU_xQueueSelectFromSet
#define xQueueGenericReset MPU_xQueueGenericReset
#if( configQUEUE_REGISTRY_SIZE > 0 )
#define vQueueAddToRegistry MPU_vQueueAddToRegistry
#define vQueueUnregisterQueue MPU_vQueueUnregisterQueue
#define pcQueueGetName MPU_pcQueueGetName
#endif
/* Map standard timer.h API functions to the MPU equivalents. */
#define xTimerCreate MPU_xTimerCreate
#define xTimerCreateStatic MPU_xTimerCreateStatic
#define pvTimerGetTimerID MPU_pvTimerGetTimerID
#define vTimerSetTimerID MPU_vTimerSetTimerID
#define xTimerIsTimerActive MPU_xTimerIsTimerActive
#define xTimerGetTimerDaemonTaskHandle MPU_xTimerGetTimerDaemonTaskHandle
#define xTimerPendFunctionCall MPU_xTimerPendFunctionCall
#define pcTimerGetName MPU_pcTimerGetName
#define xTimerGetPeriod MPU_xTimerGetPeriod
#define xTimerGetExpiryTime MPU_xTimerGetExpiryTime
#define xTimerGenericCommand MPU_xTimerGenericCommand
/* Map standard event_group.h API functions to the MPU equivalents. */
#define xEventGroupCreate MPU_xEventGroupCreate
#define xEventGroupCreateStatic MPU_xEventGroupCreateStatic
#define xEventGroupWaitBits MPU_xEventGroupWaitBits
#define xEventGroupClearBits MPU_xEventGroupClearBits
#define xEventGroupSetBits MPU_xEventGroupSetBits
#define xEventGroupSync MPU_xEventGroupSync
#define vEventGroupDelete MPU_vEventGroupDelete
/* Map standard message/stream_buffer.h API functions to the MPU
equivalents. */
#define xStreamBufferSend MPU_xStreamBufferSend
#define xStreamBufferSendFromISR MPU_xStreamBufferSendFromISR
#define xStreamBufferReceive MPU_xStreamBufferReceive
#define xStreamBufferNextMessageLengthBytes MPU_xStreamBufferNextMessageLengthBytes
#define xStreamBufferReceiveFromISR MPU_xStreamBufferReceiveFromISR
#define vStreamBufferDelete MPU_vStreamBufferDelete
#define xStreamBufferIsFull MPU_xStreamBufferIsFull
#define xStreamBufferIsEmpty MPU_xStreamBufferIsEmpty
#define xStreamBufferReset MPU_xStreamBufferReset
#define xStreamBufferSpacesAvailable MPU_xStreamBufferSpacesAvailable
#define xStreamBufferBytesAvailable MPU_xStreamBufferBytesAvailable
#define xStreamBufferSetTriggerLevel MPU_xStreamBufferSetTriggerLevel
#define xStreamBufferGenericCreate MPU_xStreamBufferGenericCreate
#define xStreamBufferGenericCreateStatic MPU_xStreamBufferGenericCreateStatic
/* Remove the privileged function macro, but keep the PRIVILEGED_DATA
macro so applications can place data in privileged access sections
(useful when using statically allocated objects). */
#define PRIVILEGED_FUNCTION
#define PRIVILEGED_DATA __attribute__((section("privileged_data")))
#else /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */
/* Ensure API functions go in the privileged execution section. */
#define PRIVILEGED_FUNCTION __attribute__((section("privileged_functions")))
#define PRIVILEGED_DATA __attribute__((section("privileged_data")))
#endif /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */
#else /* portUSING_MPU_WRAPPERS */
#define PRIVILEGED_FUNCTION
#define PRIVILEGED_DATA
#define portUSING_MPU_WRAPPERS 0
#endif /* portUSING_MPU_WRAPPERS */
#endif /* MPU_WRAPPERS_H */
@@ -0,0 +1,165 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/*-----------------------------------------------------------
* Portable layer API. Each function must be defined for each port.
*----------------------------------------------------------*/
#ifndef PORTABLE_H
#define PORTABLE_H
/* Each FreeRTOS port has a unique portmacro.h header file. Originally a
pre-processor definition was used to ensure the pre-processor found the correct
portmacro.h file for the port being used. That scheme was deprecated in favour
of setting the compiler's include path such that it found the correct
portmacro.h file - removing the need for the constant and allowing the
portmacro.h file to be located anywhere in relation to the port being used.
Purely for reasons of backward compatibility the old method is still valid, but
to make it clear that new projects should not use it, support for the port
specific constants has been moved into the deprecated_definitions.h header
file. */
#include "deprecated_definitions.h"
/* If portENTER_CRITICAL is not defined then including deprecated_definitions.h
did not result in a portmacro.h header file being included - and it should be
included here. In this case the path to the correct portmacro.h header file
must be set in the compiler's include path. */
#ifndef portENTER_CRITICAL
#include "portmacro.h"
#endif
#if portBYTE_ALIGNMENT == 32
#define portBYTE_ALIGNMENT_MASK ( 0x001f )
#endif
#if portBYTE_ALIGNMENT == 16
#define portBYTE_ALIGNMENT_MASK ( 0x000f )
#endif
#if portBYTE_ALIGNMENT == 8
#define portBYTE_ALIGNMENT_MASK ( 0x0007 )
#endif
#if portBYTE_ALIGNMENT == 4
#define portBYTE_ALIGNMENT_MASK ( 0x0003 )
#endif
#if portBYTE_ALIGNMENT == 2
#define portBYTE_ALIGNMENT_MASK ( 0x0001 )
#endif
#if portBYTE_ALIGNMENT == 1
#define portBYTE_ALIGNMENT_MASK ( 0x0000 )
#endif
#ifndef portBYTE_ALIGNMENT_MASK
#error "Invalid portBYTE_ALIGNMENT definition"
#endif
#ifndef portNUM_CONFIGURABLE_REGIONS
#define portNUM_CONFIGURABLE_REGIONS 1
#endif
#ifdef __cplusplus
extern "C" {
#endif
#include "mpu_wrappers.h"
/*
* Setup the stack of a new task so it is ready to be placed under the
* scheduler control. The registers have to be placed on the stack in
* the order that the port expects to find them.
*
*/
#if( portUSING_MPU_WRAPPERS == 1 )
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters, BaseType_t xRunPrivileged ) PRIVILEGED_FUNCTION;
#else
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters ) PRIVILEGED_FUNCTION;
#endif
/* Used by heap_5.c. */
typedef struct HeapRegion
{
uint8_t *pucStartAddress;
size_t xSizeInBytes;
} HeapRegion_t;
/*
* Used to define multiple heap regions for use by heap_5.c. This function
* must be called before any calls to pvPortMalloc() - not creating a task,
* queue, semaphore, mutex, software timer, event group, etc. will result in
* pvPortMalloc being called.
*
* pxHeapRegions passes in an array of HeapRegion_t structures - each of which
* defines a region of memory that can be used as the heap. The array is
* terminated by a HeapRegions_t structure that has a size of 0. The region
* with the lowest start address must appear first in the array.
*/
void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ) PRIVILEGED_FUNCTION;
/*
* Map to the memory management routines required for the port.
*/
void *pvPortMalloc( size_t xSize ) PRIVILEGED_FUNCTION;
void vPortFree( void *pv ) PRIVILEGED_FUNCTION;
void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION;
size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION;
size_t xPortGetMinimumEverFreeHeapSize( void ) PRIVILEGED_FUNCTION;
/*
* Setup the hardware ready for the scheduler to take control. This generally
* sets up a tick interrupt and sets timers for the correct tick frequency.
*/
BaseType_t xPortStartScheduler( void ) PRIVILEGED_FUNCTION;
/*
* Undo any hardware/ISR setup that was performed by xPortStartScheduler() so
* the hardware is left in its original condition after the scheduler stops
* executing.
*/
void vPortEndScheduler( void ) PRIVILEGED_FUNCTION;
/*
* The structures and methods of manipulating the MPU are contained within the
* port layer.
*
* Fills the xMPUSettings structure with the memory region information
* contained in xRegions.
*/
#if( portUSING_MPU_WRAPPERS == 1 )
struct xMEMORY_REGION;
void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, StackType_t *pxBottomOfStack, uint32_t ulStackDepth ) PRIVILEGED_FUNCTION;
#endif
#ifdef __cplusplus
}
#endif
#endif /* PORTABLE_H */
@@ -0,0 +1,124 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef PROJDEFS_H
#define PROJDEFS_H
/*
* Defines the prototype to which task functions must conform. Defined in this
* file to ensure the type is known before portable.h is included.
*/
typedef void (*TaskFunction_t)( void * );
/* Converts a time in milliseconds to a time in ticks. This macro can be
overridden by a macro of the same name defined in FreeRTOSConfig.h in case the
definition here is not suitable for your application. */
#ifndef pdMS_TO_TICKS
#define pdMS_TO_TICKS( xTimeInMs ) ( ( TickType_t ) ( ( ( TickType_t ) ( xTimeInMs ) * ( TickType_t ) configTICK_RATE_HZ ) / ( TickType_t ) 1000 ) )
#endif
#define pdFALSE ( ( BaseType_t ) 0 )
#define pdTRUE ( ( BaseType_t ) 1 )
#define pdPASS ( pdTRUE )
#define pdFAIL ( pdFALSE )
#define errQUEUE_EMPTY ( ( BaseType_t ) 0 )
#define errQUEUE_FULL ( ( BaseType_t ) 0 )
/* FreeRTOS error definitions. */
#define errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ( -1 )
#define errQUEUE_BLOCKED ( -4 )
#define errQUEUE_YIELD ( -5 )
/* Macros used for basic data corruption checks. */
#ifndef configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES
#define configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 0
#endif
#if( configUSE_16_BIT_TICKS == 1 )
#define pdINTEGRITY_CHECK_VALUE 0x5a5a
#else
#define pdINTEGRITY_CHECK_VALUE 0x5a5a5a5aUL
#endif
/* The following errno values are used by FreeRTOS+ components, not FreeRTOS
itself. */
#define pdFREERTOS_ERRNO_NONE 0 /* No errors */
#define pdFREERTOS_ERRNO_ENOENT 2 /* No such file or directory */
#define pdFREERTOS_ERRNO_EINTR 4 /* Interrupted system call */
#define pdFREERTOS_ERRNO_EIO 5 /* I/O error */
#define pdFREERTOS_ERRNO_ENXIO 6 /* No such device or address */
#define pdFREERTOS_ERRNO_EBADF 9 /* Bad file number */
#define pdFREERTOS_ERRNO_EAGAIN 11 /* No more processes */
#define pdFREERTOS_ERRNO_EWOULDBLOCK 11 /* Operation would block */
#define pdFREERTOS_ERRNO_ENOMEM 12 /* Not enough memory */
#define pdFREERTOS_ERRNO_EACCES 13 /* Permission denied */
#define pdFREERTOS_ERRNO_EFAULT 14 /* Bad address */
#define pdFREERTOS_ERRNO_EBUSY 16 /* Mount device busy */
#define pdFREERTOS_ERRNO_EEXIST 17 /* File exists */
#define pdFREERTOS_ERRNO_EXDEV 18 /* Cross-device link */
#define pdFREERTOS_ERRNO_ENODEV 19 /* No such device */
#define pdFREERTOS_ERRNO_ENOTDIR 20 /* Not a directory */
#define pdFREERTOS_ERRNO_EISDIR 21 /* Is a directory */
#define pdFREERTOS_ERRNO_EINVAL 22 /* Invalid argument */
#define pdFREERTOS_ERRNO_ENOSPC 28 /* No space left on device */
#define pdFREERTOS_ERRNO_ESPIPE 29 /* Illegal seek */
#define pdFREERTOS_ERRNO_EROFS 30 /* Read only file system */
#define pdFREERTOS_ERRNO_EUNATCH 42 /* Protocol driver not attached */
#define pdFREERTOS_ERRNO_EBADE 50 /* Invalid exchange */
#define pdFREERTOS_ERRNO_EFTYPE 79 /* Inappropriate file type or format */
#define pdFREERTOS_ERRNO_ENMFILE 89 /* No more files */
#define pdFREERTOS_ERRNO_ENOTEMPTY 90 /* Directory not empty */
#define pdFREERTOS_ERRNO_ENAMETOOLONG 91 /* File or path name too long */
#define pdFREERTOS_ERRNO_EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
#define pdFREERTOS_ERRNO_ENOBUFS 105 /* No buffer space available */
#define pdFREERTOS_ERRNO_ENOPROTOOPT 109 /* Protocol not available */
#define pdFREERTOS_ERRNO_EADDRINUSE 112 /* Address already in use */
#define pdFREERTOS_ERRNO_ETIMEDOUT 116 /* Connection timed out */
#define pdFREERTOS_ERRNO_EINPROGRESS 119 /* Connection already in progress */
#define pdFREERTOS_ERRNO_EALREADY 120 /* Socket already connected */
#define pdFREERTOS_ERRNO_EADDRNOTAVAIL 125 /* Address not available */
#define pdFREERTOS_ERRNO_EISCONN 127 /* Socket is already connected */
#define pdFREERTOS_ERRNO_ENOTCONN 128 /* Socket is not connected */
#define pdFREERTOS_ERRNO_ENOMEDIUM 135 /* No medium inserted */
#define pdFREERTOS_ERRNO_EILSEQ 138 /* An invalid UTF-16 sequence was encountered. */
#define pdFREERTOS_ERRNO_ECANCELED 140 /* Operation canceled. */
/* The following endian values are used by FreeRTOS+ components, not FreeRTOS
itself. */
#define pdFREERTOS_LITTLE_ENDIAN 0
#define pdFREERTOS_BIG_ENDIAN 1
/* Re-defining endian values for generic naming. */
#define pdLITTLE_ENDIAN pdFREERTOS_LITTLE_ENDIAN
#define pdBIG_ENDIAN pdFREERTOS_BIG_ENDIAN
#endif /* PROJDEFS_H */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,129 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef STACK_MACROS_H
#define STACK_MACROS_H
/*
* Call the stack overflow hook function if the stack of the task being swapped
* out is currently overflowed, or looks like it might have overflowed in the
* past.
*
* Setting configCHECK_FOR_STACK_OVERFLOW to 1 will cause the macro to check
* the current stack state only - comparing the current top of stack value to
* the stack limit. Setting configCHECK_FOR_STACK_OVERFLOW to greater than 1
* will also cause the last few stack bytes to be checked to ensure the value
* to which the bytes were set when the task was created have not been
* overwritten. Note this second test does not guarantee that an overflowed
* stack will always be recognised.
*/
/*-----------------------------------------------------------*/
#if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH < 0 ) )
/* Only the current stack state is to be checked. */
#define taskCHECK_FOR_STACK_OVERFLOW() \
{ \
/* Is the currently saved stack pointer within the stack limit? */ \
if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack ) \
{ \
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
} \
}
#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */
/*-----------------------------------------------------------*/
#if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH > 0 ) )
/* Only the current stack state is to be checked. */
#define taskCHECK_FOR_STACK_OVERFLOW() \
{ \
\
/* Is the currently saved stack pointer within the stack limit? */ \
if( pxCurrentTCB->pxTopOfStack >= pxCurrentTCB->pxEndOfStack ) \
{ \
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
} \
}
#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */
/*-----------------------------------------------------------*/
#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH < 0 ) )
#define taskCHECK_FOR_STACK_OVERFLOW() \
{ \
const uint32_t * const pulStack = ( uint32_t * ) pxCurrentTCB->pxStack; \
const uint32_t ulCheckValue = ( uint32_t ) 0xa5a5a5a5; \
\
if( ( pulStack[ 0 ] != ulCheckValue ) || \
( pulStack[ 1 ] != ulCheckValue ) || \
( pulStack[ 2 ] != ulCheckValue ) || \
( pulStack[ 3 ] != ulCheckValue ) ) \
{ \
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
} \
}
#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */
/*-----------------------------------------------------------*/
#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH > 0 ) )
#define taskCHECK_FOR_STACK_OVERFLOW() \
{ \
int8_t *pcEndOfStack = ( int8_t * ) pxCurrentTCB->pxEndOfStack; \
static const uint8_t ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \
\
\
pcEndOfStack -= sizeof( ucExpectedStackBytes ); \
\
/* Has the extremity of the task stack ever been written over? */ \
if( memcmp( ( void * ) pcEndOfStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \
{ \
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
} \
}
#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */
/*-----------------------------------------------------------*/
/* Remove stack overflow macro if not being used. */
#ifndef taskCHECK_FOR_STACK_OVERFLOW
#define taskCHECK_FOR_STACK_OVERFLOW()
#endif
#endif /* STACK_MACROS_H */
@@ -0,0 +1,27 @@
#ifndef FREERTOS_STDINT
#define FREERTOS_STDINT
/*******************************************************************************
* THIS IS NOT A FULL stdint.h IMPLEMENTATION - It only contains the definitions
* necessary to build the FreeRTOS code. It is provided to allow FreeRTOS to be
* built using compilers that do not provide their own stdint.h definition.
*
* To use this file:
*
* 1) Copy this file into the directory that contains your FreeRTOSConfig.h
* header file, as that directory will already be in the compilers include
* path.
*
* 2) Rename the copied file stdint.h.
*
*/
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef short int16_t;
typedef unsigned short uint16_t;
typedef long int32_t;
typedef unsigned long uint32_t;
#endif /* FREERTOS_STDINT */
@@ -0,0 +1,855 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/*
* Stream buffers are used to send a continuous stream of data from one task or
* interrupt to another. Their implementation is light weight, making them
* particularly suited for interrupt to task and core to core communication
* scenarios.
*
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
* implementation (so also the message buffer implementation, as message buffers
* are built on top of stream buffers) assumes there is only one task or
* interrupt that will write to the buffer (the writer), and only one task or
* interrupt that will read from the buffer (the reader). It is safe for the
* writer and reader to be different tasks or interrupts, but, unlike other
* FreeRTOS objects, it is not safe to have multiple different writers or
* multiple different readers. If there are to be multiple different writers
* then the application writer must place each call to a writing API function
* (such as xStreamBufferSend()) inside a critical section and set the send
* block time to 0. Likewise, if there are to be multiple different readers
* then the application writer must place each call to a reading API function
* (such as xStreamBufferRead()) inside a critical section section and set the
* receive block time to 0.
*
*/
#ifndef STREAM_BUFFER_H
#define STREAM_BUFFER_H
#if defined( __cplusplus )
extern "C" {
#endif
/**
* Type by which stream buffers are referenced. For example, a call to
* xStreamBufferCreate() returns an StreamBufferHandle_t variable that can
* then be used as a parameter to xStreamBufferSend(), xStreamBufferReceive(),
* etc.
*/
struct StreamBufferDef_t;
typedef struct StreamBufferDef_t * StreamBufferHandle_t;
/**
* message_buffer.h
*
<pre>
StreamBufferHandle_t xStreamBufferCreate( size_t xBufferSizeBytes, size_t xTriggerLevelBytes );
</pre>
*
* Creates a new stream buffer using dynamically allocated memory. See
* xStreamBufferCreateStatic() for a version that uses statically allocated
* memory (memory that is allocated at compile time).
*
* configSUPPORT_DYNAMIC_ALLOCATION must be set to 1 or left undefined in
* FreeRTOSConfig.h for xStreamBufferCreate() to be available.
*
* @param xBufferSizeBytes The total number of bytes the stream buffer will be
* able to hold at any one time.
*
* @param xTriggerLevelBytes The number of bytes that must be in the stream
* buffer before a task that is blocked on the stream buffer to wait for data is
* moved out of the blocked state. For example, if a task is blocked on a read
* of an empty stream buffer that has a trigger level of 1 then the task will be
* unblocked when a single byte is written to the buffer or the task's block
* time expires. As another example, if a task is blocked on a read of an empty
* stream buffer that has a trigger level of 10 then the task will not be
* unblocked until the stream buffer contains at least 10 bytes or the task's
* block time expires. If a reading task's block time expires before the
* trigger level is reached then the task will still receive however many bytes
* are actually available. Setting a trigger level of 0 will result in a
* trigger level of 1 being used. It is not valid to specify a trigger level
* that is greater than the buffer size.
*
* @return If NULL is returned, then the stream buffer cannot be created
* because there is insufficient heap memory available for FreeRTOS to allocate
* the stream buffer data structures and storage area. A non-NULL value being
* returned indicates that the stream buffer has been created successfully -
* the returned value should be stored as the handle to the created stream
* buffer.
*
* Example use:
<pre>
void vAFunction( void )
{
StreamBufferHandle_t xStreamBuffer;
const size_t xStreamBufferSizeBytes = 100, xTriggerLevel = 10;
// Create a stream buffer that can hold 100 bytes. The memory used to hold
// both the stream buffer structure and the data in the stream buffer is
// allocated dynamically.
xStreamBuffer = xStreamBufferCreate( xStreamBufferSizeBytes, xTriggerLevel );
if( xStreamBuffer == NULL )
{
// There was not enough heap memory space available to create the
// stream buffer.
}
else
{
// The stream buffer was created successfully and can now be used.
}
}
</pre>
* \defgroup xStreamBufferCreate xStreamBufferCreate
* \ingroup StreamBufferManagement
*/
#define xStreamBufferCreate( xBufferSizeBytes, xTriggerLevelBytes ) xStreamBufferGenericCreate( xBufferSizeBytes, xTriggerLevelBytes, pdFALSE )
/**
* stream_buffer.h
*
<pre>
StreamBufferHandle_t xStreamBufferCreateStatic( size_t xBufferSizeBytes,
size_t xTriggerLevelBytes,
uint8_t *pucStreamBufferStorageArea,
StaticStreamBuffer_t *pxStaticStreamBuffer );
</pre>
* Creates a new stream buffer using statically allocated memory. See
* xStreamBufferCreate() for a version that uses dynamically allocated memory.
*
* configSUPPORT_STATIC_ALLOCATION must be set to 1 in FreeRTOSConfig.h for
* xStreamBufferCreateStatic() to be available.
*
* @param xBufferSizeBytes The size, in bytes, of the buffer pointed to by the
* pucStreamBufferStorageArea parameter.
*
* @param xTriggerLevelBytes The number of bytes that must be in the stream
* buffer before a task that is blocked on the stream buffer to wait for data is
* moved out of the blocked state. For example, if a task is blocked on a read
* of an empty stream buffer that has a trigger level of 1 then the task will be
* unblocked when a single byte is written to the buffer or the task's block
* time expires. As another example, if a task is blocked on a read of an empty
* stream buffer that has a trigger level of 10 then the task will not be
* unblocked until the stream buffer contains at least 10 bytes or the task's
* block time expires. If a reading task's block time expires before the
* trigger level is reached then the task will still receive however many bytes
* are actually available. Setting a trigger level of 0 will result in a
* trigger level of 1 being used. It is not valid to specify a trigger level
* that is greater than the buffer size.
*
* @param pucStreamBufferStorageArea Must point to a uint8_t array that is at
* least xBufferSizeBytes + 1 big. This is the array to which streams are
* copied when they are written to the stream buffer.
*
* @param pxStaticStreamBuffer Must point to a variable of type
* StaticStreamBuffer_t, which will be used to hold the stream buffer's data
* structure.
*
* @return If the stream buffer is created successfully then a handle to the
* created stream buffer is returned. If either pucStreamBufferStorageArea or
* pxStaticstreamBuffer are NULL then NULL is returned.
*
* Example use:
<pre>
// Used to dimension the array used to hold the streams. The available space
// will actually be one less than this, so 999.
#define STORAGE_SIZE_BYTES 1000
// Defines the memory that will actually hold the streams within the stream
// buffer.
static uint8_t ucStorageBuffer[ STORAGE_SIZE_BYTES ];
// The variable used to hold the stream buffer structure.
StaticStreamBuffer_t xStreamBufferStruct;
void MyFunction( void )
{
StreamBufferHandle_t xStreamBuffer;
const size_t xTriggerLevel = 1;
xStreamBuffer = xStreamBufferCreateStatic( sizeof( ucBufferStorage ),
xTriggerLevel,
ucBufferStorage,
&xStreamBufferStruct );
// As neither the pucStreamBufferStorageArea or pxStaticStreamBuffer
// parameters were NULL, xStreamBuffer will not be NULL, and can be used to
// reference the created stream buffer in other stream buffer API calls.
// Other code that uses the stream buffer can go here.
}
</pre>
* \defgroup xStreamBufferCreateStatic xStreamBufferCreateStatic
* \ingroup StreamBufferManagement
*/
#define xStreamBufferCreateStatic( xBufferSizeBytes, xTriggerLevelBytes, pucStreamBufferStorageArea, pxStaticStreamBuffer ) xStreamBufferGenericCreateStatic( xBufferSizeBytes, xTriggerLevelBytes, pdFALSE, pucStreamBufferStorageArea, pxStaticStreamBuffer )
/**
* stream_buffer.h
*
<pre>
size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
const void *pvTxData,
size_t xDataLengthBytes,
TickType_t xTicksToWait );
</pre>
*
* Sends bytes to a stream buffer. The bytes are copied into the stream buffer.
*
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
* implementation (so also the message buffer implementation, as message buffers
* are built on top of stream buffers) assumes there is only one task or
* interrupt that will write to the buffer (the writer), and only one task or
* interrupt that will read from the buffer (the reader). It is safe for the
* writer and reader to be different tasks or interrupts, but, unlike other
* FreeRTOS objects, it is not safe to have multiple different writers or
* multiple different readers. If there are to be multiple different writers
* then the application writer must place each call to a writing API function
* (such as xStreamBufferSend()) inside a critical section and set the send
* block time to 0. Likewise, if there are to be multiple different readers
* then the application writer must place each call to a reading API function
* (such as xStreamBufferRead()) inside a critical section and set the receive
* block time to 0.
*
* Use xStreamBufferSend() to write to a stream buffer from a task. Use
* xStreamBufferSendFromISR() to write to a stream buffer from an interrupt
* service routine (ISR).
*
* @param xStreamBuffer The handle of the stream buffer to which a stream is
* being sent.
*
* @param pvTxData A pointer to the buffer that holds the bytes to be copied
* into the stream buffer.
*
* @param xDataLengthBytes The maximum number of bytes to copy from pvTxData
* into the stream buffer.
*
* @param xTicksToWait The maximum amount of time the task should remain in the
* Blocked state to wait for enough space to become available in the stream
* buffer, should the stream buffer contain too little space to hold the
* another xDataLengthBytes bytes. The block time is specified in tick periods,
* so the absolute time it represents is dependent on the tick frequency. The
* macro pdMS_TO_TICKS() can be used to convert a time specified in milliseconds
* into a time specified in ticks. Setting xTicksToWait to portMAX_DELAY will
* cause the task to wait indefinitely (without timing out), provided
* INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h. If a task times out
* before it can write all xDataLengthBytes into the buffer it will still write
* as many bytes as possible. A task does not use any CPU time when it is in
* the blocked state.
*
* @return The number of bytes written to the stream buffer. If a task times
* out before it can write all xDataLengthBytes into the buffer it will still
* write as many bytes as possible.
*
* Example use:
<pre>
void vAFunction( StreamBufferHandle_t xStreamBuffer )
{
size_t xBytesSent;
uint8_t ucArrayToSend[] = { 0, 1, 2, 3 };
char *pcStringToSend = "String to send";
const TickType_t x100ms = pdMS_TO_TICKS( 100 );
// Send an array to the stream buffer, blocking for a maximum of 100ms to
// wait for enough space to be available in the stream buffer.
xBytesSent = xStreamBufferSend( xStreamBuffer, ( void * ) ucArrayToSend, sizeof( ucArrayToSend ), x100ms );
if( xBytesSent != sizeof( ucArrayToSend ) )
{
// The call to xStreamBufferSend() times out before there was enough
// space in the buffer for the data to be written, but it did
// successfully write xBytesSent bytes.
}
// Send the string to the stream buffer. Return immediately if there is not
// enough space in the buffer.
xBytesSent = xStreamBufferSend( xStreamBuffer, ( void * ) pcStringToSend, strlen( pcStringToSend ), 0 );
if( xBytesSent != strlen( pcStringToSend ) )
{
// The entire string could not be added to the stream buffer because
// there was not enough free space in the buffer, but xBytesSent bytes
// were sent. Could try again to send the remaining bytes.
}
}
</pre>
* \defgroup xStreamBufferSend xStreamBufferSend
* \ingroup StreamBufferManagement
*/
size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
const void *pvTxData,
size_t xDataLengthBytes,
TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
/**
* stream_buffer.h
*
<pre>
size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer,
const void *pvTxData,
size_t xDataLengthBytes,
BaseType_t *pxHigherPriorityTaskWoken );
</pre>
*
* Interrupt safe version of the API function that sends a stream of bytes to
* the stream buffer.
*
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
* implementation (so also the message buffer implementation, as message buffers
* are built on top of stream buffers) assumes there is only one task or
* interrupt that will write to the buffer (the writer), and only one task or
* interrupt that will read from the buffer (the reader). It is safe for the
* writer and reader to be different tasks or interrupts, but, unlike other
* FreeRTOS objects, it is not safe to have multiple different writers or
* multiple different readers. If there are to be multiple different writers
* then the application writer must place each call to a writing API function
* (such as xStreamBufferSend()) inside a critical section and set the send
* block time to 0. Likewise, if there are to be multiple different readers
* then the application writer must place each call to a reading API function
* (such as xStreamBufferRead()) inside a critical section and set the receive
* block time to 0.
*
* Use xStreamBufferSend() to write to a stream buffer from a task. Use
* xStreamBufferSendFromISR() to write to a stream buffer from an interrupt
* service routine (ISR).
*
* @param xStreamBuffer The handle of the stream buffer to which a stream is
* being sent.
*
* @param pvTxData A pointer to the data that is to be copied into the stream
* buffer.
*
* @param xDataLengthBytes The maximum number of bytes to copy from pvTxData
* into the stream buffer.
*
* @param pxHigherPriorityTaskWoken It is possible that a stream buffer will
* have a task blocked on it waiting for data. Calling
* xStreamBufferSendFromISR() can make data available, and so cause a task that
* was waiting for data to leave the Blocked state. If calling
* xStreamBufferSendFromISR() causes a task to leave the Blocked state, and the
* unblocked task has a priority higher than the currently executing task (the
* task that was interrupted), then, internally, xStreamBufferSendFromISR()
* will set *pxHigherPriorityTaskWoken to pdTRUE. If
* xStreamBufferSendFromISR() sets this value to pdTRUE, then normally a
* context switch should be performed before the interrupt is exited. This will
* ensure that the interrupt returns directly to the highest priority Ready
* state task. *pxHigherPriorityTaskWoken should be set to pdFALSE before it
* is passed into the function. See the example code below for an example.
*
* @return The number of bytes actually written to the stream buffer, which will
* be less than xDataLengthBytes if the stream buffer didn't have enough free
* space for all the bytes to be written.
*
* Example use:
<pre>
// A stream buffer that has already been created.
StreamBufferHandle_t xStreamBuffer;
void vAnInterruptServiceRoutine( void )
{
size_t xBytesSent;
char *pcStringToSend = "String to send";
BaseType_t xHigherPriorityTaskWoken = pdFALSE; // Initialised to pdFALSE.
// Attempt to send the string to the stream buffer.
xBytesSent = xStreamBufferSendFromISR( xStreamBuffer,
( void * ) pcStringToSend,
strlen( pcStringToSend ),
&xHigherPriorityTaskWoken );
if( xBytesSent != strlen( pcStringToSend ) )
{
// There was not enough free space in the stream buffer for the entire
// string to be written, ut xBytesSent bytes were written.
}
// If xHigherPriorityTaskWoken was set to pdTRUE inside
// xStreamBufferSendFromISR() then a task that has a priority above the
// priority of the currently executing task was unblocked and a context
// switch should be performed to ensure the ISR returns to the unblocked
// task. In most FreeRTOS ports this is done by simply passing
// xHigherPriorityTaskWoken into taskYIELD_FROM_ISR(), which will test the
// variables value, and perform the context switch if necessary. Check the
// documentation for the port in use for port specific instructions.
taskYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
</pre>
* \defgroup xStreamBufferSendFromISR xStreamBufferSendFromISR
* \ingroup StreamBufferManagement
*/
size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer,
const void *pvTxData,
size_t xDataLengthBytes,
BaseType_t * const pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
/**
* stream_buffer.h
*
<pre>
size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
void *pvRxData,
size_t xBufferLengthBytes,
TickType_t xTicksToWait );
</pre>
*
* Receives bytes from a stream buffer.
*
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
* implementation (so also the message buffer implementation, as message buffers
* are built on top of stream buffers) assumes there is only one task or
* interrupt that will write to the buffer (the writer), and only one task or
* interrupt that will read from the buffer (the reader). It is safe for the
* writer and reader to be different tasks or interrupts, but, unlike other
* FreeRTOS objects, it is not safe to have multiple different writers or
* multiple different readers. If there are to be multiple different writers
* then the application writer must place each call to a writing API function
* (such as xStreamBufferSend()) inside a critical section and set the send
* block time to 0. Likewise, if there are to be multiple different readers
* then the application writer must place each call to a reading API function
* (such as xStreamBufferRead()) inside a critical section and set the receive
* block time to 0.
*
* Use xStreamBufferReceive() to read from a stream buffer from a task. Use
* xStreamBufferReceiveFromISR() to read from a stream buffer from an
* interrupt service routine (ISR).
*
* @param xStreamBuffer The handle of the stream buffer from which bytes are to
* be received.
*
* @param pvRxData A pointer to the buffer into which the received bytes will be
* copied.
*
* @param xBufferLengthBytes The length of the buffer pointed to by the
* pvRxData parameter. This sets the maximum number of bytes to receive in one
* call. xStreamBufferReceive will return as many bytes as possible up to a
* maximum set by xBufferLengthBytes.
*
* @param xTicksToWait The maximum amount of time the task should remain in the
* Blocked state to wait for data to become available if the stream buffer is
* empty. xStreamBufferReceive() will return immediately if xTicksToWait is
* zero. The block time is specified in tick periods, so the absolute time it
* represents is dependent on the tick frequency. The macro pdMS_TO_TICKS() can
* be used to convert a time specified in milliseconds into a time specified in
* ticks. Setting xTicksToWait to portMAX_DELAY will cause the task to wait
* indefinitely (without timing out), provided INCLUDE_vTaskSuspend is set to 1
* in FreeRTOSConfig.h. A task does not use any CPU time when it is in the
* Blocked state.
*
* @return The number of bytes actually read from the stream buffer, which will
* be less than xBufferLengthBytes if the call to xStreamBufferReceive() timed
* out before xBufferLengthBytes were available.
*
* Example use:
<pre>
void vAFunction( StreamBuffer_t xStreamBuffer )
{
uint8_t ucRxData[ 20 ];
size_t xReceivedBytes;
const TickType_t xBlockTime = pdMS_TO_TICKS( 20 );
// Receive up to another sizeof( ucRxData ) bytes from the stream buffer.
// Wait in the Blocked state (so not using any CPU processing time) for a
// maximum of 100ms for the full sizeof( ucRxData ) number of bytes to be
// available.
xReceivedBytes = xStreamBufferReceive( xStreamBuffer,
( void * ) ucRxData,
sizeof( ucRxData ),
xBlockTime );
if( xReceivedBytes > 0 )
{
// A ucRxData contains another xRecievedBytes bytes of data, which can
// be processed here....
}
}
</pre>
* \defgroup xStreamBufferReceive xStreamBufferReceive
* \ingroup StreamBufferManagement
*/
size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
void *pvRxData,
size_t xBufferLengthBytes,
TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
/**
* stream_buffer.h
*
<pre>
size_t xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer,
void *pvRxData,
size_t xBufferLengthBytes,
BaseType_t *pxHigherPriorityTaskWoken );
</pre>
*
* An interrupt safe version of the API function that receives bytes from a
* stream buffer.
*
* Use xStreamBufferReceive() to read bytes from a stream buffer from a task.
* Use xStreamBufferReceiveFromISR() to read bytes from a stream buffer from an
* interrupt service routine (ISR).
*
* @param xStreamBuffer The handle of the stream buffer from which a stream
* is being received.
*
* @param pvRxData A pointer to the buffer into which the received bytes are
* copied.
*
* @param xBufferLengthBytes The length of the buffer pointed to by the
* pvRxData parameter. This sets the maximum number of bytes to receive in one
* call. xStreamBufferReceive will return as many bytes as possible up to a
* maximum set by xBufferLengthBytes.
*
* @param pxHigherPriorityTaskWoken It is possible that a stream buffer will
* have a task blocked on it waiting for space to become available. Calling
* xStreamBufferReceiveFromISR() can make space available, and so cause a task
* that is waiting for space to leave the Blocked state. If calling
* xStreamBufferReceiveFromISR() causes a task to leave the Blocked state, and
* the unblocked task has a priority higher than the currently executing task
* (the task that was interrupted), then, internally,
* xStreamBufferReceiveFromISR() will set *pxHigherPriorityTaskWoken to pdTRUE.
* If xStreamBufferReceiveFromISR() sets this value to pdTRUE, then normally a
* context switch should be performed before the interrupt is exited. That will
* ensure the interrupt returns directly to the highest priority Ready state
* task. *pxHigherPriorityTaskWoken should be set to pdFALSE before it is
* passed into the function. See the code example below for an example.
*
* @return The number of bytes read from the stream buffer, if any.
*
* Example use:
<pre>
// A stream buffer that has already been created.
StreamBuffer_t xStreamBuffer;
void vAnInterruptServiceRoutine( void )
{
uint8_t ucRxData[ 20 ];
size_t xReceivedBytes;
BaseType_t xHigherPriorityTaskWoken = pdFALSE; // Initialised to pdFALSE.
// Receive the next stream from the stream buffer.
xReceivedBytes = xStreamBufferReceiveFromISR( xStreamBuffer,
( void * ) ucRxData,
sizeof( ucRxData ),
&xHigherPriorityTaskWoken );
if( xReceivedBytes > 0 )
{
// ucRxData contains xReceivedBytes read from the stream buffer.
// Process the stream here....
}
// If xHigherPriorityTaskWoken was set to pdTRUE inside
// xStreamBufferReceiveFromISR() then a task that has a priority above the
// priority of the currently executing task was unblocked and a context
// switch should be performed to ensure the ISR returns to the unblocked
// task. In most FreeRTOS ports this is done by simply passing
// xHigherPriorityTaskWoken into taskYIELD_FROM_ISR(), which will test the
// variables value, and perform the context switch if necessary. Check the
// documentation for the port in use for port specific instructions.
taskYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
</pre>
* \defgroup xStreamBufferReceiveFromISR xStreamBufferReceiveFromISR
* \ingroup StreamBufferManagement
*/
size_t xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer,
void *pvRxData,
size_t xBufferLengthBytes,
BaseType_t * const pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
/**
* stream_buffer.h
*
<pre>
void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer );
</pre>
*
* Deletes a stream buffer that was previously created using a call to
* xStreamBufferCreate() or xStreamBufferCreateStatic(). If the stream
* buffer was created using dynamic memory (that is, by xStreamBufferCreate()),
* then the allocated memory is freed.
*
* A stream buffer handle must not be used after the stream buffer has been
* deleted.
*
* @param xStreamBuffer The handle of the stream buffer to be deleted.
*
* \defgroup vStreamBufferDelete vStreamBufferDelete
* \ingroup StreamBufferManagement
*/
void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
/**
* stream_buffer.h
*
<pre>
BaseType_t xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer );
</pre>
*
* Queries a stream buffer to see if it is full. A stream buffer is full if it
* does not have any free space, and therefore cannot accept any more data.
*
* @param xStreamBuffer The handle of the stream buffer being queried.
*
* @return If the stream buffer is full then pdTRUE is returned. Otherwise
* pdFALSE is returned.
*
* \defgroup xStreamBufferIsFull xStreamBufferIsFull
* \ingroup StreamBufferManagement
*/
BaseType_t xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
/**
* stream_buffer.h
*
<pre>
BaseType_t xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer );
</pre>
*
* Queries a stream buffer to see if it is empty. A stream buffer is empty if
* it does not contain any data.
*
* @param xStreamBuffer The handle of the stream buffer being queried.
*
* @return If the stream buffer is empty then pdTRUE is returned. Otherwise
* pdFALSE is returned.
*
* \defgroup xStreamBufferIsEmpty xStreamBufferIsEmpty
* \ingroup StreamBufferManagement
*/
BaseType_t xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
/**
* stream_buffer.h
*
<pre>
BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer );
</pre>
*
* Resets a stream buffer to its initial, empty, state. Any data that was in
* the stream buffer is discarded. A stream buffer can only be reset if there
* are no tasks blocked waiting to either send to or receive from the stream
* buffer.
*
* @param xStreamBuffer The handle of the stream buffer being reset.
*
* @return If the stream buffer is reset then pdPASS is returned. If there was
* a task blocked waiting to send to or read from the stream buffer then the
* stream buffer is not reset and pdFAIL is returned.
*
* \defgroup xStreamBufferReset xStreamBufferReset
* \ingroup StreamBufferManagement
*/
BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
/**
* stream_buffer.h
*
<pre>
size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer );
</pre>
*
* Queries a stream buffer to see how much free space it contains, which is
* equal to the amount of data that can be sent to the stream buffer before it
* is full.
*
* @param xStreamBuffer The handle of the stream buffer being queried.
*
* @return The number of bytes that can be written to the stream buffer before
* the stream buffer would be full.
*
* \defgroup xStreamBufferSpacesAvailable xStreamBufferSpacesAvailable
* \ingroup StreamBufferManagement
*/
size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
/**
* stream_buffer.h
*
<pre>
size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer );
</pre>
*
* Queries a stream buffer to see how much data it contains, which is equal to
* the number of bytes that can be read from the stream buffer before the stream
* buffer would be empty.
*
* @param xStreamBuffer The handle of the stream buffer being queried.
*
* @return The number of bytes that can be read from the stream buffer before
* the stream buffer would be empty.
*
* \defgroup xStreamBufferBytesAvailable xStreamBufferBytesAvailable
* \ingroup StreamBufferManagement
*/
size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
/**
* stream_buffer.h
*
<pre>
BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, size_t xTriggerLevel );
</pre>
*
* A stream buffer's trigger level is the number of bytes that must be in the
* stream buffer before a task that is blocked on the stream buffer to
* wait for data is moved out of the blocked state. For example, if a task is
* blocked on a read of an empty stream buffer that has a trigger level of 1
* then the task will be unblocked when a single byte is written to the buffer
* or the task's block time expires. As another example, if a task is blocked
* on a read of an empty stream buffer that has a trigger level of 10 then the
* task will not be unblocked until the stream buffer contains at least 10 bytes
* or the task's block time expires. If a reading task's block time expires
* before the trigger level is reached then the task will still receive however
* many bytes are actually available. Setting a trigger level of 0 will result
* in a trigger level of 1 being used. It is not valid to specify a trigger
* level that is greater than the buffer size.
*
* A trigger level is set when the stream buffer is created, and can be modified
* using xStreamBufferSetTriggerLevel().
*
* @param xStreamBuffer The handle of the stream buffer being updated.
*
* @param xTriggerLevel The new trigger level for the stream buffer.
*
* @return If xTriggerLevel was less than or equal to the stream buffer's length
* then the trigger level will be updated and pdTRUE is returned. Otherwise
* pdFALSE is returned.
*
* \defgroup xStreamBufferSetTriggerLevel xStreamBufferSetTriggerLevel
* \ingroup StreamBufferManagement
*/
BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, size_t xTriggerLevel ) PRIVILEGED_FUNCTION;
/**
* stream_buffer.h
*
<pre>
BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken );
</pre>
*
* For advanced users only.
*
* The sbSEND_COMPLETED() macro is called from within the FreeRTOS APIs when
* data is sent to a message buffer or stream buffer. If there was a task that
* was blocked on the message or stream buffer waiting for data to arrive then
* the sbSEND_COMPLETED() macro sends a notification to the task to remove it
* from the Blocked state. xStreamBufferSendCompletedFromISR() does the same
* thing. It is provided to enable application writers to implement their own
* version of sbSEND_COMPLETED(), and MUST NOT BE USED AT ANY OTHER TIME.
*
* See the example implemented in FreeRTOS/Demo/Minimal/MessageBufferAMP.c for
* additional information.
*
* @param xStreamBuffer The handle of the stream buffer to which data was
* written.
*
* @param pxHigherPriorityTaskWoken *pxHigherPriorityTaskWoken should be
* initialised to pdFALSE before it is passed into
* xStreamBufferSendCompletedFromISR(). If calling
* xStreamBufferSendCompletedFromISR() removes a task from the Blocked state,
* and the task has a priority above the priority of the currently running task,
* then *pxHigherPriorityTaskWoken will get set to pdTRUE indicating that a
* context switch should be performed before exiting the ISR.
*
* @return If a task was removed from the Blocked state then pdTRUE is returned.
* Otherwise pdFALSE is returned.
*
* \defgroup xStreamBufferSendCompletedFromISR xStreamBufferSendCompletedFromISR
* \ingroup StreamBufferManagement
*/
BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
/**
* stream_buffer.h
*
<pre>
BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken );
</pre>
*
* For advanced users only.
*
* The sbRECEIVE_COMPLETED() macro is called from within the FreeRTOS APIs when
* data is read out of a message buffer or stream buffer. If there was a task
* that was blocked on the message or stream buffer waiting for data to arrive
* then the sbRECEIVE_COMPLETED() macro sends a notification to the task to
* remove it from the Blocked state. xStreamBufferReceiveCompletedFromISR()
* does the same thing. It is provided to enable application writers to
* implement their own version of sbRECEIVE_COMPLETED(), and MUST NOT BE USED AT
* ANY OTHER TIME.
*
* See the example implemented in FreeRTOS/Demo/Minimal/MessageBufferAMP.c for
* additional information.
*
* @param xStreamBuffer The handle of the stream buffer from which data was
* read.
*
* @param pxHigherPriorityTaskWoken *pxHigherPriorityTaskWoken should be
* initialised to pdFALSE before it is passed into
* xStreamBufferReceiveCompletedFromISR(). If calling
* xStreamBufferReceiveCompletedFromISR() removes a task from the Blocked state,
* and the task has a priority above the priority of the currently running task,
* then *pxHigherPriorityTaskWoken will get set to pdTRUE indicating that a
* context switch should be performed before exiting the ISR.
*
* @return If a task was removed from the Blocked state then pdTRUE is returned.
* Otherwise pdFALSE is returned.
*
* \defgroup xStreamBufferReceiveCompletedFromISR xStreamBufferReceiveCompletedFromISR
* \ingroup StreamBufferManagement
*/
BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
/* Functions below here are not part of the public API. */
StreamBufferHandle_t xStreamBufferGenericCreate( size_t xBufferSizeBytes,
size_t xTriggerLevelBytes,
BaseType_t xIsMessageBuffer ) PRIVILEGED_FUNCTION;
StreamBufferHandle_t xStreamBufferGenericCreateStatic( size_t xBufferSizeBytes,
size_t xTriggerLevelBytes,
BaseType_t xIsMessageBuffer,
uint8_t * const pucStreamBufferStorageArea,
StaticStreamBuffer_t * const pxStaticStreamBuffer ) PRIVILEGED_FUNCTION;
size_t xStreamBufferNextMessageLengthBytes( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
#if( configUSE_TRACE_FACILITY == 1 )
void vStreamBufferSetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer, UBaseType_t uxStreamBufferNumber ) PRIVILEGED_FUNCTION;
UBaseType_t uxStreamBufferGetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
uint8_t ucStreamBufferGetStreamBufferType( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
#endif
#if defined( __cplusplus )
}
#endif
#endif /* !defined( STREAM_BUFFER_H ) */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,198 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#include <stdlib.h>
#include "FreeRTOS.h"
#include "list.h"
/*-----------------------------------------------------------
* PUBLIC LIST API documented in list.h
*----------------------------------------------------------*/
void vListInitialise( List_t * const pxList )
{
/* The list structure contains a list item which is used to mark the
end of the list. To initialise the list the list end is inserted
as the only list entry. */
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */
/* The list end value is the highest possible value in the list to
ensure it remains at the end of the list. */
pxList->xListEnd.xItemValue = portMAX_DELAY;
/* The list end next and previous pointers point to itself so we know
when the list is empty. */
pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */
pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );/*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */
pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
/* Write known values into the list if
configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
}
/*-----------------------------------------------------------*/
void vListInitialiseItem( ListItem_t * const pxItem )
{
/* Make sure the list item is not recorded as being on a list. */
pxItem->pxContainer = NULL;
/* Write known values into the list item if
configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
}
/*-----------------------------------------------------------*/
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
{
ListItem_t * const pxIndex = pxList->pxIndex;
/* Only effective when configASSERT() is also defined, these tests may catch
the list data structures being overwritten in memory. They will not catch
data errors caused by incorrect configuration or use of FreeRTOS. */
listTEST_LIST_INTEGRITY( pxList );
listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
/* Insert a new list item into pxList, but rather than sort the list,
makes the new list item the last item to be removed by a call to
listGET_OWNER_OF_NEXT_ENTRY(). */
pxNewListItem->pxNext = pxIndex;
pxNewListItem->pxPrevious = pxIndex->pxPrevious;
/* Only used during decision coverage testing. */
mtCOVERAGE_TEST_DELAY();
pxIndex->pxPrevious->pxNext = pxNewListItem;
pxIndex->pxPrevious = pxNewListItem;
/* Remember which list the item is in. */
pxNewListItem->pxContainer = pxList;
( pxList->uxNumberOfItems )++;
}
/*-----------------------------------------------------------*/
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
{
ListItem_t *pxIterator;
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
/* Only effective when configASSERT() is also defined, these tests may catch
the list data structures being overwritten in memory. They will not catch
data errors caused by incorrect configuration or use of FreeRTOS. */
listTEST_LIST_INTEGRITY( pxList );
listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
/* Insert the new list item into the list, sorted in xItemValue order.
If the list already contains a list item with the same item value then the
new list item should be placed after it. This ensures that TCBs which are
stored in ready lists (all of which have the same xItemValue value) get a
share of the CPU. However, if the xItemValue is the same as the back marker
the iteration loop below will not end. Therefore the value is checked
first, and the algorithm slightly modified if necessary. */
if( xValueOfInsertion == portMAX_DELAY )
{
pxIterator = pxList->xListEnd.pxPrevious;
}
else
{
/* *** NOTE ***********************************************************
If you find your application is crashing here then likely causes are
listed below. In addition see https://www.freertos.org/FAQHelp.html for
more tips, and ensure configASSERT() is defined!
https://www.freertos.org/a00110.html#configASSERT
1) Stack overflow -
see https://www.freertos.org/Stacks-and-stack-overflow-checking.html
2) Incorrect interrupt priority assignment, especially on Cortex-M
parts where numerically high priority values denote low actual
interrupt priorities, which can seem counter intuitive. See
https://www.freertos.org/RTOS-Cortex-M3-M4.html and the definition
of configMAX_SYSCALL_INTERRUPT_PRIORITY on
https://www.freertos.org/a00110.html
3) Calling an API function from within a critical section or when
the scheduler is suspended, or calling an API function that does
not end in "FromISR" from an interrupt.
4) Using a queue or semaphore before it has been initialised or
before the scheduler has been started (are interrupts firing
before vTaskStartScheduler() has been called?).
**********************************************************************/
for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. *//*lint !e440 The iterator moves to a different value, not xValueOfInsertion. */
{
/* There is nothing to do here, just iterating to the wanted
insertion position. */
}
}
pxNewListItem->pxNext = pxIterator->pxNext;
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
pxNewListItem->pxPrevious = pxIterator;
pxIterator->pxNext = pxNewListItem;
/* Remember which list the item is in. This allows fast removal of the
item later. */
pxNewListItem->pxContainer = pxList;
( pxList->uxNumberOfItems )++;
}
/*-----------------------------------------------------------*/
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{
/* The list item knows which list it is in. Obtain the list from the list
item. */
List_t * const pxList = pxItemToRemove->pxContainer;
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
/* Only used during decision coverage testing. */
mtCOVERAGE_TEST_DELAY();
/* Make sure the index is left pointing to a valid item. */
if( pxList->pxIndex == pxItemToRemove )
{
pxList->pxIndex = pxItemToRemove->pxPrevious;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
pxItemToRemove->pxContainer = NULL;
( pxList->uxNumberOfItems )--;
return pxList->uxNumberOfItems;
}
/*-----------------------------------------------------------*/
@@ -0,0 +1,242 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#ifdef __cplusplus
extern "C" {
#endif
/*-----------------------------------------------------------
* Port specific definitions.
*
* The settings in this file configure FreeRTOS correctly for the
* given hardware and compiler.
*
* These settings should not be altered.
*-----------------------------------------------------------
*/
/* Type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE uint32_t
#define portBASE_TYPE long
typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1
#endif
/*-----------------------------------------------------------*/
/* Architecture specifics. */
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 8
/*-----------------------------------------------------------*/
/* Scheduler utilities. */
#define portYIELD() \
{ \
/* Set a PendSV to request a context switch. */ \
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
\
/* Barriers are normally not required but do ensure the code is completely \
within the specified behaviour for the architecture. */ \
__asm volatile( "dsb" ::: "memory" ); \
__asm volatile( "isb" ); \
}
#define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/
/* Critical section management. */
extern void vPortEnterCritical( void );
extern void vPortExitCritical( void );
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x)
#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()
#define portENABLE_INTERRUPTS() vPortSetBASEPRI(0)
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are
not necessary for to use this port. They are defined so the common demo files
(which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/*-----------------------------------------------------------*/
/* Tickless idle/low power functionality. */
#ifndef portSUPPRESS_TICKS_AND_SLEEP
extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
#endif
/*-----------------------------------------------------------*/
/* Architecture specific optimisations. */
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Generic helper function. */
__attribute__( ( always_inline ) ) static inline uint8_t ucPortCountLeadingZeros( uint32_t ulBitmap )
{
uint8_t ucReturn;
__asm volatile ( "clz %0, %1" : "=r" ( ucReturn ) : "r" ( ulBitmap ) : "memory" );
return ucReturn;
}
/* Check the configuration. */
#if( configMAX_PRIORITIES > 32 )
#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.
#endif
/* Store/clear the ready priorities in a bit map. */
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
/*-----------------------------------------------------------*/
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( uint32_t ) ucPortCountLeadingZeros( ( uxReadyPriorities ) ) )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
/*-----------------------------------------------------------*/
#ifdef configASSERT
void vPortValidateInterruptPriority( void );
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
#endif
/* portNOP() is not required by this port. */
#define portNOP()
#define portINLINE __inline
#ifndef portFORCE_INLINE
#define portFORCE_INLINE inline __attribute__(( always_inline))
#endif
portFORCE_INLINE static BaseType_t xPortIsInsideInterrupt( void )
{
uint32_t ulCurrentInterrupt;
BaseType_t xReturn;
/* Obtain the number of the currently executing interrupt. */
__asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" );
if( ulCurrentInterrupt == 0 )
{
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
return xReturn;
}
/*-----------------------------------------------------------*/
portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;
__asm volatile
(
" mov %0, %1 \n" \
" msr basepri, %0 \n" \
" isb \n" \
" dsb \n" \
:"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
);
}
/*-----------------------------------------------------------*/
portFORCE_INLINE static uint32_t ulPortRaiseBASEPRI( void )
{
uint32_t ulOriginalBASEPRI, ulNewBASEPRI;
__asm volatile
(
" mrs %0, basepri \n" \
" mov %1, %2 \n" \
" msr basepri, %1 \n" \
" isb \n" \
" dsb \n" \
:"=r" (ulOriginalBASEPRI), "=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
);
/* This return will not be reached but is necessary to prevent compiler
warnings. */
return ulOriginalBASEPRI;
}
/*-----------------------------------------------------------*/
portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue )
{
__asm volatile
(
" msr basepri, %0 " :: "r" ( ulNewMaskValue ) : "memory"
);
}
/*-----------------------------------------------------------*/
#ifdef __cplusplus
}
#endif
#endif /* PORTMACRO_H */
@@ -0,0 +1,242 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#ifdef __cplusplus
extern "C" {
#endif
/*-----------------------------------------------------------
* Port specific definitions.
*
* The settings in this file configure FreeRTOS correctly for the
* given hardware and compiler.
*
* These settings should not be altered.
*-----------------------------------------------------------
*/
/* Type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE uint32_t
#define portBASE_TYPE long
typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1
#endif
/*-----------------------------------------------------------*/
/* Architecture specifics. */
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 8
/*-----------------------------------------------------------*/
/* Scheduler utilities. */
#define portYIELD() \
{ \
/* Set a PendSV to request a context switch. */ \
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
\
/* Barriers are normally not required but do ensure the code is completely \
within the specified behaviour for the architecture. */ \
__asm volatile( "dsb" ::: "memory" ); \
__asm volatile( "isb" ); \
}
#define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/
/* Critical section management. */
extern void vPortEnterCritical( void );
extern void vPortExitCritical( void );
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x)
#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()
#define portENABLE_INTERRUPTS() vPortSetBASEPRI(0)
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are
not necessary for to use this port. They are defined so the common demo files
(which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/*-----------------------------------------------------------*/
/* Tickless idle/low power functionality. */
#ifndef portSUPPRESS_TICKS_AND_SLEEP
extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
#endif
/*-----------------------------------------------------------*/
/* Architecture specific optimisations. */
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Generic helper function. */
__attribute__( ( always_inline ) ) static inline uint8_t ucPortCountLeadingZeros( uint32_t ulBitmap )
{
uint8_t ucReturn;
__asm volatile ( "clz %0, %1" : "=r" ( ucReturn ) : "r" ( ulBitmap ) : "memory" );
return ucReturn;
}
/* Check the configuration. */
#if( configMAX_PRIORITIES > 32 )
#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.
#endif
/* Store/clear the ready priorities in a bit map. */
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
/*-----------------------------------------------------------*/
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( uint32_t ) ucPortCountLeadingZeros( ( uxReadyPriorities ) ) )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
/*-----------------------------------------------------------*/
#ifdef configASSERT
void vPortValidateInterruptPriority( void );
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
#endif
/* portNOP() is not required by this port. */
#define portNOP()
#define portINLINE __inline
#ifndef portFORCE_INLINE
#define portFORCE_INLINE inline __attribute__(( always_inline))
#endif
portFORCE_INLINE static BaseType_t xPortIsInsideInterrupt( void )
{
uint32_t ulCurrentInterrupt;
BaseType_t xReturn;
/* Obtain the number of the currently executing interrupt. */
__asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" );
if( ulCurrentInterrupt == 0 )
{
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
return xReturn;
}
/*-----------------------------------------------------------*/
portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;
__asm volatile
(
" mov %0, %1 \n" \
" msr basepri, %0 \n" \
" isb \n" \
" dsb \n" \
:"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
);
}
/*-----------------------------------------------------------*/
portFORCE_INLINE static uint32_t ulPortRaiseBASEPRI( void )
{
uint32_t ulOriginalBASEPRI, ulNewBASEPRI;
__asm volatile
(
" mrs %0, basepri \n" \
" mov %1, %2 \n" \
" msr basepri, %1 \n" \
" isb \n" \
" dsb \n" \
:"=r" (ulOriginalBASEPRI), "=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
);
/* This return will not be reached but is necessary to prevent compiler
warnings. */
return ulOriginalBASEPRI;
}
/*-----------------------------------------------------------*/
portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue )
{
__asm volatile
(
" msr basepri, %0 " :: "r" ( ulNewMaskValue ) : "memory"
);
}
/*-----------------------------------------------------------*/
#ifdef __cplusplus
}
#endif
#endif /* PORTMACRO_H */
@@ -0,0 +1,775 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/*-----------------------------------------------------------
* Implementation of functions defined in portable.h for the ARM CM4F port.
*----------------------------------------------------------*/
/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#ifndef __VFP_FP__
#error This port can only be used when the project options are configured to enable hardware floating point support.
#endif
#ifndef configSYSTICK_CLOCK_HZ
#define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ
/* Ensure the SysTick is clocked at the same frequency as the core. */
#define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL )
#else
/* The way the SysTick is clocked is not modified in case it is not the same
as the core. */
#define portNVIC_SYSTICK_CLK_BIT ( 0 )
#endif
/* Constants required to manipulate the core. Registers first... */
#define portNVIC_SYSTICK_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000e010 ) )
#define portNVIC_SYSTICK_LOAD_REG ( * ( ( volatile uint32_t * ) 0xe000e014 ) )
#define portNVIC_SYSTICK_CURRENT_VALUE_REG ( * ( ( volatile uint32_t * ) 0xe000e018 ) )
#define portNVIC_SYSPRI2_REG ( * ( ( volatile uint32_t * ) 0xe000ed20 ) )
/* ...then bits in the registers. */
#define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL )
#define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL )
#define portNVIC_SYSTICK_COUNT_FLAG_BIT ( 1UL << 16UL )
#define portNVIC_PENDSVCLEAR_BIT ( 1UL << 27UL )
#define portNVIC_PEND_SYSTICK_CLEAR_BIT ( 1UL << 25UL )
/* Constants used to detect a Cortex-M7 r0p1 core, which should use the ARM_CM7
r0p1 port. */
#define portCPUID ( * ( ( volatile uint32_t * ) 0xE000ed00 ) )
#define portCORTEX_M7_r0p1_ID ( 0x410FC271UL )
#define portCORTEX_M7_r0p0_ID ( 0x410FC270UL )
#define portNVIC_PENDSV_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )
#define portNVIC_SYSTICK_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )
/* Constants required to check the validity of an interrupt priority. */
#define portFIRST_USER_INTERRUPT_NUMBER ( 16 )
#define portNVIC_IP_REGISTERS_OFFSET_16 ( 0xE000E3F0 )
#define portAIRCR_REG ( * ( ( volatile uint32_t * ) 0xE000ED0C ) )
#define portMAX_8_BIT_VALUE ( ( uint8_t ) 0xff )
#define portTOP_BIT_OF_BYTE ( ( uint8_t ) 0x80 )
#define portMAX_PRIGROUP_BITS ( ( uint8_t ) 7 )
#define portPRIORITY_GROUP_MASK ( 0x07UL << 8UL )
#define portPRIGROUP_SHIFT ( 8UL )
/* Masks off all bits but the VECTACTIVE bits in the ICSR register. */
#define portVECTACTIVE_MASK ( 0xFFUL )
/* Constants required to manipulate the VFP. */
#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating point context control register. */
#define portASPEN_AND_LSPEN_BITS ( 0x3UL << 30UL )
/* Constants required to set up the initial stack. */
#define portINITIAL_XPSR ( 0x01000000 )
#define portINITIAL_EXC_RETURN ( 0xfffffffd )
/* The systick is a 24-bit counter. */
#define portMAX_24_BIT_NUMBER ( 0xffffffUL )
/* For strict compliance with the Cortex-M spec the task start address should
have bit-0 clear, as it is loaded into the PC on exit from an ISR. */
#define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL )
/* A fiddle factor to estimate the number of SysTick counts that would have
occurred while the SysTick counter is stopped during tickless idle
calculations. */
#define portMISSED_COUNTS_FACTOR ( 45UL )
/* Let the user override the pre-loading of the initial LR with the address of
prvTaskExitError() in case it messes up unwinding of the stack in the
debugger. */
#ifdef configTASK_RETURN_ADDRESS
#define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS
#else
#define portTASK_RETURN_ADDRESS prvTaskExitError
#endif
/*
* Setup the timer to generate the tick interrupts. The implementation in this
* file is weak to allow application writers to change the timer used to
* generate the tick interrupt.
*/
void vPortSetupTimerInterrupt( void );
/*
* Exception handlers.
*/
void xPortPendSVHandler( void ) __attribute__ (( naked ));
void xPortSysTickHandler( void );
void vPortSVCHandler( void ) __attribute__ (( naked ));
/*
* Start first task is a separate function so it can be tested in isolation.
*/
static void prvPortStartFirstTask( void ) __attribute__ (( naked ));
/*
* Function to enable the VFP.
*/
static void vPortEnableVFP( void ) __attribute__ (( naked ));
/*
* Used to catch tasks that attempt to return from their implementing function.
*/
static void prvTaskExitError( void );
/*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/*
* The number of SysTick increments that make up one tick period.
*/
#if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulTimerCountsForOneTick = 0;
#endif /* configUSE_TICKLESS_IDLE */
/*
* The maximum number of tick periods that can be suppressed is limited by the
* 24 bit resolution of the SysTick timer.
*/
#if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t xMaximumPossibleSuppressedTicks = 0;
#endif /* configUSE_TICKLESS_IDLE */
/*
* Compensate for the CPU cycles that pass while the SysTick is stopped (low
* power functionality only.
*/
#if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulStoppedTimerCompensation = 0;
#endif /* configUSE_TICKLESS_IDLE */
/*
* Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure
* FreeRTOS API functions are not called from interrupts that have been assigned
* a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.
*/
#if( configASSERT_DEFINED == 1 )
static uint8_t ucMaxSysCallPriority = 0;
static uint32_t ulMaxPRIGROUPValue = 0;
static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16;
#endif /* configASSERT_DEFINED */
/*-----------------------------------------------------------*/
/*
* See header file for description.
*/
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
/* Simulate the stack frame as it would be created by a context switch
interrupt. */
/* Offset added to account for the way the MCU uses the stack on entry/exit
of interrupts, and to ensure alignment. */
pxTopOfStack--;
*pxTopOfStack = portINITIAL_XPSR; /* xPSR */
pxTopOfStack--;
*pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR */
/* Save code space by skipping register initialisation. */
pxTopOfStack -= 5; /* R12, R3, R2 and R1. */
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
/* A save method is being used that requires each task to maintain its
own exec return value. */
pxTopOfStack--;
*pxTopOfStack = portINITIAL_EXC_RETURN;
pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */
return pxTopOfStack;
}
/*-----------------------------------------------------------*/
static void prvTaskExitError( void )
{
volatile uint32_t ulDummy = 0;
/* A function that implements a task must not exit or attempt to return to
its caller as there is nothing to return to. If a task wants to exit it
should instead call vTaskDelete( NULL ).
Artificially force an assert() to be triggered if configASSERT() is
defined, then stop here so application writers can catch the error. */
configASSERT( uxCriticalNesting == ~0UL );
portDISABLE_INTERRUPTS();
while( ulDummy == 0 )
{
/* This file calls prvTaskExitError() after the scheduler has been
started to remove a compiler warning about the function being defined
but never called. ulDummy is used purely to quieten other warnings
about code appearing after this function is called - making ulDummy
volatile makes the compiler think the function could return and
therefore not output an 'unreachable code' warning for code that appears
after it. */
}
}
/*-----------------------------------------------------------*/
void vPortSVCHandler( void )
{
__asm volatile (
" ldr r3, pxCurrentTCBConst2 \n" /* Restore the context. */
" ldr r1, [r3] \n" /* Use pxCurrentTCBConst to get the pxCurrentTCB address. */
" ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. */
" ldmia r0!, {r4-r11, r14} \n" /* Pop the registers that are not automatically saved on exception entry and the critical nesting count. */
" msr psp, r0 \n" /* Restore the task stack pointer. */
" isb \n"
" mov r0, #0 \n"
" msr basepri, r0 \n"
" bx r14 \n"
" \n"
" .align 4 \n"
"pxCurrentTCBConst2: .word pxCurrentTCB \n"
);
}
/*-----------------------------------------------------------*/
static void prvPortStartFirstTask( void )
{
/* Start the first task. This also clears the bit that indicates the FPU is
in use in case the FPU was used before the scheduler was started - which
would otherwise result in the unnecessary leaving of space in the SVC stack
for lazy saving of FPU registers. */
__asm volatile(
" ldr r0, =0xE000ED08 \n" /* Use the NVIC offset register to locate the stack. */
" ldr r0, [r0] \n"
" ldr r0, [r0] \n"
" msr msp, r0 \n" /* Set the msp back to the start of the stack. */
" mov r0, #0 \n" /* Clear the bit that indicates the FPU is in use, see comment above. */
" msr control, r0 \n"
" cpsie i \n" /* Globally enable interrupts. */
" cpsie f \n"
" dsb \n"
" isb \n"
" svc 0 \n" /* System call to start first task. */
" nop \n"
);
}
/*-----------------------------------------------------------*/
/*
* See header file for description.
*/
BaseType_t xPortStartScheduler( void )
{
/* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0.
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY );
/* This port can be used on all revisions of the Cortex-M7 core other than
the r0p1 parts. r0p1 parts should use the port from the
/source/portable/GCC/ARM_CM7/r0p1 directory. */
configASSERT( portCPUID != portCORTEX_M7_r0p1_ID );
configASSERT( portCPUID != portCORTEX_M7_r0p0_ID );
#if( configASSERT_DEFINED == 1 )
{
volatile uint32_t ulOriginalPriority;
volatile uint8_t * const pucFirstUserPriorityRegister = ( volatile uint8_t * const ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER );
volatile uint8_t ucMaxPriorityValue;
/* Determine the maximum priority from which ISR safe FreeRTOS API
functions can be called. ISR safe functions are those that end in
"FromISR". FreeRTOS maintains separate thread and ISR API functions to
ensure interrupt entry is as fast and simple as possible.
Save the interrupt priority value that is about to be clobbered. */
ulOriginalPriority = *pucFirstUserPriorityRegister;
/* Determine the number of priority bits available. First write to all
possible bits. */
*pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
/* Read the value back to see how many bits stuck. */
ucMaxPriorityValue = *pucFirstUserPriorityRegister;
/* Use the same mask on the maximum system call priority. */
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
/* Calculate the maximum acceptable priority group value for the number
of bits read back. */
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
{
ulMaxPRIGROUPValue--;
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
}
#ifdef __NVIC_PRIO_BITS
{
/* Check the CMSIS configuration that defines the number of
priority bits matches the number of priority bits actually queried
from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS );
}
#endif
#ifdef configPRIO_BITS
{
/* Check the FreeRTOS configuration that defines the number of
priority bits matches the number of priority bits actually queried
from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS );
}
#endif
/* Shift the priority group value back to its position within the AIRCR
register. */
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
/* Restore the clobbered interrupt priority register to its original
value. */
*pucFirstUserPriorityRegister = ulOriginalPriority;
}
#endif /* conifgASSERT_DEFINED */
/* Make PendSV and SysTick the lowest priority interrupts. */
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
/* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */
vPortSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */
uxCriticalNesting = 0;
/* Ensure the VFP is enabled - it should be anyway. */
vPortEnableVFP();
/* Lazy save always. */
*( portFPCCR ) |= portASPEN_AND_LSPEN_BITS;
/* Start the first task. */
prvPortStartFirstTask();
/* Should never get here as the tasks will now be executing! Call the task
exit error function to prevent compiler warnings about a static function
not being called in the case that the application writer overrides this
functionality by defining configTASK_RETURN_ADDRESS. Call
vTaskSwitchContext() so link time optimisation does not remove the
symbol. */
vTaskSwitchContext();
prvTaskExitError();
/* Should not get here! */
return 0;
}
/*-----------------------------------------------------------*/
void vPortEndScheduler( void )
{
/* Not implemented in ports where there is nothing to return to.
Artificially force an assert. */
configASSERT( uxCriticalNesting == 1000UL );
}
/*-----------------------------------------------------------*/
void vPortEnterCritical( void )
{
portDISABLE_INTERRUPTS();
uxCriticalNesting++;
/* This is not the interrupt safe version of the enter critical function so
assert() if it is being called from an interrupt context. Only API
functions that end in "FromISR" can be used in an interrupt. Only assert if
the critical nesting count is 1 to protect against recursive calls if the
assert function also uses a critical section. */
if( uxCriticalNesting == 1 )
{
configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
}
}
/*-----------------------------------------------------------*/
void vPortExitCritical( void )
{
configASSERT( uxCriticalNesting );
uxCriticalNesting--;
if( uxCriticalNesting == 0 )
{
portENABLE_INTERRUPTS();
}
}
/*-----------------------------------------------------------*/
void xPortPendSVHandler( void )
{
/* This is a naked function. */
__asm volatile
(
" mrs r0, psp \n"
" isb \n"
" \n"
" ldr r3, pxCurrentTCBConst \n" /* Get the location of the current TCB. */
" ldr r2, [r3] \n"
" \n"
" tst r14, #0x10 \n" /* Is the task using the FPU context? If so, push high vfp registers. */
" it eq \n"
" vstmdbeq r0!, {s16-s31} \n"
" \n"
" stmdb r0!, {r4-r11, r14} \n" /* Save the core registers. */
" str r0, [r2] \n" /* Save the new top of stack into the first member of the TCB. */
" \n"
" stmdb sp!, {r0, r3} \n"
" mov r0, %0 \n"
" msr basepri, r0 \n"
" dsb \n"
" isb \n"
" bl vTaskSwitchContext \n"
" mov r0, #0 \n"
" msr basepri, r0 \n"
" ldmia sp!, {r0, r3} \n"
" \n"
" ldr r1, [r3] \n" /* The first item in pxCurrentTCB is the task top of stack. */
" ldr r0, [r1] \n"
" \n"
" ldmia r0!, {r4-r11, r14} \n" /* Pop the core registers. */
" \n"
" tst r14, #0x10 \n" /* Is the task using the FPU context? If so, pop the high vfp registers too. */
" it eq \n"
" vldmiaeq r0!, {s16-s31} \n"
" \n"
" msr psp, r0 \n"
" isb \n"
" \n"
#ifdef WORKAROUND_PMU_CM001 /* XMC4000 specific errata workaround. */
#if WORKAROUND_PMU_CM001 == 1
" push { r14 } \n"
" pop { pc } \n"
#endif
#endif
" \n"
" bx r14 \n"
" \n"
" .align 4 \n"
"pxCurrentTCBConst: .word pxCurrentTCB \n"
::"i"(configMAX_SYSCALL_INTERRUPT_PRIORITY)
);
}
/*-----------------------------------------------------------*/
void xPortSysTickHandler( void )
{
/* The SysTick runs at the lowest interrupt priority, so when this interrupt
executes all interrupts must be unmasked. There is therefore no need to
save and then restore the interrupt mask value as its value is already
known. */
portDISABLE_INTERRUPTS();
{
/* Increment the RTOS tick. */
if( xTaskIncrementTick() != pdFALSE )
{
/* A context switch is required. Context switching is performed in
the PendSV interrupt. Pend the PendSV interrupt. */
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
}
}
portENABLE_INTERRUPTS();
}
/*-----------------------------------------------------------*/
#if( configUSE_TICKLESS_IDLE == 1 )
__attribute__((weak)) void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{
uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
TickType_t xModifiableIdleTime;
/* Make sure the SysTick reload value does not overflow the counter. */
if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )
{
xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
}
/* Stop the SysTick momentarily. The time the SysTick is stopped for
is accounted for as best it can be, but using the tickless mode will
inevitably result in some tiny drift of the time maintained by the
kernel with respect to calendar time. */
portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;
/* Calculate the reload value required to wait xExpectedIdleTime
tick periods. -1 is used because this code will execute part way
through one of the tick periods. */
ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
if( ulReloadValue > ulStoppedTimerCompensation )
{
ulReloadValue -= ulStoppedTimerCompensation;
}
/* Enter a critical section but don't use the taskENTER_CRITICAL()
method as that will mask interrupts that should exit sleep mode. */
__asm volatile( "cpsid i" ::: "memory" );
__asm volatile( "dsb" );
__asm volatile( "isb" );
/* If a context switch is pending or a task is waiting for the scheduler
to be unsuspended then abandon the low power entry. */
if( eTaskConfirmSleepModeStatus() == eAbortSleep )
{
/* Restart from whatever is left in the count register to complete
this tick period. */
portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;
/* Restart SysTick. */
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
/* Reset the reload register to the value required for normal tick
periods. */
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
/* Re-enable interrupts - see comments above the cpsid instruction()
above. */
__asm volatile( "cpsie i" ::: "memory" );
}
else
{
/* Set the new reload value. */
portNVIC_SYSTICK_LOAD_REG = ulReloadValue;
/* Clear the SysTick count flag and set the count value back to
zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Restart SysTick. */
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
/* Sleep until something happens. configPRE_SLEEP_PROCESSING() can
set its parameter to 0 to indicate that its implementation contains
its own wait for interrupt or wait for event instruction, and so wfi
should not be executed again. However, the original expected idle
time variable must remain unmodified, so a copy is taken. */
xModifiableIdleTime = xExpectedIdleTime;
configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
if( xModifiableIdleTime > 0 )
{
__asm volatile( "dsb" ::: "memory" );
__asm volatile( "wfi" );
__asm volatile( "isb" );
}
configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Re-enable interrupts to allow the interrupt that brought the MCU
out of sleep mode to execute immediately. see comments above
__disable_interrupt() call above. */
__asm volatile( "cpsie i" ::: "memory" );
__asm volatile( "dsb" );
__asm volatile( "isb" );
/* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar
time. */
__asm volatile( "cpsid i" ::: "memory" );
__asm volatile( "dsb" );
__asm volatile( "isb" );
/* Disable the SysTick clock without reading the
portNVIC_SYSTICK_CTRL_REG register to ensure the
portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set. Again,
the time the SysTick is stopped for is accounted for as best it can
be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar
time*/
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
/* Determine if the SysTick clock has already counted to zero and
been set back to the current reload value (the reload back being
correct for the entire expected idle time) or if the SysTick is yet
to count to zero (in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{
uint32_t ulCalculatedLoadValue;
/* The tick interrupt is already pending, and the SysTick count
reloaded with ulReloadValue. Reset the
portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick
period. */
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );
/* Don't allow a tiny value, or values that have somehow
underflowed because the post sleep hook did something
that took too long. */
if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
{
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );
}
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* As the pending tick will be processed as soon as this
function exits, the tick value maintained by the tick is stepped
forward by one less than the time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
}
else
{
/* Something other than the tick interrupt ended the sleep.
Work out how long the sleep lasted rounded to complete tick
periods (not the ulReload value which accounted for part
ticks). */
ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;
/* How many complete tick periods passed while the processor
was waiting? */
ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;
/* The reload value is set to whatever fraction of a single tick
period remains. */
portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;
}
/* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG
again, then set portNVIC_SYSTICK_LOAD_REG back to its standard
value. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods );
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
/* Exit with interrpts enabled. */
__asm volatile( "cpsie i" ::: "memory" );
}
}
#endif /* #if configUSE_TICKLESS_IDLE */
/*-----------------------------------------------------------*/
/*
* Setup the systick timer to generate the tick interrupts at the required
* frequency.
*/
__attribute__(( weak )) void vPortSetupTimerInterrupt( void )
{
/* Calculate the constants required to configure the tick interrupt. */
#if( configUSE_TICKLESS_IDLE == 1 )
{
ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ );
}
#endif /* configUSE_TICKLESS_IDLE */
/* Stop and clear the SysTick. */
portNVIC_SYSTICK_CTRL_REG = 0UL;
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Configure SysTick to interrupt at the requested rate. */
portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );
}
/*-----------------------------------------------------------*/
/* This is a naked function. */
static void vPortEnableVFP( void )
{
__asm volatile
(
" ldr.w r0, =0xE000ED88 \n" /* The FPU enable bits are in the CPACR. */
" ldr r1, [r0] \n"
" \n"
" orr r1, r1, #( 0xf << 20 ) \n" /* Enable CP10 and CP11 coprocessors, then save back. */
" str r1, [r0] \n"
" bx r14 "
);
}
/*-----------------------------------------------------------*/
#if( configASSERT_DEFINED == 1 )
void vPortValidateInterruptPriority( void )
{
uint32_t ulCurrentInterrupt;
uint8_t ucCurrentPriority;
/* Obtain the number of the currently executing interrupt. */
__asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" );
/* Is the interrupt number a user defined interrupt? */
if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )
{
/* Look up the interrupt's priority. */
ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
/* The following assertion will fail if a service routine (ISR) for
an interrupt that has been assigned a priority above
configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
function. ISR safe FreeRTOS API functions must *only* be called
from interrupts that have been assigned a priority at or below
configMAX_SYSCALL_INTERRUPT_PRIORITY.
Numerically low interrupt priority numbers represent logically high
interrupt priorities, therefore the priority of the interrupt must
be set to a value equal to or numerically *higher* than
configMAX_SYSCALL_INTERRUPT_PRIORITY.
Interrupts that use the FreeRTOS API must not be left at their
default priority of zero as that is the highest possible priority,
which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,
and therefore also guaranteed to be invalid.
FreeRTOS maintains separate thread and ISR API functions to ensure
interrupt entry is as fast and simple as possible.
The following links provide detailed information:
http://www.freertos.org/RTOS-Cortex-M3-M4.html
http://www.freertos.org/FAQHelp.html */
configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );
}
/* Priority grouping: The interrupt controller (NVIC) allows the bits
that define each interrupt's priority to be split between bits that
define the interrupt's pre-emption priority bits and bits that define
the interrupt's sub-priority. For simplicity all bits must be defined
to be pre-emption priority bits. The following assertion will fail if
this is not the case (if some bits represent a sub-priority).
If the application only uses CMSIS libraries for interrupt
configuration then the correct setting can be achieved on all Cortex-M
devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the
scheduler. Note however that some vendor specific peripheral libraries
assume a non-zero priority group setting, in which cases using a value
of zero will result in unpredictable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
}
#endif /* configASSERT_DEFINED */
@@ -0,0 +1,242 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#ifdef __cplusplus
extern "C" {
#endif
/*-----------------------------------------------------------
* Port specific definitions.
*
* The settings in this file configure FreeRTOS correctly for the
* given hardware and compiler.
*
* These settings should not be altered.
*-----------------------------------------------------------
*/
/* Type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE uint32_t
#define portBASE_TYPE long
typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1
#endif
/*-----------------------------------------------------------*/
/* Architecture specifics. */
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 8
/*-----------------------------------------------------------*/
/* Scheduler utilities. */
#define portYIELD() \
{ \
/* Set a PendSV to request a context switch. */ \
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
\
/* Barriers are normally not required but do ensure the code is completely \
within the specified behaviour for the architecture. */ \
__asm volatile( "dsb" ::: "memory" ); \
__asm volatile( "isb" ); \
}
#define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/
/* Critical section management. */
extern void vPortEnterCritical( void );
extern void vPortExitCritical( void );
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x)
#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()
#define portENABLE_INTERRUPTS() vPortSetBASEPRI(0)
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are
not necessary for to use this port. They are defined so the common demo files
(which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/*-----------------------------------------------------------*/
/* Tickless idle/low power functionality. */
#ifndef portSUPPRESS_TICKS_AND_SLEEP
extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
#endif
/*-----------------------------------------------------------*/
/* Architecture specific optimisations. */
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Generic helper function. */
__attribute__( ( always_inline ) ) static inline uint8_t ucPortCountLeadingZeros( uint32_t ulBitmap )
{
uint8_t ucReturn;
__asm volatile ( "clz %0, %1" : "=r" ( ucReturn ) : "r" ( ulBitmap ) : "memory" );
return ucReturn;
}
/* Check the configuration. */
#if( configMAX_PRIORITIES > 32 )
#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.
#endif
/* Store/clear the ready priorities in a bit map. */
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
/*-----------------------------------------------------------*/
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( uint32_t ) ucPortCountLeadingZeros( ( uxReadyPriorities ) ) )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
/*-----------------------------------------------------------*/
#ifdef configASSERT
void vPortValidateInterruptPriority( void );
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
#endif
/* portNOP() is not required by this port. */
#define portNOP()
#define portINLINE __inline
#ifndef portFORCE_INLINE
#define portFORCE_INLINE inline __attribute__(( always_inline))
#endif
portFORCE_INLINE static BaseType_t xPortIsInsideInterrupt( void )
{
uint32_t ulCurrentInterrupt;
BaseType_t xReturn;
/* Obtain the number of the currently executing interrupt. */
__asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" );
if( ulCurrentInterrupt == 0 )
{
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
return xReturn;
}
/*-----------------------------------------------------------*/
portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;
__asm volatile
(
" mov %0, %1 \n" \
" msr basepri, %0 \n" \
" isb \n" \
" dsb \n" \
:"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
);
}
/*-----------------------------------------------------------*/
portFORCE_INLINE static uint32_t ulPortRaiseBASEPRI( void )
{
uint32_t ulOriginalBASEPRI, ulNewBASEPRI;
__asm volatile
(
" mrs %0, basepri \n" \
" mov %1, %2 \n" \
" msr basepri, %1 \n" \
" isb \n" \
" dsb \n" \
:"=r" (ulOriginalBASEPRI), "=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
);
/* This return will not be reached but is necessary to prevent compiler
warnings. */
return ulOriginalBASEPRI;
}
/*-----------------------------------------------------------*/
portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue )
{
__asm volatile
(
" msr basepri, %0 " :: "r" ( ulNewMaskValue ) : "memory"
);
}
/*-----------------------------------------------------------*/
#ifdef __cplusplus
}
#endif
#endif /* PORTMACRO_H */
@@ -0,0 +1,149 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#include <FreeRTOSConfig.h>
RSEG CODE:CODE(2)
thumb
EXTERN pxCurrentTCB
EXTERN vTaskSwitchContext
PUBLIC xPortPendSVHandler
PUBLIC vPortSVCHandler
PUBLIC vPortStartFirstTask
PUBLIC vPortEnableVFP
/*-----------------------------------------------------------*/
xPortPendSVHandler:
mrs r0, psp
isb
/* Get the location of the current TCB. */
ldr r3, =pxCurrentTCB
ldr r2, [r3]
/* Is the task using the FPU context? If so, push high vfp registers. */
tst r14, #0x10
it eq
vstmdbeq r0!, {s16-s31}
/* Save the core registers. */
stmdb r0!, {r4-r11, r14}
/* Save the new top of stack into the first member of the TCB. */
str r0, [r2]
stmdb sp!, {r0, r3}
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr basepri, r0
dsb
isb
bl vTaskSwitchContext
mov r0, #0
msr basepri, r0
ldmia sp!, {r0, r3}
/* The first item in pxCurrentTCB is the task top of stack. */
ldr r1, [r3]
ldr r0, [r1]
/* Pop the core registers. */
ldmia r0!, {r4-r11, r14}
/* Is the task using the FPU context? If so, pop the high vfp registers
too. */
tst r14, #0x10
it eq
vldmiaeq r0!, {s16-s31}
msr psp, r0
isb
#ifdef WORKAROUND_PMU_CM001 /* XMC4000 specific errata */
#if WORKAROUND_PMU_CM001 == 1
push { r14 }
pop { pc }
#endif
#endif
bx r14
/*-----------------------------------------------------------*/
vPortSVCHandler:
/* Get the location of the current TCB. */
ldr r3, =pxCurrentTCB
ldr r1, [r3]
ldr r0, [r1]
/* Pop the core registers. */
ldmia r0!, {r4-r11, r14}
msr psp, r0
isb
mov r0, #0
msr basepri, r0
bx r14
/*-----------------------------------------------------------*/
vPortStartFirstTask
/* Use the NVIC offset register to locate the stack. */
ldr r0, =0xE000ED08
ldr r0, [r0]
ldr r0, [r0]
/* Set the msp back to the start of the stack. */
msr msp, r0
/* Clear the bit that indicates the FPU is in use in case the FPU was used
before the scheduler was started - which would otherwise result in the
unnecessary leaving of space in the SVC stack for lazy saving of FPU
registers. */
mov r0, #0
msr control, r0
/* Call SVC to start the first task. */
cpsie i
cpsie f
dsb
isb
svc 0
/*-----------------------------------------------------------*/
vPortEnableVFP:
/* The FPU enable bits are in the CPACR. */
ldr.w r0, =0xE000ED88
ldr r1, [r0]
/* Enable CP10 and CP11 coprocessors, then save back. */
orr r1, r1, #( 0xf << 20 )
str r1, [r0]
bx r14
END
@@ -0,0 +1,195 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __IAR_SYSTEMS_ICC__
#include <intrinsics.h> // __DSB(), __ISB() and other intrinsics
#endif
/*-----------------------------------------------------------
* Port specific definitions.
*
* The settings in this file configure FreeRTOS correctly for the
* given hardware and compiler.
*
* These settings should not be altered.
*-----------------------------------------------------------
*/
/* Type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE uint32_t
#define portBASE_TYPE long
typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1
#endif
/*-----------------------------------------------------------*/
/* Architecture specifics. */
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 8
/*-----------------------------------------------------------*/
/* Scheduler utilities. */
#define portYIELD() \
{ \
/* Set a PendSV to request a context switch. */ \
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
__DSB(); \
__ISB(); \
}
#define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/
/* Architecture specific optimisations. */
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif
#if( configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 )
/* Check the configuration. */
#if( configMAX_PRIORITIES > 32 )
#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.
#endif
/* Store/clear the ready priorities in a bit map. */
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
/*-----------------------------------------------------------*/
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( ( uint32_t ) __CLZ( ( uxReadyPriorities ) ) ) )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
/*-----------------------------------------------------------*/
/* Critical section management. */
extern void vPortEnterCritical( void );
extern void vPortExitCritical( void );
#define portDISABLE_INTERRUPTS() \
{ \
__set_BASEPRI( configMAX_SYSCALL_INTERRUPT_PRIORITY ); \
__DSB(); \
__ISB(); \
}
#define portENABLE_INTERRUPTS() __set_BASEPRI( 0 )
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
#define portSET_INTERRUPT_MASK_FROM_ISR() __get_BASEPRI(); portDISABLE_INTERRUPTS()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) __set_BASEPRI( x )
/*-----------------------------------------------------------*/
/* Tickless idle/low power functionality. */
#ifndef portSUPPRESS_TICKS_AND_SLEEP
extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
#endif
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are
not necessary for to use this port. They are defined so the common demo files
(which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/*-----------------------------------------------------------*/
#ifdef configASSERT
void vPortValidateInterruptPriority( void );
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
#endif
/* portNOP() is not required by this port. */
#define portNOP()
static BaseType_t xPortIsInsideInterrupt( void )
{
uint32_t ulCurrentInterrupt;
BaseType_t xReturn;
/* Obtain the number of the currently executing interrupt. */
__asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) );
if( ulCurrentInterrupt == 0 )
{
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
return xReturn;
}
/*-----------------------------------------------------------*/
/* Suppress warnings that are generated by the IAR tools, but cannot be fixed in
the source code because to do so would cause other compilers to generate
warnings. */
#pragma diag_suppress=Pe191
#pragma diag_suppress=Pa082
#ifdef __cplusplus
}
#endif
#endif /* PORTMACRO_H */
@@ -0,0 +1,149 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#include <FreeRTOSConfig.h>
RSEG CODE:CODE(2)
thumb
EXTERN pxCurrentTCB
EXTERN vTaskSwitchContext
PUBLIC xPortPendSVHandler
PUBLIC vPortSVCHandler
PUBLIC vPortStartFirstTask
PUBLIC vPortEnableVFP
/*-----------------------------------------------------------*/
xPortPendSVHandler:
mrs r0, psp
isb
/* Get the location of the current TCB. */
ldr r3, =pxCurrentTCB
ldr r2, [r3]
/* Is the task using the FPU context? If so, push high vfp registers. */
tst r14, #0x10
it eq
vstmdbeq r0!, {s16-s31}
/* Save the core registers. */
stmdb r0!, {r4-r11, r14}
/* Save the new top of stack into the first member of the TCB. */
str r0, [r2]
stmdb sp!, {r0, r3}
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr basepri, r0
dsb
isb
bl vTaskSwitchContext
mov r0, #0
msr basepri, r0
ldmia sp!, {r0, r3}
/* The first item in pxCurrentTCB is the task top of stack. */
ldr r1, [r3]
ldr r0, [r1]
/* Pop the core registers. */
ldmia r0!, {r4-r11, r14}
/* Is the task using the FPU context? If so, pop the high vfp registers
too. */
tst r14, #0x10
it eq
vldmiaeq r0!, {s16-s31}
msr psp, r0
isb
#ifdef WORKAROUND_PMU_CM001 /* XMC4000 specific errata */
#if WORKAROUND_PMU_CM001 == 1
push { r14 }
pop { pc }
#endif
#endif
bx r14
/*-----------------------------------------------------------*/
vPortSVCHandler:
/* Get the location of the current TCB. */
ldr r3, =pxCurrentTCB
ldr r1, [r3]
ldr r0, [r1]
/* Pop the core registers. */
ldmia r0!, {r4-r11, r14}
msr psp, r0
isb
mov r0, #0
msr basepri, r0
bx r14
/*-----------------------------------------------------------*/
vPortStartFirstTask
/* Use the NVIC offset register to locate the stack. */
ldr r0, =0xE000ED08
ldr r0, [r0]
ldr r0, [r0]
/* Set the msp back to the start of the stack. */
msr msp, r0
/* Clear the bit that indicates the FPU is in use in case the FPU was used
before the scheduler was started - which would otherwise result in the
unnecessary leaving of space in the SVC stack for lazy saving of FPU
registers. */
mov r0, #0
msr control, r0
/* Call SVC to start the first task. */
cpsie i
cpsie f
dsb
isb
svc 0
/*-----------------------------------------------------------*/
vPortEnableVFP:
/* The FPU enable bits are in the CPACR. */
ldr.w r0, =0xE000ED88
ldr r1, [r0]
/* Enable CP10 and CP11 coprocessors, then save back. */
orr r1, r1, #( 0xf << 20 )
str r1, [r0]
bx r14
END
@@ -0,0 +1,195 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __IAR_SYSTEMS_ICC__
#include <intrinsics.h> // __DSB(), __ISB() and other intrinsics
#endif
/*-----------------------------------------------------------
* Port specific definitions.
*
* The settings in this file configure FreeRTOS correctly for the
* given hardware and compiler.
*
* These settings should not be altered.
*-----------------------------------------------------------
*/
/* Type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE uint32_t
#define portBASE_TYPE long
typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1
#endif
/*-----------------------------------------------------------*/
/* Architecture specifics. */
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 8
/*-----------------------------------------------------------*/
/* Scheduler utilities. */
#define portYIELD() \
{ \
/* Set a PendSV to request a context switch. */ \
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
__DSB(); \
__ISB(); \
}
#define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/
/* Architecture specific optimisations. */
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif
#if( configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 )
/* Check the configuration. */
#if( configMAX_PRIORITIES > 32 )
#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.
#endif
/* Store/clear the ready priorities in a bit map. */
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
/*-----------------------------------------------------------*/
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( ( uint32_t ) __CLZ( ( uxReadyPriorities ) ) ) )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
/*-----------------------------------------------------------*/
/* Critical section management. */
extern void vPortEnterCritical( void );
extern void vPortExitCritical( void );
#define portDISABLE_INTERRUPTS() \
{ \
__set_BASEPRI( configMAX_SYSCALL_INTERRUPT_PRIORITY ); \
__DSB(); \
__ISB(); \
}
#define portENABLE_INTERRUPTS() __set_BASEPRI( 0 )
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
#define portSET_INTERRUPT_MASK_FROM_ISR() __get_BASEPRI(); portDISABLE_INTERRUPTS()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) __set_BASEPRI( x )
/*-----------------------------------------------------------*/
/* Tickless idle/low power functionality. */
#ifndef portSUPPRESS_TICKS_AND_SLEEP
extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
#endif
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are
not necessary for to use this port. They are defined so the common demo files
(which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/*-----------------------------------------------------------*/
#ifdef configASSERT
void vPortValidateInterruptPriority( void );
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
#endif
/* portNOP() is not required by this port. */
#define portNOP()
static BaseType_t xPortIsInsideInterrupt( void )
{
uint32_t ulCurrentInterrupt;
BaseType_t xReturn;
/* Obtain the number of the currently executing interrupt. */
__asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) );
if( ulCurrentInterrupt == 0 )
{
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
return xReturn;
}
/*-----------------------------------------------------------*/
/* Suppress warnings that are generated by the IAR tools, but cannot be fixed in
the source code because to do so would cause other compilers to generate
warnings. */
#pragma diag_suppress=Pe191
#pragma diag_suppress=Pa082
#ifdef __cplusplus
}
#endif
#endif /* PORTMACRO_H */
@@ -0,0 +1,656 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/*-----------------------------------------------------------
* Implementation of functions defined in portable.h for the ARM CM4F port.
*----------------------------------------------------------*/
/* IAR includes. */
#include <intrinsics.h>
/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#ifndef __ARMVFP__
#error This port can only be used when the project options are configured to enable hardware floating point support.
#endif
#if( configMAX_SYSCALL_INTERRUPT_PRIORITY == 0 )
#error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html
#endif
#ifndef configSYSTICK_CLOCK_HZ
#define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ
/* Ensure the SysTick is clocked at the same frequency as the core. */
#define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL )
#else
/* The way the SysTick is clocked is not modified in case it is not the same
as the core. */
#define portNVIC_SYSTICK_CLK_BIT ( 0 )
#endif
/* Constants required to manipulate the core. Registers first... */
#define portNVIC_SYSTICK_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000e010 ) )
#define portNVIC_SYSTICK_LOAD_REG ( * ( ( volatile uint32_t * ) 0xe000e014 ) )
#define portNVIC_SYSTICK_CURRENT_VALUE_REG ( * ( ( volatile uint32_t * ) 0xe000e018 ) )
#define portNVIC_SYSPRI2_REG ( * ( ( volatile uint32_t * ) 0xe000ed20 ) )
/* ...then bits in the registers. */
#define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL )
#define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL )
#define portNVIC_SYSTICK_COUNT_FLAG_BIT ( 1UL << 16UL )
#define portNVIC_PENDSVCLEAR_BIT ( 1UL << 27UL )
#define portNVIC_PEND_SYSTICK_CLEAR_BIT ( 1UL << 25UL )
/* Constants used to detect a Cortex-M7 r0p1 core, which should use the ARM_CM7
r0p1 port. */
#define portCPUID ( * ( ( volatile uint32_t * ) 0xE000ed00 ) )
#define portCORTEX_M7_r0p1_ID ( 0x410FC271UL )
#define portCORTEX_M7_r0p0_ID ( 0x410FC270UL )
#define portNVIC_PENDSV_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )
#define portNVIC_SYSTICK_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )
/* Constants required to check the validity of an interrupt priority. */
#define portFIRST_USER_INTERRUPT_NUMBER ( 16 )
#define portNVIC_IP_REGISTERS_OFFSET_16 ( 0xE000E3F0 )
#define portAIRCR_REG ( * ( ( volatile uint32_t * ) 0xE000ED0C ) )
#define portMAX_8_BIT_VALUE ( ( uint8_t ) 0xff )
#define portTOP_BIT_OF_BYTE ( ( uint8_t ) 0x80 )
#define portMAX_PRIGROUP_BITS ( ( uint8_t ) 7 )
#define portPRIORITY_GROUP_MASK ( 0x07UL << 8UL )
#define portPRIGROUP_SHIFT ( 8UL )
/* Masks off all bits but the VECTACTIVE bits in the ICSR register. */
#define portVECTACTIVE_MASK ( 0xFFUL )
/* Constants required to manipulate the VFP. */
#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating point context control register. */
#define portASPEN_AND_LSPEN_BITS ( 0x3UL << 30UL )
/* Constants required to set up the initial stack. */
#define portINITIAL_XPSR ( 0x01000000 )
#define portINITIAL_EXC_RETURN ( 0xfffffffd )
/* The systick is a 24-bit counter. */
#define portMAX_24_BIT_NUMBER ( 0xffffffUL )
/* A fiddle factor to estimate the number of SysTick counts that would have
occurred while the SysTick counter is stopped during tickless idle
calculations. */
#define portMISSED_COUNTS_FACTOR ( 45UL )
/* For strict compliance with the Cortex-M spec the task start address should
have bit-0 clear, as it is loaded into the PC on exit from an ISR. */
#define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL )
/*
* Setup the timer to generate the tick interrupts. The implementation in this
* file is weak to allow application writers to change the timer used to
* generate the tick interrupt.
*/
void vPortSetupTimerInterrupt( void );
/*
* Exception handlers.
*/
void xPortSysTickHandler( void );
/*
* Start first task is a separate function so it can be tested in isolation.
*/
extern void vPortStartFirstTask( void );
/*
* Turn the VFP on.
*/
extern void vPortEnableVFP( void );
/*
* Used to catch tasks that attempt to return from their implementing function.
*/
static void prvTaskExitError( void );
/*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/*
* The number of SysTick increments that make up one tick period.
*/
#if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulTimerCountsForOneTick = 0;
#endif /* configUSE_TICKLESS_IDLE */
/*
* The maximum number of tick periods that can be suppressed is limited by the
* 24 bit resolution of the SysTick timer.
*/
#if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t xMaximumPossibleSuppressedTicks = 0;
#endif /* configUSE_TICKLESS_IDLE */
/*
* Compensate for the CPU cycles that pass while the SysTick is stopped (low
* power functionality only.
*/
#if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulStoppedTimerCompensation = 0;
#endif /* configUSE_TICKLESS_IDLE */
/*
* Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure
* FreeRTOS API functions are not called from interrupts that have been assigned
* a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.
*/
#if( configASSERT_DEFINED == 1 )
static uint8_t ucMaxSysCallPriority = 0;
static uint32_t ulMaxPRIGROUPValue = 0;
static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16;
#endif /* configASSERT_DEFINED */
/*-----------------------------------------------------------*/
/*
* See header file for description.
*/
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
/* Simulate the stack frame as it would be created by a context switch
interrupt. */
/* Offset added to account for the way the MCU uses the stack on entry/exit
of interrupts, and to ensure alignment. */
pxTopOfStack--;
*pxTopOfStack = portINITIAL_XPSR; /* xPSR */
pxTopOfStack--;
*pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) prvTaskExitError; /* LR */
/* Save code space by skipping register initialisation. */
pxTopOfStack -= 5; /* R12, R3, R2 and R1. */
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
/* A save method is being used that requires each task to maintain its
own exec return value. */
pxTopOfStack--;
*pxTopOfStack = portINITIAL_EXC_RETURN;
pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */
return pxTopOfStack;
}
/*-----------------------------------------------------------*/
static void prvTaskExitError( void )
{
/* A function that implements a task must not exit or attempt to return to
its caller as there is nothing to return to. If a task wants to exit it
should instead call vTaskDelete( NULL ).
Artificially force an assert() to be triggered if configASSERT() is
defined, then stop here so application writers can catch the error. */
configASSERT( uxCriticalNesting == ~0UL );
portDISABLE_INTERRUPTS();
for( ;; );
}
/*-----------------------------------------------------------*/
/*
* See header file for description.
*/
BaseType_t xPortStartScheduler( void )
{
/* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0.
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY );
/* This port can be used on all revisions of the Cortex-M7 core other than
the r0p1 parts. r0p1 parts should use the port from the
/source/portable/GCC/ARM_CM7/r0p1 directory. */
configASSERT( portCPUID != portCORTEX_M7_r0p1_ID );
configASSERT( portCPUID != portCORTEX_M7_r0p0_ID );
#if( configASSERT_DEFINED == 1 )
{
volatile uint32_t ulOriginalPriority;
volatile uint8_t * const pucFirstUserPriorityRegister = ( volatile uint8_t * const ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER );
volatile uint8_t ucMaxPriorityValue;
/* Determine the maximum priority from which ISR safe FreeRTOS API
functions can be called. ISR safe functions are those that end in
"FromISR". FreeRTOS maintains separate thread and ISR API functions to
ensure interrupt entry is as fast and simple as possible.
Save the interrupt priority value that is about to be clobbered. */
ulOriginalPriority = *pucFirstUserPriorityRegister;
/* Determine the number of priority bits available. First write to all
possible bits. */
*pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
/* Read the value back to see how many bits stuck. */
ucMaxPriorityValue = *pucFirstUserPriorityRegister;
/* Use the same mask on the maximum system call priority. */
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
/* Calculate the maximum acceptable priority group value for the number
of bits read back. */
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
{
ulMaxPRIGROUPValue--;
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
}
#ifdef __NVIC_PRIO_BITS
{
/* Check the CMSIS configuration that defines the number of
priority bits matches the number of priority bits actually queried
from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS );
}
#endif
#ifdef configPRIO_BITS
{
/* Check the FreeRTOS configuration that defines the number of
priority bits matches the number of priority bits actually queried
from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS );
}
#endif
/* Shift the priority group value back to its position within the AIRCR
register. */
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
/* Restore the clobbered interrupt priority register to its original
value. */
*pucFirstUserPriorityRegister = ulOriginalPriority;
}
#endif /* conifgASSERT_DEFINED */
/* Make PendSV and SysTick the lowest priority interrupts. */
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
/* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */
vPortSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */
uxCriticalNesting = 0;
/* Ensure the VFP is enabled - it should be anyway. */
vPortEnableVFP();
/* Lazy save always. */
*( portFPCCR ) |= portASPEN_AND_LSPEN_BITS;
/* Start the first task. */
vPortStartFirstTask();
/* Should not get here! */
return 0;
}
/*-----------------------------------------------------------*/
void vPortEndScheduler( void )
{
/* Not implemented in ports where there is nothing to return to.
Artificially force an assert. */
configASSERT( uxCriticalNesting == 1000UL );
}
/*-----------------------------------------------------------*/
void vPortEnterCritical( void )
{
portDISABLE_INTERRUPTS();
uxCriticalNesting++;
/* This is not the interrupt safe version of the enter critical function so
assert() if it is being called from an interrupt context. Only API
functions that end in "FromISR" can be used in an interrupt. Only assert if
the critical nesting count is 1 to protect against recursive calls if the
assert function also uses a critical section. */
if( uxCriticalNesting == 1 )
{
configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
}
}
/*-----------------------------------------------------------*/
void vPortExitCritical( void )
{
configASSERT( uxCriticalNesting );
uxCriticalNesting--;
if( uxCriticalNesting == 0 )
{
portENABLE_INTERRUPTS();
}
}
/*-----------------------------------------------------------*/
void xPortSysTickHandler( void )
{
/* The SysTick runs at the lowest interrupt priority, so when this interrupt
executes all interrupts must be unmasked. There is therefore no need to
save and then restore the interrupt mask value as its value is already
known. */
portDISABLE_INTERRUPTS();
{
/* Increment the RTOS tick. */
if( xTaskIncrementTick() != pdFALSE )
{
/* A context switch is required. Context switching is performed in
the PendSV interrupt. Pend the PendSV interrupt. */
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
}
}
portENABLE_INTERRUPTS();
}
/*-----------------------------------------------------------*/
#if( configUSE_TICKLESS_IDLE == 1 )
__weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{
uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
TickType_t xModifiableIdleTime;
/* Make sure the SysTick reload value does not overflow the counter. */
if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )
{
xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
}
/* Stop the SysTick momentarily. The time the SysTick is stopped for
is accounted for as best it can be, but using the tickless mode will
inevitably result in some tiny drift of the time maintained by the
kernel with respect to calendar time. */
portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;
/* Calculate the reload value required to wait xExpectedIdleTime
tick periods. -1 is used because this code will execute part way
through one of the tick periods. */
ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
if( ulReloadValue > ulStoppedTimerCompensation )
{
ulReloadValue -= ulStoppedTimerCompensation;
}
/* Enter a critical section but don't use the taskENTER_CRITICAL()
method as that will mask interrupts that should exit sleep mode. */
__disable_interrupt();
__DSB();
__ISB();
/* If a context switch is pending or a task is waiting for the scheduler
to be unsuspended then abandon the low power entry. */
if( eTaskConfirmSleepModeStatus() == eAbortSleep )
{
/* Restart from whatever is left in the count register to complete
this tick period. */
portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;
/* Restart SysTick. */
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
/* Reset the reload register to the value required for normal tick
periods. */
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
/* Re-enable interrupts - see comments above __disable_interrupt()
call above. */
__enable_interrupt();
}
else
{
/* Set the new reload value. */
portNVIC_SYSTICK_LOAD_REG = ulReloadValue;
/* Clear the SysTick count flag and set the count value back to
zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Restart SysTick. */
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
/* Sleep until something happens. configPRE_SLEEP_PROCESSING() can
set its parameter to 0 to indicate that its implementation contains
its own wait for interrupt or wait for event instruction, and so wfi
should not be executed again. However, the original expected idle
time variable must remain unmodified, so a copy is taken. */
xModifiableIdleTime = xExpectedIdleTime;
configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
if( xModifiableIdleTime > 0 )
{
__DSB();
__WFI();
__ISB();
}
configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Re-enable interrupts to allow the interrupt that brought the MCU
out of sleep mode to execute immediately. see comments above
__disable_interrupt() call above. */
__enable_interrupt();
__DSB();
__ISB();
/* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar
time. */
__disable_interrupt();
__DSB();
__ISB();
/* Disable the SysTick clock without reading the
portNVIC_SYSTICK_CTRL_REG register to ensure the
portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set. Again,
the time the SysTick is stopped for is accounted for as best it can
be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar
time*/
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
/* Determine if the SysTick clock has already counted to zero and
been set back to the current reload value (the reload back being
correct for the entire expected idle time) or if the SysTick is yet
to count to zero (in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{
uint32_t ulCalculatedLoadValue;
/* The tick interrupt is already pending, and the SysTick count
reloaded with ulReloadValue. Reset the
portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick
period. */
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );
/* Don't allow a tiny value, or values that have somehow
underflowed because the post sleep hook did something
that took too long. */
if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
{
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );
}
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* As the pending tick will be processed as soon as this
function exits, the tick value maintained by the tick is stepped
forward by one less than the time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
}
else
{
/* Something other than the tick interrupt ended the sleep.
Work out how long the sleep lasted rounded to complete tick
periods (not the ulReload value which accounted for part
ticks). */
ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;
/* How many complete tick periods passed while the processor
was waiting? */
ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;
/* The reload value is set to whatever fraction of a single tick
period remains. */
portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;
}
/* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG
again, then set portNVIC_SYSTICK_LOAD_REG back to its standard
value. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods );
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
/* Exit with interrpts enabled. */
__enable_interrupt();
}
}
#endif /* configUSE_TICKLESS_IDLE */
/*-----------------------------------------------------------*/
/*
* Setup the systick timer to generate the tick interrupts at the required
* frequency.
*/
__weak void vPortSetupTimerInterrupt( void )
{
/* Calculate the constants required to configure the tick interrupt. */
#if( configUSE_TICKLESS_IDLE == 1 )
{
ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ );
}
#endif /* configUSE_TICKLESS_IDLE */
/* Stop and clear the SysTick. */
portNVIC_SYSTICK_CTRL_REG = 0UL;
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Configure SysTick to interrupt at the requested rate. */
portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );
}
/*-----------------------------------------------------------*/
#if( configASSERT_DEFINED == 1 )
void vPortValidateInterruptPriority( void )
{
uint32_t ulCurrentInterrupt;
uint8_t ucCurrentPriority;
/* Obtain the number of the currently executing interrupt. */
__asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" );
/* Is the interrupt number a user defined interrupt? */
if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )
{
/* Look up the interrupt's priority. */
ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
/* The following assertion will fail if a service routine (ISR) for
an interrupt that has been assigned a priority above
configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
function. ISR safe FreeRTOS API functions must *only* be called
from interrupts that have been assigned a priority at or below
configMAX_SYSCALL_INTERRUPT_PRIORITY.
Numerically low interrupt priority numbers represent logically high
interrupt priorities, therefore the priority of the interrupt must
be set to a value equal to or numerically *higher* than
configMAX_SYSCALL_INTERRUPT_PRIORITY.
Interrupts that use the FreeRTOS API must not be left at their
default priority of zero as that is the highest possible priority,
which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,
and therefore also guaranteed to be invalid.
FreeRTOS maintains separate thread and ISR API functions to ensure
interrupt entry is as fast and simple as possible.
The following links provide detailed information:
http://www.freertos.org/RTOS-Cortex-M3-M4.html
http://www.freertos.org/FAQHelp.html */
configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );
}
/* Priority grouping: The interrupt controller (NVIC) allows the bits
that define each interrupt's priority to be split between bits that
define the interrupt's pre-emption priority bits and bits that define
the interrupt's sub-priority. For simplicity all bits must be defined
to be pre-emption priority bits. The following assertion will fail if
this is not the case (if some bits represent a sub-priority).
If the application only uses CMSIS libraries for interrupt
configuration then the correct setting can be achieved on all Cortex-M
devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the
scheduler. Note however that some vendor specific peripheral libraries
assume a non-zero priority group setting, in which cases using a value
of zero will result in unpredictable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
}
#endif /* configASSERT_DEFINED */
@@ -0,0 +1,149 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#include <FreeRTOSConfig.h>
RSEG CODE:CODE(2)
thumb
EXTERN pxCurrentTCB
EXTERN vTaskSwitchContext
PUBLIC xPortPendSVHandler
PUBLIC vPortSVCHandler
PUBLIC vPortStartFirstTask
PUBLIC vPortEnableVFP
/*-----------------------------------------------------------*/
xPortPendSVHandler:
mrs r0, psp
isb
/* Get the location of the current TCB. */
ldr r3, =pxCurrentTCB
ldr r2, [r3]
/* Is the task using the FPU context? If so, push high vfp registers. */
tst r14, #0x10
it eq
vstmdbeq r0!, {s16-s31}
/* Save the core registers. */
stmdb r0!, {r4-r11, r14}
/* Save the new top of stack into the first member of the TCB. */
str r0, [r2]
stmdb sp!, {r0, r3}
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr basepri, r0
dsb
isb
bl vTaskSwitchContext
mov r0, #0
msr basepri, r0
ldmia sp!, {r0, r3}
/* The first item in pxCurrentTCB is the task top of stack. */
ldr r1, [r3]
ldr r0, [r1]
/* Pop the core registers. */
ldmia r0!, {r4-r11, r14}
/* Is the task using the FPU context? If so, pop the high vfp registers
too. */
tst r14, #0x10
it eq
vldmiaeq r0!, {s16-s31}
msr psp, r0
isb
#ifdef WORKAROUND_PMU_CM001 /* XMC4000 specific errata */
#if WORKAROUND_PMU_CM001 == 1
push { r14 }
pop { pc }
#endif
#endif
bx r14
/*-----------------------------------------------------------*/
vPortSVCHandler:
/* Get the location of the current TCB. */
ldr r3, =pxCurrentTCB
ldr r1, [r3]
ldr r0, [r1]
/* Pop the core registers. */
ldmia r0!, {r4-r11, r14}
msr psp, r0
isb
mov r0, #0
msr basepri, r0
bx r14
/*-----------------------------------------------------------*/
vPortStartFirstTask
/* Use the NVIC offset register to locate the stack. */
ldr r0, =0xE000ED08
ldr r0, [r0]
ldr r0, [r0]
/* Set the msp back to the start of the stack. */
msr msp, r0
/* Clear the bit that indicates the FPU is in use in case the FPU was used
before the scheduler was started - which would otherwise result in the
unnecessary leaving of space in the SVC stack for lazy saving of FPU
registers. */
mov r0, #0
msr control, r0
/* Call SVC to start the first task. */
cpsie i
cpsie f
dsb
isb
svc 0
/*-----------------------------------------------------------*/
vPortEnableVFP:
/* The FPU enable bits are in the CPACR. */
ldr.w r0, =0xE000ED88
ldr r1, [r0]
/* Enable CP10 and CP11 coprocessors, then save back. */
orr r1, r1, #( 0xf << 20 )
str r1, [r0]
bx r14
END
@@ -0,0 +1,173 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#ifdef __cplusplus
extern "C" {
#endif
/*-----------------------------------------------------------
* Port specific definitions.
*
* The settings in this file configure FreeRTOS correctly for the
* given hardware and compiler.
*
* These settings should not be altered.
*-----------------------------------------------------------
*/
/* IAR includes. */
#include <intrinsics.h>
/* Type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE uint32_t
#define portBASE_TYPE long
typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1
#endif
/*-----------------------------------------------------------*/
/* Architecture specifics. */
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 8
/*-----------------------------------------------------------*/
/* Scheduler utilities. */
#define portYIELD() \
{ \
/* Set a PendSV to request a context switch. */ \
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
__DSB(); \
__ISB(); \
}
#define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/
/* Architecture specific optimisations. */
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif
#if( configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 )
/* Check the configuration. */
#if( configMAX_PRIORITIES > 32 )
#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.
#endif
/* Store/clear the ready priorities in a bit map. */
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
/*-----------------------------------------------------------*/
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( ( uint32_t ) __CLZ( ( uxReadyPriorities ) ) ) )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
/*-----------------------------------------------------------*/
/* Critical section management. */
extern void vPortEnterCritical( void );
extern void vPortExitCritical( void );
#define portDISABLE_INTERRUPTS() \
{ \
__set_BASEPRI( configMAX_SYSCALL_INTERRUPT_PRIORITY ); \
__DSB(); \
__ISB(); \
}
#define portENABLE_INTERRUPTS() __set_BASEPRI( 0 )
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
#define portSET_INTERRUPT_MASK_FROM_ISR() __get_BASEPRI(); portDISABLE_INTERRUPTS()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) __set_BASEPRI( x )
/*-----------------------------------------------------------*/
/* Tickless idle/low power functionality. */
#ifndef portSUPPRESS_TICKS_AND_SLEEP
extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
#endif
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are
not necessary for to use this port. They are defined so the common demo files
(which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/*-----------------------------------------------------------*/
#ifdef configASSERT
void vPortValidateInterruptPriority( void );
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
#endif
/* portNOP() is not required by this port. */
#define portNOP()
/*-----------------------------------------------------------*/
/* Suppress warnings that are generated by the IAR tools, but cannot be fixed in
the source code because to do so would cause other compilers to generate
warnings. */
#pragma diag_suppress=Pe191
#pragma diag_suppress=Pa082
#ifdef __cplusplus
}
#endif
#endif /* PORTMACRO_H */
@@ -0,0 +1,252 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#ifdef __cplusplus
extern "C" {
#endif
/*-----------------------------------------------------------
* Port specific definitions.
*
* The settings in this file configure FreeRTOS correctly for the
* given hardware and compiler.
*
* These settings should not be altered.
*-----------------------------------------------------------
*/
/* Type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE uint32_t
#define portBASE_TYPE long
typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1
#endif
/*-----------------------------------------------------------*/
/* Architecture specifics. */
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 8
/* Constants used with memory barrier intrinsics. */
#define portSY_FULL_READ_WRITE ( 15 )
/*-----------------------------------------------------------*/
/* Scheduler utilities. */
#define portYIELD() \
{ \
/* Set a PendSV to request a context switch. */ \
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
\
/* Barriers are normally not required but do ensure the code is completely \
within the specified behaviour for the architecture. */ \
__dsb( portSY_FULL_READ_WRITE ); \
__isb( portSY_FULL_READ_WRITE ); \
}
/*-----------------------------------------------------------*/
#define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/
/* Critical section management. */
extern void vPortEnterCritical( void );
extern void vPortExitCritical( void );
#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()
#define portENABLE_INTERRUPTS() vPortSetBASEPRI( 0 )
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x)
/*-----------------------------------------------------------*/
/* Tickless idle/low power functionality. */
#ifndef portSUPPRESS_TICKS_AND_SLEEP
extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
#endif
/*-----------------------------------------------------------*/
/* Port specific optimisations. */
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Check the configuration. */
#if( configMAX_PRIORITIES > 32 )
#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.
#endif
/* Store/clear the ready priorities in a bit map. */
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
/*-----------------------------------------------------------*/
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( uint32_t ) __clz( ( uxReadyPriorities ) ) )
#endif /* taskRECORD_READY_PRIORITY */
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are
not necessary for to use this port. They are defined so the common demo files
(which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/*-----------------------------------------------------------*/
#ifdef configASSERT
void vPortValidateInterruptPriority( void );
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
#endif
/* portNOP() is not required by this port. */
#define portNOP()
#define portINLINE __inline
#ifndef portFORCE_INLINE
#define portFORCE_INLINE __forceinline
#endif
/*-----------------------------------------------------------*/
static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )
{
__asm
{
/* Barrier instructions are not used as this function is only used to
lower the BASEPRI value. */
msr basepri, ulBASEPRI
}
}
/*-----------------------------------------------------------*/
static portFORCE_INLINE void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
__asm
{
/* Set BASEPRI to the max syscall priority to effect a critical
section. */
msr basepri, ulNewBASEPRI
dsb
isb
}
}
/*-----------------------------------------------------------*/
static portFORCE_INLINE void vPortClearBASEPRIFromISR( void )
{
__asm
{
/* Set BASEPRI to 0 so no interrupts are masked. This function is only
used to lower the mask in an interrupt, so memory barriers are not
used. */
msr basepri, #0
}
}
/*-----------------------------------------------------------*/
static portFORCE_INLINE uint32_t ulPortRaiseBASEPRI( void )
{
uint32_t ulReturn, ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
__asm
{
/* Set BASEPRI to the max syscall priority to effect a critical
section. */
mrs ulReturn, basepri
msr basepri, ulNewBASEPRI
dsb
isb
}
return ulReturn;
}
/*-----------------------------------------------------------*/
static portFORCE_INLINE BaseType_t xPortIsInsideInterrupt( void )
{
uint32_t ulCurrentInterrupt;
BaseType_t xReturn;
/* Obtain the number of the currently executing interrupt. */
__asm
{
mrs ulCurrentInterrupt, ipsr
}
if( ulCurrentInterrupt == 0 )
{
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
return xReturn;
}
#ifdef __cplusplus
}
#endif
#endif /* PORTMACRO_H */
@@ -0,0 +1,252 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#ifdef __cplusplus
extern "C" {
#endif
/*-----------------------------------------------------------
* Port specific definitions.
*
* The settings in this file configure FreeRTOS correctly for the
* given hardware and compiler.
*
* These settings should not be altered.
*-----------------------------------------------------------
*/
/* Type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE uint32_t
#define portBASE_TYPE long
typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1
#endif
/*-----------------------------------------------------------*/
/* Architecture specifics. */
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 8
/* Constants used with memory barrier intrinsics. */
#define portSY_FULL_READ_WRITE ( 15 )
/*-----------------------------------------------------------*/
/* Scheduler utilities. */
#define portYIELD() \
{ \
/* Set a PendSV to request a context switch. */ \
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
\
/* Barriers are normally not required but do ensure the code is completely \
within the specified behaviour for the architecture. */ \
__dsb( portSY_FULL_READ_WRITE ); \
__isb( portSY_FULL_READ_WRITE ); \
}
/*-----------------------------------------------------------*/
#define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/
/* Critical section management. */
extern void vPortEnterCritical( void );
extern void vPortExitCritical( void );
#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()
#define portENABLE_INTERRUPTS() vPortSetBASEPRI( 0 )
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x)
/*-----------------------------------------------------------*/
/* Tickless idle/low power functionality. */
#ifndef portSUPPRESS_TICKS_AND_SLEEP
extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
#endif
/*-----------------------------------------------------------*/
/* Port specific optimisations. */
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Check the configuration. */
#if( configMAX_PRIORITIES > 32 )
#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.
#endif
/* Store/clear the ready priorities in a bit map. */
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
/*-----------------------------------------------------------*/
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( uint32_t ) __clz( ( uxReadyPriorities ) ) )
#endif /* taskRECORD_READY_PRIORITY */
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are
not necessary for to use this port. They are defined so the common demo files
(which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/*-----------------------------------------------------------*/
#ifdef configASSERT
void vPortValidateInterruptPriority( void );
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
#endif
/* portNOP() is not required by this port. */
#define portNOP()
#define portINLINE __inline
#ifndef portFORCE_INLINE
#define portFORCE_INLINE __forceinline
#endif
/*-----------------------------------------------------------*/
static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )
{
__asm
{
/* Barrier instructions are not used as this function is only used to
lower the BASEPRI value. */
msr basepri, ulBASEPRI
}
}
/*-----------------------------------------------------------*/
static portFORCE_INLINE void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
__asm
{
/* Set BASEPRI to the max syscall priority to effect a critical
section. */
msr basepri, ulNewBASEPRI
dsb
isb
}
}
/*-----------------------------------------------------------*/
static portFORCE_INLINE void vPortClearBASEPRIFromISR( void )
{
__asm
{
/* Set BASEPRI to 0 so no interrupts are masked. This function is only
used to lower the mask in an interrupt, so memory barriers are not
used. */
msr basepri, #0
}
}
/*-----------------------------------------------------------*/
static portFORCE_INLINE uint32_t ulPortRaiseBASEPRI( void )
{
uint32_t ulReturn, ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
__asm
{
/* Set BASEPRI to the max syscall priority to effect a critical
section. */
mrs ulReturn, basepri
msr basepri, ulNewBASEPRI
dsb
isb
}
return ulReturn;
}
/*-----------------------------------------------------------*/
static portFORCE_INLINE BaseType_t xPortIsInsideInterrupt( void )
{
uint32_t ulCurrentInterrupt;
BaseType_t xReturn;
/* Obtain the number of the currently executing interrupt. */
__asm
{
mrs ulCurrentInterrupt, ipsr
}
if( ulCurrentInterrupt == 0 )
{
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
return xReturn;
}
#ifdef __cplusplus
}
#endif
#endif /* PORTMACRO_H */
@@ -0,0 +1,788 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/*-----------------------------------------------------------
* Implementation of functions defined in portable.h for the ARM CM4F port.
*----------------------------------------------------------*/
/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#ifndef __TARGET_FPU_VFP
#error This port can only be used when the project options are configured to enable hardware floating point support.
#endif
#if configMAX_SYSCALL_INTERRUPT_PRIORITY == 0
#error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html
#endif
#ifndef configSYSTICK_CLOCK_HZ
#define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ
/* Ensure the SysTick is clocked at the same frequency as the core. */
#define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL )
#else
/* The way the SysTick is clocked is not modified in case it is not the same
as the core. */
#define portNVIC_SYSTICK_CLK_BIT ( 0 )
#endif
/* The __weak attribute does not work as you might expect with the Keil tools
so the configOVERRIDE_DEFAULT_TICK_CONFIGURATION constant must be set to 1 if
the application writer wants to provide their own implementation of
vPortSetupTimerInterrupt(). Ensure configOVERRIDE_DEFAULT_TICK_CONFIGURATION
is defined. */
#ifndef configOVERRIDE_DEFAULT_TICK_CONFIGURATION
#define configOVERRIDE_DEFAULT_TICK_CONFIGURATION 0
#endif
/* Constants required to manipulate the core. Registers first... */
#define portNVIC_SYSTICK_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000e010 ) )
#define portNVIC_SYSTICK_LOAD_REG ( * ( ( volatile uint32_t * ) 0xe000e014 ) )
#define portNVIC_SYSTICK_CURRENT_VALUE_REG ( * ( ( volatile uint32_t * ) 0xe000e018 ) )
#define portNVIC_SYSPRI2_REG ( * ( ( volatile uint32_t * ) 0xe000ed20 ) )
/* ...then bits in the registers. */
#define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL )
#define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL )
#define portNVIC_SYSTICK_COUNT_FLAG_BIT ( 1UL << 16UL )
#define portNVIC_PENDSVCLEAR_BIT ( 1UL << 27UL )
#define portNVIC_PEND_SYSTICK_CLEAR_BIT ( 1UL << 25UL )
/* Constants used to detect a Cortex-M7 r0p1 core, which should use the ARM_CM7
r0p1 port. */
#define portCPUID ( * ( ( volatile uint32_t * ) 0xE000ed00 ) )
#define portCORTEX_M7_r0p1_ID ( 0x410FC271UL )
#define portCORTEX_M7_r0p0_ID ( 0x410FC270UL )
#define portNVIC_PENDSV_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )
#define portNVIC_SYSTICK_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )
/* Constants required to check the validity of an interrupt priority. */
#define portFIRST_USER_INTERRUPT_NUMBER ( 16 )
#define portNVIC_IP_REGISTERS_OFFSET_16 ( 0xE000E3F0 )
#define portAIRCR_REG ( * ( ( volatile uint32_t * ) 0xE000ED0C ) )
#define portMAX_8_BIT_VALUE ( ( uint8_t ) 0xff )
#define portTOP_BIT_OF_BYTE ( ( uint8_t ) 0x80 )
#define portMAX_PRIGROUP_BITS ( ( uint8_t ) 7 )
#define portPRIORITY_GROUP_MASK ( 0x07UL << 8UL )
#define portPRIGROUP_SHIFT ( 8UL )
/* Masks off all bits but the VECTACTIVE bits in the ICSR register. */
#define portVECTACTIVE_MASK ( 0xFFUL )
/* Constants required to manipulate the VFP. */
#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating point context control register. */
#define portASPEN_AND_LSPEN_BITS ( 0x3UL << 30UL )
/* Constants required to set up the initial stack. */
#define portINITIAL_XPSR ( 0x01000000 )
#define portINITIAL_EXC_RETURN ( 0xfffffffd )
/* The systick is a 24-bit counter. */
#define portMAX_24_BIT_NUMBER ( 0xffffffUL )
/* A fiddle factor to estimate the number of SysTick counts that would have
occurred while the SysTick counter is stopped during tickless idle
calculations. */
#define portMISSED_COUNTS_FACTOR ( 45UL )
/* For strict compliance with the Cortex-M spec the task start address should
have bit-0 clear, as it is loaded into the PC on exit from an ISR. */
#define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL )
/*
* Setup the timer to generate the tick interrupts. The implementation in this
* file is weak to allow application writers to change the timer used to
* generate the tick interrupt.
*/
void vPortSetupTimerInterrupt( void );
/*
* Exception handlers.
*/
void xPortPendSVHandler( void );
void xPortSysTickHandler( void );
void vPortSVCHandler( void );
/*
* Start first task is a separate function so it can be tested in isolation.
*/
static void prvStartFirstTask( void );
/*
* Functions defined in portasm.s to enable the VFP.
*/
static void prvEnableVFP( void );
/*
* Used to catch tasks that attempt to return from their implementing function.
*/
static void prvTaskExitError( void );
/*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/*
* The number of SysTick increments that make up one tick period.
*/
#if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulTimerCountsForOneTick = 0;
#endif /* configUSE_TICKLESS_IDLE */
/*
* The maximum number of tick periods that can be suppressed is limited by the
* 24 bit resolution of the SysTick timer.
*/
#if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t xMaximumPossibleSuppressedTicks = 0;
#endif /* configUSE_TICKLESS_IDLE */
/*
* Compensate for the CPU cycles that pass while the SysTick is stopped (low
* power functionality only.
*/
#if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulStoppedTimerCompensation = 0;
#endif /* configUSE_TICKLESS_IDLE */
/*
* Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure
* FreeRTOS API functions are not called from interrupts that have been assigned
* a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.
*/
#if ( configASSERT_DEFINED == 1 )
static uint8_t ucMaxSysCallPriority = 0;
static uint32_t ulMaxPRIGROUPValue = 0;
static const volatile uint8_t * const pcInterruptPriorityRegisters = ( uint8_t * ) portNVIC_IP_REGISTERS_OFFSET_16;
#endif /* configASSERT_DEFINED */
/*-----------------------------------------------------------*/
/*
* See header file for description.
*/
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
/* Simulate the stack frame as it would be created by a context switch
interrupt. */
/* Offset added to account for the way the MCU uses the stack on entry/exit
of interrupts, and to ensure alignment. */
pxTopOfStack--;
*pxTopOfStack = portINITIAL_XPSR; /* xPSR */
pxTopOfStack--;
*pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) prvTaskExitError; /* LR */
/* Save code space by skipping register initialisation. */
pxTopOfStack -= 5; /* R12, R3, R2 and R1. */
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
/* A save method is being used that requires each task to maintain its
own exec return value. */
pxTopOfStack--;
*pxTopOfStack = portINITIAL_EXC_RETURN;
pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */
return pxTopOfStack;
}
/*-----------------------------------------------------------*/
static void prvTaskExitError( void )
{
/* A function that implements a task must not exit or attempt to return to
its caller as there is nothing to return to. If a task wants to exit it
should instead call vTaskDelete( NULL ).
Artificially force an assert() to be triggered if configASSERT() is
defined, then stop here so application writers can catch the error. */
configASSERT( uxCriticalNesting == ~0UL );
portDISABLE_INTERRUPTS();
for( ;; );
}
/*-----------------------------------------------------------*/
__asm void vPortSVCHandler( void )
{
PRESERVE8
/* Get the location of the current TCB. */
ldr r3, =pxCurrentTCB
ldr r1, [r3]
ldr r0, [r1]
/* Pop the core registers. */
ldmia r0!, {r4-r11, r14}
msr psp, r0
isb
mov r0, #0
msr basepri, r0
bx r14
}
/*-----------------------------------------------------------*/
__asm void prvStartFirstTask( void )
{
PRESERVE8
/* Use the NVIC offset register to locate the stack. */
ldr r0, =0xE000ED08
ldr r0, [r0]
ldr r0, [r0]
/* Set the msp back to the start of the stack. */
msr msp, r0
/* Clear the bit that indicates the FPU is in use in case the FPU was used
before the scheduler was started - which would otherwise result in the
unnecessary leaving of space in the SVC stack for lazy saving of FPU
registers. */
mov r0, #0
msr control, r0
/* Globally enable interrupts. */
cpsie i
cpsie f
dsb
isb
/* Call SVC to start the first task. */
svc 0
nop
nop
}
/*-----------------------------------------------------------*/
__asm void prvEnableVFP( void )
{
PRESERVE8
/* The FPU enable bits are in the CPACR. */
ldr.w r0, =0xE000ED88
ldr r1, [r0]
/* Enable CP10 and CP11 coprocessors, then save back. */
orr r1, r1, #( 0xf << 20 )
str r1, [r0]
bx r14
nop
}
/*-----------------------------------------------------------*/
/*
* See header file for description.
*/
BaseType_t xPortStartScheduler( void )
{
/* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0.
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY );
/* This port can be used on all revisions of the Cortex-M7 core other than
the r0p1 parts. r0p1 parts should use the port from the
/source/portable/GCC/ARM_CM7/r0p1 directory. */
configASSERT( portCPUID != portCORTEX_M7_r0p1_ID );
configASSERT( portCPUID != portCORTEX_M7_r0p0_ID );
#if( configASSERT_DEFINED == 1 )
{
volatile uint32_t ulOriginalPriority;
volatile uint8_t * const pucFirstUserPriorityRegister = ( uint8_t * ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER );
volatile uint8_t ucMaxPriorityValue;
/* Determine the maximum priority from which ISR safe FreeRTOS API
functions can be called. ISR safe functions are those that end in
"FromISR". FreeRTOS maintains separate thread and ISR API functions to
ensure interrupt entry is as fast and simple as possible.
Save the interrupt priority value that is about to be clobbered. */
ulOriginalPriority = *pucFirstUserPriorityRegister;
/* Determine the number of priority bits available. First write to all
possible bits. */
*pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
/* Read the value back to see how many bits stuck. */
ucMaxPriorityValue = *pucFirstUserPriorityRegister;
/* The kernel interrupt priority should be set to the lowest
priority. */
configASSERT( ucMaxPriorityValue == ( configKERNEL_INTERRUPT_PRIORITY & ucMaxPriorityValue ) );
/* Use the same mask on the maximum system call priority. */
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
/* Calculate the maximum acceptable priority group value for the number
of bits read back. */
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
{
ulMaxPRIGROUPValue--;
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
}
#ifdef __NVIC_PRIO_BITS
{
/* Check the CMSIS configuration that defines the number of
priority bits matches the number of priority bits actually queried
from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS );
}
#endif
#ifdef configPRIO_BITS
{
/* Check the FreeRTOS configuration that defines the number of
priority bits matches the number of priority bits actually queried
from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS );
}
#endif
/* Shift the priority group value back to its position within the AIRCR
register. */
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
/* Restore the clobbered interrupt priority register to its original
value. */
*pucFirstUserPriorityRegister = ulOriginalPriority;
}
#endif /* conifgASSERT_DEFINED */
/* Make PendSV and SysTick the lowest priority interrupts. */
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
/* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */
vPortSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */
uxCriticalNesting = 0;
/* Ensure the VFP is enabled - it should be anyway. */
prvEnableVFP();
/* Lazy save always. */
*( portFPCCR ) |= portASPEN_AND_LSPEN_BITS;
/* Start the first task. */
prvStartFirstTask();
/* Should not get here! */
return 0;
}
/*-----------------------------------------------------------*/
void vPortEndScheduler( void )
{
/* Not implemented in ports where there is nothing to return to.
Artificially force an assert. */
configASSERT( uxCriticalNesting == 1000UL );
}
/*-----------------------------------------------------------*/
void vPortEnterCritical( void )
{
portDISABLE_INTERRUPTS();
uxCriticalNesting++;
/* This is not the interrupt safe version of the enter critical function so
assert() if it is being called from an interrupt context. Only API
functions that end in "FromISR" can be used in an interrupt. Only assert if
the critical nesting count is 1 to protect against recursive calls if the
assert function also uses a critical section. */
if( uxCriticalNesting == 1 )
{
configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
}
}
/*-----------------------------------------------------------*/
void vPortExitCritical( void )
{
configASSERT( uxCriticalNesting );
uxCriticalNesting--;
if( uxCriticalNesting == 0 )
{
portENABLE_INTERRUPTS();
}
}
/*-----------------------------------------------------------*/
__asm void xPortPendSVHandler( void )
{
extern uxCriticalNesting;
extern pxCurrentTCB;
extern vTaskSwitchContext;
PRESERVE8
mrs r0, psp
isb
/* Get the location of the current TCB. */
ldr r3, =pxCurrentTCB
ldr r2, [r3]
/* Is the task using the FPU context? If so, push high vfp registers. */
tst r14, #0x10
it eq
vstmdbeq r0!, {s16-s31}
/* Save the core registers. */
stmdb r0!, {r4-r11, r14}
/* Save the new top of stack into the first member of the TCB. */
str r0, [r2]
stmdb sp!, {r0, r3}
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr basepri, r0
dsb
isb
bl vTaskSwitchContext
mov r0, #0
msr basepri, r0
ldmia sp!, {r0, r3}
/* The first item in pxCurrentTCB is the task top of stack. */
ldr r1, [r3]
ldr r0, [r1]
/* Pop the core registers. */
ldmia r0!, {r4-r11, r14}
/* Is the task using the FPU context? If so, pop the high vfp registers
too. */
tst r14, #0x10
it eq
vldmiaeq r0!, {s16-s31}
msr psp, r0
isb
#ifdef WORKAROUND_PMU_CM001 /* XMC4000 specific errata */
#if WORKAROUND_PMU_CM001 == 1
push { r14 }
pop { pc }
nop
#endif
#endif
bx r14
}
/*-----------------------------------------------------------*/
void xPortSysTickHandler( void )
{
/* The SysTick runs at the lowest interrupt priority, so when this interrupt
executes all interrupts must be unmasked. There is therefore no need to
save and then restore the interrupt mask value as its value is already
known - therefore the slightly faster vPortRaiseBASEPRI() function is used
in place of portSET_INTERRUPT_MASK_FROM_ISR(). */
vPortRaiseBASEPRI();
{
/* Increment the RTOS tick. */
if( xTaskIncrementTick() != pdFALSE )
{
/* A context switch is required. Context switching is performed in
the PendSV interrupt. Pend the PendSV interrupt. */
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
}
}
vPortClearBASEPRIFromISR();
}
/*-----------------------------------------------------------*/
#if( configUSE_TICKLESS_IDLE == 1 )
__weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{
uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
TickType_t xModifiableIdleTime;
/* Make sure the SysTick reload value does not overflow the counter. */
if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )
{
xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
}
/* Stop the SysTick momentarily. The time the SysTick is stopped for
is accounted for as best it can be, but using the tickless mode will
inevitably result in some tiny drift of the time maintained by the
kernel with respect to calendar time. */
portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;
/* Calculate the reload value required to wait xExpectedIdleTime
tick periods. -1 is used because this code will execute part way
through one of the tick periods. */
ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
if( ulReloadValue > ulStoppedTimerCompensation )
{
ulReloadValue -= ulStoppedTimerCompensation;
}
/* Enter a critical section but don't use the taskENTER_CRITICAL()
method as that will mask interrupts that should exit sleep mode. */
__disable_irq();
__dsb( portSY_FULL_READ_WRITE );
__isb( portSY_FULL_READ_WRITE );
/* If a context switch is pending or a task is waiting for the scheduler
to be unsuspended then abandon the low power entry. */
if( eTaskConfirmSleepModeStatus() == eAbortSleep )
{
/* Restart from whatever is left in the count register to complete
this tick period. */
portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;
/* Restart SysTick. */
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
/* Reset the reload register to the value required for normal tick
periods. */
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
/* Re-enable interrupts - see comments above __disable_irq() call
above. */
__enable_irq();
}
else
{
/* Set the new reload value. */
portNVIC_SYSTICK_LOAD_REG = ulReloadValue;
/* Clear the SysTick count flag and set the count value back to
zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Restart SysTick. */
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
/* Sleep until something happens. configPRE_SLEEP_PROCESSING() can
set its parameter to 0 to indicate that its implementation contains
its own wait for interrupt or wait for event instruction, and so wfi
should not be executed again. However, the original expected idle
time variable must remain unmodified, so a copy is taken. */
xModifiableIdleTime = xExpectedIdleTime;
configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
if( xModifiableIdleTime > 0 )
{
__dsb( portSY_FULL_READ_WRITE );
__wfi();
__isb( portSY_FULL_READ_WRITE );
}
configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Re-enable interrupts to allow the interrupt that brought the MCU
out of sleep mode to execute immediately. see comments above
__disable_interrupt() call above. */
__enable_irq();
__dsb( portSY_FULL_READ_WRITE );
__isb( portSY_FULL_READ_WRITE );
/* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar
time. */
__disable_irq();
__dsb( portSY_FULL_READ_WRITE );
__isb( portSY_FULL_READ_WRITE );
/* Disable the SysTick clock without reading the
portNVIC_SYSTICK_CTRL_REG register to ensure the
portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set. Again,
the time the SysTick is stopped for is accounted for as best it can
be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar
time*/
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
/* Determine if the SysTick clock has already counted to zero and
been set back to the current reload value (the reload back being
correct for the entire expected idle time) or if the SysTick is yet
to count to zero (in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{
uint32_t ulCalculatedLoadValue;
/* The tick interrupt is already pending, and the SysTick count
reloaded with ulReloadValue. Reset the
portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick
period. */
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );
/* Don't allow a tiny value, or values that have somehow
underflowed because the post sleep hook did something
that took too long. */
if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
{
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );
}
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* As the pending tick will be processed as soon as this
function exits, the tick value maintained by the tick is stepped
forward by one less than the time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
}
else
{
/* Something other than the tick interrupt ended the sleep.
Work out how long the sleep lasted rounded to complete tick
periods (not the ulReload value which accounted for part
ticks). */
ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;
/* How many complete tick periods passed while the processor
was waiting? */
ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;
/* The reload value is set to whatever fraction of a single tick
period remains. */
portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;
}
/* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG
again, then set portNVIC_SYSTICK_LOAD_REG back to its standard
value. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods );
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
/* Exit with interrpts enabled. */
__enable_irq();
}
}
#endif /* #if configUSE_TICKLESS_IDLE */
/*-----------------------------------------------------------*/
/*
* Setup the SysTick timer to generate the tick interrupts at the required
* frequency.
*/
#if( configOVERRIDE_DEFAULT_TICK_CONFIGURATION == 0 )
void vPortSetupTimerInterrupt( void )
{
/* Calculate the constants required to configure the tick interrupt. */
#if( configUSE_TICKLESS_IDLE == 1 )
{
ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ );
}
#endif /* configUSE_TICKLESS_IDLE */
/* Stop and clear the SysTick. */
portNVIC_SYSTICK_CTRL_REG = 0UL;
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Configure SysTick to interrupt at the requested rate. */
portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );
}
#endif /* configOVERRIDE_DEFAULT_TICK_CONFIGURATION */
/*-----------------------------------------------------------*/
__asm uint32_t vPortGetIPSR( void )
{
PRESERVE8
mrs r0, ipsr
bx r14
}
/*-----------------------------------------------------------*/
#if( configASSERT_DEFINED == 1 )
void vPortValidateInterruptPriority( void )
{
uint32_t ulCurrentInterrupt;
uint8_t ucCurrentPriority;
/* Obtain the number of the currently executing interrupt. */
ulCurrentInterrupt = vPortGetIPSR();
/* Is the interrupt number a user defined interrupt? */
if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )
{
/* Look up the interrupt's priority. */
ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
/* The following assertion will fail if a service routine (ISR) for
an interrupt that has been assigned a priority above
configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
function. ISR safe FreeRTOS API functions must *only* be called
from interrupts that have been assigned a priority at or below
configMAX_SYSCALL_INTERRUPT_PRIORITY.
Numerically low interrupt priority numbers represent logically high
interrupt priorities, therefore the priority of the interrupt must
be set to a value equal to or numerically *higher* than
configMAX_SYSCALL_INTERRUPT_PRIORITY.
Interrupts that use the FreeRTOS API must not be left at their
default priority of zero as that is the highest possible priority,
which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,
and therefore also guaranteed to be invalid.
FreeRTOS maintains separate thread and ISR API functions to ensure
interrupt entry is as fast and simple as possible.
The following links provide detailed information:
http://www.freertos.org/RTOS-Cortex-M3-M4.html
http://www.freertos.org/FAQHelp.html */
configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );
}
/* Priority grouping: The interrupt controller (NVIC) allows the bits
that define each interrupt's priority to be split between bits that
define the interrupt's pre-emption priority bits and bits that define
the interrupt's sub-priority. For simplicity all bits must be defined
to be pre-emption priority bits. The following assertion will fail if
this is not the case (if some bits represent a sub-priority).
If the application only uses CMSIS libraries for interrupt
configuration then the correct setting can be achieved on all Cortex-M
devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the
scheduler. Note however that some vendor specific peripheral libraries
assume a non-zero priority group setting, in which cases using a value
of zero will result in unpredictable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
}
#endif /* configASSERT_DEFINED */
@@ -0,0 +1,252 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#ifdef __cplusplus
extern "C" {
#endif
/*-----------------------------------------------------------
* Port specific definitions.
*
* The settings in this file configure FreeRTOS correctly for the
* given hardware and compiler.
*
* These settings should not be altered.
*-----------------------------------------------------------
*/
/* Type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE uint32_t
#define portBASE_TYPE long
typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1
#endif
/*-----------------------------------------------------------*/
/* Architecture specifics. */
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 8
/* Constants used with memory barrier intrinsics. */
#define portSY_FULL_READ_WRITE ( 15 )
/*-----------------------------------------------------------*/
/* Scheduler utilities. */
#define portYIELD() \
{ \
/* Set a PendSV to request a context switch. */ \
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
\
/* Barriers are normally not required but do ensure the code is completely \
within the specified behaviour for the architecture. */ \
__dsb( portSY_FULL_READ_WRITE ); \
__isb( portSY_FULL_READ_WRITE ); \
}
/*-----------------------------------------------------------*/
#define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/
/* Critical section management. */
extern void vPortEnterCritical( void );
extern void vPortExitCritical( void );
#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()
#define portENABLE_INTERRUPTS() vPortSetBASEPRI( 0 )
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x)
/*-----------------------------------------------------------*/
/* Tickless idle/low power functionality. */
#ifndef portSUPPRESS_TICKS_AND_SLEEP
extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
#endif
/*-----------------------------------------------------------*/
/* Port specific optimisations. */
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Check the configuration. */
#if( configMAX_PRIORITIES > 32 )
#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.
#endif
/* Store/clear the ready priorities in a bit map. */
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
/*-----------------------------------------------------------*/
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( uint32_t ) __clz( ( uxReadyPriorities ) ) )
#endif /* taskRECORD_READY_PRIORITY */
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are
not necessary for to use this port. They are defined so the common demo files
(which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/*-----------------------------------------------------------*/
#ifdef configASSERT
void vPortValidateInterruptPriority( void );
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
#endif
/* portNOP() is not required by this port. */
#define portNOP()
#define portINLINE __inline
#ifndef portFORCE_INLINE
#define portFORCE_INLINE __forceinline
#endif
/*-----------------------------------------------------------*/
static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )
{
__asm
{
/* Barrier instructions are not used as this function is only used to
lower the BASEPRI value. */
msr basepri, ulBASEPRI
}
}
/*-----------------------------------------------------------*/
static portFORCE_INLINE void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
__asm
{
/* Set BASEPRI to the max syscall priority to effect a critical
section. */
msr basepri, ulNewBASEPRI
dsb
isb
}
}
/*-----------------------------------------------------------*/
static portFORCE_INLINE void vPortClearBASEPRIFromISR( void )
{
__asm
{
/* Set BASEPRI to 0 so no interrupts are masked. This function is only
used to lower the mask in an interrupt, so memory barriers are not
used. */
msr basepri, #0
}
}
/*-----------------------------------------------------------*/
static portFORCE_INLINE uint32_t ulPortRaiseBASEPRI( void )
{
uint32_t ulReturn, ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
__asm
{
/* Set BASEPRI to the max syscall priority to effect a critical
section. */
mrs ulReturn, basepri
msr basepri, ulNewBASEPRI
dsb
isb
}
return ulReturn;
}
/*-----------------------------------------------------------*/
static portFORCE_INLINE BaseType_t xPortIsInsideInterrupt( void )
{
uint32_t ulCurrentInterrupt;
BaseType_t xReturn;
/* Obtain the number of the currently executing interrupt. */
__asm
{
mrs ulCurrentInterrupt, ipsr
}
if( ulCurrentInterrupt == 0 )
{
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
return xReturn;
}
#ifdef __cplusplus
}
#endif
#endif /* PORTMACRO_H */
@@ -0,0 +1,242 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#ifdef __cplusplus
extern "C" {
#endif
/*-----------------------------------------------------------
* Port specific definitions.
*
* The settings in this file configure FreeRTOS correctly for the
* given hardware and compiler.
*
* These settings should not be altered.
*-----------------------------------------------------------
*/
/* Type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE uint32_t
#define portBASE_TYPE long
typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1
#endif
/*-----------------------------------------------------------*/
/* Architecture specifics. */
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 8
/*-----------------------------------------------------------*/
/* Scheduler utilities. */
#define portYIELD() \
{ \
/* Set a PendSV to request a context switch. */ \
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
\
/* Barriers are normally not required but do ensure the code is completely \
within the specified behaviour for the architecture. */ \
__asm volatile( "dsb" ::: "memory" ); \
__asm volatile( "isb" ); \
}
#define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/
/* Critical section management. */
extern void vPortEnterCritical( void );
extern void vPortExitCritical( void );
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x)
#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()
#define portENABLE_INTERRUPTS() vPortSetBASEPRI(0)
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are
not necessary for to use this port. They are defined so the common demo files
(which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/*-----------------------------------------------------------*/
/* Tickless idle/low power functionality. */
#ifndef portSUPPRESS_TICKS_AND_SLEEP
extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
#endif
/*-----------------------------------------------------------*/
/* Architecture specific optimisations. */
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Generic helper function. */
__attribute__( ( always_inline ) ) static inline uint8_t ucPortCountLeadingZeros( uint32_t ulBitmap )
{
uint8_t ucReturn;
__asm volatile ( "clz %0, %1" : "=r" ( ucReturn ) : "r" ( ulBitmap ) : "memory" );
return ucReturn;
}
/* Check the configuration. */
#if( configMAX_PRIORITIES > 32 )
#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.
#endif
/* Store/clear the ready priorities in a bit map. */
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
/*-----------------------------------------------------------*/
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( uint32_t ) ucPortCountLeadingZeros( ( uxReadyPriorities ) ) )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
/*-----------------------------------------------------------*/
#ifdef configASSERT
void vPortValidateInterruptPriority( void );
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
#endif
/* portNOP() is not required by this port. */
#define portNOP()
#define portINLINE __inline
#ifndef portFORCE_INLINE
#define portFORCE_INLINE inline __attribute__(( always_inline))
#endif
portFORCE_INLINE static BaseType_t xPortIsInsideInterrupt( void )
{
uint32_t ulCurrentInterrupt;
BaseType_t xReturn;
/* Obtain the number of the currently executing interrupt. */
__asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" );
if( ulCurrentInterrupt == 0 )
{
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
return xReturn;
}
/*-----------------------------------------------------------*/
portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;
__asm volatile
(
" mov %0, %1 \n" \
" msr basepri, %0 \n" \
" isb \n" \
" dsb \n" \
:"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
);
}
/*-----------------------------------------------------------*/
portFORCE_INLINE static uint32_t ulPortRaiseBASEPRI( void )
{
uint32_t ulOriginalBASEPRI, ulNewBASEPRI;
__asm volatile
(
" mrs %0, basepri \n" \
" mov %1, %2 \n" \
" msr basepri, %1 \n" \
" isb \n" \
" dsb \n" \
:"=r" (ulOriginalBASEPRI), "=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
);
/* This return will not be reached but is necessary to prevent compiler
warnings. */
return ulOriginalBASEPRI;
}
/*-----------------------------------------------------------*/
portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue )
{
__asm volatile
(
" msr basepri, %0 " :: "r" ( ulNewMaskValue ) : "memory"
);
}
/*-----------------------------------------------------------*/
#ifdef __cplusplus
}
#endif
#endif /* PORTMACRO_H */
@@ -0,0 +1,242 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#ifdef __cplusplus
extern "C" {
#endif
/*-----------------------------------------------------------
* Port specific definitions.
*
* The settings in this file configure FreeRTOS correctly for the
* given hardware and compiler.
*
* These settings should not be altered.
*-----------------------------------------------------------
*/
/* Type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE uint32_t
#define portBASE_TYPE long
typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1
#endif
/*-----------------------------------------------------------*/
/* Architecture specifics. */
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 8
/*-----------------------------------------------------------*/
/* Scheduler utilities. */
#define portYIELD() \
{ \
/* Set a PendSV to request a context switch. */ \
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
\
/* Barriers are normally not required but do ensure the code is completely \
within the specified behaviour for the architecture. */ \
__asm volatile( "dsb" ::: "memory" ); \
__asm volatile( "isb" ); \
}
#define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/
/* Critical section management. */
extern void vPortEnterCritical( void );
extern void vPortExitCritical( void );
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x)
#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()
#define portENABLE_INTERRUPTS() vPortSetBASEPRI(0)
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are
not necessary for to use this port. They are defined so the common demo files
(which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/*-----------------------------------------------------------*/
/* Tickless idle/low power functionality. */
#ifndef portSUPPRESS_TICKS_AND_SLEEP
extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
#endif
/*-----------------------------------------------------------*/
/* Architecture specific optimisations. */
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Generic helper function. */
__attribute__( ( always_inline ) ) static inline uint8_t ucPortCountLeadingZeros( uint32_t ulBitmap )
{
uint8_t ucReturn;
__asm volatile ( "clz %0, %1" : "=r" ( ucReturn ) : "r" ( ulBitmap ) : "memory" );
return ucReturn;
}
/* Check the configuration. */
#if( configMAX_PRIORITIES > 32 )
#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.
#endif
/* Store/clear the ready priorities in a bit map. */
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
/*-----------------------------------------------------------*/
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( uint32_t ) ucPortCountLeadingZeros( ( uxReadyPriorities ) ) )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
/*-----------------------------------------------------------*/
#ifdef configASSERT
void vPortValidateInterruptPriority( void );
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
#endif
/* portNOP() is not required by this port. */
#define portNOP()
#define portINLINE __inline
#ifndef portFORCE_INLINE
#define portFORCE_INLINE inline __attribute__(( always_inline))
#endif
portFORCE_INLINE static BaseType_t xPortIsInsideInterrupt( void )
{
uint32_t ulCurrentInterrupt;
BaseType_t xReturn;
/* Obtain the number of the currently executing interrupt. */
__asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" );
if( ulCurrentInterrupt == 0 )
{
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
return xReturn;
}
/*-----------------------------------------------------------*/
portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;
__asm volatile
(
" mov %0, %1 \n" \
" msr basepri, %0 \n" \
" isb \n" \
" dsb \n" \
:"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
);
}
/*-----------------------------------------------------------*/
portFORCE_INLINE static uint32_t ulPortRaiseBASEPRI( void )
{
uint32_t ulOriginalBASEPRI, ulNewBASEPRI;
__asm volatile
(
" mrs %0, basepri \n" \
" mov %1, %2 \n" \
" msr basepri, %1 \n" \
" isb \n" \
" dsb \n" \
:"=r" (ulOriginalBASEPRI), "=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
);
/* This return will not be reached but is necessary to prevent compiler
warnings. */
return ulOriginalBASEPRI;
}
/*-----------------------------------------------------------*/
portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue )
{
__asm volatile
(
" msr basepri, %0 " :: "r" ( ulNewMaskValue ) : "memory"
);
}
/*-----------------------------------------------------------*/
#ifdef __cplusplus
}
#endif
#endif /* PORTMACRO_H */
@@ -0,0 +1,775 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/*-----------------------------------------------------------
* Implementation of functions defined in portable.h for the ARM CM4F port.
*----------------------------------------------------------*/
/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#ifndef __VFP_FP__
#error This port can only be used when the project options are configured to enable hardware floating point support.
#endif
#ifndef configSYSTICK_CLOCK_HZ
#define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ
/* Ensure the SysTick is clocked at the same frequency as the core. */
#define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL )
#else
/* The way the SysTick is clocked is not modified in case it is not the same
as the core. */
#define portNVIC_SYSTICK_CLK_BIT ( 0 )
#endif
/* Constants required to manipulate the core. Registers first... */
#define portNVIC_SYSTICK_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000e010 ) )
#define portNVIC_SYSTICK_LOAD_REG ( * ( ( volatile uint32_t * ) 0xe000e014 ) )
#define portNVIC_SYSTICK_CURRENT_VALUE_REG ( * ( ( volatile uint32_t * ) 0xe000e018 ) )
#define portNVIC_SYSPRI2_REG ( * ( ( volatile uint32_t * ) 0xe000ed20 ) )
/* ...then bits in the registers. */
#define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL )
#define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL )
#define portNVIC_SYSTICK_COUNT_FLAG_BIT ( 1UL << 16UL )
#define portNVIC_PENDSVCLEAR_BIT ( 1UL << 27UL )
#define portNVIC_PEND_SYSTICK_CLEAR_BIT ( 1UL << 25UL )
/* Constants used to detect a Cortex-M7 r0p1 core, which should use the ARM_CM7
r0p1 port. */
#define portCPUID ( * ( ( volatile uint32_t * ) 0xE000ed00 ) )
#define portCORTEX_M7_r0p1_ID ( 0x410FC271UL )
#define portCORTEX_M7_r0p0_ID ( 0x410FC270UL )
#define portNVIC_PENDSV_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )
#define portNVIC_SYSTICK_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )
/* Constants required to check the validity of an interrupt priority. */
#define portFIRST_USER_INTERRUPT_NUMBER ( 16 )
#define portNVIC_IP_REGISTERS_OFFSET_16 ( 0xE000E3F0 )
#define portAIRCR_REG ( * ( ( volatile uint32_t * ) 0xE000ED0C ) )
#define portMAX_8_BIT_VALUE ( ( uint8_t ) 0xff )
#define portTOP_BIT_OF_BYTE ( ( uint8_t ) 0x80 )
#define portMAX_PRIGROUP_BITS ( ( uint8_t ) 7 )
#define portPRIORITY_GROUP_MASK ( 0x07UL << 8UL )
#define portPRIGROUP_SHIFT ( 8UL )
/* Masks off all bits but the VECTACTIVE bits in the ICSR register. */
#define portVECTACTIVE_MASK ( 0xFFUL )
/* Constants required to manipulate the VFP. */
#define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating point context control register. */
#define portASPEN_AND_LSPEN_BITS ( 0x3UL << 30UL )
/* Constants required to set up the initial stack. */
#define portINITIAL_XPSR ( 0x01000000 )
#define portINITIAL_EXC_RETURN ( 0xfffffffd )
/* The systick is a 24-bit counter. */
#define portMAX_24_BIT_NUMBER ( 0xffffffUL )
/* For strict compliance with the Cortex-M spec the task start address should
have bit-0 clear, as it is loaded into the PC on exit from an ISR. */
#define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL )
/* A fiddle factor to estimate the number of SysTick counts that would have
occurred while the SysTick counter is stopped during tickless idle
calculations. */
#define portMISSED_COUNTS_FACTOR ( 45UL )
/* Let the user override the pre-loading of the initial LR with the address of
prvTaskExitError() in case it messes up unwinding of the stack in the
debugger. */
#ifdef configTASK_RETURN_ADDRESS
#define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS
#else
#define portTASK_RETURN_ADDRESS prvTaskExitError
#endif
/*
* Setup the timer to generate the tick interrupts. The implementation in this
* file is weak to allow application writers to change the timer used to
* generate the tick interrupt.
*/
void vPortSetupTimerInterrupt( void );
/*
* Exception handlers.
*/
void xPortPendSVHandler( void ) __attribute__ (( naked ));
void xPortSysTickHandler( void );
void vPortSVCHandler( void ) __attribute__ (( naked ));
/*
* Start first task is a separate function so it can be tested in isolation.
*/
static void prvPortStartFirstTask( void ) __attribute__ (( naked ));
/*
* Function to enable the VFP.
*/
static void vPortEnableVFP( void ) __attribute__ (( naked ));
/*
* Used to catch tasks that attempt to return from their implementing function.
*/
static void prvTaskExitError( void );
/*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/*
* The number of SysTick increments that make up one tick period.
*/
#if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulTimerCountsForOneTick = 0;
#endif /* configUSE_TICKLESS_IDLE */
/*
* The maximum number of tick periods that can be suppressed is limited by the
* 24 bit resolution of the SysTick timer.
*/
#if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t xMaximumPossibleSuppressedTicks = 0;
#endif /* configUSE_TICKLESS_IDLE */
/*
* Compensate for the CPU cycles that pass while the SysTick is stopped (low
* power functionality only.
*/
#if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulStoppedTimerCompensation = 0;
#endif /* configUSE_TICKLESS_IDLE */
/*
* Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure
* FreeRTOS API functions are not called from interrupts that have been assigned
* a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.
*/
#if( configASSERT_DEFINED == 1 )
static uint8_t ucMaxSysCallPriority = 0;
static uint32_t ulMaxPRIGROUPValue = 0;
static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16;
#endif /* configASSERT_DEFINED */
/*-----------------------------------------------------------*/
/*
* See header file for description.
*/
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
/* Simulate the stack frame as it would be created by a context switch
interrupt. */
/* Offset added to account for the way the MCU uses the stack on entry/exit
of interrupts, and to ensure alignment. */
pxTopOfStack--;
*pxTopOfStack = portINITIAL_XPSR; /* xPSR */
pxTopOfStack--;
*pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR */
/* Save code space by skipping register initialisation. */
pxTopOfStack -= 5; /* R12, R3, R2 and R1. */
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
/* A save method is being used that requires each task to maintain its
own exec return value. */
pxTopOfStack--;
*pxTopOfStack = portINITIAL_EXC_RETURN;
pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */
return pxTopOfStack;
}
/*-----------------------------------------------------------*/
static void prvTaskExitError( void )
{
volatile uint32_t ulDummy = 0;
/* A function that implements a task must not exit or attempt to return to
its caller as there is nothing to return to. If a task wants to exit it
should instead call vTaskDelete( NULL ).
Artificially force an assert() to be triggered if configASSERT() is
defined, then stop here so application writers can catch the error. */
configASSERT( uxCriticalNesting == ~0UL );
portDISABLE_INTERRUPTS();
while( ulDummy == 0 )
{
/* This file calls prvTaskExitError() after the scheduler has been
started to remove a compiler warning about the function being defined
but never called. ulDummy is used purely to quieten other warnings
about code appearing after this function is called - making ulDummy
volatile makes the compiler think the function could return and
therefore not output an 'unreachable code' warning for code that appears
after it. */
}
}
/*-----------------------------------------------------------*/
void vPortSVCHandler( void )
{
__asm volatile (
" ldr r3, pxCurrentTCBConst2 \n" /* Restore the context. */
" ldr r1, [r3] \n" /* Use pxCurrentTCBConst to get the pxCurrentTCB address. */
" ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. */
" ldmia r0!, {r4-r11, r14} \n" /* Pop the registers that are not automatically saved on exception entry and the critical nesting count. */
" msr psp, r0 \n" /* Restore the task stack pointer. */
" isb \n"
" mov r0, #0 \n"
" msr basepri, r0 \n"
" bx r14 \n"
" \n"
" .align 4 \n"
"pxCurrentTCBConst2: .word pxCurrentTCB \n"
);
}
/*-----------------------------------------------------------*/
static void prvPortStartFirstTask( void )
{
/* Start the first task. This also clears the bit that indicates the FPU is
in use in case the FPU was used before the scheduler was started - which
would otherwise result in the unnecessary leaving of space in the SVC stack
for lazy saving of FPU registers. */
__asm volatile(
" ldr r0, =0xE000ED08 \n" /* Use the NVIC offset register to locate the stack. */
" ldr r0, [r0] \n"
" ldr r0, [r0] \n"
" msr msp, r0 \n" /* Set the msp back to the start of the stack. */
" mov r0, #0 \n" /* Clear the bit that indicates the FPU is in use, see comment above. */
" msr control, r0 \n"
" cpsie i \n" /* Globally enable interrupts. */
" cpsie f \n"
" dsb \n"
" isb \n"
" svc 0 \n" /* System call to start first task. */
" nop \n"
);
}
/*-----------------------------------------------------------*/
/*
* See header file for description.
*/
BaseType_t xPortStartScheduler( void )
{
/* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0.
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY );
/* This port can be used on all revisions of the Cortex-M7 core other than
the r0p1 parts. r0p1 parts should use the port from the
/source/portable/GCC/ARM_CM7/r0p1 directory. */
configASSERT( portCPUID != portCORTEX_M7_r0p1_ID );
configASSERT( portCPUID != portCORTEX_M7_r0p0_ID );
#if( configASSERT_DEFINED == 1 )
{
volatile uint32_t ulOriginalPriority;
volatile uint8_t * const pucFirstUserPriorityRegister = ( volatile uint8_t * const ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER );
volatile uint8_t ucMaxPriorityValue;
/* Determine the maximum priority from which ISR safe FreeRTOS API
functions can be called. ISR safe functions are those that end in
"FromISR". FreeRTOS maintains separate thread and ISR API functions to
ensure interrupt entry is as fast and simple as possible.
Save the interrupt priority value that is about to be clobbered. */
ulOriginalPriority = *pucFirstUserPriorityRegister;
/* Determine the number of priority bits available. First write to all
possible bits. */
*pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
/* Read the value back to see how many bits stuck. */
ucMaxPriorityValue = *pucFirstUserPriorityRegister;
/* Use the same mask on the maximum system call priority. */
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
/* Calculate the maximum acceptable priority group value for the number
of bits read back. */
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
{
ulMaxPRIGROUPValue--;
ucMaxPriorityValue <<= ( uint8_t ) 0x01;
}
#ifdef __NVIC_PRIO_BITS
{
/* Check the CMSIS configuration that defines the number of
priority bits matches the number of priority bits actually queried
from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS );
}
#endif
#ifdef configPRIO_BITS
{
/* Check the FreeRTOS configuration that defines the number of
priority bits matches the number of priority bits actually queried
from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS );
}
#endif
/* Shift the priority group value back to its position within the AIRCR
register. */
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
/* Restore the clobbered interrupt priority register to its original
value. */
*pucFirstUserPriorityRegister = ulOriginalPriority;
}
#endif /* conifgASSERT_DEFINED */
/* Make PendSV and SysTick the lowest priority interrupts. */
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
/* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */
vPortSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */
uxCriticalNesting = 0;
/* Ensure the VFP is enabled - it should be anyway. */
vPortEnableVFP();
/* Lazy save always. */
*( portFPCCR ) |= portASPEN_AND_LSPEN_BITS;
/* Start the first task. */
prvPortStartFirstTask();
/* Should never get here as the tasks will now be executing! Call the task
exit error function to prevent compiler warnings about a static function
not being called in the case that the application writer overrides this
functionality by defining configTASK_RETURN_ADDRESS. Call
vTaskSwitchContext() so link time optimisation does not remove the
symbol. */
vTaskSwitchContext();
prvTaskExitError();
/* Should not get here! */
return 0;
}
/*-----------------------------------------------------------*/
void vPortEndScheduler( void )
{
/* Not implemented in ports where there is nothing to return to.
Artificially force an assert. */
configASSERT( uxCriticalNesting == 1000UL );
}
/*-----------------------------------------------------------*/
void vPortEnterCritical( void )
{
portDISABLE_INTERRUPTS();
uxCriticalNesting++;
/* This is not the interrupt safe version of the enter critical function so
assert() if it is being called from an interrupt context. Only API
functions that end in "FromISR" can be used in an interrupt. Only assert if
the critical nesting count is 1 to protect against recursive calls if the
assert function also uses a critical section. */
if( uxCriticalNesting == 1 )
{
configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
}
}
/*-----------------------------------------------------------*/
void vPortExitCritical( void )
{
configASSERT( uxCriticalNesting );
uxCriticalNesting--;
if( uxCriticalNesting == 0 )
{
portENABLE_INTERRUPTS();
}
}
/*-----------------------------------------------------------*/
void xPortPendSVHandler( void )
{
/* This is a naked function. */
__asm volatile
(
" mrs r0, psp \n"
" isb \n"
" \n"
" ldr r3, pxCurrentTCBConst \n" /* Get the location of the current TCB. */
" ldr r2, [r3] \n"
" \n"
" tst r14, #0x10 \n" /* Is the task using the FPU context? If so, push high vfp registers. */
" it eq \n"
" vstmdbeq r0!, {s16-s31} \n"
" \n"
" stmdb r0!, {r4-r11, r14} \n" /* Save the core registers. */
" str r0, [r2] \n" /* Save the new top of stack into the first member of the TCB. */
" \n"
" stmdb sp!, {r0, r3} \n"
" mov r0, %0 \n"
" msr basepri, r0 \n"
" dsb \n"
" isb \n"
" bl vTaskSwitchContext \n"
" mov r0, #0 \n"
" msr basepri, r0 \n"
" ldmia sp!, {r0, r3} \n"
" \n"
" ldr r1, [r3] \n" /* The first item in pxCurrentTCB is the task top of stack. */
" ldr r0, [r1] \n"
" \n"
" ldmia r0!, {r4-r11, r14} \n" /* Pop the core registers. */
" \n"
" tst r14, #0x10 \n" /* Is the task using the FPU context? If so, pop the high vfp registers too. */
" it eq \n"
" vldmiaeq r0!, {s16-s31} \n"
" \n"
" msr psp, r0 \n"
" isb \n"
" \n"
#ifdef WORKAROUND_PMU_CM001 /* XMC4000 specific errata workaround. */
#if WORKAROUND_PMU_CM001 == 1
" push { r14 } \n"
" pop { pc } \n"
#endif
#endif
" \n"
" bx r14 \n"
" \n"
" .align 4 \n"
"pxCurrentTCBConst: .word pxCurrentTCB \n"
::"i"(configMAX_SYSCALL_INTERRUPT_PRIORITY)
);
}
/*-----------------------------------------------------------*/
void xPortSysTickHandler( void )
{
/* The SysTick runs at the lowest interrupt priority, so when this interrupt
executes all interrupts must be unmasked. There is therefore no need to
save and then restore the interrupt mask value as its value is already
known. */
portDISABLE_INTERRUPTS();
{
/* Increment the RTOS tick. */
if( xTaskIncrementTick() != pdFALSE )
{
/* A context switch is required. Context switching is performed in
the PendSV interrupt. Pend the PendSV interrupt. */
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
}
}
portENABLE_INTERRUPTS();
}
/*-----------------------------------------------------------*/
#if( configUSE_TICKLESS_IDLE == 1 )
__attribute__((weak)) void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{
uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
TickType_t xModifiableIdleTime;
/* Make sure the SysTick reload value does not overflow the counter. */
if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )
{
xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
}
/* Stop the SysTick momentarily. The time the SysTick is stopped for
is accounted for as best it can be, but using the tickless mode will
inevitably result in some tiny drift of the time maintained by the
kernel with respect to calendar time. */
portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;
/* Calculate the reload value required to wait xExpectedIdleTime
tick periods. -1 is used because this code will execute part way
through one of the tick periods. */
ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
if( ulReloadValue > ulStoppedTimerCompensation )
{
ulReloadValue -= ulStoppedTimerCompensation;
}
/* Enter a critical section but don't use the taskENTER_CRITICAL()
method as that will mask interrupts that should exit sleep mode. */
__asm volatile( "cpsid i" ::: "memory" );
__asm volatile( "dsb" );
__asm volatile( "isb" );
/* If a context switch is pending or a task is waiting for the scheduler
to be unsuspended then abandon the low power entry. */
if( eTaskConfirmSleepModeStatus() == eAbortSleep )
{
/* Restart from whatever is left in the count register to complete
this tick period. */
portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;
/* Restart SysTick. */
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
/* Reset the reload register to the value required for normal tick
periods. */
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
/* Re-enable interrupts - see comments above the cpsid instruction()
above. */
__asm volatile( "cpsie i" ::: "memory" );
}
else
{
/* Set the new reload value. */
portNVIC_SYSTICK_LOAD_REG = ulReloadValue;
/* Clear the SysTick count flag and set the count value back to
zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Restart SysTick. */
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
/* Sleep until something happens. configPRE_SLEEP_PROCESSING() can
set its parameter to 0 to indicate that its implementation contains
its own wait for interrupt or wait for event instruction, and so wfi
should not be executed again. However, the original expected idle
time variable must remain unmodified, so a copy is taken. */
xModifiableIdleTime = xExpectedIdleTime;
configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
if( xModifiableIdleTime > 0 )
{
__asm volatile( "dsb" ::: "memory" );
__asm volatile( "wfi" );
__asm volatile( "isb" );
}
configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Re-enable interrupts to allow the interrupt that brought the MCU
out of sleep mode to execute immediately. see comments above
__disable_interrupt() call above. */
__asm volatile( "cpsie i" ::: "memory" );
__asm volatile( "dsb" );
__asm volatile( "isb" );
/* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar
time. */
__asm volatile( "cpsid i" ::: "memory" );
__asm volatile( "dsb" );
__asm volatile( "isb" );
/* Disable the SysTick clock without reading the
portNVIC_SYSTICK_CTRL_REG register to ensure the
portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set. Again,
the time the SysTick is stopped for is accounted for as best it can
be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar
time*/
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
/* Determine if the SysTick clock has already counted to zero and
been set back to the current reload value (the reload back being
correct for the entire expected idle time) or if the SysTick is yet
to count to zero (in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{
uint32_t ulCalculatedLoadValue;
/* The tick interrupt is already pending, and the SysTick count
reloaded with ulReloadValue. Reset the
portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick
period. */
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );
/* Don't allow a tiny value, or values that have somehow
underflowed because the post sleep hook did something
that took too long. */
if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
{
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );
}
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* As the pending tick will be processed as soon as this
function exits, the tick value maintained by the tick is stepped
forward by one less than the time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
}
else
{
/* Something other than the tick interrupt ended the sleep.
Work out how long the sleep lasted rounded to complete tick
periods (not the ulReload value which accounted for part
ticks). */
ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;
/* How many complete tick periods passed while the processor
was waiting? */
ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;
/* The reload value is set to whatever fraction of a single tick
period remains. */
portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;
}
/* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG
again, then set portNVIC_SYSTICK_LOAD_REG back to its standard
value. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods );
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
/* Exit with interrpts enabled. */
__asm volatile( "cpsie i" ::: "memory" );
}
}
#endif /* #if configUSE_TICKLESS_IDLE */
/*-----------------------------------------------------------*/
/*
* Setup the systick timer to generate the tick interrupts at the required
* frequency.
*/
__attribute__(( weak )) void vPortSetupTimerInterrupt( void )
{
/* Calculate the constants required to configure the tick interrupt. */
#if( configUSE_TICKLESS_IDLE == 1 )
{
ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ );
}
#endif /* configUSE_TICKLESS_IDLE */
/* Stop and clear the SysTick. */
portNVIC_SYSTICK_CTRL_REG = 0UL;
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Configure SysTick to interrupt at the requested rate. */
portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );
}
/*-----------------------------------------------------------*/
/* This is a naked function. */
static void vPortEnableVFP( void )
{
__asm volatile
(
" ldr.w r0, =0xE000ED88 \n" /* The FPU enable bits are in the CPACR. */
" ldr r1, [r0] \n"
" \n"
" orr r1, r1, #( 0xf << 20 ) \n" /* Enable CP10 and CP11 coprocessors, then save back. */
" str r1, [r0] \n"
" bx r14 "
);
}
/*-----------------------------------------------------------*/
#if( configASSERT_DEFINED == 1 )
void vPortValidateInterruptPriority( void )
{
uint32_t ulCurrentInterrupt;
uint8_t ucCurrentPriority;
/* Obtain the number of the currently executing interrupt. */
__asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" );
/* Is the interrupt number a user defined interrupt? */
if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )
{
/* Look up the interrupt's priority. */
ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
/* The following assertion will fail if a service routine (ISR) for
an interrupt that has been assigned a priority above
configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
function. ISR safe FreeRTOS API functions must *only* be called
from interrupts that have been assigned a priority at or below
configMAX_SYSCALL_INTERRUPT_PRIORITY.
Numerically low interrupt priority numbers represent logically high
interrupt priorities, therefore the priority of the interrupt must
be set to a value equal to or numerically *higher* than
configMAX_SYSCALL_INTERRUPT_PRIORITY.
Interrupts that use the FreeRTOS API must not be left at their
default priority of zero as that is the highest possible priority,
which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,
and therefore also guaranteed to be invalid.
FreeRTOS maintains separate thread and ISR API functions to ensure
interrupt entry is as fast and simple as possible.
The following links provide detailed information:
http://www.freertos.org/RTOS-Cortex-M3-M4.html
http://www.freertos.org/FAQHelp.html */
configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );
}
/* Priority grouping: The interrupt controller (NVIC) allows the bits
that define each interrupt's priority to be split between bits that
define the interrupt's pre-emption priority bits and bits that define
the interrupt's sub-priority. For simplicity all bits must be defined
to be pre-emption priority bits. The following assertion will fail if
this is not the case (if some bits represent a sub-priority).
If the application only uses CMSIS libraries for interrupt
configuration then the correct setting can be achieved on all Cortex-M
devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the
scheduler. Note however that some vendor specific peripheral libraries
assume a non-zero priority group setting, in which cases using a value
of zero will result in unpredictable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
}
#endif /* configASSERT_DEFINED */
@@ -0,0 +1,242 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#ifdef __cplusplus
extern "C" {
#endif
/*-----------------------------------------------------------
* Port specific definitions.
*
* The settings in this file configure FreeRTOS correctly for the
* given hardware and compiler.
*
* These settings should not be altered.
*-----------------------------------------------------------
*/
/* Type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE uint32_t
#define portBASE_TYPE long
typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1
#endif
/*-----------------------------------------------------------*/
/* Architecture specifics. */
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 8
/*-----------------------------------------------------------*/
/* Scheduler utilities. */
#define portYIELD() \
{ \
/* Set a PendSV to request a context switch. */ \
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
\
/* Barriers are normally not required but do ensure the code is completely \
within the specified behaviour for the architecture. */ \
__asm volatile( "dsb" ::: "memory" ); \
__asm volatile( "isb" ); \
}
#define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/
/* Critical section management. */
extern void vPortEnterCritical( void );
extern void vPortExitCritical( void );
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x)
#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()
#define portENABLE_INTERRUPTS() vPortSetBASEPRI(0)
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are
not necessary for to use this port. They are defined so the common demo files
(which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/*-----------------------------------------------------------*/
/* Tickless idle/low power functionality. */
#ifndef portSUPPRESS_TICKS_AND_SLEEP
extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
#endif
/*-----------------------------------------------------------*/
/* Architecture specific optimisations. */
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Generic helper function. */
__attribute__( ( always_inline ) ) static inline uint8_t ucPortCountLeadingZeros( uint32_t ulBitmap )
{
uint8_t ucReturn;
__asm volatile ( "clz %0, %1" : "=r" ( ucReturn ) : "r" ( ulBitmap ) : "memory" );
return ucReturn;
}
/* Check the configuration. */
#if( configMAX_PRIORITIES > 32 )
#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.
#endif
/* Store/clear the ready priorities in a bit map. */
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
/*-----------------------------------------------------------*/
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( uint32_t ) ucPortCountLeadingZeros( ( uxReadyPriorities ) ) )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
/*-----------------------------------------------------------*/
#ifdef configASSERT
void vPortValidateInterruptPriority( void );
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
#endif
/* portNOP() is not required by this port. */
#define portNOP()
#define portINLINE __inline
#ifndef portFORCE_INLINE
#define portFORCE_INLINE inline __attribute__(( always_inline))
#endif
portFORCE_INLINE static BaseType_t xPortIsInsideInterrupt( void )
{
uint32_t ulCurrentInterrupt;
BaseType_t xReturn;
/* Obtain the number of the currently executing interrupt. */
__asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" );
if( ulCurrentInterrupt == 0 )
{
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
return xReturn;
}
/*-----------------------------------------------------------*/
portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;
__asm volatile
(
" mov %0, %1 \n" \
" msr basepri, %0 \n" \
" isb \n" \
" dsb \n" \
:"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
);
}
/*-----------------------------------------------------------*/
portFORCE_INLINE static uint32_t ulPortRaiseBASEPRI( void )
{
uint32_t ulOriginalBASEPRI, ulNewBASEPRI;
__asm volatile
(
" mrs %0, basepri \n" \
" mov %1, %2 \n" \
" msr basepri, %1 \n" \
" isb \n" \
" dsb \n" \
:"=r" (ulOriginalBASEPRI), "=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
);
/* This return will not be reached but is necessary to prevent compiler
warnings. */
return ulOriginalBASEPRI;
}
/*-----------------------------------------------------------*/
portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue )
{
__asm volatile
(
" msr basepri, %0 " :: "r" ( ulNewMaskValue ) : "memory"
);
}
/*-----------------------------------------------------------*/
#ifdef __cplusplus
}
#endif
#endif /* PORTMACRO_H */
@@ -0,0 +1,5 @@
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,2
[InternetShortcut]
URL=http://www.freertos.org/a00111.html
IDList=
@@ -0,0 +1,146 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/*
* The simplest possible implementation of pvPortMalloc(). Note that this
* implementation does NOT allow allocated memory to be freed again.
*
* See heap_2.c, heap_3.c and heap_4.c for alternative implementations, and the
* memory management pages of http://www.FreeRTOS.org for more information.
*/
#include <stdlib.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
all the API functions to use the MPU wrappers. That should only be done when
task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#include "FreeRTOS.h"
#include "task.h"
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#if( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
#endif
/* A few bytes might be lost to byte aligning the heap start address. */
#define configADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT )
/* Allocate the memory for the heap. */
#if( configAPPLICATION_ALLOCATED_HEAP == 1 )
/* The application writer has already defined the array used for the RTOS
heap - probably so it can be placed in a special segment or address. */
extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#else
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#endif /* configAPPLICATION_ALLOCATED_HEAP */
/* Index into the ucHeap array. */
static size_t xNextFreeByte = ( size_t ) 0;
/*-----------------------------------------------------------*/
void *pvPortMalloc( size_t xWantedSize )
{
void *pvReturn = NULL;
static uint8_t *pucAlignedHeap = NULL;
/* Ensure that blocks are always aligned to the required number of bytes. */
#if( portBYTE_ALIGNMENT != 1 )
{
if( xWantedSize & portBYTE_ALIGNMENT_MASK )
{
/* Byte alignment required. */
xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
}
}
#endif
vTaskSuspendAll();
{
if( pucAlignedHeap == NULL )
{
/* Ensure the heap starts on a correctly aligned boundary. */
pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
}
/* Check there is enough room left for the allocation. */
if( ( ( xNextFreeByte + xWantedSize ) < configADJUSTED_HEAP_SIZE ) &&
( ( xNextFreeByte + xWantedSize ) > xNextFreeByte ) )/* Check for overflow. */
{
/* Return the next free byte then increment the index past this
block. */
pvReturn = pucAlignedHeap + xNextFreeByte;
xNextFreeByte += xWantedSize;
}
traceMALLOC( pvReturn, xWantedSize );
}
( void ) xTaskResumeAll();
#if( configUSE_MALLOC_FAILED_HOOK == 1 )
{
if( pvReturn == NULL )
{
extern void vApplicationMallocFailedHook( void );
vApplicationMallocFailedHook();
}
}
#endif
return pvReturn;
}
/*-----------------------------------------------------------*/
void vPortFree( void *pv )
{
/* Memory cannot be freed using this scheme. See heap_2.c, heap_3.c and
heap_4.c for alternative implementations, and the memory management pages of
http://www.FreeRTOS.org for more information. */
( void ) pv;
/* Force an assert as it is invalid to call this function. */
configASSERT( pv == NULL );
}
/*-----------------------------------------------------------*/
void vPortInitialiseBlocks( void )
{
/* Only required when static memory is not cleared. */
xNextFreeByte = ( size_t ) 0;
}
/*-----------------------------------------------------------*/
size_t xPortGetFreeHeapSize( void )
{
return ( configADJUSTED_HEAP_SIZE - xNextFreeByte );
}
@@ -0,0 +1,272 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/*
* A sample implementation of pvPortMalloc() and vPortFree() that permits
* allocated blocks to be freed, but does not combine adjacent free blocks
* into a single larger block (and so will fragment memory). See heap_4.c for
* an equivalent that does combine adjacent blocks into single larger blocks.
*
* See heap_1.c, heap_3.c and heap_4.c for alternative implementations, and the
* memory management pages of http://www.FreeRTOS.org for more information.
*/
#include <stdlib.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
all the API functions to use the MPU wrappers. That should only be done when
task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#include "FreeRTOS.h"
#include "task.h"
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#if( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
#endif
/* A few bytes might be lost to byte aligning the heap start address. */
#define configADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT )
/*
* Initialises the heap structures before their first use.
*/
static void prvHeapInit( void );
/* Allocate the memory for the heap. */
#if( configAPPLICATION_ALLOCATED_HEAP == 1 )
/* The application writer has already defined the array used for the RTOS
heap - probably so it can be placed in a special segment or address. */
extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#else
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#endif /* configAPPLICATION_ALLOCATED_HEAP */
/* Define the linked list structure. This is used to link free blocks in order
of their size. */
typedef struct A_BLOCK_LINK
{
struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */
size_t xBlockSize; /*<< The size of the free block. */
} BlockLink_t;
static const uint16_t heapSTRUCT_SIZE = ( ( sizeof ( BlockLink_t ) + ( portBYTE_ALIGNMENT - 1 ) ) & ~portBYTE_ALIGNMENT_MASK );
#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( heapSTRUCT_SIZE * 2 ) )
/* Create a couple of list links to mark the start and end of the list. */
static BlockLink_t xStart, xEnd;
/* Keeps track of the number of free bytes remaining, but says nothing about
fragmentation. */
static size_t xFreeBytesRemaining = configADJUSTED_HEAP_SIZE;
/* STATIC FUNCTIONS ARE DEFINED AS MACROS TO MINIMIZE THE FUNCTION CALL DEPTH. */
/*
* Insert a block into the list of free blocks - which is ordered by size of
* the block. Small blocks at the start of the list and large blocks at the end
* of the list.
*/
#define prvInsertBlockIntoFreeList( pxBlockToInsert ) \
{ \
BlockLink_t *pxIterator; \
size_t xBlockSize; \
\
xBlockSize = pxBlockToInsert->xBlockSize; \
\
/* Iterate through the list until a block is found that has a larger size */ \
/* than the block we are inserting. */ \
for( pxIterator = &xStart; pxIterator->pxNextFreeBlock->xBlockSize < xBlockSize; pxIterator = pxIterator->pxNextFreeBlock ) \
{ \
/* There is nothing to do here - just iterate to the correct position. */ \
} \
\
/* Update the list to include the block being inserted in the correct */ \
/* position. */ \
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock; \
pxIterator->pxNextFreeBlock = pxBlockToInsert; \
}
/*-----------------------------------------------------------*/
void *pvPortMalloc( size_t xWantedSize )
{
BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
static BaseType_t xHeapHasBeenInitialised = pdFALSE;
void *pvReturn = NULL;
vTaskSuspendAll();
{
/* If this is the first call to malloc then the heap will require
initialisation to setup the list of free blocks. */
if( xHeapHasBeenInitialised == pdFALSE )
{
prvHeapInit();
xHeapHasBeenInitialised = pdTRUE;
}
/* The wanted size is increased so it can contain a BlockLink_t
structure in addition to the requested amount of bytes. */
if( xWantedSize > 0 )
{
xWantedSize += heapSTRUCT_SIZE;
/* Ensure that blocks are always aligned to the required number of bytes. */
if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0 )
{
/* Byte alignment required. */
xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
}
}
if( ( xWantedSize > 0 ) && ( xWantedSize < configADJUSTED_HEAP_SIZE ) )
{
/* Blocks are stored in byte order - traverse the list from the start
(smallest) block until one of adequate size is found. */
pxPreviousBlock = &xStart;
pxBlock = xStart.pxNextFreeBlock;
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
{
pxPreviousBlock = pxBlock;
pxBlock = pxBlock->pxNextFreeBlock;
}
/* If we found the end marker then a block of adequate size was not found. */
if( pxBlock != &xEnd )
{
/* Return the memory space - jumping over the BlockLink_t structure
at its start. */
pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE );
/* This block is being returned for use so must be taken out of the
list of free blocks. */
pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
/* If the block is larger than required it can be split into two. */
if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
{
/* This block is to be split into two. Create a new block
following the number of bytes requested. The void cast is
used to prevent byte alignment warnings from the compiler. */
pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );
/* Calculate the sizes of two blocks split from the single
block. */
pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
pxBlock->xBlockSize = xWantedSize;
/* Insert the new block into the list of free blocks. */
prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );
}
xFreeBytesRemaining -= pxBlock->xBlockSize;
}
}
traceMALLOC( pvReturn, xWantedSize );
}
( void ) xTaskResumeAll();
#if( configUSE_MALLOC_FAILED_HOOK == 1 )
{
if( pvReturn == NULL )
{
extern void vApplicationMallocFailedHook( void );
vApplicationMallocFailedHook();
}
}
#endif
return pvReturn;
}
/*-----------------------------------------------------------*/
void vPortFree( void *pv )
{
uint8_t *puc = ( uint8_t * ) pv;
BlockLink_t *pxLink;
if( pv != NULL )
{
/* The memory being freed will have an BlockLink_t structure immediately
before it. */
puc -= heapSTRUCT_SIZE;
/* This unexpected casting is to keep some compilers from issuing
byte alignment warnings. */
pxLink = ( void * ) puc;
vTaskSuspendAll();
{
/* Add this block to the list of free blocks. */
prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
xFreeBytesRemaining += pxLink->xBlockSize;
traceFREE( pv, pxLink->xBlockSize );
}
( void ) xTaskResumeAll();
}
}
/*-----------------------------------------------------------*/
size_t xPortGetFreeHeapSize( void )
{
return xFreeBytesRemaining;
}
/*-----------------------------------------------------------*/
void vPortInitialiseBlocks( void )
{
/* This just exists to keep the linker quiet. */
}
/*-----------------------------------------------------------*/
static void prvHeapInit( void )
{
BlockLink_t *pxFirstFreeBlock;
uint8_t *pucAlignedHeap;
/* Ensure the heap starts on a correctly aligned boundary. */
pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
/* xStart is used to hold a pointer to the first item in the list of free
blocks. The void cast is used to prevent compiler warnings. */
xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap;
xStart.xBlockSize = ( size_t ) 0;
/* xEnd is used to mark the end of the list of free blocks. */
xEnd.xBlockSize = configADJUSTED_HEAP_SIZE;
xEnd.pxNextFreeBlock = NULL;
/* To start with there is a single free block that is sized to take up the
entire heap space. */
pxFirstFreeBlock = ( void * ) pucAlignedHeap;
pxFirstFreeBlock->xBlockSize = configADJUSTED_HEAP_SIZE;
pxFirstFreeBlock->pxNextFreeBlock = &xEnd;
}
/*-----------------------------------------------------------*/
@@ -0,0 +1,97 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/*
* Implementation of pvPortMalloc() and vPortFree() that relies on the
* compilers own malloc() and free() implementations.
*
* This file can only be used if the linker is configured to to generate
* a heap memory area.
*
* See heap_1.c, heap_2.c and heap_4.c for alternative implementations, and the
* memory management pages of http://www.FreeRTOS.org for more information.
*/
#include <stdlib.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
all the API functions to use the MPU wrappers. That should only be done when
task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#include "FreeRTOS.h"
#include "task.h"
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#if( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
#endif
/*-----------------------------------------------------------*/
void *pvPortMalloc( size_t xWantedSize )
{
void *pvReturn;
vTaskSuspendAll();
{
pvReturn = malloc( xWantedSize );
traceMALLOC( pvReturn, xWantedSize );
}
( void ) xTaskResumeAll();
#if( configUSE_MALLOC_FAILED_HOOK == 1 )
{
if( pvReturn == NULL )
{
extern void vApplicationMallocFailedHook( void );
vApplicationMallocFailedHook();
}
}
#endif
return pvReturn;
}
/*-----------------------------------------------------------*/
void vPortFree( void *pv )
{
if( pv )
{
vTaskSuspendAll();
{
free( pv );
traceFREE( pv, 0 );
}
( void ) xTaskResumeAll();
}
}
@@ -0,0 +1,436 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/*
* A sample implementation of pvPortMalloc() and vPortFree() that combines
* (coalescences) adjacent memory blocks as they are freed, and in so doing
* limits memory fragmentation.
*
* See heap_1.c, heap_2.c and heap_3.c for alternative implementations, and the
* memory management pages of http://www.FreeRTOS.org for more information.
*/
#include <stdlib.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
all the API functions to use the MPU wrappers. That should only be done when
task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#include "FreeRTOS.h"
#include "task.h"
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#if( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
#endif
/* Block sizes must not get too small. */
#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( xHeapStructSize << 1 ) )
/* Assumes 8bit bytes! */
#define heapBITS_PER_BYTE ( ( size_t ) 8 )
/* Allocate the memory for the heap. */
#if( configAPPLICATION_ALLOCATED_HEAP == 1 )
/* The application writer has already defined the array used for the RTOS
heap - probably so it can be placed in a special segment or address. */
extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#else
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#endif /* configAPPLICATION_ALLOCATED_HEAP */
/* Define the linked list structure. This is used to link free blocks in order
of their memory address. */
typedef struct A_BLOCK_LINK
{
struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */
size_t xBlockSize; /*<< The size of the free block. */
} BlockLink_t;
/*-----------------------------------------------------------*/
/*
* Inserts a block of memory that is being freed into the correct position in
* the list of free memory blocks. The block being freed will be merged with
* the block in front it and/or the block behind it if the memory blocks are
* adjacent to each other.
*/
static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert );
/*
* Called automatically to setup the required heap structures the first time
* pvPortMalloc() is called.
*/
static void prvHeapInit( void );
/*-----------------------------------------------------------*/
/* The size of the structure placed at the beginning of each allocated memory
block must by correctly byte aligned. */
static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
/* Create a couple of list links to mark the start and end of the list. */
static BlockLink_t xStart, *pxEnd = NULL;
/* Keeps track of the number of free bytes remaining, but says nothing about
fragmentation. */
static size_t xFreeBytesRemaining = 0U;
static size_t xMinimumEverFreeBytesRemaining = 0U;
/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize
member of an BlockLink_t structure is set then the block belongs to the
application. When the bit is free the block is still part of the free heap
space. */
static size_t xBlockAllocatedBit = 0;
/*-----------------------------------------------------------*/
void *pvPortMalloc( size_t xWantedSize )
{
BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
void *pvReturn = NULL;
vTaskSuspendAll();
{
/* If this is the first call to malloc then the heap will require
initialisation to setup the list of free blocks. */
if( pxEnd == NULL )
{
prvHeapInit();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* Check the requested block size is not so large that the top bit is
set. The top bit of the block size member of the BlockLink_t structure
is used to determine who owns the block - the application or the
kernel, so it must be free. */
if( ( xWantedSize & xBlockAllocatedBit ) == 0 )
{
/* The wanted size is increased so it can contain a BlockLink_t
structure in addition to the requested amount of bytes. */
if( xWantedSize > 0 )
{
xWantedSize += xHeapStructSize;
/* Ensure that blocks are always aligned to the required number
of bytes. */
if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
{
/* Byte alignment required. */
xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
configASSERT( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) == 0 );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
{
/* Traverse the list from the start (lowest address) block until
one of adequate size is found. */
pxPreviousBlock = &xStart;
pxBlock = xStart.pxNextFreeBlock;
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
{
pxPreviousBlock = pxBlock;
pxBlock = pxBlock->pxNextFreeBlock;
}
/* If the end marker was reached then a block of adequate size
was not found. */
if( pxBlock != pxEnd )
{
/* Return the memory space pointed to - jumping over the
BlockLink_t structure at its start. */
pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );
/* This block is being returned for use so must be taken out
of the list of free blocks. */
pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
/* If the block is larger than required it can be split into
two. */
if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
{
/* This block is to be split into two. Create a new
block following the number of bytes requested. The void
cast is used to prevent byte alignment warnings from the
compiler. */
pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );
configASSERT( ( ( ( size_t ) pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );
/* Calculate the sizes of two blocks split from the
single block. */
pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
pxBlock->xBlockSize = xWantedSize;
/* Insert the new block into the list of free blocks. */
prvInsertBlockIntoFreeList( pxNewBlockLink );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
xFreeBytesRemaining -= pxBlock->xBlockSize;
if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
{
xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* The block is being returned - it is allocated and owned
by the application and has no "next" block. */
pxBlock->xBlockSize |= xBlockAllocatedBit;
pxBlock->pxNextFreeBlock = NULL;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
traceMALLOC( pvReturn, xWantedSize );
}
( void ) xTaskResumeAll();
#if( configUSE_MALLOC_FAILED_HOOK == 1 )
{
if( pvReturn == NULL )
{
extern void vApplicationMallocFailedHook( void );
vApplicationMallocFailedHook();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif
configASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) portBYTE_ALIGNMENT_MASK ) == 0 );
return pvReturn;
}
/*-----------------------------------------------------------*/
void vPortFree( void *pv )
{
uint8_t *puc = ( uint8_t * ) pv;
BlockLink_t *pxLink;
if( pv != NULL )
{
/* The memory being freed will have an BlockLink_t structure immediately
before it. */
puc -= xHeapStructSize;
/* This casting is to keep the compiler from issuing warnings. */
pxLink = ( void * ) puc;
/* Check the block is actually allocated. */
configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );
configASSERT( pxLink->pxNextFreeBlock == NULL );
if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )
{
if( pxLink->pxNextFreeBlock == NULL )
{
/* The block is being returned to the heap - it is no longer
allocated. */
pxLink->xBlockSize &= ~xBlockAllocatedBit;
vTaskSuspendAll();
{
/* Add this block to the list of free blocks. */
xFreeBytesRemaining += pxLink->xBlockSize;
traceFREE( pv, pxLink->xBlockSize );
prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
}
( void ) xTaskResumeAll();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
/*-----------------------------------------------------------*/
size_t xPortGetFreeHeapSize( void )
{
return xFreeBytesRemaining;
}
/*-----------------------------------------------------------*/
size_t xPortGetMinimumEverFreeHeapSize( void )
{
return xMinimumEverFreeBytesRemaining;
}
/*-----------------------------------------------------------*/
void vPortInitialiseBlocks( void )
{
/* This just exists to keep the linker quiet. */
}
/*-----------------------------------------------------------*/
static void prvHeapInit( void )
{
BlockLink_t *pxFirstFreeBlock;
uint8_t *pucAlignedHeap;
size_t uxAddress;
size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;
/* Ensure the heap starts on a correctly aligned boundary. */
uxAddress = ( size_t ) ucHeap;
if( ( uxAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
{
uxAddress += ( portBYTE_ALIGNMENT - 1 );
uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
xTotalHeapSize -= uxAddress - ( size_t ) ucHeap;
}
pucAlignedHeap = ( uint8_t * ) uxAddress;
/* xStart is used to hold a pointer to the first item in the list of free
blocks. The void cast is used to prevent compiler warnings. */
xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap;
xStart.xBlockSize = ( size_t ) 0;
/* pxEnd is used to mark the end of the list of free blocks and is inserted
at the end of the heap space. */
uxAddress = ( ( size_t ) pucAlignedHeap ) + xTotalHeapSize;
uxAddress -= xHeapStructSize;
uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
pxEnd = ( void * ) uxAddress;
pxEnd->xBlockSize = 0;
pxEnd->pxNextFreeBlock = NULL;
/* To start with there is a single free block that is sized to take up the
entire heap space, minus the space taken by pxEnd. */
pxFirstFreeBlock = ( void * ) pucAlignedHeap;
pxFirstFreeBlock->xBlockSize = uxAddress - ( size_t ) pxFirstFreeBlock;
pxFirstFreeBlock->pxNextFreeBlock = pxEnd;
/* Only one block exists - and it covers the entire usable heap space. */
xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
/* Work out the position of the top bit in a size_t variable. */
xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );
}
/*-----------------------------------------------------------*/
static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert )
{
BlockLink_t *pxIterator;
uint8_t *puc;
/* Iterate through the list until a block is found that has a higher address
than the block being inserted. */
for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )
{
/* Nothing to do here, just iterate to the right position. */
}
/* Do the block being inserted, and the block it is being inserted after
make a contiguous block of memory? */
puc = ( uint8_t * ) pxIterator;
if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )
{
pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
pxBlockToInsert = pxIterator;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* Do the block being inserted, and the block it is being inserted before
make a contiguous block of memory? */
puc = ( uint8_t * ) pxBlockToInsert;
if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )
{
if( pxIterator->pxNextFreeBlock != pxEnd )
{
/* Form one big block from the two blocks. */
pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
}
else
{
pxBlockToInsert->pxNextFreeBlock = pxEnd;
}
}
else
{
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
}
/* If the block being inserted plugged a gab, so was merged with the block
before and the block after, then it's pxNextFreeBlock pointer will have
already been set, and should not be set here as that would make it point
to itself. */
if( pxIterator != pxBlockToInsert )
{
pxIterator->pxNextFreeBlock = pxBlockToInsert;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
@@ -0,0 +1,485 @@
/*
* FreeRTOS Kernel V10.1.1
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/*
* A sample implementation of pvPortMalloc() that allows the heap to be defined
* across multiple non-contigous blocks and combines (coalescences) adjacent
* memory blocks as they are freed.
*
* See heap_1.c, heap_2.c, heap_3.c and heap_4.c for alternative
* implementations, and the memory management pages of http://www.FreeRTOS.org
* for more information.
*
* Usage notes:
*
* vPortDefineHeapRegions() ***must*** be called before pvPortMalloc().
* pvPortMalloc() will be called if any task objects (tasks, queues, event
* groups, etc.) are created, therefore vPortDefineHeapRegions() ***must*** be
* called before any other objects are defined.
*
* vPortDefineHeapRegions() takes a single parameter. The parameter is an array
* of HeapRegion_t structures. HeapRegion_t is defined in portable.h as
*
* typedef struct HeapRegion
* {
* uint8_t *pucStartAddress; << Start address of a block of memory that will be part of the heap.
* size_t xSizeInBytes; << Size of the block of memory.
* } HeapRegion_t;
*
* The array is terminated using a NULL zero sized region definition, and the
* memory regions defined in the array ***must*** appear in address order from
* low address to high address. So the following is a valid example of how
* to use the function.
*
* HeapRegion_t xHeapRegions[] =
* {
* { ( uint8_t * ) 0x80000000UL, 0x10000 }, << Defines a block of 0x10000 bytes starting at address 0x80000000
* { ( uint8_t * ) 0x90000000UL, 0xa0000 }, << Defines a block of 0xa0000 bytes starting at address of 0x90000000
* { NULL, 0 } << Terminates the array.
* };
*
* vPortDefineHeapRegions( xHeapRegions ); << Pass the array into vPortDefineHeapRegions().
*
* Note 0x80000000 is the lower address so appears in the array first.
*
*/
#include <stdlib.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
all the API functions to use the MPU wrappers. That should only be done when
task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#include "FreeRTOS.h"
#include "task.h"
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#if( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
#endif
/* Block sizes must not get too small. */
#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( xHeapStructSize << 1 ) )
/* Assumes 8bit bytes! */
#define heapBITS_PER_BYTE ( ( size_t ) 8 )
/* Define the linked list structure. This is used to link free blocks in order
of their memory address. */
typedef struct A_BLOCK_LINK
{
struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */
size_t xBlockSize; /*<< The size of the free block. */
} BlockLink_t;
/*-----------------------------------------------------------*/
/*
* Inserts a block of memory that is being freed into the correct position in
* the list of free memory blocks. The block being freed will be merged with
* the block in front it and/or the block behind it if the memory blocks are
* adjacent to each other.
*/
static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert );
/*-----------------------------------------------------------*/
/* The size of the structure placed at the beginning of each allocated memory
block must by correctly byte aligned. */
static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
/* Create a couple of list links to mark the start and end of the list. */
static BlockLink_t xStart, *pxEnd = NULL;
/* Keeps track of the number of free bytes remaining, but says nothing about
fragmentation. */
static size_t xFreeBytesRemaining = 0U;
static size_t xMinimumEverFreeBytesRemaining = 0U;
/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize
member of an BlockLink_t structure is set then the block belongs to the
application. When the bit is free the block is still part of the free heap
space. */
static size_t xBlockAllocatedBit = 0;
/*-----------------------------------------------------------*/
void *pvPortMalloc( size_t xWantedSize )
{
BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
void *pvReturn = NULL;
/* The heap must be initialised before the first call to
prvPortMalloc(). */
configASSERT( pxEnd );
vTaskSuspendAll();
{
/* Check the requested block size is not so large that the top bit is
set. The top bit of the block size member of the BlockLink_t structure
is used to determine who owns the block - the application or the
kernel, so it must be free. */
if( ( xWantedSize & xBlockAllocatedBit ) == 0 )
{
/* The wanted size is increased so it can contain a BlockLink_t
structure in addition to the requested amount of bytes. */
if( xWantedSize > 0 )
{
xWantedSize += xHeapStructSize;
/* Ensure that blocks are always aligned to the required number
of bytes. */
if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
{
/* Byte alignment required. */
xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
{
/* Traverse the list from the start (lowest address) block until
one of adequate size is found. */
pxPreviousBlock = &xStart;
pxBlock = xStart.pxNextFreeBlock;
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
{
pxPreviousBlock = pxBlock;
pxBlock = pxBlock->pxNextFreeBlock;
}
/* If the end marker was reached then a block of adequate size
was not found. */
if( pxBlock != pxEnd )
{
/* Return the memory space pointed to - jumping over the
BlockLink_t structure at its start. */
pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );
/* This block is being returned for use so must be taken out
of the list of free blocks. */
pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
/* If the block is larger than required it can be split into
two. */
if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
{
/* This block is to be split into two. Create a new
block following the number of bytes requested. The void
cast is used to prevent byte alignment warnings from the
compiler. */
pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );
/* Calculate the sizes of two blocks split from the
single block. */
pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
pxBlock->xBlockSize = xWantedSize;
/* Insert the new block into the list of free blocks. */
prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
xFreeBytesRemaining -= pxBlock->xBlockSize;
if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
{
xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* The block is being returned - it is allocated and owned
by the application and has no "next" block. */
pxBlock->xBlockSize |= xBlockAllocatedBit;
pxBlock->pxNextFreeBlock = NULL;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
traceMALLOC( pvReturn, xWantedSize );
}
( void ) xTaskResumeAll();
#if( configUSE_MALLOC_FAILED_HOOK == 1 )
{
if( pvReturn == NULL )
{
extern void vApplicationMallocFailedHook( void );
vApplicationMallocFailedHook();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif
return pvReturn;
}
/*-----------------------------------------------------------*/
void vPortFree( void *pv )
{
uint8_t *puc = ( uint8_t * ) pv;
BlockLink_t *pxLink;
if( pv != NULL )
{
/* The memory being freed will have an BlockLink_t structure immediately
before it. */
puc -= xHeapStructSize;
/* This casting is to keep the compiler from issuing warnings. */
pxLink = ( void * ) puc;
/* Check the block is actually allocated. */
configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );
configASSERT( pxLink->pxNextFreeBlock == NULL );
if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )
{
if( pxLink->pxNextFreeBlock == NULL )
{
/* The block is being returned to the heap - it is no longer
allocated. */
pxLink->xBlockSize &= ~xBlockAllocatedBit;
vTaskSuspendAll();
{
/* Add this block to the list of free blocks. */
xFreeBytesRemaining += pxLink->xBlockSize;
traceFREE( pv, pxLink->xBlockSize );
prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
}
( void ) xTaskResumeAll();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
/*-----------------------------------------------------------*/
size_t xPortGetFreeHeapSize( void )
{
return xFreeBytesRemaining;
}
/*-----------------------------------------------------------*/
size_t xPortGetMinimumEverFreeHeapSize( void )
{
return xMinimumEverFreeBytesRemaining;
}
/*-----------------------------------------------------------*/
static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert )
{
BlockLink_t *pxIterator;
uint8_t *puc;
/* Iterate through the list until a block is found that has a higher address
than the block being inserted. */
for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )
{
/* Nothing to do here, just iterate to the right position. */
}
/* Do the block being inserted, and the block it is being inserted after
make a contiguous block of memory? */
puc = ( uint8_t * ) pxIterator;
if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )
{
pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
pxBlockToInsert = pxIterator;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* Do the block being inserted, and the block it is being inserted before
make a contiguous block of memory? */
puc = ( uint8_t * ) pxBlockToInsert;
if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )
{
if( pxIterator->pxNextFreeBlock != pxEnd )
{
/* Form one big block from the two blocks. */
pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
}
else
{
pxBlockToInsert->pxNextFreeBlock = pxEnd;
}
}
else
{
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
}
/* If the block being inserted plugged a gab, so was merged with the block
before and the block after, then it's pxNextFreeBlock pointer will have
already been set, and should not be set here as that would make it point
to itself. */
if( pxIterator != pxBlockToInsert )
{
pxIterator->pxNextFreeBlock = pxBlockToInsert;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/*-----------------------------------------------------------*/
void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions )
{
BlockLink_t *pxFirstFreeBlockInRegion = NULL, *pxPreviousFreeBlock;
size_t xAlignedHeap;
size_t xTotalRegionSize, xTotalHeapSize = 0;
BaseType_t xDefinedRegions = 0;
size_t xAddress;
const HeapRegion_t *pxHeapRegion;
/* Can only call once! */
configASSERT( pxEnd == NULL );
pxHeapRegion = &( pxHeapRegions[ xDefinedRegions ] );
while( pxHeapRegion->xSizeInBytes > 0 )
{
xTotalRegionSize = pxHeapRegion->xSizeInBytes;
/* Ensure the heap region starts on a correctly aligned boundary. */
xAddress = ( size_t ) pxHeapRegion->pucStartAddress;
if( ( xAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
{
xAddress += ( portBYTE_ALIGNMENT - 1 );
xAddress &= ~portBYTE_ALIGNMENT_MASK;
/* Adjust the size for the bytes lost to alignment. */
xTotalRegionSize -= xAddress - ( size_t ) pxHeapRegion->pucStartAddress;
}
xAlignedHeap = xAddress;
/* Set xStart if it has not already been set. */
if( xDefinedRegions == 0 )
{
/* xStart is used to hold a pointer to the first item in the list of
free blocks. The void cast is used to prevent compiler warnings. */
xStart.pxNextFreeBlock = ( BlockLink_t * ) xAlignedHeap;
xStart.xBlockSize = ( size_t ) 0;
}
else
{
/* Should only get here if one region has already been added to the
heap. */
configASSERT( pxEnd != NULL );
/* Check blocks are passed in with increasing start addresses. */
configASSERT( xAddress > ( size_t ) pxEnd );
}
/* Remember the location of the end marker in the previous region, if
any. */
pxPreviousFreeBlock = pxEnd;
/* pxEnd is used to mark the end of the list of free blocks and is
inserted at the end of the region space. */
xAddress = xAlignedHeap + xTotalRegionSize;
xAddress -= xHeapStructSize;
xAddress &= ~portBYTE_ALIGNMENT_MASK;
pxEnd = ( BlockLink_t * ) xAddress;
pxEnd->xBlockSize = 0;
pxEnd->pxNextFreeBlock = NULL;
/* To start with there is a single free block in this region that is
sized to take up the entire heap region minus the space taken by the
free block structure. */
pxFirstFreeBlockInRegion = ( BlockLink_t * ) xAlignedHeap;
pxFirstFreeBlockInRegion->xBlockSize = xAddress - ( size_t ) pxFirstFreeBlockInRegion;
pxFirstFreeBlockInRegion->pxNextFreeBlock = pxEnd;
/* If this is not the first region that makes up the entire heap space
then link the previous region to this region. */
if( pxPreviousFreeBlock != NULL )
{
pxPreviousFreeBlock->pxNextFreeBlock = pxFirstFreeBlockInRegion;
}
xTotalHeapSize += pxFirstFreeBlockInRegion->xBlockSize;
/* Move onto the next HeapRegion_t structure. */
xDefinedRegions++;
pxHeapRegion = &( pxHeapRegions[ xDefinedRegions ] );
}
xMinimumEverFreeBytesRemaining = xTotalHeapSize;
xFreeBytesRemaining = xTotalHeapSize;
/* Check something was actually defined before it is accessed. */
configASSERT( xTotalHeapSize );
/* Work out the position of the top bit in a size_t variable. */
xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );
}
@@ -0,0 +1,20 @@
Each real time kernel port consists of three files that contain the core kernel
components and are common to every port, and one or more files that are
specific to a particular microcontroller and/or compiler.
+ The FreeRTOS/Source/Portable/MemMang directory contains the five sample
memory allocators as described on the http://www.FreeRTOS.org WEB site.
+ The other directories each contain files specific to a particular
microcontroller or compiler, where the directory name denotes the compiler
specific files the directory contains.
For example, if you are interested in the [compiler] port for the [architecture]
microcontroller, then the port specific files are contained in
FreeRTOS/Source/Portable/[compiler]/[architecture] directory. If this is the
only port you are interested in then all the other directories can be
ignored.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,17 @@
Each real time kernel port consists of three files that contain the core kernel
components and are common to every port, and one or more files that are
specific to a particular microcontroller and or compiler.
+ The FreeRTOS/Source directory contains the three files that are common to
every port - list.c, queue.c and tasks.c. The kernel is contained within these
three files. croutine.c implements the optional co-routine functionality - which
is normally only used on very memory limited systems.
+ The FreeRTOS/Source/Portable directory contains the files that are specific to
a particular microcontroller and or compiler.
+ The FreeRTOS/Source/include directory contains the real time kernel header
files.
See the readme file in the FreeRTOS/Source/Portable directory for more
information.
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
@@ -0,0 +1,21 @@
Directories:
+ The FreeRTOS/Source directory contains the FreeRTOS source code, and contains
its own readme file.
+ The FreeRTOS/Demo directory contains a demo application for every official
FreeRTOS port, and contains its own readme file.
+ See 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
application projects (found in the FreeRTOS/Demo directory). That way you will
have the correct FreeRTOS source files included, and the correct include paths
configured. Once a demo application is building and executing you can remove
the demo application file, and start to add in your own application source
files.
See also -
http://www.freertos.org/FreeRTOS-quick-start-guide.html
http://www.freertos.org/FAQHelp.html
+56
View File
@@ -0,0 +1,56 @@
#******************************************************************************
#
# Makefile - Rules for building the libraries, examples and docs.
#
# Copyright (c) 2020, Ambiq Micro
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# Third party software included in this distribution is subject to the
# additional license terms as defined in the /docs/licenses directory.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# This is part of revision 2.4.2 of the AmbiqSuite Development Package.
#
#******************************************************************************
SUBDIRS=${wildcard */}
all:
@for i in ${SUBDIRS}; \
do \
if [ -f $${i}/Makefile ]; then \
$(MAKE) -C $${i} || exit $$?; fi; \
done
clean:
@for i in ${SUBDIRS}; \
do \
if [ -f $${i}/Makefile ]; then \
$(MAKE) -C $${i} clean; fi; \
done
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,334 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Attribute protocol constants and definitions from the Bluetooth specification.
*
* Copyright (c) 2009-2019 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#ifndef ATT_DEFS_H
#define ATT_DEFS_H
#ifdef __cplusplus
extern "C" {
#endif
/*! \addtogroup STACK_ATT_API
* \{ */
/**************************************************************************************************
Macros
**************************************************************************************************/
/** \name ATT PDU Format
* ATT PDU defaults and constants
*/
/**@{*/
#define ATT_HDR_LEN 1 /*!< \brief Attribute PDU header length */
#define ATT_AUTH_SIG_LEN 12 /*!< \brief Authentication signature length */
#define ATT_DEFAULT_MTU 23 /*!< \brief Default value of ATT_MTU */
#define ATT_MAX_MTU 517 /*!< \brief Maximum value of ATT_MTU */
#define ATT_DEFAULT_PAYLOAD_LEN 20 /*!< \brief Default maximum payload length for most PDUs */
/**@}*/
/** \name ATT Maximum Value Parameters
* maximum values for ATT attribute length and offset
*/
/**@{*/
#define ATT_VALUE_MAX_LEN 512 /*!< \brief Maximum attribute value length */
#define ATT_VALUE_MAX_OFFSET 511 /*!< \brief Maximum attribute value offset */
/**@}*/
/** \name ATT Transaction Timeout
* Maximum time allowed between transaction request and response.
*/
/**@{*/
#define ATT_MAX_TRANS_TIMEOUT 30 /*!< \brief Maximum transaction timeout in seconds */
/**@}*/
/** \name ATT Error Codes
* ATT Protocol operation status codes found in PDUs
*/
/**@{*/
#define ATT_SUCCESS 0x00 /*!< \brief Operation successful */
#define ATT_ERR_HANDLE 0x01 /*!< \brief Invalid handle */
#define ATT_ERR_READ 0x02 /*!< \brief Read not permitted */
#define ATT_ERR_WRITE 0x03 /*!< \brief Write not permitted */
#define ATT_ERR_INVALID_PDU 0x04 /*!< \brief Invalid pdu */
#define ATT_ERR_AUTH 0x05 /*!< \brief Insufficient authentication */
#define ATT_ERR_NOT_SUP 0x06 /*!< \brief Request not supported */
#define ATT_ERR_OFFSET 0x07 /*!< \brief Invalid offset */
#define ATT_ERR_AUTHOR 0x08 /*!< \brief Insufficient authorization */
#define ATT_ERR_QUEUE_FULL 0x09 /*!< \brief Prepare queue full */
#define ATT_ERR_NOT_FOUND 0x0A /*!< \brief Attribute not found */
#define ATT_ERR_NOT_LONG 0x0B /*!< \brief Attribute not long */
#define ATT_ERR_KEY_SIZE 0x0C /*!< \brief Insufficient encryption key size */
#define ATT_ERR_LENGTH 0x0D /*!< \brief Invalid attribute value length */
#define ATT_ERR_UNLIKELY 0x0E /*!< \brief Other unlikely error */
#define ATT_ERR_ENC 0x0F /*!< \brief Insufficient encryption */
#define ATT_ERR_GROUP_TYPE 0x10 /*!< \brief Unsupported group type */
#define ATT_ERR_RESOURCES 0x11 /*!< \brief Insufficient resources */
#define ATT_ERR_DATABASE_OUT_OF_SYNC 0x12 /*!< \brief Client out of synch with database */
#define ATT_ERR_VALUE_NOT_ALLOWED 0x13 /*!< \brief Value not allowed */
#define ATT_ERR_WRITE_REJ 0xFC /*!< \brief Write request rejected */
#define ATT_ERR_CCCD 0xFD /*!< \brief CCCD improperly configured */
#define ATT_ERR_IN_PROGRESS 0xFE /*!< \brief Procedure already in progress */
#define ATT_ERR_RANGE 0xFF /*!< \brief Value out of range */
/**@}*/
/** \name Proprietary Internal Error Codes
* These codes may be sent to application but are not present in any ATT PDU.
*/
/**@{*/
#define ATT_ERR_MEMORY 0x70 /*!< \brief Out of memory */
#define ATT_ERR_TIMEOUT 0x71 /*!< \brief Transaction timeout */
#define ATT_ERR_OVERFLOW 0x72 /*!< \brief Transaction overflow */
#define ATT_ERR_INVALID_RSP 0x73 /*!< \brief Invalid response PDU */
#define ATT_ERR_CANCELLED 0x74 /*!< \brief Request cancelled */
#define ATT_ERR_UNDEFINED 0x75 /*!< \brief Other undefined error */
#define ATT_ERR_REQ_NOT_FOUND 0x76 /*!< \brief Required characteristic not found */
#define ATT_ERR_MTU_EXCEEDED 0x77 /*!< \brief Attribute PDU length exceeded MTU size */
#define ATT_CONTINUING 0x78 /*!< \brief Procedure continuing */
#define ATT_RSP_PENDING 0x79 /*!< \brief Responsed delayed pending higher layer */
/**@}*/
/** \name ATT Application Error Codes
* These codes may be sent to application but are not present in any ATT PDU.
*/
/**@{*/
#define ATT_ERR_VALUE_RANGE 0x80 /*!< \brief Value out of range */
/**@}*/
/** \name ATT HCI Error Status
*
*/
/**@{*/
/*! \brief Base value for HCI error status values passed through ATT.
* Since the values of HCI and ATT error codes overlap, the constant
* \ref ATT_HCI_ERR_BASE is added to HCI error codes before being passed through ATT.
* See \ref HCI_SUCCESS for HCI error code values.
*/
#define ATT_HCI_ERR_BASE 0x20
/**@}*/
/** \name ATT PDU Types
* PDU Types for all possible over-the-air ATT operations.
*/
/**@{*/
#define ATT_PDU_ERR_RSP 0x01 /*!< \brief Error response */
#define ATT_PDU_MTU_REQ 0x02 /*!< \brief Exchange mtu request */
#define ATT_PDU_MTU_RSP 0x03 /*!< \brief Exchange mtu response */
#define ATT_PDU_FIND_INFO_REQ 0x04 /*!< \brief Find information request */
#define ATT_PDU_FIND_INFO_RSP 0x05 /*!< \brief Find information response */
#define ATT_PDU_FIND_TYPE_REQ 0x06 /*!< \brief Find by type value request */
#define ATT_PDU_FIND_TYPE_RSP 0x07 /*!< \brief Find by type value response */
#define ATT_PDU_READ_TYPE_REQ 0x08 /*!< \brief Read by type request */
#define ATT_PDU_READ_TYPE_RSP 0x09 /*!< \brief Read by type response */
#define ATT_PDU_READ_REQ 0x0A /*!< \brief Read request */
#define ATT_PDU_READ_RSP 0x0B /*!< \brief Read response */
#define ATT_PDU_READ_BLOB_REQ 0x0C /*!< \brief Read blob request */
#define ATT_PDU_READ_BLOB_RSP 0x0D /*!< \brief Read blob response */
#define ATT_PDU_READ_MULT_REQ 0x0E /*!< \brief Read multiple request */
#define ATT_PDU_READ_MULT_RSP 0x0F /*!< \brief Read multiple response */
#define ATT_PDU_READ_GROUP_TYPE_REQ 0x10 /*!< \brief Read by group type request */
#define ATT_PDU_READ_GROUP_TYPE_RSP 0x11 /*!< \brief Read by group type response */
#define ATT_PDU_WRITE_REQ 0x12 /*!< \brief Write request */
#define ATT_PDU_WRITE_RSP 0x13 /*!< \brief Write response */
#define ATT_PDU_WRITE_CMD 0x52 /*!< \brief Write command */
#define ATT_PDU_SIGNED_WRITE_CMD 0xD2 /*!< \brief Signed write command */
#define ATT_PDU_PREP_WRITE_REQ 0x16 /*!< \brief Prepare write request */
#define ATT_PDU_PREP_WRITE_RSP 0x17 /*!< \brief Prepare write response */
#define ATT_PDU_EXEC_WRITE_REQ 0x18 /*!< \brief Execute write request */
#define ATT_PDU_EXEC_WRITE_RSP 0x19 /*!< \brief Execute write response */
#define ATT_PDU_VALUE_NTF 0x1B /*!< \brief Handle value notification */
#define ATT_PDU_VALUE_IND 0x1D /*!< \brief Handle value indication */
#define ATT_PDU_VALUE_CNF 0x1E /*!< \brief Handle value confirmation */
#define ATT_PDU_MAX 0x1F /*!< \brief PDU Maximum */
/**@}*/
/** \name ATT PDU Length Fields
* Length constants of PDU fixed length fields
*/
/**@{*/
#define ATT_ERR_RSP_LEN 5 /*!< \brief Error response length. */
#define ATT_MTU_REQ_LEN 3 /*!< \brief MTU request length. */
#define ATT_MTU_RSP_LEN 3 /*!< \brief MTU response length. */
#define ATT_FIND_INFO_REQ_LEN 5 /*!< \brief Find information request length. */
#define ATT_FIND_INFO_RSP_LEN 2 /*!< \brief Find information response length. */
#define ATT_FIND_TYPE_REQ_LEN 7 /*!< \brief Find type request length. */
#define ATT_FIND_TYPE_RSP_LEN 1 /*!< \brief Find type response length. */
#define ATT_READ_TYPE_REQ_LEN 5 /*!< \brief Read type request length. */
#define ATT_READ_TYPE_RSP_LEN 2 /*!< \brief Read type response length. */
#define ATT_READ_REQ_LEN 3 /*!< \brief Read request length. */
#define ATT_READ_RSP_LEN 1 /*!< \brief Read response length. */
#define ATT_READ_BLOB_REQ_LEN 5 /*!< \brief Read blob request legnth. */
#define ATT_READ_BLOB_RSP_LEN 1 /*!< \brief Read blob response length. */
#define ATT_READ_MULT_REQ_LEN 1 /*!< \brief Read multiple request length. */
#define ATT_READ_MULT_RSP_LEN 1 /*!< \brief Read multiple response length. */
#define ATT_READ_GROUP_TYPE_REQ_LEN 5 /*!< \brief Read group type request length. */
#define ATT_READ_GROUP_TYPE_RSP_LEN 2 /*!< \brief Read group type response length. */
#define ATT_WRITE_REQ_LEN 3 /*!< \brief Write request length. */
#define ATT_WRITE_RSP_LEN 1 /*!< \brief Write response length. */
#define ATT_WRITE_CMD_LEN 3 /*!< \brief Write command length. */
#define ATT_SIGNED_WRITE_CMD_LEN (ATT_WRITE_CMD_LEN + ATT_AUTH_SIG_LEN) /*!< \brief Signed write command length. */
#define ATT_PREP_WRITE_REQ_LEN 5 /*!< \brief Prepared write command length. */
#define ATT_PREP_WRITE_RSP_LEN 5 /*!< \brief Prepared write response length. */
#define ATT_EXEC_WRITE_REQ_LEN 2 /*!< \brief Execute write request length. */
#define ATT_EXEC_WRITE_RSP_LEN 1 /*!< \brief Execute write response length. */
#define ATT_VALUE_NTF_LEN 3 /*!< \brief Value notification length. */
#define ATT_VALUE_IND_LEN 3 /*!< \brief Value indication length. */
#define ATT_VALUE_CNF_LEN 1 /*!< \brief Value confirmation length. */
/**@}*/
/** \name ATT Find Information Response Format
*
*/
/**@{*/
#define ATT_FIND_HANDLE_16_UUID 0x01 /*!< \brief Handle and 16 bit UUID */
#define ATT_FIND_HANDLE_128_UUID 0x02 /*!< \brief Handle and 128 bit UUID */
/**@}*/
/** \name ATT Execute Write Request Flags
*
*/
/**@{*/
#define ATT_EXEC_WRITE_CANCEL 0x00 /*!< \brief Cancel all prepared writes */
#define ATT_EXEC_WRITE_ALL 0x01 /*!< \brief Write all pending prepared writes */
/**@}*/
/** \name ATT PDU Masks
*
*/
/**@{*/
#define ATT_PDU_MASK_SERVER 0x01 /*!< \brief Server bit mask */
#define ATT_PDU_MASK_COMMAND 0x40 /*!< \brief Command bit mask */
#define ATT_PDU_MASK_SIGNED 0x80 /*!< \brief Auth signature bit mask */
/**@}*/
/** \name ATT Handle Constants
* Invalid, minimum and maximum handle values.
*/
/**@{*/
#define ATT_HANDLE_NONE 0x0000 /*!< \brief Handle none. */
#define ATT_HANDLE_START 0x0001 /*!< \brief Handle start. */
#define ATT_HANDLE_MAX 0xFFFF /*!< \brief Handle max. */
/**@}*/
/** \name ATT UUID Lengths
*
*/
/**@{*/
#define ATT_NO_UUID_LEN 0 /*!< \brief Length when no UUID is present ;-) */
#define ATT_16_UUID_LEN 2 /*!< \brief Length in bytes of a 16 bit UUID */
#define ATT_128_UUID_LEN 16 /*!< \brief Length in bytes of a 128 bit UUID */
/**@}*/
/** \name GATT Characteristic Properties
* Properties for how a characteristic may be interacted with through the ATT Protocol.
*/
/**@{*/
#define ATT_PROP_BROADCAST 0x01 /*!< \brief Permit broadcasts */
#define ATT_PROP_READ 0x02 /*!< \brief Permit reads */
#define ATT_PROP_WRITE_NO_RSP 0x04 /*!< \brief Permit writes without response */
#define ATT_PROP_WRITE 0x08 /*!< \brief Permit writes with response */
#define ATT_PROP_NOTIFY 0x10 /*!< \brief Permit notifications */
#define ATT_PROP_INDICATE 0x20 /*!< \brief Permit indications */
#define ATT_PROP_AUTHENTICATED 0x40 /*!< \brief Permit signed writes */
#define ATT_PROP_EXTENDED 0x80 /*!< \brief More properties defined in extended properties */
/**@}*/
/** \name GATT Characteristic Extended Properties
*
*/
/**@{*/
#define ATT_EXT_PROP_RELIABLE_WRITE 0x0001 /*!< \brief Permit reliable writes */
#define ATT_EXT_PROP_WRITEABLE_AUX 0x0002 /*!< \brief Permit write to characteristic descriptor */
/**@}*/
/** \name GATT Client Charactertic Configuration
* Configures a characteristic to send notifications or indications, if applicable.
*/
/**@{*/
#define ATT_CLIENT_CFG_NOTIFY 0x0001 /*!< \brief Notify the value */
#define ATT_CLIENT_CFG_INDICATE 0x0002 /*!< \brief Indicate the value */
/**@}*/
/** \name GATT Server Characteristic Configuration
*
*/
/**@{*/
#define ATT_SERVER_CFG_BROADCAST 0x0001 /*!< \brief Broadcast the value */
/**@}*/
/** \name GATT Characteristic Format
* GATT Format descriptor values
*/
/**@{*/
#define ATT_FORMAT_BOOLEAN 0x01 /*!< \brief Boolean */
#define ATT_FORMAT_2BIT 0x02 /*!< \brief Unsigned 2 bit integer */
#define ATT_FORMAT_NIBBLE 0x03 /*!< \brief Unsigned 4 bit integer */
#define ATT_FORMAT_UINT8 0x04 /*!< \brief Unsigned 8 bit integer */
#define ATT_FORMAT_UINT12 0x05 /*!< \brief Unsigned 12 bit integer */
#define ATT_FORMAT_UINT16 0x06 /*!< \brief Unsigned 16 bit integer */
#define ATT_FORMAT_UINT24 0x07 /*!< \brief Unsigned 24 bit integer */
#define ATT_FORMAT_UINT32 0x08 /*!< \brief Unsigned 32 bit integer */
#define ATT_FORMAT_UINT48 0x09 /*!< \brief Unsigned 48 bit integer */
#define ATT_FORMAT_UINT64 0x0A /*!< \brief Unsigned 64 bit integer */
#define ATT_FORMAT_UINT128 0x0B /*!< \brief Unsigned 128 bit integer */
#define ATT_FORMAT_SINT8 0x0C /*!< \brief Signed 8 bit integer */
#define ATT_FORMAT_SINT12 0x0D /*!< \brief Signed 12 bit integer */
#define ATT_FORMAT_SINT16 0x0E /*!< \brief Signed 16 bit integer */
#define ATT_FORMAT_SINT24 0x0F /*!< \brief Signed 24 bit integer */
#define ATT_FORMAT_SINT32 0x10 /*!< \brief Signed 32 bit integer */
#define ATT_FORMAT_SINT48 0x11 /*!< \brief Signed 48 bit integer */
#define ATT_FORMAT_SINT64 0x12 /*!< \brief Signed 64 bit integer */
#define ATT_FORMAT_SINT128 0x13 /*!< \brief Signed 128 bit integer */
#define ATT_FORMAT_FLOAT32 0x14 /*!< \brief IEEE-754 32 bit floating point */
#define ATT_FORMAT_FLOAT64 0x15 /*!< \brief IEEE-754 64 bit floating point */
#define ATT_FORMAT_SFLOAT 0x16 /*!< \brief IEEE-11073 16 bit SFLOAT */
#define ATT_FORMAT_FLOAT 0x17 /*!< \brief IEEE-11073 32 bit FLOAT */
#define ATT_FORMAT_DUINT16 0x18 /*!< \brief IEEE-20601 format */
#define ATT_FORMAT_UTF8 0x19 /*!< \brief UTF-8 string */
#define ATT_FORMAT_UTF16 0x1A /*!< \brief UTF-16 string */
#define ATT_FORMAT_STRUCT 0x1B /*!< \brief Opaque structure */
/**@}*/
/** \name GATT Database Hash
* GATT database hash values
*/
/**@{*/
#define ATT_DATABASE_HASH_LEN 16 /*!< \brief Database hash length. */
/**@}*/
/** \name GATT Client Supported Features
* Flags of features supported by the GATT Client
*/
/**@{*/
#define ATTS_CSF_ROBUST_CACHING 1 /*!< \brief Robust caching. */
#define ATTS_CSF_OCT0_FEATURES ATTS_CSF_ROBUST_CACHING /*!< \brief Mask of all client supported features. */
#define ATT_CSF_LEN 1 /*!< \brief Length of client supported features array. */
/**@}*/
/*! \} */ /* STACK_ATT_API */
#ifdef __cplusplus
};
#endif
#endif /* ATT_DEFS_H */
@@ -0,0 +1,77 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Interface to ATT event handler.
*
* Copyright (c) 2009-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#ifndef ATT_HANDLER_H
#define ATT_HANDLER_H
#include "wsf_os.h"
#ifdef __cplusplus
extern "C" {
#endif
/*! \addtogroup STACK_EVENT
* \{ */
/** \name ATT Event Handling
* Message passing interface to ATT from other tasks through WSF.
*/
/**@{*/
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief ATT handler init function called during system initialization.
*
* \param handlerId WSF handler ID for ATT.
*
* \return None.
*/
/*************************************************************************************************/
void AttHandlerInit(wsfHandlerId_t handlerId);
/*************************************************************************************************/
/*!
* \brief WSF event handler for ATT.
*
* \param event WSF event mask.
* \param pMsg WSF message.
*
* \return None.
*/
/*************************************************************************************************/
void AttHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
/**@}*/
/*! \} */ /* STACK_EVENT */
#ifdef __cplusplus
};
#endif
#endif /* ATT_HANDLER_H */
@@ -0,0 +1,544 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Attribute protocol UUIDs from the Bluetooth specification.
*
* Copyright (c) 2011-2019 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#ifndef ATT_UUID_H
#define ATT_UUID_H
#include "att_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/*! \addtogroup STACK_ATT_API
* \{ */
/**************************************************************************************************
Macros
**************************************************************************************************/
/** \name ATT Service UUIDs
* Defined BLE Service UUID constants.
*/
/**@{*/
#define ATT_UUID_GAP_SERVICE 0x1800 /*!< \brief Generic Access Profile Service */
#define ATT_UUID_GATT_SERVICE 0x1801 /*!< \brief Generic Attribute Profile Service */
#define ATT_UUID_IMMEDIATE_ALERT_SERVICE 0x1802 /*!< \brief Immediate Alert Service */
#define ATT_UUID_LINK_LOSS_SERVICE 0x1803 /*!< \brief Link Loss Service */
#define ATT_UUID_TX_POWER_SERVICE 0x1804 /*!< \brief Tx Power Service */
#define ATT_UUID_CURRENT_TIME_SERVICE 0x1805 /*!< \brief Current Time Service */
#define ATT_UUID_REF_TIME_UPDATE_SERVICE 0x1806 /*!< \brief Reference Time Update Service */
#define ATT_UUID_DST_CHANGE_SERVICE 0x1807 /*!< \brief Next DST Change Service */
#define ATT_UUID_GLUCOSE_SERVICE 0x1808 /*!< \brief Glucose Service */
#define ATT_UUID_HEALTH_THERM_SERVICE 0x1809 /*!< \brief Health Thermometer Service */
#define ATT_UUID_DEVICE_INFO_SERVICE 0x180A /*!< \brief Device Information Service */
#define ATT_UUID_NETWORK_AVAIL_SERVICE 0x180B /*!< \brief Network Availability Service */
#define ATT_UUID_WATCHDOG_SERVICE 0x180C /*!< \brief Watchdog Service */
#define ATT_UUID_HEART_RATE_SERVICE 0x180D /*!< \brief Heart Rate Service */
#define ATT_UUID_PHONE_ALERT_SERVICE 0x180E /*!< \brief Phone Alert Status Service */
#define ATT_UUID_BATTERY_SERVICE 0x180F /*!< \brief Battery Service */
#define ATT_UUID_BLOOD_PRESSURE_SERVICE 0x1810 /*!< \brief Blood Pressure Service */
#define ATT_UUID_ALERT_NOTIF_SERVICE 0x1811 /*!< \brief Alert Notification Service */
#define ATT_UUID_HID_SERVICE 0x1812 /*!< \brief Human Interface Device Service */
#define ATT_UUID_SCAN_PARAM_SERVICE 0x1813 /*!< \brief Scan Parameter Service */
#define ATT_UUID_RUNNING_SPEED_SERVICE 0x1814 /*!< \brief Running Speed Service */
#define ATT_UUID_CYCLING_SPEED_SERVICE 0x1816 /*!< \brief Cycling Speed Service */
#define ATT_UUID_CYCLING_POWER_SERVICE 0x1818 /*!< \brief Cycling Power Service */
#define ATT_UUID_USER_DATA_SERVICE 0x181C /*!< \brief User Data Service */
#define ATT_UUID_WEIGHT_SCALE_SERVICE 0x181D /*!< \brief Weight Scale Service */
#define ATT_UUID_IP_SUPPORT_SERVICE 0x1820 /*!< \brief IP Support Service */
#define ATT_UUID_PULSE_OXIMITER_SERVICE 0x1822 /*!< \brief Pulse Oximeter Service */
#define ATT_UUID_MESH_PRV_SERVICE 0x1827 /*!< \brief Mesh Provisioning Service */
#define ATT_UUID_MESH_PROXY_SERVICE 0x1828 /*!< \brief Mesh Proxy Service */
#define ATT_UUID_CONSTANT_TONE_SERVICE 0x7F7F /*!< \brief Constant Tone Extension */
/**@}*/
/** \name GATT UUIDs
* BLE Defined UUIDs of GATT Service components
*/
/**@{*/
#define ATT_UUID_PRIMARY_SERVICE 0x2800 /*!< \brief Primary Service */
#define ATT_UUID_SECONDARY_SERVICE 0x2801 /*!< \brief Secondary Service */
#define ATT_UUID_INCLUDE 0x2802 /*!< \brief Include */
#define ATT_UUID_CHARACTERISTIC 0x2803 /*!< \brief Characteristic */
/**@}*/
/** \name GATT Characteristic Descriptor UUIDs
* BLE Defined UUIDs of Characteristic Descriptors
*/
/**@{*/
#define ATT_UUID_CHARACTERISTIC_EXT 0x2900 /*!< \brief Characteristic Extended Properties */
#define ATT_UUID_CHAR_USER_DESC 0x2901 /*!< \brief Characteristic User Description */
#define ATT_UUID_CLIENT_CHAR_CONFIG 0x2902 /*!< \brief Client Characteristic Configuration */
#define ATT_UUID_SERVER_CHAR_CONFIG 0x2903 /*!< \brief Server Characteristic Configuration */
#define ATT_UUID_CHAR_PRES_FORMAT 0x2904 /*!< \brief Characteristic Presentation Format */
#define ATT_UUID_AGGREGATE_FORMAT 0x2905 /*!< \brief Characteristic Aggregate Format */
#define ATT_UUID_VALID_RANGE 0x2906 /*!< \brief Valid Range */
#define ATT_UUID_HID_EXT_REPORT_MAPPING 0x2907 /*!< \brief HID External Report ID Mapping */
#define ATT_UUID_HID_REPORT_ID_MAPPING 0x2908 /*!< \brief HID Report ID Mapping */
/**@}*/
/** \name GATT Characistic UUIDs
* BLE Defined UUIDs of Characeristics
*/
/**@{*/
#define ATT_UUID_DEVICE_NAME 0x2A00 /*!< \brief Device Name */
#define ATT_UUID_APPEARANCE 0x2A01 /*!< \brief Appearance */
#define ATT_UUID_PERIPH_PRIVACY_FLAG 0x2A02 /*!< \brief Peripheral Privacy Flag */
#define ATT_UUID_RECONN_ADDR 0x2A03 /*!< \brief Reconnection Address */
#define ATT_UUID_PREF_CONN_PARAM 0x2A04 /*!< \brief Peripheral Preferred Connection Parameters */
#define ATT_UUID_SERVICE_CHANGED 0x2A05 /*!< \brief Service Changed */
#define ATT_UUID_ALERT_LEVEL 0x2A06 /*!< \brief Alert Level */
#define ATT_UUID_TX_POWER_LEVEL 0x2A07 /*!< \brief Tx Power Level */
#define ATT_UUID_DATE_TIME 0x2A08 /*!< \brief Date Time */
#define ATT_UUID_DAY_OF_WEEK 0x2A09 /*!< \brief Day of Week */
#define ATT_UUID_DAY_DATE_TIME 0x2A0A /*!< \brief Day Date Time */
#define ATT_UUID_EXACT_TIME_100 0x2A0B /*!< \brief Exact Time 100 */
#define ATT_UUID_EXACT_TIME_256 0x2A0C /*!< \brief Exact Time 256 */
#define ATT_UUID_DST_OFFSET 0x2A0D /*!< \brief DST Offset */
#define ATT_UUID_TIME_ZONE 0x2A0E /*!< \brief Time Zone */
#define ATT_UUID_LOCAL_TIME_INFO 0x2A0F /*!< \brief Local Time Information */
#define ATT_UUID_SECONDARY_TIME_ZONE 0x2A10 /*!< \brief Secondary Time Zone */
#define ATT_UUID_TIME_WITH_DST 0x2A11 /*!< \brief Time with DST */
#define ATT_UUID_TIME_ACCURACY 0x2A12 /*!< \brief Time Accuracy */
#define ATT_UUID_TIME_SOURCE 0x2A13 /*!< \brief Time Source */
#define ATT_UUID_REFERENCE_TIME_INFO 0x2A14 /*!< \brief Reference Time Information */
#define ATT_UUID_TIME_BROADCAST 0x2A15 /*!< \brief Time Broadcast */
#define ATT_UUID_TIME_UPDATE_CP 0x2A16 /*!< \brief Time Update Control Point */
#define ATT_UUID_TIME_UPDATE_STATE 0x2A17 /*!< \brief Time Update State */
#define ATT_UUID_GLUCOSE_MEAS 0x2A18 /*!< \brief Glucose Measurement */
#define ATT_UUID_BATTERY_LEVEL 0x2A19 /*!< \brief Battery Level */
#define ATT_UUID_BATTERY_POWER_STATE 0x2A1A /*!< \brief Battery Power State */
#define ATT_UUID_BATTERY_LEVEL_STATE 0x2A1B /*!< \brief Battery Level State */
#define ATT_UUID_TEMP_MEAS 0x2A1C /*!< \brief Temperature Measurement */
#define ATT_UUID_TEMP_TYPE 0x2A1D /*!< \brief Temperature Type */
#define ATT_UUID_INTERMEDIATE_TEMP 0x2A1E /*!< \brief Intermediate Temperature */
#define ATT_UUID_TEMP_C 0x2A1F /*!< \brief Temperature Celsius */
#define ATT_UUID_TEMP_F 0x2A20 /*!< \brief Temperature Fahrenheit */
#define ATT_UUID_MEAS_INTERVAL 0x2A21 /*!< \brief Measurement Interval */
#define ATT_UUID_HID_BOOT_KEYBOARD_IN 0x2A22 /*!< \brief HID Boot Keyboard In */
#define ATT_UUID_SYSTEM_ID 0x2A23 /*!< \brief System ID */
#define ATT_UUID_MODEL_NUMBER 0x2A24 /*!< \brief Model Number String */
#define ATT_UUID_SERIAL_NUMBER 0x2A25 /*!< \brief Serial Number String */
#define ATT_UUID_FIRMWARE_REV 0x2A26 /*!< \brief Firmware Revision String */
#define ATT_UUID_HARDWARE_REV 0x2A27 /*!< \brief Hardware Revision String */
#define ATT_UUID_SOFTWARE_REV 0x2A28 /*!< \brief Software Revision String */
#define ATT_UUID_MANUFACTURER_NAME 0x2A29 /*!< \brief Manufacturer Name String */
#define ATT_UUID_11073_CERT_DATA 0x2A2A /*!< \brief IEEE 11073-20601 Regulatory Certification Data List */
#define ATT_UUID_CURRENT_TIME 0x2A2B /*!< \brief Current Time */
#define ATT_UUID_ELEVATION 0x2A2C /*!< \brief Elevation */
#define ATT_UUID_LATITUDE 0x2A2D /*!< \brief Latitude */
#define ATT_UUID_LONGITUDE 0x2A2E /*!< \brief Longitude */
#define ATT_UUID_POSITION_2D 0x2A2F /*!< \brief Position 2D */
#define ATT_UUID_POSITION_3D 0x2A30 /*!< \brief Position 3D */
#define ATT_UUID_VENDOR_ID 0x2A31 /*!< \brief Vendor ID */
#define ATT_UUID_HID_BOOT_KEYBOARD_OUT 0x2A32 /*!< \brief HID Boot Keyboard Out */
#define ATT_UUID_HID_BOOT_MOUSE_IN 0x2A33 /*!< \brief HID Boot Mouse In */
#define ATT_UUID_GLUCOSE_MEAS_CONTEXT 0x2A34 /*!< \brief Glucose Measurement Context */
#define ATT_UUID_BP_MEAS 0x2A35 /*!< \brief Blood Pressure Measurement */
#define ATT_UUID_INTERMEDIATE_BP 0x2A36 /*!< \brief Intermediate Cuff Pressure */
#define ATT_UUID_HR_MEAS 0x2A37 /*!< \brief Heart Rate Measurement */
#define ATT_UUID_HR_SENSOR_LOC 0x2A38 /*!< \brief Body Sensor Location */
#define ATT_UUID_HR_CP 0x2A39 /*!< \brief Heart Rate Control Point */
#define ATT_UUID_REMOVABLE 0x2A3A /*!< \brief Removable */
#define ATT_UUID_SERVICE_REQ 0x2A3B /*!< \brief Service Required */
#define ATT_UUID_SCI_TEMP_C 0x2A3C /*!< \brief Scientific Temperature in Celsius */
#define ATT_UUID_STRING 0x2A3D /*!< \brief String */
#define ATT_UUID_NETWORK_AVAIL 0x2A3E /*!< \brief Network Availability */
#define ATT_UUID_ALERT_STATUS 0x2A3F /*!< \brief Alert Status */
#define ATT_UUID_RINGER_CP 0x2A40 /*!< \brief Ringer Control Point */
#define ATT_UUID_RINGER_SETTING 0x2A41 /*!< \brief Ringer Setting */
#define ATT_UUID_ALERT_CAT_ID_MASK 0x2A42 /*!< \brief Alert Category ID Bit Mask */
#define ATT_UUID_ALERT_CAT_ID 0x2A43 /*!< \brief Alert Category ID */
#define ATT_UUID_ALERT_NOTIF_CP 0x2A44 /*!< \brief Alert Notification Control Point */
#define ATT_UUID_UNREAD_ALERT_STATUS 0x2A45 /*!< \brief Unread Alert Status */
#define ATT_UUID_NEW_ALERT 0x2A46 /*!< \brief New Alert */
#define ATT_UUID_SUP_NEW_ALERT_CAT 0x2A47 /*!< \brief Supported New Alert Category */
#define ATT_UUID_SUP_UNREAD_ALERT_CAT 0x2A48 /*!< \brief Supported Unread Alert Category */
#define ATT_UUID_BP_FEATURE 0x2A49 /*!< \brief Blood Pressure Feature */
#define ATT_UUID_HID_INFORMATION 0x2A4A /*!< \brief HID Information */
#define ATT_UUID_HID_REPORT_MAP 0x2A4B /*!< \brief HID Report Map */
#define ATT_UUID_HID_CONTROL_POINT 0x2A4C /*!< \brief HID Control Point */
#define ATT_UUID_HID_REPORT 0x2A4D /*!< \brief HID Report */
#define ATT_UUID_HID_PROTOCOL_MODE 0x2A4E /*!< \brief HID Protocol Mode */
#define ATT_UUID_SCAN_INT_WIND 0x2A4F /*!< \brief Scan Interval Window */
#define ATT_UUID_PNP_ID 0x2A50 /*!< \brief PnP ID */
#define ATT_UUID_GLUCOSE_FEATURE 0x2A51 /*!< \brief Glucose Feature */
#define ATT_UUID_RACP 0x2A52 /*!< \brief Record Access Control Point */
#define ATT_UUID_CAR 0x2AA6 /*!< \brief Central Address Resolution */
#define ATT_UUID_RUNNING_SPEED_FEATURE 0x2A54 /*!< \brief Running Speed Feature */
#define ATT_UUID_RUNNING_SPEED_MEASUREMENT 0x2A53 /*!< \brief Running Speed Measurement */
#define ATT_UUID_PULSE_OX_FEATURES 0x2A60 /*!< \brief Pulse Oximeter Features */
#define ATT_UUID_PULSE_OX_SPOT_CHECK 0x2A5E /*!< \brief Pulse Oximeter Features */
#define ATT_UUID_PULSE_OX_CONTINUOUS 0x2A5F /*!< \brief Pulse Oximeter Features */
#define ATT_UUID_CYCLING_POWER_FEATURE 0x2A65 /*!< \brief Cycling Power Feature */
#define ATT_UUID_CYCLING_POWER_MEASUREMENT 0x2A63 /*!< \brief Cycling Power Measurement */
#define ATT_UUID_CYCLING_SPEED_FEATURE 0x2A5C /*!< \brief Cycling Speed Feature */
#define ATT_UUID_CYCLING_SPEED_MEASUREMENT 0x2A5B /*!< \brief Cycling Speed Measurement */
#define ATT_UUID_SENSOR_LOCATION 0x2A5D /*!< \brief Sensor Location */
#define ATT_UUID_DB_CHANGE_INCREMENT 0x2A99 /*!< \brief Database Change Increment */
#define ATT_UUID_USER_INDEX 0x2A9A /*!< \brief User Index */
#define ATT_UUID_WEIGHT_MEAS 0x2A9D /*!< \brief Weight Measurement */
#define ATT_UUID_WEIGHT_SCALE_FEATURE 0x2A9E /*!< \brief Weight Scale Feature */
#define ATT_UUID_USER_CONTROL_POINT 0x2A9F /*!< \brief User Control Point */
#define ATT_UUID_RPAO 0x2AC9 /*!< \brief Resolvable Prviate Address Only */
#define ATT_UUID_MESH_PRV_DATA_IN 0x2ADB /*!< \brief Mesh Provisioning Data In */
#define ATT_UUID_MESH_PRV_DATA_OUT 0x2ADC /*!< \brief Mesh Provisioning Data Out */
#define ATT_UUID_MESH_PROXY_DATA_IN 0x2ADD /*!< \brief Mesh Proxy Data In */
#define ATT_UUID_MESH_PROXY_DATA_OUT 0x2ADE /*!< \brief Mesh Proxy Data Out */
#define ATT_UUID_CLIENT_SUPPORTED_FEATURES 0x2B29 /*!< \brief Client Supported Features */
#define ATT_UUID_DATABASE_HASH 0x2B2A /*!< \brief Database Hash */
#define ATT_UUID_CTE_ENABLE 0x7F80 /*!< \brief Constant Tone Extension enable */
#define ATT_UUID_CTE_MIN_LEN 0x7F81 /*!< \brief Constant Tone Extension minimum length */
#define ATT_UUID_CTE_TX_CNT 0x7F82 /*!< \brief Constant Tone Extension transmit count */
#define ATT_UUID_CTE_TX_DURATION 0x7F83 /*!< \brief Constant Tone Extension transmit duration */
#define ATT_UUID_CTE_INTERVAL 0x7F84 /*!< \brief Constant Tone Extension interval */
#define ATT_UUID_CTE_PHY 0x7F85 /*!< \brief Constant Tone Extension PHY */
/**@}*/
/** \name GATT Unit UUIDs
* BLE Defined GATT Unit UUIDs.
*/
/**@{*/
#define ATT_UUID_UNITLESS 0x2700 /*!< \brief unitless */
#define ATT_UUID_LENGTH_M 0x2701 /*!< \brief length metre */
#define ATT_UUID_MASS_KG 0x2702 /*!< \brief mass kilogram */
#define ATT_UUID_TIME_SEC 0x2703 /*!< \brief time second */
#define ATT_UUID_ELECTRIC_CURRENT_AMP 0x2704 /*!< \brief electric current ampere */
#define ATT_UUID_THERMO_TEMP_K 0x2705 /*!< \brief thermodynamic temperature kelvin */
#define ATT_UUID_AMOUNT_OF_SUBSTANCE_MOLE 0x2706 /*!< \brief amount of substance mole */
#define ATT_UUID_LUMINOUS_INTENSITY_CAND 0x2707 /*!< \brief luminous intensity candela */
#define ATT_UUID_AREA_SQ_M 0x2710 /*!< \brief area square metres */
#define ATT_UUID_VOLUME_CU_M 0x2711 /*!< \brief volume cubic metres */
#define ATT_UUID_VELOCITY_MPS 0x2712 /*!< \brief velocity metres per second */
#define ATT_UUID_ACCELERATION_MPS_SQ 0x2713 /*!< \brief acceleration metres per second squared */
#define ATT_UUID_WAVENUMBER_RECIPROCAL_M 0x2714 /*!< \brief wavenumber reciprocal metre */
#define ATT_UUID_DENSITY_KG_PER_CU_M 0x2715 /*!< \brief density kilogram per cubic metre */
#define ATT_UUID_SURFACE_DENS_KG_PER_SQ_M 0x2716 /*!< \brief surface density kilogram per square metre */
#define ATT_UUID_SPECIFIC_VOL_CU_M_PER_KG 0x2717 /*!< \brief specific volume cubic metre per kilogram */
#define ATT_UUID_CURRENT_DENS_AMP_PER_SQ_M 0x2718 /*!< \brief current density ampere per square metre */
#define ATT_UUID_MAG_FIELD_STR_AMP_PER_M 0x2719 /*!< \brief magnetic field strength ampere per metre */
#define ATT_UUID_AMOUNT_CONC_MOLE_PER_CU_M 0x271A /*!< \brief amount concentration mole per cubic metre */
#define ATT_UUID_MASS_CONC_KG_PER_CU_M 0x271B /*!< \brief mass concentration kilogram per cubic metre */
#define ATT_UUID_LUM_CAND_PER_SQ_M 0x271C /*!< \brief luminance candela per square metre */
#define ATT_UUID_REFRACTIVE_INDEX 0x271D /*!< \brief refractive index */
#define ATT_UUID_RELATIVE_PERMEABILITY 0x271E /*!< \brief relative permeability */
#define ATT_UUID_PLANE_ANGLE_R 0x2720 /*!< \brief plane angle radian */
#define ATT_UUID_SOLID_ANGLE_STER 0x2721 /*!< \brief solid angle steradian */
#define ATT_UUID_FREQUENCY_HERTZ 0x2722 /*!< \brief frequency hertz */
#define ATT_UUID_FORCE_NEWT 0x2723 /*!< \brief force newton */
#define ATT_UUID_PRESSURE_PASCAL 0x2724 /*!< \brief pressure pascal */
#define ATT_UUID_ENERGY_J 0x2725 /*!< \brief energy joule */
#define ATT_UUID_POWER_W 0x2726 /*!< \brief power watt */
#define ATT_UUID_ELECTRIC_CHG_C 0x2727 /*!< \brief electric charge coulomb */
#define ATT_UUID_ELECTRIC_POTENTIAL_VOLT 0x2728 /*!< \brief electric potential difference volt */
#define ATT_UUID_CAPACITANCE_F 0x2729 /*!< \brief capacitance farad */
#define ATT_UUID_ELECTRIC_RESISTANCE_OHM 0x272A /*!< \brief electric resistance ohm */
#define ATT_UUID_ELECTRIC_COND_SIEMENS 0x272B /*!< \brief electric conductance siemens */
#define ATT_UUID_MAGNETIC_FLEX_WEBER 0x272C /*!< \brief magnetic flex weber */
#define ATT_UUID_MAGNETIC_FLEX_DENS_TESLA 0x272D /*!< \brief magnetic flex density tesla */
#define ATT_UUID_INDUCTANCE_H 0x272E /*!< \brief inductance henry */
#define ATT_UUID_C_TEMP_DEG_C 0x272F /*!< \brief Celsius temperature degree Celsius */
#define ATT_UUID_LUMINOUS_FLUX_LUMEN 0x2730 /*!< \brief luminous flux lumen */
#define ATT_UUID_ILLUMINANCE_LUX 0x2731 /*!< \brief illuminance lux */
#define ATT_UUID_RADIONUCLIDE_BECQUEREL 0x2732 /*!< \brief activity referred to a radionuclide becquerel */
#define ATT_UUID_ABSORBED_DOSE_GRAY 0x2733 /*!< \brief absorbed dose gray */
#define ATT_UUID_DOSE_EQUIVALENT_SIEVERT 0x2734 /*!< \brief dose equivalent sievert */
#define ATT_UUID_CATALYTIC_ACTIVITY_KATAL 0x2735 /*!< \brief catalytic activity katal */
#define ATT_UUID_DYNAMIC_VISC_PASCAL_SEC 0x2740 /*!< \brief dynamic viscosity pascal second */
#define ATT_UUID_MOMENT_OF_FORCE_NEWT_M 0x2741 /*!< \brief moment of force newton metre */
#define ATT_UUID_SURFACE_TENSION_NEWT_PER_M 0x2742 /*!< \brief surface tension newton per metre */
#define ATT_UUID_ANG_VELOCITY_R_PER_SEC 0x2743 /*!< \brief angular velocity radian per second */
#define ATT_UUID_ANG_ACCEL_R_PER_SEC_SQD 0x2744 /*!< \brief angular acceleration radian per second squared */
#define ATT_UUID_HEAT_FLUX_DEN_W_PER_SQ_M 0x2745 /*!< \brief heat flux density watt per square metre */
#define ATT_UUID_HEAT_CAP_J_PER_K 0x2746 /*!< \brief heat capacity joule per kelvin */
#define ATT_UUID_SPEC_HEAT_CAP_J_PER_KG_K 0x2747 /*!< \brief specific heat capacity joule per kilogram kelvin */
#define ATT_UUID_SPEC_ENERGY_J_PER_KG 0x2748 /*!< \brief specific energy joule per kilogram */
#define ATT_UUID_THERMAL_COND_W_PER_M_K 0x2749 /*!< \brief thermal conductivity watt per metre kelvin */
#define ATT_UUID_ENERGY_DENSITY_J_PER_CU_M 0x274A /*!< \brief energy density joule per cubic metre */
#define ATT_UUID_ELEC_FIELD_STR_VOLT_PER_M 0x274B /*!< \brief electric field strength volt per metre */
#define ATT_UUID_ELEC_CHG_DENS_C_PER_CU_M 0x274C /*!< \brief electric charge density coulomb per cubic metre */
#define ATT_UUID_SURF_CHG_DENS_C_PER_SQ_M 0x274D /*!< \brief surface charge density coulomb per square metre */
#define ATT_UUID_ELEC_FLUX_DENS_C_PER_SQ_M 0x274E /*!< \brief electric flux density coulomb per square metre */
#define ATT_UUID_PERMITTIVITY_F_PER_M 0x274F /*!< \brief permittivity farad per metre */
#define ATT_UUID_PERMEABILITY_H_PER_M 0x2750 /*!< \brief permeability henry per metre */
#define ATT_UUID_MOLAR_ENERGY_J_PER_MOLE 0x2751 /*!< \brief molar energy joule per mole */
#define ATT_UUID_MOLAR_ENTROPY_J_PER_MOLE_K 0x2752 /*!< \brief molar entropy joule per mole kelvin */
#define ATT_UUID_EXPOSURE_C_PER_KG 0x2753 /*!< \brief exposure coulomb per kilogram */
#define ATT_UUID_DOSE_RATE_GRAY_PER_SEC 0x2754 /*!< \brief absorbed dose rate gray per second */
#define ATT_UUID_RT_INTENSITY_W_PER_STER 0x2755 /*!< \brief radiant intensity watt per steradian */
#define ATT_UUID_RCE_W_PER_SQ_METER_STER 0x2756 /*!< \brief radiance watt per square meter steradian */
#define ATT_UUID_CATALYTIC_KATAL_PER_CU_M 0x2757 /*!< \brief catalytic activity concentration katal per cubic metre */
#define ATT_UUID_TIME_MIN 0x2760 /*!< \brief time minute */
#define ATT_UUID_TIME_HR 0x2761 /*!< \brief time hour */
#define ATT_UUID_TIME_DAY 0x2762 /*!< \brief time day */
#define ATT_UUID_PLANE_ANGLE_DEG 0x2763 /*!< \brief plane angle degree */
#define ATT_UUID_PLANE_ANGLE_MIN 0x2764 /*!< \brief plane angle minute */
#define ATT_UUID_PLANE_ANGLE_SEC 0x2765 /*!< \brief plane angle second */
#define ATT_UUID_AREA_HECTARE 0x2766 /*!< \brief area hectare */
#define ATT_UUID_VOLUME_L 0x2767 /*!< \brief volume litre */
#define ATT_UUID_MASS_TONNE 0x2768 /*!< \brief mass tonne */
#define ATT_UUID_PRESSURE_BAR 0x2780 /*!< \brief pressure bar */
#define ATT_UUID_PRESSURE_MM 0x2781 /*!< \brief pressure millimetre of mercury */
#define ATT_UUID_LENGTH_ANGSTROM 0x2782 /*!< \brief length angstrom */
#define ATT_UUID_LENGTH_NAUTICAL_MILE 0x2783 /*!< \brief length nautical mile */
#define ATT_UUID_AREA_BARN 0x2784 /*!< \brief area barn */
#define ATT_UUID_VELOCITY_KNOT 0x2785 /*!< \brief velocity knot */
#define ATT_UUID_LOG_RADIO_QUANT_NEPER 0x2786 /*!< \brief logarithmic radio quantity neper */
#define ATT_UUID_LOG_RADIO_QUANT_BEL 0x2787 /*!< \brief logarithmic radio quantity bel */
#define ATT_UUID_LOG_RADIO_QUANT_DB 0x2788 /*!< \brief logarithmic radio quantity decibel */
#define ATT_UUID_LENGTH_YARD 0x27A0 /*!< \brief length yard */
#define ATT_UUID_LENGTH_PARSEC 0x27A1 /*!< \brief length parsec */
#define ATT_UUID_LENGTH_IN 0x27A2 /*!< \brief length inch */
#define ATT_UUID_LENGTH_FOOT 0x27A3 /*!< \brief length foot */
#define ATT_UUID_LENGTH_MILE 0x27A4 /*!< \brief length mile */
#define ATT_UUID_PRESSURE_POUND_PER_SQ_IN 0x27A5 /*!< \brief pressure pound-force per square inch */
#define ATT_UUID_VELOCITY_KPH 0x27A6 /*!< \brief velocity kilometre per hour */
#define ATT_UUID_VELOCITY_MPH 0x27A7 /*!< \brief velocity mile per hour */
#define ATT_UUID_ANG_VELOCITY_RPM 0x27A8 /*!< \brief angular velocity revolution per minute */
#define ATT_UUID_ENERGY_GRAM_CALORIE 0x27A9 /*!< \brief energy gram calorie */
#define ATT_UUID_ENERGY_KG_CALORIE 0x27AA /*!< \brief energy kilogram calorie */
#define ATT_UUID_ENERGY_KILOWATT_HR 0x27AB /*!< \brief energy kilowatt hour */
#define ATT_UUID_THERM_TEMP_F 0x27AC /*!< \brief thermodynamic temperature degree Fahrenheit */
#define ATT_UUID_PERCENTAGE 0x27AD /*!< \brief percentage */
#define ATT_UUID_PER_MILLE 0x27AE /*!< \brief per mille */
#define ATT_UUID_PERIOD_BEATS_PER_MIN 0x27AF /*!< \brief period beats per minute */
#define ATT_UUID_ELECTRIC_CHG_AMP_HRS 0x27B0 /*!< \brief electric charge ampere hours */
#define ATT_UUID_MASS_DENSITY_MG_PER_DL 0x27B1 /*!< \brief mass density milligram per decilitre */
#define ATT_UUID_MASS_DENSITY_MMOLE_PER_L 0x27B2 /*!< \brief mass density millimole per litre */
#define ATT_UUID_TIME_YEAR 0x27B3 /*!< \brief time year */
#define ATT_UUID_TIME_MONTH 0x27B4 /*!< \brief time month */
/**@}*/
/** \name Arm Ltd. proprietary UUIDs
* propertietary services defined by Arm Ltd.
*/
/**@{*/
/*! \brief Base UUID: E0262760-08C2-11E1-9073-0E8AC72EXXXX */
#define ATT_UUID_ARM_BASE 0x2E, 0xC7, 0x8A, 0x0E, 0x73, 0x90, \
0xE1, 0x11, 0xC2, 0x08, 0x60, 0x27, 0x26, 0xE0
/*! \brief Macro for building Arm Ltd. UUIDs */
#define ATT_UUID_ARM_BUILD(part) UINT16_TO_BYTES(part), ATT_UUID_ARM_BASE
/** \brief Partial proprietary service P1 UUID */
#define ATT_UUID_P1_SERVICE_PART 0x1001
/** \brief Partial proprietary characteristic data D1 UUID */
#define ATT_UUID_D1_DATA_PART 0x0001
/*! \brief Proprietary services */
#define ATT_UUID_P1_SERVICE ATT_UUID_ARM_BUILD(ATT_UUID_P1_SERVICE_PART)
/*! \brief Proprietary characteristics */
#define ATT_UUID_D1_DATA ATT_UUID_ARM_BUILD(ATT_UUID_D1_DATA_PART)
/**@}*/
/**************************************************************************************************
Global Variables
**************************************************************************************************/
/** \name ATT Service UUID Variables
*
*/
/**@{*/
extern const uint8_t attGapSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Generic Access Profile Service */
extern const uint8_t attGattSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Generic Attribute Profile Service */
extern const uint8_t attIasSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Immediate Alert Service */
extern const uint8_t attLlsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Link Loss Service */
extern const uint8_t attTpsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Tx Power Service */
extern const uint8_t attCtsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Current Time Service */
extern const uint8_t attRtusSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Reference Time Update Service */
extern const uint8_t attNdcsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Next DST Change Service */
extern const uint8_t attGlsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Glucose Service */
extern const uint8_t attHtsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Health Thermometer Service */
extern const uint8_t attDisSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Device Information Service */
extern const uint8_t attNwaSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Network Availability Service */
extern const uint8_t attWdsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Watchdog Service */
extern const uint8_t attHrsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Heart Rate Service */
extern const uint8_t attPassSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Phone Alert Status Service */
extern const uint8_t attBasSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Battery Service */
extern const uint8_t attBpsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Blood Pressure Service */
extern const uint8_t attAnsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Alert Notification Service */
extern const uint8_t attHidSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Human Interface Device Service */
extern const uint8_t attSpsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Scan Parameter Service */
extern const uint8_t attPlxsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Pulse Oximeter Service */
extern const uint8_t attUdsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief User Data Service */
extern const uint8_t attMprvSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Mesh Provisioning Service */
extern const uint8_t attMprxSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Mesh Proxy Service */
/**@}*/
/** \name GATT UUID Variables
*
*/
/**@{*/
extern const uint8_t attPrimSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Primary Service */
extern const uint8_t attSecSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Secondary Service */
extern const uint8_t attIncUuid[ATT_16_UUID_LEN]; /*!< \brief Include */
extern const uint8_t attChUuid[ATT_16_UUID_LEN]; /*!< \brief Characteristic */
/**@}*/
/** \name GATT Characteristic Descriptor UUID Variables
*
*/
/**@{*/
extern const uint8_t attChExtUuid[ATT_16_UUID_LEN]; /*!< \brief Characteristic Extended Properties */
extern const uint8_t attChUserDescUuid[ATT_16_UUID_LEN]; /*!< \brief Characteristic User Description */
extern const uint8_t attCliChCfgUuid[ATT_16_UUID_LEN]; /*!< \brief Client Characteristic Configuration */
extern const uint8_t attSrvChCfgUuid[ATT_16_UUID_LEN]; /*!< \brief Server Characteristic Configuration */
extern const uint8_t attChPresFmtUuid[ATT_16_UUID_LEN]; /*!< \brief Characteristic Presentation Format */
extern const uint8_t attAggFmtUuid[ATT_16_UUID_LEN]; /*!< \brief Characteristic Aggregate Format */
extern const uint8_t attHidErmUuid[ATT_16_UUID_LEN]; /*!< \brief HID External Report Reference */
extern const uint8_t attHidRimUuid[ATT_16_UUID_LEN]; /*!< \brief HID Report ID Mapping */
extern const uint8_t attValRangeUuid[ATT_16_UUID_LEN]; /*!< \brief Valid Range */
/**@}*/
/** \name GATT Characteristic UUID Variables
*
*/
/**@{*/
extern const uint8_t attDnChUuid[ATT_16_UUID_LEN]; /*!< \brief Device Name */
extern const uint8_t attApChUuid[ATT_16_UUID_LEN]; /*!< \brief Appearance */
extern const uint8_t attPpfChUuid[ATT_16_UUID_LEN]; /*!< \brief Peripheral Privacy Flag */
extern const uint8_t attRaChUuid[ATT_16_UUID_LEN]; /*!< \brief Reconnection Address */
extern const uint8_t attPpcpChUuid[ATT_16_UUID_LEN]; /*!< \brief Peripheral Preferred Connection Parameters */
extern const uint8_t attScChUuid[ATT_16_UUID_LEN]; /*!< \brief Service Changed */
extern const uint8_t attAlChUuid[ATT_16_UUID_LEN]; /*!< \brief Alert Level */
extern const uint8_t attTxpChUuid[ATT_16_UUID_LEN]; /*!< \brief Tx Power Level */
extern const uint8_t attDtChUuid[ATT_16_UUID_LEN]; /*!< \brief Date Time */
extern const uint8_t attDwChUuid[ATT_16_UUID_LEN]; /*!< \brief Day of Week */
extern const uint8_t attDdtChUuid[ATT_16_UUID_LEN]; /*!< \brief Day Date Time */
extern const uint8_t attEt100ChUuid[ATT_16_UUID_LEN]; /*!< \brief Exact Time 100 */
extern const uint8_t attEt256ChUuid[ATT_16_UUID_LEN]; /*!< \brief Exact Time 256 */
extern const uint8_t attDstoChUuid[ATT_16_UUID_LEN]; /*!< \brief DST Offset */
extern const uint8_t attTzChUuid[ATT_16_UUID_LEN]; /*!< \brief Time Zone */
extern const uint8_t attLtiChUuid[ATT_16_UUID_LEN]; /*!< \brief Local Time Information */
extern const uint8_t attStzChUuid[ATT_16_UUID_LEN]; /*!< \brief Secondary Time Zone */
extern const uint8_t attTdstChUuid[ATT_16_UUID_LEN]; /*!< \brief Time with DST */
extern const uint8_t attTaChUuid[ATT_16_UUID_LEN]; /*!< \brief Time Accuracy */
extern const uint8_t attTsChUuid[ATT_16_UUID_LEN]; /*!< \brief Time Source */
extern const uint8_t attRtiChUuid[ATT_16_UUID_LEN]; /*!< \brief Reference Time Information */
extern const uint8_t attTbChUuid[ATT_16_UUID_LEN]; /*!< \brief Time Broadcast */
extern const uint8_t attTucpChUuid[ATT_16_UUID_LEN]; /*!< \brief Time Update Control Point */
extern const uint8_t attTusChUuid[ATT_16_UUID_LEN]; /*!< \brief Time Update State */
extern const uint8_t attGlmChUuid[ATT_16_UUID_LEN]; /*!< \brief Glucose Measurement */
extern const uint8_t attBlChUuid[ATT_16_UUID_LEN]; /*!< \brief Battery Level */
extern const uint8_t attBpsChUuid[ATT_16_UUID_LEN]; /*!< \brief Battery Power State */
extern const uint8_t attBlsChUuid[ATT_16_UUID_LEN]; /*!< \brief Battery Level State */
extern const uint8_t attTmChUuid[ATT_16_UUID_LEN]; /*!< \brief Temperature Measurement */
extern const uint8_t attTtChUuid[ATT_16_UUID_LEN]; /*!< \brief Temperature Type */
extern const uint8_t attItChUuid[ATT_16_UUID_LEN]; /*!< \brief Intermediate Temperature */
extern const uint8_t attTcelChUuid[ATT_16_UUID_LEN]; /*!< \brief Temperature Celsius */
extern const uint8_t attTfahChUuid[ATT_16_UUID_LEN]; /*!< \brief Temperature Fahrenheit */
extern const uint8_t attSidChUuid[ATT_16_UUID_LEN]; /*!< \brief System ID */
extern const uint8_t attMnsChUuid[ATT_16_UUID_LEN]; /*!< \brief Model Number String */
extern const uint8_t attSnsChUuid[ATT_16_UUID_LEN]; /*!< \brief Serial Number String */
extern const uint8_t attFrsChUuid[ATT_16_UUID_LEN]; /*!< \brief Firmware Revision String */
extern const uint8_t attHrsChUuid[ATT_16_UUID_LEN]; /*!< \brief Hardware Revision String */
extern const uint8_t attSrsChUuid[ATT_16_UUID_LEN]; /*!< \brief Software Revision String */
extern const uint8_t attMfnsChUuid[ATT_16_UUID_LEN]; /*!< \brief Manufacturer Name String */
extern const uint8_t attIeeeChUuid[ATT_16_UUID_LEN]; /*!< \brief IEEE 11073-20601 Regulatory Certification Data List */
extern const uint8_t attCtChUuid[ATT_16_UUID_LEN]; /*!< \brief Current Time */
extern const uint8_t attElChUuid[ATT_16_UUID_LEN]; /*!< \brief Elevation */
extern const uint8_t attLatChUuid[ATT_16_UUID_LEN]; /*!< \brief Latitude */
extern const uint8_t attLongChUuid[ATT_16_UUID_LEN]; /*!< \brief Longitude */
extern const uint8_t attP2dChUuid[ATT_16_UUID_LEN]; /*!< \brief Position 2D */
extern const uint8_t attP3dChUuid[ATT_16_UUID_LEN]; /*!< \brief Position 3D */
extern const uint8_t attVidChUuid[ATT_16_UUID_LEN]; /*!< \brief Vendor ID */
extern const uint8_t attGlmcChUuid[ATT_16_UUID_LEN]; /*!< \brief Glucose Measurement Context */
extern const uint8_t attBpmChUuid[ATT_16_UUID_LEN]; /*!< \brief Blood Pressure Measurement */
extern const uint8_t attIcpChUuid[ATT_16_UUID_LEN]; /*!< \brief Intermediate Cuff Pressure */
extern const uint8_t attHrmChUuid[ATT_16_UUID_LEN]; /*!< \brief Heart Rate Measurement */
extern const uint8_t attBslChUuid[ATT_16_UUID_LEN]; /*!< \brief Body Sensor Location */
extern const uint8_t attHrcpChUuid[ATT_16_UUID_LEN]; /*!< \brief Heart Rate Control Point */
extern const uint8_t attRemChUuid[ATT_16_UUID_LEN]; /*!< \brief Removable */
extern const uint8_t attSrChUuid[ATT_16_UUID_LEN]; /*!< \brief Service Required */
extern const uint8_t attStcChUuid[ATT_16_UUID_LEN]; /*!< \brief Scientific Temperature in Celsius */
extern const uint8_t attStrChUuid[ATT_16_UUID_LEN]; /*!< \brief String */
extern const uint8_t attNwaChUuid[ATT_16_UUID_LEN]; /*!< \brief Network Availability */
extern const uint8_t attAsChUuid[ATT_16_UUID_LEN]; /*!< \brief Alert Status */
extern const uint8_t attRcpChUuid[ATT_16_UUID_LEN]; /*!< \brief Ringer Control Point */
extern const uint8_t attRsChUuid[ATT_16_UUID_LEN]; /*!< \brief Ringer Setting */
extern const uint8_t attAcbmChUuid[ATT_16_UUID_LEN]; /*!< \brief Alert Category ID Bit Mask */
extern const uint8_t attAcChUuid[ATT_16_UUID_LEN]; /*!< \brief Alert Category ID */
extern const uint8_t attAncpChUuid[ATT_16_UUID_LEN]; /*!< \brief Alert Notification Control Point */
extern const uint8_t attUasChUuid[ATT_16_UUID_LEN]; /*!< \brief Unread Alert Status */
extern const uint8_t attNaChUuid[ATT_16_UUID_LEN]; /*!< \brief New Alert */
extern const uint8_t attSnacChUuid[ATT_16_UUID_LEN]; /*!< \brief Supported New Alert Category */
extern const uint8_t attSuacChUuid[ATT_16_UUID_LEN]; /*!< \brief Supported Unread Alert Category */
extern const uint8_t attBpfChUuid[ATT_16_UUID_LEN]; /*!< \brief Blood Pressure Feature */
extern const uint8_t attHidBmiChUuid[ATT_16_UUID_LEN]; /*!< \brief HID Information */
extern const uint8_t attHidBkiChUuid[ATT_16_UUID_LEN]; /*!< \brief HID Information */
extern const uint8_t attHidBkoChUuid[ATT_16_UUID_LEN]; /*!< \brief HID Information */
extern const uint8_t attHidiChUuid[ATT_16_UUID_LEN]; /*!< \brief HID Information */
extern const uint8_t attHidRmChUuid[ATT_16_UUID_LEN]; /*!< \brief Report Map */
extern const uint8_t attHidcpChUuid[ATT_16_UUID_LEN]; /*!< \brief HID Control Point */
extern const uint8_t attHidRepChUuid[ATT_16_UUID_LEN]; /*!< \brief Report */
extern const uint8_t attHidPmChUuid[ATT_16_UUID_LEN]; /*!< \brief Protocol Mode */
extern const uint8_t attSiwChUuid[ATT_16_UUID_LEN]; /*!< \brief Scan Interval Window */
extern const uint8_t attPnpChUuid[ATT_16_UUID_LEN]; /*!< \brief PnP ID */
extern const uint8_t attGlfChUuid[ATT_16_UUID_LEN]; /*!< \brief Glucose Feature */
extern const uint8_t attRacpChUuid[ATT_16_UUID_LEN]; /*!< \brief Record Access Control Point */
extern const uint8_t attCarChUuid[ATT_16_UUID_LEN]; /*!< \brief Central Address Resolution */
extern const uint8_t attRsfChUuid[ATT_16_UUID_LEN]; /*!< \brief Running Speed Features */
extern const uint8_t attRsmChUuid[ATT_16_UUID_LEN]; /*!< \brief Running Speed Measurement */
extern const uint8_t attCpfChUuid[ATT_16_UUID_LEN]; /*!< \brief Cycling Power Features */
extern const uint8_t attCpmChUuid[ATT_16_UUID_LEN]; /*!< \brief Cycling Power Measurement */
extern const uint8_t attCsfChUuid[ATT_16_UUID_LEN]; /*!< \brief Cycling Speed Features */
extern const uint8_t attCsmChUuid[ATT_16_UUID_LEN]; /*!< \brief Cycling Speed Measurement */
extern const uint8_t attSlChUuid[ATT_16_UUID_LEN]; /*!< \brief Sensor Location */
extern const uint8_t attPlxfChUuid[ATT_16_UUID_LEN]; /*!< \brief Pulse Oximeter Features */
extern const uint8_t attPlxscmChUuid[ATT_16_UUID_LEN]; /*!< \brief Pulse Oximeter Spot Check Measurement */
extern const uint8_t attPlxcmChUuid[ATT_16_UUID_LEN]; /*!< \brief Pulse Oximeter Continuous Measurement */
extern const uint8_t attRpaoChUuid[ATT_16_UUID_LEN]; /*!< \brief Resolvable Private Address Only */
extern const uint8_t attDbciChUuid[ATT_16_UUID_LEN]; /*!< \brief Database Change Increment */
extern const uint8_t attUiChUuid[ATT_16_UUID_LEN]; /*!< \brief User Index */
extern const uint8_t attUcpChUuid[ATT_16_UUID_LEN]; /*!< \brief User Control Point */
extern const uint8_t attMprvDinChUuid[ATT_16_UUID_LEN]; /*!< \brief Mesh Provisioning Data In */
extern const uint8_t attMprvDoutChUuid[ATT_16_UUID_LEN]; /*!< \brief Mesh Provisioning Data Out */
extern const uint8_t attMprxDinChUuid[ATT_16_UUID_LEN]; /*!< \brief Mesh Proxy Data In */
extern const uint8_t attMprxDoutChUuid[ATT_16_UUID_LEN]; /*!< \brief Mesh Proxy Data Out */
extern const uint8_t attWssSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Weight scale service */
extern const uint8_t attWmChUuid[ATT_16_UUID_LEN]; /*!< \brief Weight measurement */
extern const uint8_t attWsfChUuid[ATT_16_UUID_LEN]; /*!< \brief Weight scale feature */
extern const uint8_t attGattCsfChUuid[ATT_16_UUID_LEN]; /*!< \brief Client supported features */
extern const uint8_t attGattDbhChUuid[ATT_16_UUID_LEN]; /*!< \brief Database hash */
extern const uint8_t attCteSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Constant Tone Extension service */
extern const uint8_t attCteEnChUuid[ATT_16_UUID_LEN]; /*!< \brief Constant Tone Extension enable */
extern const uint8_t attCteMinLenChUuid[ATT_16_UUID_LEN];/*!< \brief Constant Tone Extension minimum length */
extern const uint8_t attCteTxCntChUuid[ATT_16_UUID_LEN]; /*!< \brief Constant Tone Extension minimum transmit count */
extern const uint8_t attCteTxDurChUuid[ATT_16_UUID_LEN]; /*!< \brief Constant Tone Extension transmit duration */
extern const uint8_t attCteIntChUuid[ATT_16_UUID_LEN]; /*!< \brief Constant Tone Extension interval */
extern const uint8_t attCtePhyChUuid[ATT_16_UUID_LEN]; /*!< \brief Constant Tone Extension PHY */
/**@}*/
/*! \} */ /* STACK_ATT_API */
#ifdef __cplusplus
};
#endif
#endif /* ATT_UUID_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,77 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Interface to DM event handler.
*
* Copyright (c) 2009-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#ifndef DM_HANDLER_H
#define DM_HANDLER_H
#include "wsf_os.h"
#ifdef __cplusplus
extern "C" {
#endif
/*! \addtogroup STACK_EVENT
* \{ */
/** \name DM Event Handling
* Message passing interface to DM from other tasks through WSF.
*/
/**@{*/
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief DM handler init function called during system initialization.
*
* \param handlerId WSF handler ID for DM.
*
* \return None.
*/
/*************************************************************************************************/
void DmHandlerInit(wsfHandlerId_t handlerId);
/*************************************************************************************************/
/*!
* \brief WSF event handler for DM.
*
* \param event WSF event mask.
* \param pMsg WSF message.
*
* \return None.
*/
/*************************************************************************************************/
void DmHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
/**@}*/
/*! \} */ /* STACK_DM_API */
#ifdef __cplusplus
};
#endif
#endif /* DM_HANDLER_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,95 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief HCI command module.
*
* Copyright (c) 2009-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#ifndef HCI_CMD_H
#define HCI_CMD_H
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief Send an HCI command and service the HCI command queue.
*
* \param pData Buffer containing HCI command to send or NULL.
*
* \return None.
*/
/*************************************************************************************************/
void hciCmdSend(uint8_t *pData);
/*************************************************************************************************/
/*!
* \brief Allocate an HCI command buffer and set the command header fields.
*
* \param opcode Command opcode.
* \param len length of command parameters.
*
* \return Pointer to WSF msg buffer.
*/
/*************************************************************************************************/
uint8_t *hciCmdAlloc(uint16_t opcode, uint16_t len);
/*************************************************************************************************/
/*!
* \brief Initialize the HCI cmd module.
*
* \return None.
*/
/*************************************************************************************************/
void hciCmdInit(void);
/*************************************************************************************************/
/*!
* \brief Process an HCI command timeout.
*
* \param pMsg Message.
*
* \return None.
*/
/*************************************************************************************************/
void hciCmdTimeout(wsfMsgHdr_t *pMsg);
/*************************************************************************************************/
/*!
* \brief Process an HCI Command Complete or Command Status event.
*
* \param numCmdPkts Number of commands that can be sent to the controller.
*
* \return None.
*/
/*************************************************************************************************/
void hciCmdRecvCmpl(uint8_t numCmdPkts);
#ifdef __cplusplus
};
#endif
#endif /* HCI_CMD_H */
@@ -0,0 +1,254 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief HCI core interfaces.
*
* Copyright (c) 2009-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#ifndef HCI_CORE_H
#define HCI_CORE_H
#include "hci_core_ps.h"
#include "wsf_queue.h"
#include "wsf_os.h"
#include "hci_api.h"
#include "cfg_stack.h"
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************************************
Callback Function Types
**************************************************************************************************/
/*! \brief HCI Reset sequence callback type */
typedef void(*hciResetSeq_t)(uint8_t *pMsg, uint16_t opcode);
/**************************************************************************************************
Data Types
**************************************************************************************************/
/*! \brief Per-connection structure for ACL packet accounting */
typedef struct
{
uint8_t *pTxAclPkt; /*!< \brief Fragmenting TX ACL packet pointer */
uint8_t *pNextTxFrag; /*!< \brief Next TX ACL packet fragment */
uint8_t *pRxAclPkt; /*!< \brief RX ACL packet pointer */
uint8_t *pNextRxFrag; /*!< \brief Next RX ACL packet fragment */
uint16_t handle; /*!< \brief Connection handle */
uint16_t txAclRemLen; /*!< \brief Fragmenting TX ACL packet remaining length */
uint16_t rxAclRemLen; /*!< \brief Fragmented RX ACL packet remaining length */
bool_t fragmenting; /*!< \brief TRUE if fragmenting a TX ACL packet */
bool_t flowDisabled; /*!< \brief TRUE if data flow disabled */
uint8_t queuedBufs; /*!< \brief Queued ACL buffers on this connection */
uint8_t outBufs; /*!< \brief Outstanding ACL buffers sent to controller */
} hciCoreConn_t;
/*! \brief Main control block for dual-chip implementation */
typedef struct
{
hciCoreConn_t conn[DM_CONN_MAX]; /*!< \brief Connection structures */
uint8_t leStates[HCI_LE_STATES_LEN]; /*!< \brief Controller LE supported states */
bdAddr_t bdAddr; /*!< \brief Bluetooth device address */
wsfQueue_t aclQueue; /*!< \brief HCI ACL TX queue */
hciCoreConn_t *pConnRx; /*!< \brief Connection struct for current transport RX packet */
uint16_t maxRxAclLen; /*!< \brief Maximum reassembled RX ACL packet length */
uint16_t bufSize; /*!< \brief Controller ACL data buffer size */
uint8_t aclQueueHi; /*!< \brief Disable flow when this many ACL buffers queued */
uint8_t aclQueueLo; /*!< \brief Enable flow when this many ACL buffers queued */
uint8_t availBufs; /*!< \brief Current avail ACL data buffers */
uint8_t numBufs; /*!< \brief Controller number of ACL data buffers */
uint8_t whiteListSize; /*!< \brief Controller white list size */
uint8_t numCmdPkts; /*!< \brief Controller command packed count */
uint32_t leSupFeat; /*!< \brief Controller LE supported features */
int8_t advTxPwr; /*!< \brief Controller advertising TX power */
uint8_t resListSize; /*!< \brief Controller resolving list size */
uint16_t maxAdvDataLen; /*!< \brief Controller maximum advertisement (or scan response) data length */
uint8_t numSupAdvSets; /*!< \brief Controller maximum number of advertising sets */
uint8_t perAdvListSize; /*!< \brief Controller periodic advertising list size */
hciLocalVerInfo_t locVerInfo; /*!< \brief Controller version information */
hciResetSeq_t extResetSeq; /*!< \brief HCI extended reset sequence callback */
} hciCoreCb_t;
/**************************************************************************************************
Global Variables
**************************************************************************************************/
/*! \brief Control block */
extern hciCoreCb_t hciCoreCb;
/*! \brief Event mask */
extern const uint8_t hciEventMask[HCI_EVT_MASK_LEN];
/*! \brief LE event mask */
extern const uint8_t hciLeEventMask[HCI_LE_EVT_MASK_LEN];
/*! \brief Event mask page 2 */
extern const uint8_t hciEventMaskPage2[HCI_EVT_MASK_LEN];
/*! \brief LE supported features configuration mask */
extern uint32_t hciLeSupFeatCfg;
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief HCI core initialization.
*
* \return None.
*/
/*************************************************************************************************/
void hciCoreInit(void);
/*************************************************************************************************/
/*!
* \fn hciCoreResetStart
*
* \brief Start the HCI reset sequence.
*
* \return None.
*/
/*************************************************************************************************/
void hciCoreResetStart(void);
/*************************************************************************************************/
/*!
* \brief Perform internal processing on HCI connection open.
*
* \param handle Connection handle.
*
* \return None.
*/
/*************************************************************************************************/
void hciCoreConnOpen(uint16_t handle);
/*************************************************************************************************/
/*!
* \brief Perform internal processing on HCI connection close.
*
* \param handle Connection handle.
*
* \return None.
*/
/*************************************************************************************************/
void hciCoreConnClose(uint16_t handle);
/*************************************************************************************************/
/*!
* \brief Get a connection structure by handle
*
* \param handle Connection handle.
*
* \return Pointer to connection structure or NULL if not found.
*/
/*************************************************************************************************/
hciCoreConn_t *hciCoreConnByHandle(uint16_t handle);
/*************************************************************************************************/
/*!
* \brief Send ACL data to transport.
*
* \param pConn Pointer to connection structure.
* \param pData WSF buffer containing an ACL packet.
*
* \return None.
*/
/*************************************************************************************************/
void hciCoreSendAclData(hciCoreConn_t *pConn, uint8_t *pData);
/*************************************************************************************************/
/*!
* \brief Service the TX data path.
*
* \param bufs Number of new buffers now available.
*
* \return None.
*/
/*************************************************************************************************/
void hciCoreTxReady(uint8_t bufs);
/*************************************************************************************************/
/*!
* \brief Send ACL packets, start of packet.
*
* \param pConn Pointer to connection structure.
* \param len ACL packet length.
* \param pData WSF buffer containing an ACL packet.
*
* \return None.
*/
/*************************************************************************************************/
void hciCoreTxAclStart(hciCoreConn_t *pConn, uint16_t len, uint8_t *pData);
/*************************************************************************************************/
/*!
* \brief Send ACL packets, continuation of fragmented packets.
*
* \param pConn Pointer to connection structure. If set non-NULL, then a fragment is
* sent from this connection structure. If NULL the function finds the next
* connection structure with a fragment to be sent.
*
* \return TRUE if packet sent, FALSE otherwise.
*/
/*************************************************************************************************/
bool_t hciCoreTxAclContinue(hciCoreConn_t *pConn);
/*************************************************************************************************/
/*!
* \brief This function is called from the HCI transport layer when transmission of an ACL
* packet is complete.
*
* \param pConn Pointer to connection structure.
* \param pData WSF buffer containing an ACL packet.
*
* \return None.
*/
/*************************************************************************************************/
void hciCoreTxAclComplete(hciCoreConn_t *pConn, uint8_t *pData);
/*************************************************************************************************/
/*!
* \brief Reassemble an ACL packet.
*
* \param pData Input ACL packet.
*
* \return pointer to ACL packet to send, or NULL if no packet to send.
*/
/*************************************************************************************************/
uint8_t *hciCoreAclReassembly(uint8_t *pData);
/*************************************************************************************************/
/*!
* \brief Check if a TX ACL packet is being fragmented.
*
* \param pConn Connection context.
*
* \return TRUE if fragmenting a TX ACL packet, FALSE otherwise.
*/
/*************************************************************************************************/
bool_t hciCoreTxAclDataFragmented(hciCoreConn_t *pConn);
#ifdef __cplusplus
};
#endif
#endif /* HCI_CORE_H */
@@ -0,0 +1,76 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief HCI driver interface.
*
* Copyright (c) 2012-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#ifndef HCI_DRV_H
#define HCI_DRV_H
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief Write data the driver.
*
* \param type HCI packet type
* \param len Number of bytes to write.
* \param pData Byte array to write.
*
* \return Return actual number of data bytes written.
*
* \note The type parameter allows the driver layer to prepend the data with a header on the
* same write transaction.
*/
/*************************************************************************************************/
uint16_t hciDrvWrite(uint8_t type, uint16_t len, uint8_t *pData);
/*************************************************************************************************/
/*!
* \brief Read data bytes from the driver.
*
* \param len Number of bytes to read.
* \param pData Byte array to store data.
*
* \return Return actual number of data bytes read.
*/
/*************************************************************************************************/
uint16_t hciDrvRead(uint16_t len, uint8_t *pData);
/*************************************************************************************************/
/*!
* \brief Returns TRUE if driver allows MCU to enter low power sleep mode.
*
* \return TRUE if ready to sleep, FALSE otherwise.
*/
/*************************************************************************************************/
bool_t hciDrvReadyToSleep(void);
#ifdef __cplusplus
};
#endif
#endif /* HCI_DRV_H */
@@ -0,0 +1,86 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief HCI event module.
*
* Copyright (c) 2009-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#ifndef HCI_EVT_H
#define HCI_EVT_H
#ifdef __cplusplus
extern "C" {
#endif
/*! \addtogroup STACK_HCI_API
* \{ */
/**************************************************************************************************
Data Types
**************************************************************************************************/
/*! \brief HCI event statistics */
typedef struct
{
uint16_t numDiscCmplEvt; /*!< \brief Number discovery complete events. */
uint16_t numEncChangeEvt; /*!< \brief Number encryption change events. */
uint16_t numReadRemoteVerInfoCmpEvt; /*!< \brief Number read remote version info complete events. */
uint16_t numCmdCmplEvt; /*!< \brief Number command complete events. */
uint16_t numCmdStatusEvt; /*!< \brief Number command status events. */
uint16_t numHwErrorEvt; /*!< \brief Number hardware error events. */
uint16_t numCmplPktsEvt; /*!< \brief Number complete packet events. */
uint16_t numDataBufOverflowEvt; /*!< \brief Number data buf overflow events. */
uint16_t numEncKeyRefreshCmplEvt; /*!< \brief Number encryption key refresh complete events. */
uint16_t numLeMetaEvt; /*!< \brief Number LE meta events. */
uint16_t numVendorSpecEvt; /*!< \brief Number vendor specific events. */
uint16_t numAuthToEvt; /*!< \brief Number authenticated to events. */
} hciEvtStats_t;
/*! \} */ /* STACK_HCI_API */
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief Process received HCI events.
*
* \param pEvt Buffer containing HCI event.
*
* \return None.
*/
/*************************************************************************************************/
void hciEvtProcessMsg(uint8_t *pEvt);
/*************************************************************************************************/
/*!
* \brief Get event statistics.
*
* \return Event statistics.
*/
/*************************************************************************************************/
hciEvtStats_t *hciEvtGetStats(void);
#ifdef __cplusplus
};
#endif
#endif /* HCI_EVT_H */
@@ -0,0 +1,76 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Interface to HCI event handler.
*
* Copyright (c) 2009-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#ifndef HCI_HANDLER_H
#define HCI_HANDLER_H
#include "wsf_os.h"
#ifdef __cplusplus
extern "C" {
#endif
/*! \addtogroup STACK_EVENT
* \{ */
/** \name HCI Event Handling
* Message passing interface to HCI from application and other stack layers through WSF.
*/
/**@{*/
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief HCI handler init function called during system initialization.
*
* \param handlerId WSF handler ID for HCI.
*
* \return None.
*/
/*************************************************************************************************/
void HciHandlerInit(wsfHandlerId_t handlerId);
/*************************************************************************************************/
/*!
* \brief WSF event handler for HCI.
*
* \param event WSF event mask.
* \param pMsg WSF message.
*
* \return None.
*/
/*************************************************************************************************/
void HciHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
/**@}*/
/*! \} */ /* STACK_HCI_API */
#ifdef __cplusplus
};
#endif
#endif /* HCI_HANDLER_H */
@@ -0,0 +1,84 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief HCI transport interface.
*
* Copyright (c) 2009-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#ifndef HCI_TR_H
#define HCI_TR_H
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief Send a complete HCI ACL packet to the transport.
*
* \param pContext Connection context.
* \param pAclData WSF msg buffer containing an ACL packet.
*
* \return None.
*/
/*************************************************************************************************/
void hciTrSendAclData(void *pContext, uint8_t *pAclData);
/*************************************************************************************************/
/*!
* \brief Send a complete HCI command to the transport.
*
* \param pCmdData WSF msg buffer containing an HCI command.
*
* \return None.
*/
/*************************************************************************************************/
void hciTrSendCmd(uint8_t *pCmdData);
/*************************************************************************************************/
/*!
* \brief Initialize HCI transport resources.
*
* \param port COM port.
* \param baudRate Baud rate.
* \param flowControl TRUE if flow control is enabled
*
* \return TRUE if initialization succeeds, FALSE otherwise.
*/
/*************************************************************************************************/
bool_t hciTrInit(uint8_t port, uint32_t baudRate, bool_t flowControl);
/*************************************************************************************************/
/*!
* \brief Close HCI transport resources.
*
* \return None.
*/
/*************************************************************************************************/
void hciTrShutdown(void);
#ifdef __cplusplus
};
#endif
#endif /* HCI_TR_H */
@@ -0,0 +1,476 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief L2CAP subsystem API.
*
* Copyright (c) 2009-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#ifndef L2C_API_H
#define L2C_API_H
#include "dm_api.h"
#include "l2c_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/*! \addtogroup STACK_L2CAP_API
* \{ */
/**************************************************************************************************
Macros
**************************************************************************************************/
/** \name L2CAP Control Callback Events
* Control callback message events
*/
/**@{*/
#define L2C_CTRL_FLOW_ENABLE_IND 0 /*!< \brief Data flow enabled */
#define L2C_CTRL_FLOW_DISABLE_IND 1 /*!< \brief Data flow disabled */
/**@}*/
/*! \brief Invalid channel registration ID for connection oriented channels */
#define L2C_COC_REG_ID_NONE 0
/*! \brief Invalid channel ID for connection oriented channels */
#define L2C_COC_CID_NONE 0
/*! \brief Invalid signal identifier */
#define L2C_SIGNAL_ID_INVALID 0
/** \name L2CAP COC Channel Roles
* Connection oriented channel initiator/acceptor role
*/
/**@{*/
#define L2C_COC_ROLE_NONE 0x00 /*!< \brief No role (unallocated) */
#define L2C_COC_ROLE_INITIATOR 0x01 /*!< \brief Channel initiator */
#define L2C_COC_ROLE_ACCEPTOR 0x02 /*!< \brief Channel acceptor */
/**@}*/
/** \name L2CAP COC Data Confirm Codes
* Connection oriented channel data confirm status values
*/
/**@{*/
#define L2C_COC_DATA_SUCCESS 0 /*!< \brief Data request successful */
#define L2C_COC_DATA_ERR_MEMORY 1 /*!< \brief Out of memory */
#define L2C_COC_DATA_ERR_OVERFLOW 2 /*!< \brief Transaction overflow */
/**@}*/
/** \name L2CAP COC Callback Events
* Connection oriented channel callback events.
*/
/**@{*/
#define L2C_COC_CBACK_START 0x70 /*!< \brief L2C callback event starting value */
/*! \brief COC callback events */
enum
{
L2C_COC_CONNECT_IND = L2C_COC_CBACK_START, /*!< \brief Channel connect indication */
L2C_COC_DISCONNECT_IND, /*!< \brief Channel disconnect indication */
L2C_COC_DATA_IND, /*!< \brief Received data indication */
L2C_COC_DATA_CNF /*!< \brief Transmit data confirm */
};
#define L2C_COC_CBACK_CBACK_END L2C_COC_DATA_CNF /*!< \brief L2C callback event ending value */
/**@}*/
/**************************************************************************************************
Data Types
**************************************************************************************************/
/*! \brief Connection oriented channel registration ID */
typedef uint16_t l2cCocRegId_t;
/*! \brief Connection oriented channel registration structure */
typedef struct
{
uint16_t psm; /*!< \brief Protocol service multiplexer */
uint16_t mps; /*!< \brief Maximum receive PDU fragment size */
uint16_t mtu; /*!< \brief Maximum receive data packet size */
uint16_t credits; /*!< \brief Data packet receive credits for this channel */
bool_t authoriz; /*!< \brief TRUE if authorization is required */
uint8_t secLevel; /*!< \brief Channel minimum security level requirements */
uint8_t role; /*!< \brief Channel initiator/acceptor role */
} l2cCocReg_t;
/*! \brief Connection oriented channel connect indication structure */
typedef struct
{
wsfMsgHdr_t hdr; /*!< \brief Header structure */
uint16_t cid; /*!< \brief Local channel ID */
uint16_t peerMtu; /*!< \brief Data packet MTU peer can receive */
uint16_t psm; /*!< \brief Connected PSM */
} l2cCocConnectInd_t;
/*! \brief Connection oriented channel disconnect indication structure */
typedef struct
{
wsfMsgHdr_t hdr; /*!< \brief Header structure */
uint16_t cid; /*!< \brief Local channel ID */
uint16_t result; /*!< \brief Connection failure result code */
} l2cCocDisconnectInd_t;
/*! \brief Connection oriented channel data indication structure */
typedef struct
{
wsfMsgHdr_t hdr; /*!< \brief Header structure */
uint16_t cid; /*!< \brief Local channel ID */
uint8_t *pData; /*!< \brief Pointer to packet data */
uint16_t dataLen; /*!< \brief packet data length */
} l2cCocDataInd_t;
/*! \brief Connection oriented channel disconnect indication structure */
typedef struct
{
wsfMsgHdr_t hdr; /*!< \brief Header structure */
uint16_t cid; /*!< \brief Local channel ID */
} l2cCocDataCnf_t;
/*!
* \brief Connection oriented channel event structure
*
* Connection oriented channel callback header parameters:
*
* \param hdr.event Callback event
* \param hdr.param DM connection ID
* \param hdr.status Event status (L2C_COC_DATA_CNF only)
*/
typedef union
{
wsfMsgHdr_t hdr; /*!< \brief Header structure */
l2cCocConnectInd_t connectInd; /*!< \brief Channel connect indication */
l2cCocDisconnectInd_t disconnectInd; /*!< \brief Channel disconnect indication */
l2cCocDataInd_t dataInd; /*!< \brief Received data indication */
l2cCocDataCnf_t dataCnf; /*!< \brief Transmit data confirm */
} l2cCocEvt_t;
/*! \brief Configurable parameters */
typedef struct
{
uint16_t reqTimeout; /*!< \brief Request timeout in seconds */
} l2cCfg_t;
/*! \} */ /* STACK_L2CAP_API */
/**************************************************************************************************
Global Variables;
**************************************************************************************************/
/*! \addtogroup STACK_INIT
* \{ */
/** \name L2CAP Configuration Structure
* Pointer to structure containing initialization details of the L2CAP Subsystem. To be configured
* by Application.
*/
/**@{*/
/*! \brief Configuration pointer */
extern l2cCfg_t *pL2cCfg;
/**@}*/
/*! \} */ /* STACK_INIT */
/**************************************************************************************************
Callback Function Types
**************************************************************************************************/
/*! \addtogroup STACK_L2CAP_API
* \{ */
/*************************************************************************************************/
/*!
* \brief This callback function sends a received L2CAP packet to the client.
*
* \param handle The connection handle.
* \param len The length of the L2CAP payload data in pPacket.
* \param pPacket A buffer containing the packet.
*
* \return None.
*/
/*************************************************************************************************/
typedef void (*l2cDataCback_t)(uint16_t handle, uint16_t len, uint8_t *pPacket);
/*************************************************************************************************/
/*!
* \brief This callback function sends control messages to the client.
*
* \param pMsg Pointer to message structure.
*
* \return None.
*/
/*************************************************************************************************/
typedef void (*l2cCtrlCback_t)(wsfMsgHdr_t *pMsg);
/*************************************************************************************************/
/*!
* \brief This callback function sends data and other events to connection oriented
* channels clients.
*
* \param pMsg Pointer to message structure.
*
* \return None.
*/
/*************************************************************************************************/
typedef void (*l2cCocCback_t)(l2cCocEvt_t *pMsg);
/*************************************************************************************************/
/*!
* \brief This callback function is used for authoriztion of connection oriented channels.
*
* \param connId DM connection ID.
* \param regId The registration instance requiring authorization.
* \param psm The PSM of the registration instance.
*
* \return L2C_CONN_SUCCESS if authorization is successful, any other value for failure.
*/
/*************************************************************************************************/
typedef uint16_t (*l2cCocAuthorCback_t)(dmConnId_t connId, l2cCocRegId_t regId, uint16_t psm);
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/** \name L2CAP Initialization
* Initialization and registration functions
*/
/**@{*/
/*************************************************************************************************/
/*!
* \brief Initialize L2C subsystem.
*
* \return None.
*/
/*************************************************************************************************/
void L2cInit(void);
/*************************************************************************************************/
/*!
* \brief Initialize L2C for operation as a Bluetooth LE master.
*
* \return None.
*/
/*************************************************************************************************/
void L2cMasterInit(void);
/*************************************************************************************************/
/*!
* \brief Initialize L2C for operation as a Bluetooth LE slave.
*
* \return None.
*/
/*************************************************************************************************/
void L2cSlaveInit(void);
/**@}*/
/** \name L2CAP CID Functions
* Register and send data over a CID
*/
/**@{*/
/*************************************************************************************************/
/*!
* \brief called by the L2C client, such as ATT or SMP, to register for the given CID.
*
* \param cid channel identifier.
* \param dataCback Callback function for L2CAP data received for this CID.
* \param ctrlCback Callback function for control events for this CID.
*
* \return None.
*/
/*************************************************************************************************/
void L2cRegister(uint16_t cid, l2cDataCback_t dataCback, l2cCtrlCback_t ctrlCback);
/*************************************************************************************************/
/*!
* \brief Send an L2CAP data packet on the given CID.
*
* \param cid The channel identifier.
* \param handle The connection handle. The client receives this handle from DM.
* \param len The length of the payload data in pPacket.
* \param pL2cPacket A buffer containing the packet.
*
* \return None.
*/
/*************************************************************************************************/
void L2cDataReq(uint16_t cid, uint16_t handle, uint16_t len, uint8_t *pL2cPacket);
/*************************************************************************************************/
/*!
* \brief Build and send a signaling packet.
*
* \param handle The connection handle.
* \param code Type of command.
* \param len Length of the parameter.
* \param pParam parameters of command to send.
*
* \return None.
*/
/*************************************************************************************************/
void L2cDmSigReq(uint16_t handle, uint8_t code, uint16_t len, uint8_t *pParam);
/**@}*/
/** \name L2CAP COC Functions
* Connection Oriented Channels Functions
*/
/**@{*/
/*************************************************************************************************/
/*!
* \brief Initialize L2C connection oriented channel subsystem.
*
* \return None.
*/
/*************************************************************************************************/
void L2cCocInit(void);
/*************************************************************************************************/
/*!
* \brief Register to use a connection oriented channel, as either a channel acceptor,
* initiator, or both. If registering as channel acceptor then the PSM is specified.
* After registering a connection can be established by the client using this
* registration instance.
*
* \param cback Client callback function.
* \param pReg Registration parameter structure.
*
* \return Registration instance ID or L2C_COC_REG_ID_NONE if registration failed.
*/
/*************************************************************************************************/
l2cCocRegId_t L2cCocRegister(l2cCocCback_t cback, l2cCocReg_t *pReg);
/*************************************************************************************************/
/*!
* \brief Deregister and deallocate a connection oriented channel registration instance.
* This function should only be called if there are no active channels using this
* registration instance.
*
* \param regId Registration instance ID.
*
* \return None.
*/
/*************************************************************************************************/
void L2cCocDeregister(l2cCocRegId_t regId);
/*************************************************************************************************/
/*!
* \brief Initiate a connection to the given peer PSM.
*
* \param connId DM connection ID.
* \param regId The associated registration instance.
* \param psm Peer PSM.
*
* \return Local CID or L2C_COC_CID_NONE none if failure.
*/
/*************************************************************************************************/
uint16_t L2cCocConnectReq(dmConnId_t connId, l2cCocRegId_t regId, uint16_t psm);
/*************************************************************************************************/
/*!
* \brief Disconnect the channel for the given CID.
*
* \param cid Channel ID.
*
* \return None.
*/
/*************************************************************************************************/
void L2cCocDisconnectReq(uint16_t cid);
/*************************************************************************************************/
/*!
* \brief Send an L2CAP data packet on the given connection oriented CID.
*
* \param cid The local channel identifier.
* \param len The length of the payload data in pPacket.
* \param pPayload Packet payload data.
*
* \return None.
*/
/*************************************************************************************************/
void L2cCocDataReq(uint16_t cid, uint16_t len, uint8_t *pPayload);
/*************************************************************************************************/
/*!
* \brief For testing purposes only.
*
* \param result Result code
*
* \return None.
*/
/*************************************************************************************************/
void L2cCocErrorTest(uint16_t result);
/*************************************************************************************************/
/*!
* \brief For testing purposes only.
*
* \param cid The local channel identifier.
* \param credits Credits to send.
*
* \return None.
*/
/*************************************************************************************************/
void L2cCocCreditSendTest(uint16_t cid, uint16_t credits);
/**@}*/
/** \name L2CAP Connection Parameter Update Functions
*
*/
/**@{*/
/*************************************************************************************************/
/*!
* \brief For internal use only. This function is called by DM to send an L2CAP
* connection update request.
*
* \param handle The connection handle.
* \param pConnSpec Pointer to the connection specification structure.
*
* \return None.
*/
/*************************************************************************************************/
void L2cDmConnUpdateReq(uint16_t handle, hciConnSpec_t *pConnSpec);
/*************************************************************************************************/
/*!
* \brief For internal use only. This function is called by DM to send an L2CAP
* connection update response.
*
* \param identifier Identifier value previously passed from L2C to DM.
* \param handle The connection handle.
* \param result Connection update response result.
*
* \return None.
*/
/*************************************************************************************************/
void L2cDmConnUpdateRsp(uint8_t identifier, uint16_t handle, uint16_t result);
/**@}*/
/*! \} */ /*! STACK_L2CAP_API */
#ifdef __cplusplus
};
#endif
#endif /* L2C_API_H */
@@ -0,0 +1,158 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief L2CAP constants and definitions from the Bluetooth specification.
*
* Copyright (c) 2009-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#ifndef L2C_DEFS_H
#define L2C_DEFS_H
#ifdef __cplusplus
extern "C" {
#endif
/*! \addtogroup STACK_L2CAP_API
* \{ */
/**************************************************************************************************
Macros
**************************************************************************************************/
/** \name L2CAP Packet Constants
*
*/
/**@{*/
#define L2C_HDR_LEN 4 /*!< \brief L2CAP packet header length */
#define L2C_MIN_MTU 23 /*!< \brief Minimum packet payload MTU for LE */
#define L2C_SIG_HDR_LEN 4 /*!< \brief L2CAP signaling command header length */
#define L2C_LE_SDU_HDR_LEN 2 /*!< \brief L2CAP LE SDU data header length */
/**@}*/
/*! \brief Start of L2CAP payload in an HCI ACL packet buffer */
#define L2C_PAYLOAD_START (HCI_ACL_HDR_LEN + L2C_HDR_LEN)
/*! \brief L2CAP signaling packet base length, including HCI header */
#define L2C_SIG_PKT_BASE_LEN (HCI_ACL_HDR_LEN + L2C_HDR_LEN + L2C_SIG_HDR_LEN)
/*! \brief L2CAP LE SDU packet base length, including HCI header */
#define L2C_LE_SDU_PKT_BASE_LEN (HCI_ACL_HDR_LEN + L2C_HDR_LEN + L2C_LE_SDU_HDR_LEN)
/** \name L2CAP Parameter Lengths
* Signaling packet parameter lengths
*/
/**@{*/
#define L2C_SIG_CONN_UPDATE_REQ_LEN 8 /*!< \brief Connection update request length. */
#define L2C_SIG_CONN_UPDATE_RSP_LEN 2 /*!< \brief Connection update response length. */
#define L2C_SIG_CMD_REJ_LEN 2 /*!< \brief Command reject length. */
#define L2C_SIG_DISCONN_REQ_LEN 4 /*!< \brief Disconnection request length. */
#define L2C_SIG_DISCONN_RSP_LEN 4 /*!< \brief Disconnection response length. */
#define L2C_SIG_LE_CONN_REQ_LEN 10 /*!< \brief LE connection request length. */
#define L2C_SIG_LE_CONN_RSP_LEN 10 /*!< \brief LE connection response length. */
#define L2C_SIG_FLOW_CTRL_CREDIT_LEN 4 /*!< \brief Flow control credit lenghth. */
/**@}*/
/** \name L2CAP Connection Identifiers
* BLE Defined Connection Identifiers (CID)
*/
/**@{*/
#define L2C_CID_ATT 0x0004 /*!< \brief CID for attribute protocol */
#define L2C_CID_LE_SIGNALING 0x0005 /*!< \brief CID for LE signaling */
#define L2C_CID_SMP 0x0006 /*!< \brief CID for security manager protocol */
/**@}*/
/** \name L2CAP Signaling Codes
*
*/
/**@{*/
#define L2C_SIG_CMD_REJ 0x01 /*!< \brief Comand reject */
#define L2C_SIG_DISCONNECT_REQ 0x06 /*!< \brief Disconnect request */
#define L2C_SIG_DISCONNECT_RSP 0x07 /*!< \brief Disconnect response */
#define L2C_SIG_CONN_UPDATE_REQ 0x12 /*!< \brief Connection parameter update request */
#define L2C_SIG_CONN_UPDATE_RSP 0x13 /*!< \brief Connection parameter update response */
#define L2C_SIG_LE_CONNECT_REQ 0x14 /*!< \brief LE credit based connection request */
#define L2C_SIG_LE_CONNECT_RSP 0x15 /*!< \brief LE credit based connection response */
#define L2C_SIG_FLOW_CTRL_CREDIT 0x16 /*!< \brief LE flow control credit */
/**@}*/
/*! \brief Signaling response code flag */
#define L2C_SIG_RSP_FLAG 0x01
/** \name L2CAP Command Rejection Codes
* BLE defined Command rejection reason codes
*/
/**@{*/
#define L2C_REJ_NOT_UNDERSTOOD 0x0000 /*!< \brief Command not understood */
#define L2C_REJ_MTU_EXCEEDED 0x0001 /*!< \brief Signaling MTU exceeded */
#define L2C_REJ_INVALID_CID 0x0002 /*!< \brief Invalid CID in request */
/**@}*/
/** \name L2CAP Connection Parameter Update Result Codes
* BLE defined result codes
*/
/**@{*/
#define L2C_CONN_PARAM_ACCEPTED 0x0000 /*!< \brief Connection parameters accepted */
#define L2C_CONN_PARAM_REJECTED 0x0001 /*!< \brief Connection parameters rejected */
/**@}*/
/** \name L2CAP Connection Result Codes
* BLE defined result codes
*/
/**@{*/
#define L2C_CONN_SUCCESS 0x0000 /*!< \brief Connection successful */
#define L2C_CONN_NONE 0x0001 /*!< \brief No connection result value available */
#define L2C_CONN_FAIL_PSM 0x0002 /*!< \brief Connection refused LE_PSM not supported */
#define L2C_CONN_FAIL_RES 0x0004 /*!< \brief Connection refused no resources available */
#define L2C_CONN_FAIL_AUTH 0x0005 /*!< \brief Connection refused insufficient authentication */
#define L2C_CONN_FAIL_AUTHORIZ 0x0006 /*!< \brief Connection refused insufficient authorization */
#define L2C_CONN_FAIL_KEY_SIZE 0x0007 /*!< \brief Connection refused insufficient encryption key size */
#define L2C_CONN_FAIL_ENC 0x0008 /*!< \brief Connection Refused insufficient encryption */
#define L2C_CONN_FAIL_INVALID_SCID 0x0009 /*!< \brief Connection refused invalid source CID */
#define L2C_CONN_FAIL_ALLOCATED_SCID 0x000A /*!< \brief Connection refused source CID already allocated */
#define L2C_CONN_FAIL_UNACCEPT_PARAM 0x000B /*!< \brief Connection refused unacceptable parameters */
/**@}*/
/** \name L2CAP Interal Connection Result Codes
* Proprietary codes not sent in any L2CAP packet.
*/
/**@{*/
#define L2C_CONN_FAIL_TIMEOUT 0xF000 /*!< \brief Request timeout */
/**@}*/
/** \name L2CAP Signaling Parameter Value Ranges
*
*/
/**@{*/
#define L2C_PSM_MIN 0x0001 /*!< \brief PSM minimum. */
#define L2C_PSM_MAX 0x00FF /*!< \brief PSM maximum. */
#define L2C_CID_DYN_MIN 0x0040 /*!< \brief CID dynamic minimum. */
#define L2C_CID_DYN_MAX 0x007F /*!< \brief CID dynamic maximum. */
#define L2C_MTU_MIN 0x0017 /*!< \brief MTU minimum. */
#define L2C_MPS_MIN 0x0017 /*!< \brief MPS minimum. */
#define L2C_MPS_MAX 0xFFFD /*!< \brief MPS maximum. */
#define L2C_CREDITS_MAX 0xFFFF /*!< \brief Credits maximum. */
/**@}*/
/*! \} */ /*! STACK_L2CAP_API */
#ifdef __cplusplus
};
#endif
#endif /* L2C_DEFS_H */
@@ -0,0 +1,99 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief L2CAP handler interface.
*
* Copyright (c) 2009-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#ifndef L2C_HANDLER_H
#define L2C_HANDLER_H
#include "wsf_os.h"
#ifdef __cplusplus
extern "C" {
#endif
/*! \addtogroup STACK_EVENT
* \{ */
/** \name L2CAP Event Handling
* Message passing interface to L2CAP from other tasks through WSF.
*/
/**@{*/
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief Event handler initialization function for L2C when operating as a slave.
*
* \param handlerId ID for this event handler.
*
* \return None.
*/
/*************************************************************************************************/
void L2cSlaveHandlerInit(wsfHandlerId_t handlerId);
/*************************************************************************************************/
/*!
* \brief The WSF event handler for L2C when operating as a slave.
*
* \param event Event mask.
* \param pMsg Pointer to message.
*
* \return None.
*/
/*************************************************************************************************/
void L2cSlaveHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
/*************************************************************************************************/
/*!
* \brief Event handler initialization function for L2C with connection oriented channels.
*
* \param handlerId ID for this event handler.
*
* \return None.
*/
/*************************************************************************************************/
void L2cCocHandlerInit(wsfHandlerId_t handlerId);
/*************************************************************************************************/
/*!
* \brief The WSF event handler for L2C with connection oriented channels.
*
* \param event Event mask.
* \param pMsg Pointer to message.
*
* \return None.
*/
/*************************************************************************************************/
void L2cCocHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
/**@}*/
/*! \} */ /* STACK_EVENT */
#ifdef __cplusplus
};
#endif
#endif /* L2C_HANDLER_H */
@@ -0,0 +1,387 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief AES and random number security service API.
*
* Copyright (c) 2010-2019 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#ifndef SEC_API_H
#define SEC_API_H
#include "wsf_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/*! \addtogroup STACK_SECURITY_API
* \{ */
/**************************************************************************************************
Macros
**************************************************************************************************/
/*! \brief CMAC algorithm key length. */
#define SEC_CMAC_KEY_LEN 16
/*! \brief CMAC algorithm result length. */
#define SEC_CMAC_HASH_LEN 16
/*! \brief ECC algorithm key length. */
#define SEC_ECC_KEY_LEN 32
/** \name CCM-Mode algorithm lengths
*
*/
/**@{*/
#define SEC_CCM_KEY_LEN 16
#define SEC_CCM_MAX_ADDITIONAL_LEN ((1<<16) - (1<<8))
#define SEC_CCM_L 2
#define SEC_CCM_NONCE_LEN (15-SEC_CCM_L)
/**@}*/
/*! \brief Invalid AES Token. */
#define SEC_TOKEN_INVALID 0xFF
/**************************************************************************************************
Data Types
**************************************************************************************************/
/*! \brief AES Security callback parameters structure. */
typedef struct
{
wsfMsgHdr_t hdr; /*!< Header. */
uint8_t *pCiphertext; /*!< Pointer to 16 bytes of ciphertext data. */
} secAes_t;
/*! \brief CMAC Security callback parameters structure. */
typedef struct
{
wsfMsgHdr_t hdr; /*!< Header. */
uint8_t *pCiphertext; /*!< Pointer to 16 bytes of ciphertext data. */
uint8_t *pPlainText; /*!< Pointer to pPlaintext parameter passed to SecCmac. */
} secCmacMsg_t;
/*! \brief CCM-Mode encrypt callback parameters structure. */
typedef struct
{
wsfMsgHdr_t hdr; /*!< Header. */
uint8_t *pCiphertext; /*!< Pointer to ciphertext data. */
uint16_t textLen; /*!< Length of pCiphertext in bytes. */
} secCcmEncMsg_t;
/*! \brief CCM-Mode decrypt and authenticate callback parameters structure. */
typedef struct
{
wsfMsgHdr_t hdr; /*!< Header. */
uint8_t *pText; /*!< Pointer to decrypted text within result buffer. */
uint8_t *pResult; /*!< Pointer to result buffer (passed into SecCcmDec). */
uint16_t textLen; /*!< Length of pText in bytes. */
bool_t success; /*!< TRUE if message is authenticated. */
} secCcmDecMsg_t;
/*! \brief Generic security callback parameters structure. */
typedef union
{
wsfMsgHdr_t hdr; /*!< Header. */
secAes_t aes; /*!< AES complete message. */
secCmacMsg_t cmac; /*!< CMAC complete message. */
secCcmEncMsg_t ccmEnc; /*!< CCM-Mode Encrypt complete message. */
secCcmDecMsg_t ccmDec; /*!< CCM-Mode Decrypt complete message. */
} secMsg_t;
/*! \brief ECC Security public/private key pair. */
typedef struct
{
uint8_t pubKey_x[SEC_ECC_KEY_LEN]; /*!< x component of ECC public key. */
uint8_t pubKey_y[SEC_ECC_KEY_LEN]; /*!< y component of ECC public key. */
uint8_t privKey[SEC_ECC_KEY_LEN]; /*!< ECC private key. */
} secEccKey_t;
/*! \brief ECC security DH Key shared secret. */
typedef struct
{
uint8_t secret[SEC_ECC_KEY_LEN]; /*!< DH Key Shared secret. */
} secEccSharedSec_t;
/*! \brief ECC Security callback parameters structure. */
typedef struct
{
wsfMsgHdr_t hdr; /*!< Header. */
union
{
secEccSharedSec_t sharedSecret; /*!< Shared secret. */
secEccKey_t key; /*!< ECC public/private key pair. */
bool_t keyValid; /*!< TRUE if ECC public/private key pair is valid. */
} data; /*!< ECC message data union. */
} secEccMsg_t;
/*! \brief Block encryption function. */
typedef void (*SecBlkEncFunc_t)(uint8_t *pKey, uint8_t *pMessage, void *pParam);
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/** \name Security Initialization Functions
*
*/
/**@{*/
/*************************************************************************************************/
/*!
* \brief Initialize the security service. This function should only be called once
* upon system initialization.
*
* \return None.
*/
/*************************************************************************************************/
void SecInit(void);
/*************************************************************************************************/
/*!
* \brief Initialize the random number service. This function should only be called once
* upon system initialization.
*
* \return None.
*/
/*************************************************************************************************/
void SecRandInit(void);
/*************************************************************************************************/
/*!
* \brief Initialize the AES service. This function should only be called once
* upon system initialization.
*
* \return None.
*/
/*************************************************************************************************/
void SecAesInit(void);
/*************************************************************************************************/
/*!
* \brief Initialize the AES (reverse) service. This function should only be called once
* upon system initialization.
*
* \return None.
*/
/*************************************************************************************************/
void SecAesRevInit(void);
/*************************************************************************************************/
/*!
* \brief Called to initialize CMAC security. This function should only be called once
* upon system initialization.
*
* \return None.
*/
/*************************************************************************************************/
void SecCmacInit(void);
/*************************************************************************************************/
/*!
* \brief Called to initialize CCM security.
*
* \return None.
*/
/*************************************************************************************************/
void SecCcmInit(void);
/*************************************************************************************************/
/*!
* \brief Called to initialize ECC security. This function should only be called once
* upon system initialization.
*
* \return None.
*/
/*************************************************************************************************/
void SecEccInit(void);
/**@}*/
/** \name Security AES, CMAC and CCM Functions
*
*/
/**@{*/
/*************************************************************************************************/
/*!
* \brief Execute an AES calculation. When the calculation completes, a WSF message will be
* sent to the specified handler. This function returns a token value that
* the client can use to match calls to this function with messages.
*
* \param pKey Pointer to 16 byte key.
* \param pPlaintext Pointer to 16 byte plaintext.
* \param handlerId WSF handler ID.
* \param param Client-defined parameter returned in message.
* \param event Event for client's WSF handler.
*
* \return Token value.
*/
/*************************************************************************************************/
uint8_t SecAes(uint8_t *pKey, uint8_t *pPlaintext, wsfHandlerId_t handlerId,
uint16_t param, uint8_t event);
/*************************************************************************************************/
/*!
* \brief Execute an AES calculation. When the calculation completes, a WSF message will be
* sent to the specified handler. This function returns a token value that
* the client can use to match calls to this function with messages. Note this version
* reverses the key and plaintext bytes.
*
* \param pKey Pointer to 16 byte key.
* \param pPlaintext Pointer to 16 byte plaintext.
* \param handlerId WSF handler ID.
* \param param Client-defined parameter returned in message.
* \param event Event for client's WSF handler.
*
* \return Token value.
*/
/*************************************************************************************************/
uint8_t SecAesRev(uint8_t *pKey, uint8_t *pPlaintext, wsfHandlerId_t handlerId,
uint16_t param, uint8_t event);
/*************************************************************************************************/
/*!
* \brief Execute the CMAC algorithm.
*
* \param pKey Key used in CMAC operation.
* \param pPlaintext Plain text buffer - buffer must persist until secCmacMsg_t callback.
* \param textLen Size of pPlaintext in bytes.
* \param handlerId WSF handler ID for client.
* \param param Optional parameter sent to client's WSF handler.
* \param event Event for client's WSF handler.
*
* \return TRUE if successful, else FALSE.
*/
/*************************************************************************************************/
bool_t SecCmac(const uint8_t *pKey, uint8_t *pPlaintext, uint16_t textLen, wsfHandlerId_t handlerId,
uint16_t param, uint8_t event);
/*************************************************************************************************/
/*!
* \brief Execute the CCM-Mode encryption algorithm.
*
* \param pKey Pointer to encryption key (SEC_CCM_KEY_LEN bytes).
* \param pNonce Pointer to nonce (SEC_CCM_NONCE_LEN bytes).
* \param pPlainText Pointer to text to encrypt.
* \param textLen Length of pPlainText in bytes.
* \param pClear Pointer to additional, unencrypted authentication text.
* \param clearLen Length of pClear in bytes.
* \param micLen Size of MIC in bytes (4, 8 or 16).
* \param pResult Buffer to hold result (returned in complete event).
* \param handlerId Task handler ID to receive complete event.
* \param param Optional parameter passed in complete event.
* \param event Event ID of complete event.
* \return TRUE if successful, else FALSE.
*/
/*************************************************************************************************/
bool_t SecCcmEnc(const uint8_t *pKey, uint8_t *pNonce, uint8_t *pPlainText, uint16_t textLen,
uint8_t *pClear, uint16_t clearLen, uint8_t micLen, uint8_t *pResult,
wsfHandlerId_t handlerId, uint16_t param, uint8_t event);
/*************************************************************************************************/
/*!
* \brief Execute the CCM-Mode verify and decrypt algorithm.
*
* \param pKey Pointer to encryption key (SEC_CCM_KEY_LEN bytes).
* \param pNonce Pointer to nonce (SEC_CCM_NONCE_LEN bytes).
* \param pCypherText Pointer to text to decrypt.
* \param textLen Length of pCypherText in bytes.
* \param pClear Pointer to additional, unencrypted authentication text.
* \param clearLen Length of pClear in bytes.
* \param pMic Pointer to authentication digest.
* \param micLen Size of MIC in bytes (4, 8 or 16).
* \param pResult Buffer to hold result (returned in complete event).
* \param handlerId Task handler ID to receive complete event.
* \param param Optional parameter passed in complete event.
* \param event Event ID of complete event.
*
* \return TRUE if successful, else FALSE.
*/
/*************************************************************************************************/
bool_t SecCcmDec(const uint8_t *pKey, uint8_t *pNonce, uint8_t *pCypherText, uint16_t textLen,
uint8_t *pClear, uint16_t clearLen, uint8_t *pMic, uint8_t micLen,
uint8_t *pResult, wsfHandlerId_t handlerId, uint16_t param, uint8_t event);
/**@}*/
/** \name Security ECC Functions
*
*/
/**@{*/
/*************************************************************************************************/
/*!
* \brief Generate an ECC key.
*
* \param handlerId WSF handler ID for client.
* \param param Optional parameter sent to client's WSF handler.
* \param event Event for client's WSF handler.
*
* \return TRUE if successful, else FALSE.
*/
/*************************************************************************************************/
bool_t SecEccGenKey(wsfHandlerId_t handlerId, uint16_t param, uint8_t event);
/*************************************************************************************************/
/*!
* \brief Generate an ECC key.
*
* \param pKey ECC Key structure.
* \param handlerId WSF handler ID for client.
* \param param Optional parameter sent to client's WSF handler.
* \param event Event for client's WSF handler.
*
* \return TRUE if successful, else FALSE.
*/
/*************************************************************************************************/
bool_t SecEccGenSharedSecret(secEccKey_t *pKey, wsfHandlerId_t handlerId, uint16_t param, uint8_t event);
/**@}*/
/** \name Security Random Number Generator Functions
*
*/
/**@{*/
/*************************************************************************************************/
/*!
* \brief This function returns up to 16 bytes of random data to a buffer provided by the
* client.
*
* \param pRand Pointer to returned random data.
* \param randLen Length of random data.
*
* \return None.
*/
/*************************************************************************************************/
void SecRand(uint8_t *pRand, uint8_t randLen);
/**@}*/
/*! \} */ /* STACK_SECURITY_API */
#ifdef __cplusplus
};
#endif
#endif /* SEC_API_H */
@@ -0,0 +1,310 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief SMP subsystem API.
*
* Copyright (c) 2010-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#ifndef SMP_API_H
#define SMP_API_H
#include "wsf_os.h"
#include "smp_defs.h"
#include "dm_api.h"
#ifdef __cplusplus
extern "C" {
#endif
/*! \addtogroup STACK_SMP_API
* \{ */
/**************************************************************************************************
Macros
**************************************************************************************************/
/** \name SMP Events
* Events recognized and handled by the SMP state machine.
*/
/**@{*/
/*! \brief Event handler messages for SMP state machines */
enum
{
SMP_MSG_API_PAIR_REQ = 1, /*!< \brief API pairing request */
SMP_MSG_API_PAIR_RSP, /*!< \brief API pairing response */
SMP_MSG_API_CANCEL_REQ, /*!< \brief API cancel request */
SMP_MSG_API_AUTH_RSP, /*!< \brief API pin response */
SMP_MSG_API_SECURITY_REQ, /*!< \brief API security request */
SMP_MSG_CMD_PKT, /*!< \brief SMP command packet received */
SMP_MSG_CMD_PAIRING_FAILED, /*!< \brief SMP pairing failed packet received */
SMP_MSG_DM_ENCRYPT_CMPL, /*!< \brief Link encrypted */
SMP_MSG_DM_ENCRYPT_FAILED, /*!< \brief Link encryption failed */
SMP_MSG_DM_CONN_CLOSE, /*!< \brief Connection closed */
SMP_MSG_WSF_AES_CMPL, /*!< \brief AES calculation complete */
SMP_MSG_INT_SEND_NEXT_KEY, /*!< \brief Send next key to be distributed */
SMP_MSG_INT_MAX_ATTEMPTS, /*!< \brief Maximum pairing attempts reached */
SMP_MSG_INT_PAIRING_CMPL, /*!< \brief Pairing complete */
SMP_MSG_INT_RSP_TIMEOUT, /*!< \brief Pairing protocol response timeout */
SMP_MSG_INT_WI_TIMEOUT, /*!< \brief Pairing protocol wait interval timeout */
SMP_MSG_INT_LESC, /*!< \brief Pair with Secure Connections */
SMP_MSG_INT_LEGACY, /*!< \brief Pair with Legacy Security */
SMP_MSG_INT_JW_NC, /*!< \brief LESC Just-Works/Numeric Comparison pairing */
SMP_MSG_INT_PASSKEY, /*!< \brief LESC Passkey pairing */
SMP_MSG_INT_OOB, /*!< \brief LESC Out-of-Band Pairing */
SMP_MSG_API_USER_CONFIRM, /*!< \brief User confirms valid numeric comparison */
SMP_MSG_API_USER_KEYPRESS, /*!< \brief User keypress in passkey pairing */
SMP_MSG_API_KEYPRESS_CMPL, /*!< \brief User keypress complete in passkey pairing */
SMP_MSG_WSF_ECC_CMPL, /*!< \brief WSF ECC operation complete */
SMP_MSG_INT_PK_NEXT, /*!< \brief Continue to next passkey bit */
SMP_MSG_INT_PK_CMPL, /*!< \brief Passkey operation complete */
SMP_MSG_WSF_CMAC_CMPL, /*!< \brief WSF CMAC operation complete */
SMP_MSG_DH_CHECK_FAILURE, /*!< \brief DHKey check failure */
SMP_MSG_EARLY_CNF, /*!< \brief An early Confirm from the initiator in passkey pairing */
SMP_NUM_MSGS /*!< \brief Number of SMP message types. */
};
/**@}*/
/**@{*/
/*! \brief Additional SMP messages */
enum
{
SMP_DB_SERVICE_IND = SMP_NUM_MSGS /*!< \brief SMP DB Service timer indication */
};
/**@}*/
/**************************************************************************************************
Data Types
**************************************************************************************************/
/*! \brief Configurable parameters */
typedef struct
{
uint32_t attemptTimeout; /*!< \brief 'Repeated attempts' timeout in msec */
uint8_t ioCap; /*!< \brief I/O Capability */
uint8_t minKeyLen; /*!< \brief Minimum encryption key length */
uint8_t maxKeyLen; /*!< \brief Maximum encryption key length */
uint8_t maxAttempts; /*!< \brief Attempts to trigger 'repeated attempts' timeout */
uint8_t auth; /*!< \brief Device authentication requirements */
uint32_t maxAttemptTimeout; /*!< \brief Maximum 'Repeated attempts' timeout in msec */
uint32_t attemptDecTimeout; /*!< \brief Time msec before attemptExp decreases */
uint16_t attemptExp; /*!< \brief Exponent to raise attemptTimeout on maxAttempts */
} smpCfg_t;
/*! \brief Data type for SMP_MSG_API_PAIR_REQ and SMP_MSG_API_PAIR_RSP */
typedef struct
{
wsfMsgHdr_t hdr; /*!< \brief Message header */
uint8_t oob; /*!< \brief Out-of-band data present flag */
uint8_t auth; /*!< \brief authentication flags */
uint8_t iKeyDist; /*!< \brief Initiator key distribution flags */
uint8_t rKeyDist; /*!< \brief Responder key distribution flags */
} smpDmPair_t;
/*! \brief Data type for SMP_MSG_API_AUTH_RSP */
typedef struct
{
wsfMsgHdr_t hdr; /*!< \brief Message header */
uint8_t authData[SMP_OOB_LEN]; /*!< \brief Authentication data to display */
uint8_t authDataLen; /*!< \brief Length of authentication data */
} smpDmAuthRsp_t;
/*! \brief Data type for SMP_MSG_API_USER_KEYPRESS */
typedef struct
{
wsfMsgHdr_t hdr; /*!< \brief Message header */
uint8_t keypress; /*!< \brief Keypress */
} smpDmKeypress_t;
/*! \brief Data type for SMP_MSG_API_SECURITY_REQ */
typedef struct
{
wsfMsgHdr_t hdr; /*!< \brief Message header */
uint8_t auth; /*!< \brief Authentication flags */
} smpDmSecurityReq_t;
/*! \brief Union SMP DM message data types */
typedef union
{
wsfMsgHdr_t hdr; /*!< \brief Message header */
smpDmPair_t pair; /*!< \brief Pairing request/response message */
smpDmAuthRsp_t authRsp; /*!< \brief Authentication message */
smpDmSecurityReq_t securityReq; /*!< \brief Security Request message */
smpDmKeypress_t keypress; /*!< \brief Keypress message */
} smpDmMsg_t;
/*! \} */ /* STACK_SMP_API */
/**************************************************************************************************
Global Variables;
**************************************************************************************************/
/*! \addtogroup STACK_INIT
* \{ */
/** \name SMP Configuration Structure
* Pointer to structure containing initialization details of the SMP Subsystem. To be configured
* by Application.
*/
/**@{*/
/*! \brief Configuration pointer */
extern smpCfg_t *pSmpCfg;
/**@}*/
/*! \} */ /* STACK_INIT */
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*! \addtogroup STACK_SMP_API
* \{ */
/** \name SMP Initialization Functions
* Legacy and Secure Connections initialization for Initiator and Responder roles.
*/
/**@{*/
/*************************************************************************************************/
/*!
* \brief Initialize SMP initiator role.
*
* \return None.
*/
/*************************************************************************************************/
void SmpiInit(void);
/*************************************************************************************************/
/*!
* \brief Initialize SMP responder role.
*
* \return None.
*/
/*************************************************************************************************/
void SmprInit(void);
/*************************************************************************************************/
/*!
* \brief Initialize SMP initiator role utilizing BTLE Secure Connections.
*
* \return None.
*/
/*************************************************************************************************/
void SmpiScInit(void);
/*************************************************************************************************/
/*!
* \brief Initialize SMP responder role utilizing BTLE Secure Connections.
*
* \return None.
*/
/*************************************************************************************************/
void SmprScInit(void);
/*************************************************************************************************/
/*!
* \brief Use this SMP init function when SMP is not supported.
*
* \return None.
*/
/*************************************************************************************************/
void SmpNonInit(void);
/**@}*/
/** \name SMP DM Interface Functions
* Functions that allow the DM to send messages to SMP.
*/
/**@{*/
/*************************************************************************************************/
/*!
* \brief This function is called by DM to send a message to SMP.
*
* \param pMsg Pointer to message structure.
*
* \return None.
*/
/*************************************************************************************************/
void SmpDmMsgSend(smpDmMsg_t *pMsg);
/*************************************************************************************************/
/*!
* \brief This function is called by DM to notify SMP of encrypted link status.
*
* \param pMsg Pointer to HCI message structure.
*
* \return None.
*/
/*************************************************************************************************/
void SmpDmEncryptInd(wsfMsgHdr_t *pMsg);
/*************************************************************************************************/
/*!
* \brief Return the STK for the given connection.
*
* \param connId Connection identifier.
* \param pSecLevel Returns the security level of pairing when STK was created.
*
* \return Pointer to STK or NULL if not available.
*/
/*************************************************************************************************/
uint8_t *SmpDmGetStk(dmConnId_t connId, uint8_t *pSecLevel);
/*************************************************************************************************/
/*!
* \brief Format a cancel message with consideration for the attempts counter
*
* \param connId Connection Id.
* \param pHdr Pointer to header of message to fill.
* \param status Status to include.
*
* \return none.
*/
/*************************************************************************************************/
void SmpScGetCancelMsgWithReattempt(dmConnId_t connId, wsfMsgHdr_t *pHdr, uint8_t status);
/*************************************************************************************************/
/*!
* \brief Initialize the SMP Database.
*
* \return None.
*/
/*************************************************************************************************/
void SmpDbInit(void);
/*************************************************************************************************/
/*!
* \brief Called to force the DhKey to zero for qualification test purposes.
*
* \param enable TRUE - Force DhKey to zero. FALSE - Use calculated key
*
* \return None.
*/
/*************************************************************************************************/
void SmpScEnableZeroDhKey(bool_t enable);
/**@}*/
/*! \} */ /* STACK_SMP_API */
#ifdef __cplusplus
};
#endif
#endif /* SMP_API_H */
@@ -0,0 +1,208 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Security manager constants and definitions from the Bluetooth specification.
*
* Copyright (c) 2010-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#ifndef SMP_DEFS_H
#define SMP_DEFS_H
#ifdef __cplusplus
extern "C" {
#endif
/*! \addtogroup STACK_SMP_API
* \{ */
/**************************************************************************************************
Macros
**************************************************************************************************/
/*! \brief PDU format */
#define SMP_HDR_LEN 1 /*!< \brief Attribute PDU header length. */
/*! \brief Protocol timeout */
#define SMP_TIMEOUT 30 /*!< \brief Protocol timeout in seconds. */
/** \name SMP Encryption Key Size
*
*/
/**@{*/
#define SMP_KEY_SIZE_MAX 16 /*!< \brief Maximum encryption key size. */
#define SMP_KEY_SIZE_MIN 7 /*!< \brief Minimum encryption key size. */
/**@}*/
#define SMP_OOB_LEN 16 /*!< \brief OOB Data length in bytes. */
#define SMP_PIN_LEN 3 /*!< \brief Passkey Pin lenght in bytes. */
/** \name SMP Error Codes
* SMP PDU status codes
*/
/**@{*/
#define SMP_ERR_PASSKEY_ENTRY 0x01 /*!< \brief User input of passkey failed. */
#define SMP_ERR_OOB 0x02 /*!< \brief OOB data is not available. */
#define SMP_ERR_AUTH_REQ 0x03 /*!< \brief Authentication requirements cannot be met. */
#define SMP_ERR_CONFIRM_VALUE 0x04 /*!< \brief Confirm value does not match. */
#define SMP_ERR_PAIRING_NOT_SUP 0x05 /*!< \brief Pairing is not supported by the device. */
#define SMP_ERR_ENC_KEY_SIZE 0x06 /*!< \brief Insufficient encryption key size. */
#define SMP_ERR_COMMAND_NOT_SUP 0x07 /*!< \brief Command not supported. */
#define SMP_ERR_UNSPECIFIED 0x08 /*!< \brief Unspecified reason. */
#define SMP_ERR_ATTEMPTS 0x09 /*!< \brief Repeated attempts. */
#define SMP_ERR_INVALID_PARAM 0x0A /*!< \brief Invalid parameter or command length. */
#define SMP_ERR_DH_KEY_CHECK 0x0B /*!< \brief DH Key check did not match. */
#define SMP_ERR_NUMERIC_COMPARISON 0x0C /*!< \brief Numeric comparison did not match. */
#define SMP_ERR_BR_EDR_IN_PROGRESS 0x0D /*!< \brief BR/EDR in progress. */
#define SMP_ERR_CROSS_TRANSPORT 0x0E /*!< \brief BR/EDR cross transport key generation not allowed. */
/**@}*/
/** \name Proprietary Error Codes
* Internal error codes not sent in any SMP PDU.
*/
/**@{*/
#define SMP_ERR_MEMORY 0xE0 /*!< \brief Out of memory. */
#define SMP_ERR_TIMEOUT 0xE1 /*!< \brief Transaction timeout. */
/**@}*/
/** \name SMP PDU Codes
* SMP PDU Code describing command received or sent.
*/
/**@{*/
#define SMP_CMD_PAIR_REQ 0x01 /*!< \brief Pairing request. */
#define SMP_CMD_PAIR_RSP 0x02 /*!< \brief Pairing response. */
#define SMP_CMD_PAIR_CNF 0x03 /*!< \brief Pairing confirm. */
#define SMP_CMD_PAIR_RAND 0x04 /*!< \brief Pairing random. */
#define SMP_CMD_PAIR_FAIL 0x05 /*!< \brief Pairing failed. */
#define SMP_CMD_ENC_INFO 0x06 /*!< \brief Encryption information. */
#define SMP_CMD_MASTER_ID 0x07 /*!< \brief Master identification. */
#define SMP_CMD_ID_INFO 0x08 /*!< \brief Identity information. */
#define SMP_CMD_ID_ADDR_INFO 0x09 /*!< \brief Identity address information. */
#define SMP_CMD_SIGN_INFO 0x0A /*!< \brief Signing information. */
#define SMP_CMD_SECURITY_REQ 0x0B /*!< \brief Security fequest. */
#define SMP_CMD_PUBLIC_KEY 0x0C /*!< \brief Public Kkey. */
#define SMP_CMD_DHKEY_CHECK 0x0D /*!< \brief DH Key check. */
#define SMP_CMD_KEYPRESS 0x0E /*!< \brief User key press. */
#define SMP_CMD_MAX 0x0F /*!< \brief Command code maximum. */
/**@}*/
/** \name SMP PDU Packet Lengths
* Fixed length of the PDU to be sent.
*/
/**@{*/
#define SMP_PAIR_REQ_LEN 7 /*!< \brief Pairing request message length. */
#define SMP_PAIR_RSP_LEN 7 /*!< \brief Pairing response message length. */
#define SMP_PAIR_CNF_LEN 17 /*!< \brief Pairing confirmation message length. */
#define SMP_PAIR_RAND_LEN 17 /*!< \brief Pairing random message length. */
#define SMP_PAIR_FAIL_LEN 2 /*!< \brief Pairing fail message length. */
#define SMP_ENC_INFO_LEN 17 /*!< \brief Encryption information message length. */
#define SMP_MASTER_ID_LEN 11 /*!< \brief Master identification messagelength. */
#define SMP_ID_INFO_LEN 17 /*!< \brief Identity information message length. */
#define SMP_ID_ADDR_INFO_LEN 8 /*!< \brief Identity address information message length. */
#define SMP_SIGN_INFO_LEN 17 /*!< \brief Signing information message length. */
#define SMP_SECURITY_REQ_LEN 2 /*!< \brief Security request message length. */
#define SMP_PUB_KEY_MSG_LEN (1 + 2*SMP_PUB_KEY_LEN) /*!< \brief Public key message length. */
#define SMP_DHKEY_CHECK_MSG_LEN (1 + SMP_DHKEY_CHECK_LEN) /*!< \brief Diffie-Hellman key check message length. */
#define SMP_KEYPRESS_MSG_LEN 2 /*!< \brief Keypress message length. */
/**@}*/
/** \name SMP I/O Capabilities
* I/O capabilities codes to be set for \ref SMP_CMD_PAIR_REQ and \ref SMP_CMD_PAIR_RSP
*/
/**@{*/
#define SMP_IO_DISP_ONLY 0x00 /*!< \brief Display only. */
#define SMP_IO_DISP_YES_NO 0x01 /*!< \brief Display yes/no. */
#define SMP_IO_KEY_ONLY 0x02 /*!< \brief Keyboard only. */
#define SMP_IO_NO_IN_NO_OUT 0x03 /*!< \brief No input, no output. */
#define SMP_IO_KEY_DISP 0x04 /*!< \brief Keyboard display. */
/**@}*/
/** \name SMP OOB Data Flag
* Out-of-Band codes to be set for \ref SMP_CMD_PAIR_REQ and \ref SMP_CMD_PAIR_RSP
*/
/**@{*/
#define SMP_OOB_DATA_NONE 0x00 /*!< \brief No OOB data from the remote device is present. */
#define SMP_OOB_DATA_PRESENT 0x01 /*!< \brief OOB data from the remote device is present. */
/**@}*/
/** \name SMP Authentication Requirements Flags
* Authentication Requirements Flags to be set for \ref SMP_CMD_PAIR_REQ and \ref SMP_CMD_PAIR_RSP.
*/
/**@{*/
#define SMP_AUTH_BOND_MASK 0x03 /*!< \brief Mask for bonding bits. */
#define SMP_AUTH_BOND_FLAG 0x01 /*!< \brief Bonding requested. */
#define SMP_AUTH_MITM_FLAG 0x04 /*!< \brief MITM (authenticated pairing) requested. */
#define SMP_AUTH_SC_FLAG 0x08 /*!< \brief LE Secure Connections requested. */
#define SMP_AUTH_KP_FLAG 0x10 /*!< \brief Keypress notifications requested. */
/**@}*/
/** \name SMP Key Distribution Flags
* Flags of security keys this device is requesting to be distribution once pairing completes.
*/
/**@{*/
#define SMP_KEY_DIST_ENC 0x01 /*!< \brief Distribute LTK. */
#define SMP_KEY_DIST_ID 0x02 /*!< \brief Distribute IRK. */
#define SMP_KEY_DIST_SIGN 0x04 /*!< \brief Distribute CSRK. */
/*! \brief Key distribution mask. */
#define SMP_KEY_DIST_MASK (SMP_KEY_DIST_ENC | SMP_KEY_DIST_ID | SMP_KEY_DIST_SIGN)
/**@}*/
/** \name SMP LE Secure Connection Keypress Codes
* Keypress codes found in \ref SMP_CMD_KEYPRESS PDU to be sent on the respective action when
* the \ref SMP_AUTH_KP_FLAG is set in both the \ref SMP_CMD_PAIR_REQ and \ref SMP_CMD_PAIR_RSP.
*/
/**@{*/
#define SMP_PASSKEY_ENTRY_STARTED 0x00 /*!< \brief Passkey entry started keypress type. */
#define SMP_PASSKEY_DIGIT_ENTERED 0x01 /*!< \brief Passkey digit entered keypress type. */
#define SMP_PASSKEY_DIGIT_ERASED 0x02 /*!< \brief Passkey digit erased keypress type. */
#define SMP_PASSKEY_CLEARED 0x03 /*!< \brief Passkey cleared keypress type. */
#define SMP_PASSKEY_ENTRY_COMPLETED 0x04 /*!< \brief Passkey entry complete keypress type. */
/**@}*/
/** \name SMP Value Length Constants
* Lengths of various keys and values.
*/
/**@{*/
#define SMP_RAND_LEN 16 /*!< \brief Random number length. */
#define SMP_CONFIRM_LEN 16 /*!< \brief Confirm number length. */
#define SMP_KEY_LEN 16 /*!< \brief Key length. */
#define SMP_RAND8_LEN 8 /*!< \brief Random 8-byte number length. */
#define SMP_PRIVATE_KEY_LEN 32 /*!< \brief Secure connections private key length. */
#define SMP_PUB_KEY_LEN 32 /*!< \brief Secure connecdtions public key length. */
#define SMP_DHKEY_LEN 32 /*!< \brief Secure connection Diffie-Hellman key length. */
#define SMP_DHKEY_CHECK_LEN 16 /*!< \brief Secure connection Diffie-Hellman key check length. */
/**@}*/
/** \name CMAC Input Lengths Constants
* Input lengths of SMP cryptopgraphic toolbox functions.
*/
/**@{*/
#define SMP_F4_TEXT_LEN (SMP_PUB_KEY_LEN * 2 + 1) /*!< \brief F4 input length. */
#define SMP_G2_TEXT_LEN (SMP_PUB_KEY_LEN * 2 + SMP_RAND_LEN) /*!< \brief G2 input length. */
#define SMP_F5_TKEY_TEXT_LEN (SMP_DHKEY_LEN) /*!< \brief F5 Temporary key input length. */
#define SMP_F5_TEXT_LEN (9 + 2*BDA_ADDR_LEN + 2*SMP_RAND_LEN) /*!< \brief F5 input length. */
#define SMP_F6_TEXT_LEN (2*BDA_ADDR_LEN + 3*SMP_RAND_LEN + 5) /*!< \brief F6 input length. */
/**@}*/
/*! \} */ /* STACK_SMP_API */
#ifdef __cplusplus
};
#endif
#endif /* SMP_DEFS_H */
@@ -0,0 +1,77 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Interface to SMP event handler.
*
* Copyright (c) 2010-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
#ifndef SMP_HANDLER_H
#define SMP_HANDLER_H
#include "wsf_os.h"
#ifdef __cplusplus
extern "C" {
#endif
/*! \addtogroup STACK_EVENT
* \{ */
/** \name SMP Event Handling
* Message passing interface to SMP from other tasks through WSF.
*/
/**@{*/
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief SMP handler init function called during system initialization.
*
* \param handlerId WSF handler ID for SMP.
*
* \return None.
*/
/*************************************************************************************************/
void SmpHandlerInit(wsfHandlerId_t handlerId);
/*************************************************************************************************/
/*!
* \brief WSF event handler for SMP.
*
* \param event WSF event mask.
* \param pMsg WSF message.
*
* \return None.
*/
/*************************************************************************************************/
void SmpHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
/**@}*/
/*! \} */ /* STACK_SMP_API */
#ifdef __cplusplus
};
#endif
#endif /* SMP_HANDLER_H */
@@ -0,0 +1,88 @@
//*****************************************************************************
//
//! @file hci_drv_apollo3.h
//!
//! @brief Support functions for the Nationz BTLE radio in Apollo3.
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef HCI_DRV_APOLLO3_H
#define HCI_DRV_APOLLO3_H
#ifdef __cplusplus
extern "C"
{
#endif
//*****************************************************************************
//
// NATIONZ vendor specific events
//
//*****************************************************************************
// Tx power level in dBm.
typedef enum
{
TX_POWER_LEVEL_MINUS_10P0_dBm = 0x3,
TX_POWER_LEVEL_0P0_dBm = 0x8,
TX_POWER_LEVEL_PLUS_3P0_dBm = 0xF,
TX_POWER_LEVEL_INVALID = 0x10,
}txPowerLevel_t;
bool_t HciVsA3_SetRfPowerLevelEx(txPowerLevel_t txPowerlevel);
void HciVsA3_ConstantTransmission(uint8_t txchannel);
void HciVsA3_CarrierWaveMode(uint8_t txchannel);
//*****************************************************************************
//
// Hci driver functions unique to Apollo3
//
//*****************************************************************************
extern void HciDrvHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
extern void HciDrvHandlerInit(wsfHandlerId_t handlerId);
extern void HciDrvIntService(void);
#ifdef __cplusplus
};
#endif
#endif // HCI_DRV_APOLLO3_H
@@ -0,0 +1,565 @@
//*****************************************************************************
//
//! @file hci_drv.c
//!
//! @brief HCI driver interface.
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#include <stdint.h>
#include <stdbool.h>
#include "wsf_types.h"
#include "wsf_msg.h"
#include "wsf_cs.h"
#include "hci_defs.h"
#include "hci_drv.h"
#include "hci_drv_apollo.h"
#include "hci_tr_apollo.h"
#include "hci_core.h"
#include "am_mcu_apollo.h"
#include "am_util.h"
#include "am_devices_em9304.h"
#include "hci_drv_em9304.h"
#include "em9304_patches.h"
#include "em9304_init.h"
#include "hci_apollo_config.h"
#include <string.h>
//*****************************************************************************
//
// Unless the config file overwrites this option, the HCI driver will use a
// direct call to the HAL when it needs to sleep.
//
//*****************************************************************************
#ifndef HCI_DRV_SLEEP
#define HCI_DRV_SLEEP am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP)
#endif
//*****************************************************************************
//
// If the config file doesn't say anything about MAC addresses, use a EM Microelectronic
// assigned BD address by default .
//
//*****************************************************************************
#ifndef HCI_APOLLO_MAC
#define HCI_APOLLO_MAC {0x01, 0x00, 0x00, 0xEE, 0xF3, 0x0C}
#endif
// HCI_APOLLO_USE_CUSTOMER_OWN_MAC should be defined to true if customer
// supply their own BD address.
#ifndef HCI_APOLLO_USE_CUSTOMER_OWN_MAC
#define HCI_APOLLO_USE_CUSTOMER_OWN_MAC false
#endif
uint8_t radio_boot_complete = 0;
//*****************************************************************************
//
// Mac address for the EM.
//
//*****************************************************************************
static uint8_t g_pui8BLEMacAddress[6] = HCI_APOLLO_MAC;
//*****************************************************************************
//
// HCI RX packet buffer for EM9304 Driver.
//
//*****************************************************************************
static uint32_t g_pui32HCIRXBuffer[64];
static uint32_t g_ui32HCIPacketSize;
static uint8_t g_consumed_bytes;
//*****************************************************************************
//
// Static record of the EM9304 vendor specific events
//
//*****************************************************************************
g_EMVSEvent_t g_EMVendorSpecificEvents = {0,0,0,0,0,0,0};
//*****************************************************************************
//
// Workaround for Keil memcpy()
//
// Keil's version of memcpy() contains an optimization that allows it to copy
// data more efficiently when both the source and destination pointers are well
// aligned. Unforunately, some of exactLE's complex callback structures confuse
// Keil's memcpy implementation. Left unchecked, this can lead to intermittent
// hard-faults.
//
// This function definition will intercept calls to this optimized version of
// memcpy and avoid the problem when the pointers are unexpectedly unaligned.
//
//*****************************************************************************
#if defined(__ARMCC_VERSION)
void $Super$$__aeabi_memcpy4(void *dest, const void *src, size_t n);
void
$Sub$$__aeabi_memcpy4(void *dest, const void *src, size_t n)
{
//
// If the pointers are aligned, we can use Keil's normal memcpy.
//
if ((((uint32_t)dest % 4) == 0) && (((uint32_t)src % 4) == 0))
{
$Super$$__aeabi_memcpy4(dest, src, n);
return;
}
//
// Otherwise, make sure we use 8-bit pointers.
//
uint8_t *tempSrc = (uint8_t *)(src);
uint8_t *tempDest = (uint8_t *)(dest);
//
// Copy from src to dest, one byte at a time.
//
for (uint32_t i = 0; i < n; i++)
{
*tempDest++ = *tempSrc++;
}
}
#endif
//*****************************************************************************
//
//! @brief Get the EM9304 vendor specific event counters.
//!
//! @return Returns a pointer to the EM9304 vendor specific event counters.
//
//*****************************************************************************
g_EMVSEvent_t *getEM9304VSEventCounters(void)
{
return &g_EMVendorSpecificEvents;
}
//*****************************************************************************
//
//! @brief Write data the driver.
//!
//! @param type HCI packet type
//! @param len Number of bytes to write
//! @param pData Byte array to write
//!
//! @return Returns the number of bytes written.
//
//*****************************************************************************
uint16_t
hciDrvWrite(uint8_t type, uint16_t len, uint8_t *pData)
{
//
// Turn on the IOM for this operation.
//
am_devices_em9304_spi_awake(g_sEm9304.ui32IOMModule);
//
// Write the HCI packet.
//
am_devices_em9304_block_write(&g_sEm9304, type, pData, len );
//
// Disable IOM SPI pins and turn off the IOM after operation
//
am_devices_em9304_spi_sleep(g_sEm9304.ui32IOMModule);
return len;
}
//*****************************************************************************
//
// hciDrvReadyToSleep - Stub provided to allow other layers to run correctly.
//
//*****************************************************************************
bool_t
hciDrvReadyToSleep(void)
{
return TRUE;
}
bool_t
HciDataReadyISR(void)
{
//
// If the radio boot has not yet completed, then do not process HCI packets
if (!radio_boot_complete)
{
return TRUE;
}
// check if there's pending HCI data from last time
if (g_ui32HCIPacketSize > g_consumed_bytes)
{
g_consumed_bytes += hciTrSerialRxIncoming(
((uint8_t *)g_pui32HCIRXBuffer) + g_consumed_bytes,
g_ui32HCIPacketSize - g_consumed_bytes);
if (g_consumed_bytes == g_ui32HCIPacketSize) {
g_ui32HCIPacketSize = 0;
g_consumed_bytes = 0;
}
else {
return FALSE;
}
}
//
// Turn on the IOM for this operation.
//
am_devices_em9304_spi_awake(g_sEm9304.ui32IOMModule);
g_ui32HCIPacketSize = am_devices_em9304_block_read(&g_sEm9304, g_pui32HCIRXBuffer, 0);
// Check for EM9304 Vendor Specific events and record them.
if ( (g_ui32HCIPacketSize > 3) && (0x0001FF04 == (g_pui32HCIRXBuffer[0] & 0x00FFFFFF)) )
{
switch((g_pui32HCIRXBuffer[0] & 0xFF000000) >> 24)
{
case 0x01:
g_EMVendorSpecificEvents.EM_ActiveStateEntered++;
am_util_debug_printf("Received EM_ActiveStateEntered Event\n");
break;
case 0x03:
g_EMVendorSpecificEvents.EM_TestModeEntered++;
am_util_debug_printf("Received EM_TestModeEntered Event\n");
break;
case 0x04:
g_EMVendorSpecificEvents.EM_HalNotification++;
am_util_debug_printf("Received EM_HalNotification Event\n");
break;
default:
am_util_debug_printf("Received Unknown Vendor Specific Event from EM9304\n");
break;
}
//
// Reset the packet size to 0 so that this packet will not be processed by the host stack.
//
g_ui32HCIPacketSize = 0;
}
if (g_ui32HCIPacketSize > 0)
{
g_consumed_bytes += hciTrSerialRxIncoming((uint8_t *)g_pui32HCIRXBuffer, g_ui32HCIPacketSize);
if (g_consumed_bytes == g_ui32HCIPacketSize) {
g_ui32HCIPacketSize = 0;
g_consumed_bytes = 0;
}
}
//
// Disable IOM SPI pins and turn off the IOM after operation
//
am_devices_em9304_spi_sleep(g_sEm9304.ui32IOMModule);
return (g_ui32HCIPacketSize == 0);
}
//*****************************************************************************
//
// Configure the necessary pins and start the EM9304 radio.
//
//*****************************************************************************
void
HciDrvRadioBoot(uint32_t ui32UartModule)
{
uint32_t patch_dest_memory = DEST_MEMORY_IRAM;
uint32_t ui32PN;
// disable interrupt during EM9304 initialization.
am_devices_em9304_disable_interrupt();
radio_boot_complete = 0;
//
// Enable the radio pins.
//
#ifdef HCI_APOLLO_POWER_PIN
//
// Insert a power on reset to TLSR8269
// (with TLSR8269 EVK, this is only done via power pin)
//
am_hal_gpio_pin_config(HCI_APOLLO_POWER_PIN, HCI_APOLLO_POWER_CFG);
am_hal_gpio_out_bit_clear(HCI_APOLLO_POWER_PIN);
am_util_delay_ms(100);
am_hal_gpio_out_bit_set(HCI_APOLLO_POWER_PIN);
am_util_delay_ms(100);
#endif
//
// Device identification
//
ui32PN = AM_REG(MCUCTRL, CHIP_INFO) &
AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_PN_M;
// Currently only enable this for Apollo2-Blue
if (ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLOBL)
{
am_hal_gpio_pin_config(30, AM_HAL_GPIO_OUTPUT);
am_hal_gpio_out_bit_clear(30);
am_hal_gpio_pin_config(35, AM_HAL_GPIO_OUTPUT);
am_hal_gpio_out_bit_clear(35);
am_hal_gpio_pin_config(36, AM_HAL_GPIO_OUTPUT);
am_hal_gpio_out_bit_clear(36);
}
//
// Assert RESET to the EM9304 device.
//
am_hal_gpio_pin_config(HCI_APOLLO_RESET_PIN, AM_HAL_GPIO_OUTPUT);
am_hal_gpio_out_bit_clear(HCI_APOLLO_RESET_PIN);
//
// Setup SPI interface for EM9304
//
am_devices_em9304_config_pins();
am_devices_em9304_spi_init(g_sEm9304.ui32IOMModule, &g_sEm9304IOMConfigSPI);
//
// Enable the IOM and GPIO interrupt handlers.
//
am_hal_gpio_out_bit_set(HCI_APOLLO_RESET_PIN);
//
// Delay for 20ms to make sure the em device gets ready for commands.
//
am_util_delay_ms(20);
//
// Initialize the EM9304.
//
patch_dest_memory = initEM9304();
//
// Delay for 20ms to make sure the em device completes initialization.
//
am_util_delay_ms(20);
if (patch_dest_memory == DEST_MEMORY_OTP)
{
//
// Completed the patching process by cycling RESET to the EM9304 device.
//
am_hal_gpio_pin_config(HCI_APOLLO_RESET_PIN, AM_HAL_GPIO_OUTPUT);
am_hal_gpio_out_bit_clear(HCI_APOLLO_RESET_PIN);
am_util_delay_ms(20);
am_hal_gpio_out_bit_set(HCI_APOLLO_RESET_PIN);
// delay here to make sure EM9304 is ready for operation after
// patch is loaded.
am_util_delay_ms(20);
}
//
// Set the MAC address if customer provides their own BD address
//
if (HCI_APOLLO_USE_CUSTOMER_OWN_MAC)
{
//
// currently just use the default one, customer either update g_pui8BLEMacAddress
// directly or call HciDrvAssignBDAddress() with a pointer of assigned BD address.
HciDrvAssignBDAddress(g_pui8BLEMacAddress);
}
// Initialization of the EM9304 is complete.
radio_boot_complete = 1;
g_ui32HCIPacketSize = 0;
g_consumed_bytes = 0;
am_util_debug_printf("HciDrvRadioBoot complete\n");
// enable interrupt after EM9304 initialization is done.
am_devices_em9304_enable_interrupt();
}
void
HciDrvRadioShutdown(void)
{
uint32_t ui32PN;
radio_boot_complete = 0;
g_ui32HCIPacketSize = 0;
g_consumed_bytes = 0;
am_devices_em9304_disable_interrupt();
AM_HAL_GPIO_MASKCREATE(GpioIntMask);
am_hal_gpio_int_clear(AM_HAL_GPIO_MASKBIT(pGpioIntMask, AM_BSP_GPIO_EM9304_INT));
am_hal_gpio_pin_config(AM_BSP_GPIO_EM9304_CS, AM_HAL_PIN_OUTPUT);
am_hal_gpio_out_bit_clear(AM_BSP_GPIO_EM9304_CS);
am_hal_clkgen_clkout_disable();
//
// Device identification
//
ui32PN = AM_REG(MCUCTRL, CHIP_INFO) &
AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_PN_M;
if (ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLOBL)
{
// Currently clear pin 24 only for Apollo2-Blue
am_hal_gpio_pin_config(24, AM_HAL_PIN_24_CLKOUT);
am_hal_gpio_out_bit_clear(24);
}
am_hal_gpio_pin_config(HCI_APOLLO_RESET_PIN, AM_HAL_PIN_OUTPUT);
am_hal_gpio_out_bit_clear(HCI_APOLLO_RESET_PIN);
am_hal_gpio_pin_config(AM_BSP_GPIO_EM9304_INT, AM_HAL_PIN_OUTPUT);
am_hal_gpio_out_bit_clear(AM_BSP_GPIO_EM9304_INT);
}
/*************************************************************************************************/
/*!
* \fn HciVsSetRfPowerLevelEx
*
* \brief Vendor-specific command for settting Radio transmit power level
* for EM9304.
*
* \param txPowerlevel valid range from 0 to 17 in decimal.
*
* \return true when success, otherwise false
*/
/*************************************************************************************************/
uint32_t HciVsEM_SetRfPowerLevelEx(txPowerLevel_t txPowerlevel)
{
// make sure it's 8 bit
uint8_t tx_power_level = (uint8_t)txPowerlevel;
if(tx_power_level < TX_POWER_LEVEL_INVALID) {
HciVendorSpecificCmd(0xFC26, sizeof(tx_power_level), &tx_power_level);
return true;
}
else {
return false;
}
}
/*************************************************************************************************/
/*!
* \fn HciVsEM_TransmitterTest
*
* \brief Vendor-specific command for start transmitter testing
*
* \param test_mode refer to em9304 datasheet
* \param channel_number refer to em9304 datasheet
* \param packet_len refer to em9304 datasheet
* \param packet_payload_type refer to em9304 datasheet
*
* \return None
*/
/*************************************************************************************************/
void HciVsEM_TransmitterTest(uint8_t test_mode, uint8_t channel_number, uint8_t packet_len, uint8_t packet_payload_type)
{
uint8_t params[4] = {
test_mode,
channel_number,
packet_len,
packet_payload_type
};
HciVendorSpecificCmd(0xFC11, sizeof(params), &params[0]);
}
/*************************************************************************************************/
/*!
* \fn HciVsEM_TransmitterTestEnd
*
* \brief Vendor-specific command for ending Radio transmitter testing.
*
* \param None
*
* \return None
*/
/*************************************************************************************************/
void HciVsEM_TransmitterTestEnd(void)
{
HciVendorSpecificCmd(0xFC12, 0, NULL);
}
void HciVsEM_ReadAtAddress(uint32_t addr)
{
uint8_t ReadAtAddress[5];
// only read 4 bytes
memcpy(ReadAtAddress, &addr, 4);
ReadAtAddress[4] = 4;
HciVendorSpecificCmd(0xFC20, sizeof(ReadAtAddress), ReadAtAddress);
}
void HciVsEM_WriteAtAddress(uint32_t addr, uint32_t value)
{
uint8_t WriteAtAddress[8];
// only write 4 bytes
memcpy(WriteAtAddress, &addr, 4);
memcpy(WriteAtAddress+4, &value, 4);
HciVendorSpecificCmd(0xFC22, sizeof(WriteAtAddress), WriteAtAddress);
}
void HciDrvAssignBDAddress(uint8_t * customer_unique_bd_address)
{
if (customer_unique_bd_address)
{
memcpy(g_pui8BLEMacAddress, customer_unique_bd_address, 6);
}
}
void HciVsEM_SetBDAddress(void)
{
if (HCI_APOLLO_USE_CUSTOMER_OWN_MAC)
{
HciVendorSpecificCmd(0xFC02, 6, g_pui8BLEMacAddress);
}
}
@@ -0,0 +1,99 @@
//*****************************************************************************
//
//! @file hci_drv_em9304.h
//!
//! @brief Support functions for the EM Micro EM9304 BTLE radio.
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef HCI_DRV_EM9304_H
#define HCI_DRV_EM9304_H
//*****************************************************************************
//
// EM9304 vendor specific events
//
//*****************************************************************************
typedef struct
{
uint32_t EM_ActiveStateEntered;
uint32_t EM_TestModeEntered;
uint32_t EM_HalNotification;
uint32_t EM_DebugPrint;
uint32_t EM_DebugStackUsage;
uint32_t EM_DebugBacktrace;
uint32_t EM_DebugAssert;
} g_EMVSEvent_t;
// Tx power level in dBm.
typedef enum
{
TX_POWER_LEVEL_MINOR_33P5_dBm, // 0, not compliant with BT spec
TX_POWER_LEVEL_MINOR_29P0_dBm, // 1, not compliant with BT spec
TX_POWER_LEVEL_MINOR_17P9_dBm, // 2
TX_POWER_LEVEL_MINOR_16P4_dBm, // 3
TX_POWER_LEVEL_MINOR_14P6_dBm, // 4
TX_POWER_LEVEL_MINOR_13P1_dBm, // 5
TX_POWER_LEVEL_MINOR_11P4_dBm, // 6
TX_POWER_LEVEL_MINOR_9P9_dBm, // 7
TX_POWER_LEVEL_MINOR_8P4_dBm, // 8
TX_POWER_LEVEL_MINOR_6P9_dBm, // 9
TX_POWER_LEVEL_MINOR_5P5_dBm, // 10
TX_POWER_LEVEL_MINOR_4P0_dBm, // 11
TX_POWER_LEVEL_MINOR_2P6_dBm, // 12
TX_POWER_LEVEL_MINOR_1P4_dBm, // 13
TX_POWER_LEVEL_PLUS_0P4_dBm, // 14
TX_POWER_LEVEL_PLUS_2P5_dBm, // 15
TX_POWER_LEVEL_PLUS_4P6_dBm, // 16
TX_POWER_LEVEL_PLUS_6P2_dBm, // 17
TX_POWER_LEVEL_INVALID
}txPowerLevel_t;
extern g_EMVSEvent_t *getEM9304VSEventCounters(void);
extern uint32_t HciVsEM_SetRfPowerLevelEx(txPowerLevel_t txPowerlevel);
extern void HciVsEM_TransmitterTest(uint8_t test_mode, uint8_t channel_number, uint8_t packet_len, uint8_t packet_payload_type);
extern void HciVsEM_TransmitterTestEnd(void);
extern void HciVsEM_ReadAtAddress(uint32_t addr);
extern void HciVsEM_WriteAtAddress(uint32_t addr, uint32_t value);
extern void HciDrvAssignBDAddress(uint8_t * customer_unique_bd_address);
extern void HciVsEM_SetBDAddress(void);
#endif // HCI_DRV_EM9304_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,703 @@
/* Copyright (c) 2009-2019 Arm Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
/*!
* \brief HCI Advertising Extensions (AE) command module.
*/
/*************************************************************************************************/
#include <string.h>
#include "wsf_types.h"
#include "wsf_msg.h"
#include "util/bstream.h"
#include "hci_cmd.h"
#include "hci_api.h"
#include "hci_main.h"
/*************************************************************************************************/
/*!
* \brief HCI LE set advertising set random device address command.
*
* \param advHandle Advertising handle.
* \param pAddr Random device address.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeSetAdvSetRandAddrCmd(uint8_t advHandle, const uint8_t *pAddr)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_ADV_SET_RAND_ADDR, HCI_LEN_LE_SET_ADV_SET_RAND_ADDR)) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT8_TO_BSTREAM(p, advHandle);
BDA_TO_BSTREAM(p, pAddr);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE set extended advertising parameters command.
*
* \param advHandle Advertising handle.
* \param pExtAdvParam Extended advertising parameters.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeSetExtAdvParamCmd(uint8_t advHandle, hciExtAdvParam_t *pExtAdvParam)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_EXT_ADV_PARAM, HCI_LEN_LE_SET_EXT_ADV_PARAM)) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT8_TO_BSTREAM(p, advHandle);
UINT16_TO_BSTREAM(p, pExtAdvParam->advEventProp);
UINT24_TO_BSTREAM(p, pExtAdvParam->priAdvInterMin);
UINT24_TO_BSTREAM(p, pExtAdvParam->priAdvInterMax);
UINT8_TO_BSTREAM(p, pExtAdvParam->priAdvChanMap);
UINT8_TO_BSTREAM(p, pExtAdvParam->ownAddrType);
UINT8_TO_BSTREAM(p, pExtAdvParam->peerAddrType);
BDA_TO_BSTREAM(p, pExtAdvParam->pPeerAddr);
UINT8_TO_BSTREAM(p, pExtAdvParam->advFiltPolicy);
UINT8_TO_BSTREAM(p, pExtAdvParam->advTxPwr);
UINT8_TO_BSTREAM(p, pExtAdvParam->priAdvPhy);
UINT8_TO_BSTREAM(p, pExtAdvParam->secAdvMaxSkip);
UINT8_TO_BSTREAM(p, pExtAdvParam->secAdvPhy);
UINT8_TO_BSTREAM(p, pExtAdvParam->advSetId);
UINT8_TO_BSTREAM(p, pExtAdvParam->scanReqNotifEna);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE set extended advertising data command.
*
* \param advHandle Advertising handle.
* \param op Operation.
* \param fragPref Fragment preference.
* \param len Data buffer length.
* \param pData Advertising data buffer.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeSetExtAdvDataCmd(uint8_t advHandle, uint8_t op, uint8_t fragPref, uint8_t len,
const uint8_t *pData)
{
uint8_t *pBuf;
uint8_t *p;
if (len > HCI_EXT_ADV_DATA_LEN)
{
len = HCI_EXT_ADV_DATA_LEN;
}
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_EXT_ADV_DATA, HCI_LEN_LE_SET_EXT_ADV_DATA(len))) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT8_TO_BSTREAM(p, advHandle);
UINT8_TO_BSTREAM(p, op);
UINT8_TO_BSTREAM(p, fragPref);
UINT8_TO_BSTREAM(p, len);
memcpy(p, pData, len);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE set extended scan response data command.
*
* \param advHandle Advertising handle.
* \param op Operation.
* \param fragPref Fragment preference.
* \param len Data buffer length.
* \param pData Scan response data buffer.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeSetExtScanRespDataCmd(uint8_t advHandle, uint8_t op, uint8_t fragPref, uint8_t len,
const uint8_t *pData)
{
uint8_t *pBuf;
uint8_t *p;
if (len > HCI_EXT_ADV_DATA_LEN)
{
len = HCI_EXT_ADV_DATA_LEN;
}
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_EXT_SCAN_RESP_DATA,
HCI_LEN_LE_SET_EXT_SCAN_RESP_DATA(len))) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT8_TO_BSTREAM(p, advHandle);
UINT8_TO_BSTREAM(p, op);
UINT8_TO_BSTREAM(p, fragPref);
UINT8_TO_BSTREAM(p, len);
memcpy(p, pData, len);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE set extended advertising enable command.
*
* \param enable Set to TRUE to enable advertising, FALSE to disable advertising.
* \param numSets Number of advertising sets.
* \param pScanParam Advertising enable parameter array.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeSetExtAdvEnableCmd(uint8_t enable, uint8_t numSets, hciExtAdvEnableParam_t *pEnableParam)
{
uint8_t *pBuf;
uint8_t *p;
uint8_t i;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_EXT_ADV_ENABLE, HCI_LEN_LE_EXT_ADV_ENABLE(numSets))) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT8_TO_BSTREAM(p, enable);
UINT8_TO_BSTREAM(p, numSets);
for (i = 0; i < numSets; i++)
{
UINT8_TO_BSTREAM(p, pEnableParam[i].advHandle);
UINT16_TO_BSTREAM(p, pEnableParam[i].duration);
UINT8_TO_BSTREAM(p, pEnableParam[i].maxEaEvents);
}
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE read maximum advertising data length command.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeReadMaxAdvDataLen(void)
{
uint8_t *pBuf;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_READ_MAX_ADV_DATA_LEN, HCI_LEN_LE_READ_MAX_ADV_DATA_LEN)) != NULL)
{
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE read number of supported advertising sets command.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeReadNumSupAdvSets(void)
{
uint8_t *pBuf;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_READ_NUM_SUP_ADV_SETS, HCI_LEN_LE_READ_NUM_OF_SUP_ADV_SETS)) != NULL)
{
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE remove advertising set command.
*
* \param advHandle Advertising handle.
*
* \return Status error code.
*/
/*************************************************************************************************/
void HciLeRemoveAdvSet(uint8_t advHandle)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_REMOVE_ADV_SET, HCI_LEN_LE_REMOVE_ADV_SET)) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT8_TO_BSTREAM(p, advHandle);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE clear advertising sets command.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeClearAdvSets(void)
{
uint8_t *pBuf;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_CLEAR_ADV_SETS, HCI_LEN_LE_CLEAR_ADV_SETS)) != NULL)
{
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE set periodic advertising parameters command.
*
* \param advHandle Advertising handle.
* \param advIntervalMin Periodic advertising interval minimum.
* \param advIntervalMax Periodic advertising interval maximum.
* \param advProps Periodic advertising properties.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeSetPerAdvParamCmd(uint8_t advHandle, uint16_t advIntervalMin, uint16_t advIntervalMax,
uint16_t advProps)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_PER_ADV_PARAM, HCI_LEN_LE_SET_PER_ADV_PARAM)) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT8_TO_BSTREAM(p, advHandle);
UINT16_TO_BSTREAM(p, advIntervalMin);
UINT16_TO_BSTREAM(p, advIntervalMax);
UINT16_TO_BSTREAM(p, advProps);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE set periodic advertising data command.
*
* \param advHandle Advertising handle.
* \param op Operation.
* \param len Data buffer length.
* \param pData Advertising data buffer.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeSetPerAdvDataCmd(uint8_t advHandle, uint8_t op, uint8_t len, const uint8_t *pData)
{
uint8_t *pBuf;
uint8_t *p;
if (len > HCI_PER_ADV_DATA_LEN)
{
len = HCI_PER_ADV_DATA_LEN;
}
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_PER_ADV_DATA, HCI_LEN_LE_SET_PER_ADV_DATA(len))) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT8_TO_BSTREAM(p, advHandle);
UINT8_TO_BSTREAM(p, op);
UINT8_TO_BSTREAM(p, len);
memcpy(p, pData, len);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE set periodic advertising enable command.
*
* \param enable Set to TRUE to enable advertising, FALSE to disable advertising.
* \param advHandle Advertising handle.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeSetPerAdvEnableCmd(uint8_t enable, uint8_t advHandle)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_PER_ADV_ENABLE, HCI_LEN_LE_SET_PER_ADV_ENABLE)) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT8_TO_BSTREAM(p, enable);
UINT8_TO_BSTREAM(p, advHandle);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE set extended scanning parameters command.
*
* \param ownAddrType Address type used by this device.
* \param scanFiltPolicy Scan filter policy.
* \param scanPhys Scanning PHYs.
* \param pScanParam Scanning parameter array.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeSetExtScanParamCmd(uint8_t ownAddrType, uint8_t scanFiltPolicy, uint8_t scanPhys,
hciExtScanParam_t *pScanParam)
{
uint8_t *pBuf;
uint8_t *p;
uint8_t i;
uint8_t numPhys;
/* find out number of scanning PHYs */
for (i = 0, numPhys = 0; (i < 8) && (numPhys <= HCI_MAX_NUM_PHYS); i++)
{
if (scanPhys & (1 << i))
{
numPhys++;
}
}
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_EXT_SCAN_PARAM, HCI_LEN_LE_SET_EXT_SCAN_PARAM(numPhys))) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT8_TO_BSTREAM(p, ownAddrType);
UINT8_TO_BSTREAM(p, scanFiltPolicy);
UINT8_TO_BSTREAM(p, scanPhys);
for (i = 0; i < numPhys; i++)
{
UINT8_TO_BSTREAM(p, pScanParam[i].scanType);
UINT16_TO_BSTREAM(p, pScanParam[i].scanInterval);
UINT16_TO_BSTREAM(p, pScanParam[i].scanWindow)
}
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE extended scan enable command.
*
* \param enable Set to TRUE to enable scanning, FALSE to disable scanning.
* \param filterDup Set to TRUE to filter duplicates.
* \param duration Duration.
* \param period Period.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeExtScanEnableCmd(uint8_t enable, uint8_t filterDup, uint16_t duration, uint16_t period)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_EXT_SCAN_ENABLE, HCI_LEN_LE_SET_EXT_SCAN_ENABLE)) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT8_TO_BSTREAM(p, enable);
UINT8_TO_BSTREAM(p, filterDup);
UINT16_TO_BSTREAM(p, duration);
UINT16_TO_BSTREAM(p, period);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE extended create connection command.
*
* \param pInitParam Initiating parameters.
* \param pScanParam Initiating scan parameters.
* \param pConnSpec Connection specification.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeExtCreateConnCmd(hciExtInitParam_t *pInitParam, hciExtInitScanParam_t *pScanParam,
hciConnSpec_t *pConnSpec)
{
uint8_t *pBuf;
uint8_t *p;
uint8_t i;
uint8_t numPhys;
/* find out number of initiating PHYs */
for (i = 0, numPhys = 0; (i < 8) && (numPhys <= HCI_MAX_NUM_PHYS); i++)
{
if (pInitParam->initPhys & (1 << i))
{
numPhys++;
}
}
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_EXT_CREATE_CONN, HCI_LEN_LE_EXT_CREATE_CONN(numPhys))) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT8_TO_BSTREAM(p, pInitParam->filterPolicy);
UINT8_TO_BSTREAM(p, pInitParam->ownAddrType);
UINT8_TO_BSTREAM(p, pInitParam->peerAddrType);
BDA_TO_BSTREAM(p, pInitParam->pPeerAddr);
UINT8_TO_BSTREAM(p, pInitParam->initPhys);
for (i = 0; i < numPhys; i++)
{
UINT16_TO_BSTREAM(p, pScanParam[i].scanInterval);
UINT16_TO_BSTREAM(p, pScanParam[i].scanWindow);
UINT16_TO_BSTREAM(p, pConnSpec[i].connIntervalMin);
UINT16_TO_BSTREAM(p, pConnSpec[i].connIntervalMax);
UINT16_TO_BSTREAM(p, pConnSpec[i].connLatency);
UINT16_TO_BSTREAM(p, pConnSpec[i].supTimeout);
UINT16_TO_BSTREAM(p, pConnSpec[i].minCeLen);
UINT16_TO_BSTREAM(p, pConnSpec[i].maxCeLen);
}
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE periodic advertising create sync command.
*
* \param options Options.
* \param advSid Advertising SID.
* \param advAddrType Advertiser address type.
* \param pAdvAddr Advertiser address.
* \param skip Number of periodic advertising packets that can be skipped after
* successful receive.
* \param syncTimeout Synchronization timeout.
* \param unused Reserved for future use (must be zero).
*
* \return None.
*/
/*************************************************************************************************/
void HciLePerAdvCreateSyncCmd(uint8_t options, uint8_t advSid, uint8_t advAddrType,
uint8_t *pAdvAddr, uint16_t skip, uint16_t syncTimeout, uint8_t unused)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_PER_ADV_CREATE_SYNC, HCI_LEN_LE_PER_ADV_CREATE_SYNC)) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT8_TO_BSTREAM(p, options);
UINT8_TO_BSTREAM(p, advSid);
UINT8_TO_BSTREAM(p, advAddrType);
BDA_TO_BSTREAM(p, pAdvAddr);
UINT16_TO_BSTREAM(p, skip);
UINT16_TO_BSTREAM(p, syncTimeout);
UINT8_TO_BSTREAM(p, unused);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE periodic advertising create sync cancel command.
*
* \return None.
*/
/*************************************************************************************************/
void HciLePerAdvCreateSyncCancelCmd(void)
{
uint8_t *pBuf;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_PER_ADV_CREATE_SYNC_CANCEL, HCI_LEN_LE_PER_ADV_CREATE_SYNC_CANCEL)) != NULL)
{
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE periodic advertising terminate sync command.
*
* \param syncHandle Sync handle.
*
* \return None.
*/
/*************************************************************************************************/
void HciLePerAdvTerminateSyncCmd(uint16_t syncHandle)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_PER_ADV_TERMINATE_SYNC, HCI_LEN_LE_PER_ADV_TERMINATE_SYNC)) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT16_TO_BSTREAM(p, syncHandle);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE add device to periodic advertiser list command.
*
* \param advAddrType Advertiser address type.
* \param pAdvAddr Advertiser address.
* \param advSid Advertising SID.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeAddDeviceToPerAdvListCmd(uint8_t advAddrType, uint8_t *pAdvAddr, uint8_t advSid)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_ADD_DEV_PER_ADV_LIST, HCI_LEN_LE_ADD_DEV_PER_ADV_LIST)) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT8_TO_BSTREAM(p, advAddrType);
BDA_TO_BSTREAM(p, pAdvAddr);
UINT8_TO_BSTREAM(p, advSid);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE remove device from periodic advertiser list command.
*
* \param advAddrType Advertiser address type.
* \param pAdvAddr Advertiser address.
* \param advSid Advertising SID.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeRemoveDeviceFromPerAdvListCmd(uint8_t advAddrType, uint8_t *pAdvAddr, uint8_t advSid)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_REMOVE_DEV_PER_ADV_LIST, HCI_LEN_LE_REMOVE_DEV_PER_ADV_LIST)) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT8_TO_BSTREAM(p, advAddrType);
BDA_TO_BSTREAM(p, pAdvAddr);
UINT8_TO_BSTREAM(p, advSid);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE clear periodic advertiser list command.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeClearPerAdvListCmd(void)
{
uint8_t *pBuf;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_CLEAR_PER_ADV_LIST, HCI_LEN_LE_CLEAR_PER_ADV_LIST)) != NULL)
{
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE read periodic advertiser size command.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeReadPerAdvListSizeCmd(void)
{
uint8_t *pBuf;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_READ_PER_ADV_LIST_SIZE, HCI_LEN_LE_READ_PER_ADV_LIST_SIZE)) != NULL)
{
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE read transmit power command.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeReadTxPower(void)
{
uint8_t *pBuf;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_READ_TX_POWER, HCI_LEN_LE_READ_TX_POWER)) != NULL)
{
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE read RF path compensation command.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeReadRfPathComp(void)
{
uint8_t *pBuf;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_READ_RF_PATH_COMP, HCI_LEN_LE_READ_RF_PATH_COMP)) != NULL)
{
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE write RF path compensation command.
*
* \param txPathComp RF transmit path compensation value.
* \param rxPathComp RF receive path compensation value.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeWriteRfPathComp(int16_t txPathComp, int16_t rxPathComp)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_WRITE_RF_PATH_COMP, HCI_LEN_LE_WRITE_RF_PATH_COMP)) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT16_TO_BSTREAM(p, txPathComp);
UINT16_TO_BSTREAM(p, rxPathComp);
hciCmdSend(pBuf);
}
}
@@ -0,0 +1,165 @@
/* Copyright (c) 2009-2019 Arm Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
/*!
* \brief HCI Constant Tone Extension (CTE) command module.
*/
/*************************************************************************************************/
#include <string.h>
#include "wsf_types.h"
#include "wsf_msg.h"
#include "util/bstream.h"
#include "hci_cmd.h"
#include "hci_api.h"
#include "hci_main.h"
/*************************************************************************************************/
/*!
* \brief HCI LE set connection CTE receive parameters command.
*
* \param connHandle Connection handle.
* \param samplingEnable TRUE to enable Connection IQ sampling, FALSE to disable it.
* \param slotDurations Switching and sampling slot durations to be used while receiving CTE.
* \param switchPatternLen Number of Antenna IDs in switching pattern.
* \param pAntennaIDs List of Antenna IDs in switching pattern.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeSetConnCteRxParamsCmd(uint16_t connHandle, uint8_t samplingEnable, uint8_t slotDurations,
uint8_t switchPatternLen, uint8_t *pAntennaIDs)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_CONN_CTE_RX_PARAMS,
HCI_LEN_LE_SET_CONN_CTE_RX_PARAMS(switchPatternLen))) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT16_TO_BSTREAM(p, connHandle);
UINT8_TO_BSTREAM(p, samplingEnable);
UINT8_TO_BSTREAM(p, slotDurations);
UINT8_TO_BSTREAM(p, switchPatternLen);
memcpy(p, pAntennaIDs, switchPatternLen);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE set connection CTE transmit parameters command.
*
* \param connHandle Connection handle.
* \param cteTypeBits Permitted CTE type bits used for transmitting CTEs requested by peer.
* \param switchPatternLen Number of Antenna IDs in switching pattern.
* \param pAntennaIDs List of Antenna IDs in switching pattern.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeSetConnCteTxParamsCmd(uint16_t connHandle, uint8_t cteTypeBits, uint8_t switchPatternLen,
uint8_t *pAntennaIDs)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_CONN_CTE_TX_PARAMS,
HCI_LEN_LE_SET_CONN_CTE_TX_PARAMS(switchPatternLen))) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT16_TO_BSTREAM(p, connHandle);
UINT8_TO_BSTREAM(p, cteTypeBits);
UINT8_TO_BSTREAM(p, switchPatternLen);
memcpy(p, pAntennaIDs, switchPatternLen);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE connection CTE request enable command.
*
* \param connHandle Connection handle.
* \param enable TRUE to enable CTE request for connection, FALSE to disable it.
* \param cteReqInt CTE request interval.
* \param reqCteLen Minimum length of CTE being requested in 8 us units.
* \param reqCteType Requested CTE type.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeConnCteReqEnableCmd(uint16_t connHandle, uint8_t enable, uint16_t cteReqInt,
uint8_t reqCteLen, uint8_t reqCteType)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_CONN_CTE_REQ_ENABLE,
HCI_LEN_LE_CONN_CTE_REQ_ENABLE)) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT16_TO_BSTREAM(p, connHandle);
UINT8_TO_BSTREAM(p, enable);
UINT16_TO_BSTREAM(p, cteReqInt);
UINT8_TO_BSTREAM(p, reqCteLen);
UINT8_TO_BSTREAM(p, reqCteType);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE connection CTE response enable command.
*
* \param connHandle Connection handle.
* \param enable TRUE to enable CTE response for connection, FALSE to disable it.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeConnCteRspEnableCmd(uint16_t connHandle, uint8_t enable)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_CONN_CTE_RSP_ENABLE,
HCI_LEN_LE_CONN_CTE_RSP_ENABLE)) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT16_TO_BSTREAM(p, connHandle);
UINT8_TO_BSTREAM(p, enable);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE read antenna information command.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeReadAntennaInfoCmd(void)
{
uint8_t *pBuf;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_READ_ANTENNA_INFO, HCI_LEN_LE_READ_ANTENNA_INFO)) != NULL)
{
hciCmdSend(pBuf);
}
}
@@ -0,0 +1,171 @@
/* Copyright (c) 2009-2019 Arm Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
/*!
* \brief HCI Periodic Advertising Sync Transfer (PAST) command module.
*/
/*************************************************************************************************/
#include <string.h>
#include "wsf_types.h"
#include "wsf_msg.h"
#include "util/bstream.h"
#include "hci_cmd.h"
#include "hci_api.h"
#include "hci_main.h"
/*************************************************************************************************/
/*!
* \brief HCI LE set periodic advertising receive enable command.
*
* \param syncHandle Periodic sync handle.
* \param enable TRUE to enable reports, FALSE to disable reports.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeSetPerAdvRcvEnableCmd(uint16_t syncHandle, uint8_t enable)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_PER_ADV_RCV_ENABLE,
HCI_LEN_LE_SET_PER_ADV_RCV_ENABLE)) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT16_TO_BSTREAM(p, syncHandle);
UINT8_TO_BSTREAM(p, enable);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE periodic advertising sync transfer command.
*
* \param connHandle Connection handle.
* \param serviceData Service data provided by the host.
* \param syncHandle Periodic sync handle.
*
* \return None.
*/
/*************************************************************************************************/
void HciLePerAdvSyncTrsfCmd(uint16_t connHandle, uint16_t serviceData, uint16_t syncHandle)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_PER_ADV_SYNC_TRANSFER,
HCI_LEN_LE_PER_ADV_SYNC_TRANSFER)) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT16_TO_BSTREAM(p, connHandle);
UINT16_TO_BSTREAM(p, serviceData);
UINT16_TO_BSTREAM(p, syncHandle);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE set periodic advertising set info transfer command.
*
* \param connHandle Connection handle.
* \param serviceData Service data provided by the host.
* \param advHandle Handle to identify an advertising set.
*
* \return None.
*/
/*************************************************************************************************/
void HciLePerAdvSetInfoTrsfCmd(uint16_t connHandle, uint16_t serviceData, uint8_t advHandle)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_PER_ADV_SET_INFO_TRANSFER,
HCI_LEN_LE_PER_ADV_SET_INFO_TRANSFER)) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT16_TO_BSTREAM(p, connHandle);
UINT16_TO_BSTREAM(p, serviceData);
UINT8_TO_BSTREAM(p, advHandle);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE set periodic advertising sync transfer parameters command.
*
* \param connHandle Connection handle.
* \param mode Periodic sync advertising sync transfer mode.
* \param skip The number of periodic advertising packets that can be skipped after
* a successful receive.
* \param syncTimeout Synchronization timeout for the periodic advertising.
* \param cteType Constant tone extension type(Used in AoD/AoA).
*
* \return None.
*/
/*************************************************************************************************/
void HciLeSetPerAdvSyncTrsfParamsCmd(uint16_t connHandle, uint8_t mode, uint16_t skip,
uint16_t syncTimeout, uint8_t cteType)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_PAST_PARAM, HCI_LEN_LE_SET_PAST_PARAM)) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT16_TO_BSTREAM(p, connHandle);
UINT8_TO_BSTREAM(p, mode);
UINT16_TO_BSTREAM(p, skip);
UINT16_TO_BSTREAM(p, syncTimeout);
UINT8_TO_BSTREAM(p, cteType);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI LE set default periodic advertising sync transfer parameters command.
*
* \param mode Periodic sync advertising sync transfer mode.
* \param skip The number of periodic advertising packets that can be skipped after
* a successful receive.
* \param syncTimeout Synchronization timeout for the periodic advertising.
* \param cteType Constant tone extension type(Used in AoD/AoA).
*
* \return None.
*/
/*************************************************************************************************/
void HciLeSetDefaultPerAdvSyncTrsfParamsCmd(uint8_t mode, uint16_t skip, uint16_t syncTimeout,
uint8_t cteType)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_DEFAULT_PAST_PARAM,
HCI_LEN_LE_SET_DEFAULT_PAST_PARAM)) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT8_TO_BSTREAM(p, mode);
UINT16_TO_BSTREAM(p, skip);
UINT16_TO_BSTREAM(p, syncTimeout);
UINT8_TO_BSTREAM(p, cteType);
hciCmdSend(pBuf);
}
}
@@ -0,0 +1,94 @@
/* Copyright (c) 2009-2019 Arm Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*************************************************************************************************/
/*!
* \brief HCI PHY command module.
*/
/*************************************************************************************************/
#include "wsf_types.h"
#include "wsf_msg.h"
#include "util/bstream.h"
#include "hci_cmd.h"
#include "hci_api.h"
#include "hci_main.h"
/*************************************************************************************************/
/*!
* \brief HCI read PHY command.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeReadPhyCmd(uint16_t handle)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_READ_PHY, HCI_LEN_LE_READ_PHY)) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT16_TO_BSTREAM(p, handle);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI set default PHY command.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeSetDefaultPhyCmd(uint8_t allPhys, uint8_t txPhys, uint8_t rxPhys)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_DEF_PHY, HCI_LEN_LE_SET_DEF_PHY)) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT8_TO_BSTREAM(p, allPhys);
UINT8_TO_BSTREAM(p, txPhys);
UINT8_TO_BSTREAM(p, rxPhys);
hciCmdSend(pBuf);
}
}
/*************************************************************************************************/
/*!
* \brief HCI set PHY command.
*
* \return None.
*/
/*************************************************************************************************/
void HciLeSetPhyCmd(uint16_t handle, uint8_t allPhys, uint8_t txPhys, uint8_t rxPhys, uint16_t phyOptions)
{
uint8_t *pBuf;
uint8_t *p;
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_PHY, HCI_LEN_LE_SET_PHY)) != NULL)
{
p = pBuf + HCI_CMD_HDR_LEN;
UINT16_TO_BSTREAM(p, handle);
UINT8_TO_BSTREAM(p, allPhys);
UINT8_TO_BSTREAM(p, txPhys);
UINT8_TO_BSTREAM(p, rxPhys);
UINT16_TO_BSTREAM(p, phyOptions);
hciCmdSend(pBuf);
}
}
@@ -0,0 +1,924 @@
/*************************************************************************************************/
/*!
* \file hci_core.c
*
* \brief HCI core module, platform independent functions.
*
* $Date: 2017-03-10 14:08:37 -0600 (Fri, 10 Mar 2017) $
* $Revision: 11501 $
*
* Copyright (c) 2009-2017 ARM Ltd., all rights reserved.
* ARM Ltd. confidential and proprietary.
*
* IMPORTANT. Your use of this file is governed by a Software License Agreement
* ("Agreement") that must be accepted in order to download or otherwise receive a
* copy of this file. You may not use or copy this file for any purpose other than
* as described in the Agreement. If you do not agree to all of the terms of the
* Agreement do not use this file and delete all copies in your possession or control;
* if you do not have a copy of the Agreement, you must contact ARM Ltd. prior
* to any use, copying or further distribution of this software.
*/
/*************************************************************************************************/
#include <string.h>
#include "wsf_types.h"
#include "wsf_msg.h"
#include "wsf_trace.h"
#include "wsf_assert.h"
#include "bda.h"
#include "bstream.h"
#include "hci_core.h"
#include "hci_tr.h"
#include "hci_cmd.h"
#include "hci_api.h"
#include "hci_main.h"
#include "l2c_defs.h"
#include "am_mcu_apollo.h"
/**************************************************************************************************
Macros
**************************************************************************************************/
/* Default ACL buffer flow control watermark levels */
#ifndef HCI_ACL_QUEUE_HI
#define HCI_ACL_QUEUE_HI 5 /* Disable flow when this many buffers queued */
#endif
#ifndef HCI_ACL_QUEUE_LO
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
#define HCI_ACL_QUEUE_LO 3 /* Enable flow when this many buffers queued */
#else
#define HCI_ACL_QUEUE_LO 1 /* Enable flow when this many buffers queued */
#endif
#endif
/* Default maximum ACL packet size for reassembly */
#ifndef HCI_MAX_RX_ACL_LEN
#define HCI_MAX_RX_ACL_LEN HCI_ACL_DEFAULT_LEN
#endif
/**************************************************************************************************
Local Variables
**************************************************************************************************/
/* Event mask */
const uint8_t hciEventMask[HCI_EVT_MASK_LEN] =
{
HCI_EVT_MASK_DISCONNECT_CMPL | /* Byte 0 */
HCI_EVT_MASK_ENC_CHANGE, /* Byte 0 */
HCI_EVT_MASK_READ_REMOTE_VER_INFO_CMPL | /* Byte 1 */
HCI_EVT_MASK_HW_ERROR, /* Byte 1 */
0, /* Byte 2 */
HCI_EVT_MASK_DATA_BUF_OVERFLOW, /* Byte 3 */
0, /* Byte 4 */
HCI_EVT_MASK_ENC_KEY_REFRESH_CMPL, /* Byte 5 */
0, /* Byte 6 */
HCI_EVT_MASK_LE_META /* Byte 7 */
};
/* LE event mask */
const uint8_t hciLeEventMask[HCI_LE_EVT_MASK_LEN] =
{
HCI_EVT_MASK_LE_CONN_CMPL_EVT | /* Byte 0 */
HCI_EVT_MASK_LE_ADV_REPORT_EVT | /* Byte 0 */
HCI_EVT_MASK_LE_CONN_UPDATE_CMPL_EVT | /* Byte 0 */
HCI_EVT_MASK_LE_READ_REMOTE_FEAT_CMPL_EVT | /* Byte 0 */
HCI_EVT_MASK_LE_LTK_REQ_EVT | /* Byte 0 */
HCI_EVT_MASK_LE_REMOTE_CONN_PARAM_REQ_EVT | /* Byte 0 */
HCI_EVT_MASK_LE_DATA_LEN_CHANGE_EVT | /* Byte 0 */
HCI_EVT_MASK_LE_READ_LOCAL_P256_PUB_KEY_CMPL, /* Byte 0 */
HCI_EVT_MASK_LE_GENERATE_DHKEY_CMPL | /* Byte 1 */
HCI_EVT_MASK_LE_ENHANCED_CONN_CMPL_EVT | /* Byte 1 */
HCI_EVT_MASK_LE_DIRECT_ADV_REPORT_EVT | /* Byte 1 */
HCI_EVT_MASK_LE_PHY_UPDATE_CMPL_EVT | /* Byte 1 */
HCI_EVT_MASK_LE_EXT_ADV_REPORT_EVT | /* Byte 1 */
HCI_EVT_MASK_LE_PER_ADV_SYNC_EST_EVT | /* Byte 1 */
HCI_EVT_MASK_LE_PER_ADV_REPORT_EVT | /* Byte 1 */
HCI_EVT_MASK_LE_PER_ADV_SYNC_LOST_EVT, /* Byte 1 */
HCI_EVT_MASK_LE_SCAN_TIMEOUT_EVT | /* Byte 2 */
HCI_EVT_MASK_LE_ADV_SET_TERM_EVT | /* Byte 2 */
HCI_EVT_MASK_LE_SCAN_REQ_RCVD_EVT | /* Byte 2 */
HCI_EVT_MASK_LE_CH_SEL_ALGO_EVT, /* Byte 2 */
0, /* Byte 3 */
0, /* Byte 4 */
0, /* Byte 5 */
0, /* Byte 6 */
0 /* Byte 7 */
};
/* event mask page 2 */
const uint8_t hciEventMaskPage2[HCI_EVT_MASK_PAGE_2_LEN] =
{
0, /* Byte 0 */
0, /* Byte 1 */
HCI_EVT_MASK_AUTH_PAYLOAD_TIMEOUT, /* Byte 2 */
0, /* Byte 3 */
0, /* Byte 4 */
0, /* Byte 5 */
0, /* Byte 6 */
0 /* Byte 7 */
};
/* LE supported features configuration mask */
uint32_t hciLeSupFeatCfg =
HCI_LE_SUP_FEAT_ENCRYPTION | /* LE Encryption */
HCI_LE_SUP_FEAT_CONN_PARAM_REQ_PROC | /* Connection Parameters Request Procedure */
HCI_LE_SUP_FEAT_EXT_REJECT_IND | /* Extended Reject Indication */
HCI_LE_SUP_FEAT_SLV_INIT_FEAT_EXCH | /* Slave-initiated Features Exchange */
HCI_LE_SUP_FEAT_LE_PING | /* LE Ping */
HCI_LE_SUP_FEAT_DATA_LEN_EXT | /* LE Data Packet Length Extension */
HCI_LE_SUP_FEAT_PRIVACY | /* LL Privacy */
HCI_LE_SUP_FEAT_EXT_SCAN_FILT_POLICY | /* Extended Scanner Filter Policies */
HCI_LE_SUP_FEAT_LE_2M_PHY | /* LE 2M PHY supported */
HCI_LE_SUP_FEAT_STABLE_MOD_IDX_TRANSMITTER | /* Stable Modulation Index - Transmitter supported */
HCI_LE_SUP_FEAT_STABLE_MOD_IDX_RECEIVER | /* Stable Modulation Index - Receiver supported */
HCI_LE_SUP_FEAT_LE_EXT_ADV | /* LE Extended Advertising */
HCI_LE_SUP_FEAT_LE_PER_ADV; /* LE Periodic Advertising */
/**************************************************************************************************
Global Variables
**************************************************************************************************/
/* Control block */
hciCoreCb_t hciCoreCb;
/*************************************************************************************************/
/*!
* \fn hciCoreConnAlloc
*
* \brief Allocate a connection structure.
*
* \param handle Connection handle.
*
* \return None.
*/
/*************************************************************************************************/
static void hciCoreConnAlloc(uint16_t handle)
{
uint8_t i;
hciCoreConn_t *pConn = hciCoreCb.conn;
/* find available connection struct */
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
{
if (pConn->handle == HCI_HANDLE_NONE)
{
/* allocate and initialize */
pConn->handle = handle;
pConn->flowDisabled = FALSE;
pConn->outBufs = 0;
pConn->queuedBufs = 0;
return;
}
}
HCI_TRACE_WARN0("HCI conn struct alloc failure");
}
/*************************************************************************************************/
/*!
* \fn hciCoreConnFree
*
* \brief Free a connection structure.
*
* \param handle Connection handle.
*
* \return None.
*/
/*************************************************************************************************/
static void hciCoreConnFree(uint16_t handle)
{
uint8_t i;
hciCoreConn_t *pConn = hciCoreCb.conn;
/* find connection struct */
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
{
if (pConn->handle == handle)
{
/* free any fragmenting ACL packet */
if (pConn->pTxAclPkt != NULL)
{
WsfMsgFree(pConn->pTxAclPkt);
pConn->pTxAclPkt = NULL;
}
pConn->fragmenting = FALSE;
if (pConn->pRxAclPkt != NULL)
{
WsfMsgFree(pConn->pRxAclPkt);
pConn->pRxAclPkt = NULL;
}
/* free structure */
pConn->handle = HCI_HANDLE_NONE;
/* optional: iterate through tx ACL queue and free any buffers with this handle */
/* outstanding buffers are now available; service TX data path */
hciCoreTxReady(pConn->outBufs);
return;
}
}
HCI_TRACE_WARN1("hciCoreConnFree handle not found:%u", handle);
}
/*************************************************************************************************/
/*!
* \fn hciCoreConnByHandle
*
* \brief Get a connection structure by handle
*
* \param handle Connection handle.
*
* \return Pointer to connection structure or NULL if not found.
*/
/*************************************************************************************************/
hciCoreConn_t *hciCoreConnByHandle(uint16_t handle)
{
uint8_t i;
hciCoreConn_t *pConn = hciCoreCb.conn;
/* find available connection struct */
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
{
if (pConn->handle == handle)
{
return pConn;
}
}
return NULL;
}
/*************************************************************************************************/
/*!
* \fn hciCoreNextConnFragment
*
* \brief Get the next connection structure with a packet fragment to send.
*
* \return Pointer to connection structure or NULL if not found.
*/
/*************************************************************************************************/
static hciCoreConn_t *hciCoreNextConnFragment(void)
{
uint8_t i;
hciCoreConn_t *pConn = hciCoreCb.conn;
/* find connection struct */
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
{
if (pConn->handle != HCI_HANDLE_NONE && pConn->fragmenting)
{
return pConn;
}
}
return NULL;
}
/*************************************************************************************************/
/*!
* \fn hciCoreConnOpen
*
* \brief Perform internal processing on HCI connection open.
*
* \param handle Connection handle.
*
* \return None.
*/
/*************************************************************************************************/
void hciCoreConnOpen(uint16_t handle)
{
/* allocate connection structure */
hciCoreConnAlloc(handle);
}
/*************************************************************************************************/
/*!
* \fn hciCoreConnClose
*
* \brief Perform internal processing on HCI connection close.
*
* \param handle Connection handle.
*
* \return None.
*/
/*************************************************************************************************/
void hciCoreConnClose(uint16_t handle)
{
/* free connection structure */
hciCoreConnFree(handle);
}
/*************************************************************************************************/
/*!
* \fn hciCoreSendAclData
*
* \brief Send ACL data to transport.
*
* \param pConn Pointer to connection structure.
* \param pData WSF buffer containing an ACL packet.
*
* \return None.
*/
/*************************************************************************************************/
void hciCoreSendAclData(hciCoreConn_t *pConn, uint8_t *pData)
{
/* increment outstanding buf count for handle */
pConn->outBufs++;
/* send to transport */
hciTrSendAclData(pConn, pData);
/* decrement available buffer count */
if (hciCoreCb.availBufs > 0)
{
hciCoreCb.availBufs--;
}
else
{
HCI_TRACE_WARN0("hciCoreSendAclData availBufs=0");
}
}
/*************************************************************************************************/
/*!
* \fn hciCoreTxReady
*
* \brief Service the TX data path.
*
* \param bufs Number of new buffers now available.
*
* \return None.
*/
/*************************************************************************************************/
void hciCoreTxReady(uint8_t bufs)
{
uint8_t *pData;
wsfHandlerId_t handlerId;
uint16_t handle;
uint16_t len;
hciCoreConn_t *pConn;
/* increment available buffers, with ceiling */
if (bufs > 0)
{
hciCoreCb.availBufs += bufs;
if (hciCoreCb.availBufs > hciCoreCb.numBufs)
{
hciCoreCb.availBufs = hciCoreCb.numBufs;
}
}
/* service ACL data queue and send as many buffers as we can */
while (hciCoreCb.availBufs > 0)
{
/* send continuation of any fragments first */
if (hciCoreTxAclContinue(NULL) == FALSE)
{
/* if no fragments then check for any queued ACL data */
if ((pData = WsfMsgDeq(&hciCoreCb.aclQueue, &handlerId)) != NULL)
{
/* parse handle and length */
BYTES_TO_UINT16(handle, pData);
BYTES_TO_UINT16(len, &pData[2]);
/* look up conn structure and send data */
if ((pConn = hciCoreConnByHandle(handle)) != NULL)
{
hciCoreTxAclStart(pConn, len, pData);
}
/* handle not found, connection must be closed */
else
{
/* discard buffer */
WsfMsgFree(pData);
HCI_TRACE_WARN1("hciCoreTxReady discarding buffer, handle=%u", handle);
}
}
else
{
/* no fragments or queued data to send; we're done */
break;
}
}
}
}
/*************************************************************************************************/
/*!
* \fn hciCoreTxAclStart
*
* \brief Send ACL packets, start of packet.
*
* \param pConn Pointer to connection structure.
* \param len ACL packet length.
* \param pData WSF buffer containing an ACL packet.
*
* \return None.
*/
/*************************************************************************************************/
void hciCoreTxAclStart(hciCoreConn_t *pConn, uint16_t len, uint8_t *pData)
{
uint16_t hciLen;
/* make sure not already fragmenting on this connection */
WSF_ASSERT(pConn->fragmenting == FALSE);
hciLen = HciGetBufSize();
HCI_TRACE_INFO1("hciCoreTxAclStart len=%u", len);
/* if acl len > controller acl buf len */
if (len > hciLen)
{
/* store remaining acl len = acl len - hci acl buf len */
pConn->txAclRemLen = len - hciLen;
/* store position for next fragment */
pConn->pNextTxFrag = pData + hciLen;
/* store information required for fragmentation */
pConn->pTxAclPkt = pData;
pConn->fragmenting = TRUE;
/* set acl len in packet to hci acl buf len */
UINT16_TO_BUF(&pData[2], hciLen);
/* send the packet */
hciCoreSendAclData(pConn, pData);
/* send additional fragments while there are HCI buffers available */
while ((hciCoreCb.availBufs > 0) && hciCoreTxAclContinue(pConn));
}
else
{
/* no fragmentation, just send the packet */
hciCoreSendAclData(pConn, pData);
}
}
/*************************************************************************************************/
/*!
* \fn hciCoreTxAclContinue
*
* \brief Send ACL packets, continuation of fragmented packets.
*
* \param pConn Pointer to connection structure. If set non-NULL, then a fragment is
* sent from this connection structure. If NULL the function finds the next
* connection structure with a fragment to be sent.
*
* \return TRUE if packet sent, FALSE otherwise.
*/
/*************************************************************************************************/
bool_t hciCoreTxAclContinue(hciCoreConn_t *pConn)
{
uint16_t aclLen;
if (pConn == NULL)
{
pConn = hciCoreNextConnFragment();
}
if (pConn != NULL)
{
/* get next fragment length */
aclLen = (pConn->txAclRemLen < HciGetBufSize()) ? pConn->txAclRemLen : HciGetBufSize();
if (aclLen > 0)
{
/* decrement remaining length */
pConn->txAclRemLen -= aclLen;
/* set handle in packet with continuation bit set */
UINT16_TO_BUF(pConn->pNextTxFrag, (pConn->handle | HCI_PB_CONTINUE));
/* set acl len in packet */
UINT16_TO_BUF(&(pConn->pNextTxFrag[2]), aclLen);
HCI_TRACE_INFO2("hciCoreTxAclContinue aclLen=%u remLen=%u", aclLen, pConn->txAclRemLen);
/* send the packet */
hciCoreSendAclData(pConn, pConn->pNextTxFrag);
/* set up pointer to next fragment */
if (pConn->txAclRemLen > 0)
{
pConn->pNextTxFrag += aclLen;
}
return TRUE;
}
}
return FALSE;
}
/*************************************************************************************************/
/*!
* \fn hciCoreTxAclComplete
*
* \brief This function is called from the HCI transport layer when transmission of an ACL
* packet is complete.
*
* \param pConn Pointer to connection structure.
* \param pData WSF buffer containing an ACL packet.
*
* \return None.
*/
/*************************************************************************************************/
void hciCoreTxAclComplete(hciCoreConn_t *pConn, uint8_t *pData)
{
/* if fragmenting */
if (pConn->fragmenting)
{
/* check if all fragments sent */
if (pConn->txAclRemLen == 0)
{
/* free original buffer */
WsfMsgFree(pConn->pTxAclPkt);
pConn->pTxAclPkt = NULL;
pConn->fragmenting = FALSE;
HCI_TRACE_INFO0("hciCoreTxAclComplete free pTxAclPkt");
}
}
else if (pData != NULL)
{
WsfMsgFree(pData);
}
}
/*************************************************************************************************/
/*!
* \fn hciCoreAclReassembly
*
* \brief Reassemble an ACL packet.
*
* \param pData Input ACL packet.
*
* \return pointer to ACL packet to send, or NULL if no packet to send.
*/
/*************************************************************************************************/
uint8_t *hciCoreAclReassembly(uint8_t *pData)
{
hciCoreConn_t *pConn;
uint8_t *pDataRtn = NULL;
uint16_t handle;
uint16_t aclLen;
uint16_t l2cLen;
uint16_t pbf;
bool_t freeData = TRUE;
BYTES_TO_UINT16(handle, pData);
pbf = handle & HCI_PB_FLAG_MASK;
handle &= HCI_HANDLE_MASK;
BYTES_TO_UINT16(aclLen, &pData[2]);
/* look up connection */
if ((pConn = hciCoreConnByHandle(handle)) != NULL)
{
/* if this is a start packet */
if (pbf == HCI_PB_START_C2H)
{
/* if currently reassembled packet not complete */
if (pConn->pRxAclPkt != NULL)
{
/* discard currently reassembled packet */
WsfMsgFree(pConn->pRxAclPkt);
pConn->pRxAclPkt = NULL;
HCI_TRACE_WARN1("disarded hci rx pkt handle=0x%04x", handle);
}
/* read l2cap length */
if (aclLen >= L2C_HDR_LEN)
{
BYTES_TO_UINT16(l2cLen, &pData[4]);
/* check length vs. configured maximum */
if ((l2cLen + L2C_HDR_LEN) > hciCoreCb.maxRxAclLen)
{
HCI_TRACE_WARN1("l2c len=0x%04x to large for reassembly", l2cLen);
}
/* if reassembly required */
else if ((l2cLen + L2C_HDR_LEN) > aclLen)
{
/* allocate buffer to store complete l2cap packet */
if ((pConn->pRxAclPkt = WsfMsgDataAlloc(l2cLen + L2C_HDR_LEN + HCI_ACL_HDR_LEN, 0)) != NULL)
{
/* store buffer for reassembly */
pConn->pNextRxFrag = pConn->pRxAclPkt;
/* build acl header and copy data */
UINT16_TO_BSTREAM(pConn->pNextRxFrag, handle);
UINT16_TO_BSTREAM(pConn->pNextRxFrag, l2cLen + L2C_HDR_LEN);
memcpy(pConn->pNextRxFrag, &pData[4], aclLen);
pConn->pNextRxFrag += aclLen;
/* store remaining length */
pConn->rxAclRemLen = l2cLen + L2C_HDR_LEN - aclLen;
}
else
{
/* alloc failed; discard */
HCI_TRACE_WARN1("reassembly alloc failed len=%u", (l2cLen + L2C_HDR_LEN + HCI_ACL_HDR_LEN));
}
}
else
{
/* no reassembly required, pData is ready to go */
pDataRtn = pData;
freeData = FALSE;
}
}
else
{
/* invalid l2cap packet; discard */
HCI_TRACE_WARN1("invalid l2c pkt aclLen=%u", aclLen);
}
}
/* else if this is a continuation packet */
else if (pbf == HCI_PB_CONTINUE)
{
/* if expecting a continuation */
if (pConn->pRxAclPkt != NULL)
{
if (aclLen <= pConn->rxAclRemLen)
{
/* copy data to start of next fragment */
memcpy(pConn->pNextRxFrag, &pData[HCI_ACL_HDR_LEN], aclLen);
pConn->pNextRxFrag += aclLen;
/* update remaining length */
pConn->rxAclRemLen -= aclLen;
/* if reassembly complete return reassembled packet */
if (pConn->rxAclRemLen == 0)
{
pDataRtn = pConn->pRxAclPkt;
pConn->pRxAclPkt = NULL;
}
}
else
{
HCI_TRACE_WARN2("continuation pkt too long len=%u RemLen=%u", aclLen, pConn->rxAclRemLen);
}
}
else
{
HCI_TRACE_WARN1("unexpected continuation pkt handle=0x%04x", handle);
}
}
/* else unknown packet type */
else
{
HCI_TRACE_WARN1("unknown pb flags=0x%04x", pbf);
}
}
else
{
/* connection not found */
HCI_TRACE_WARN1("pkt rcvd on unknown handle=0x%04x", (handle & HCI_HANDLE_MASK));
}
if (freeData)
{
WsfMsgFree(pData);
}
return pDataRtn;
}
/*************************************************************************************************/
/*!
* \fn hciCoreTxAclDataFragmented
*
* \brief Check if a TX ACL packet is being fragmented.
*
* \param pContext Connection context.
*
* \return TRUE if fragmenting a TX ACL packet, FALSE otherwise.
*/
/*************************************************************************************************/
bool_t hciCoreTxAclDataFragmented(hciCoreConn_t *pConn)
{
return pConn->fragmenting;
}
/*************************************************************************************************/
/*!
* \fn HciCoreInit
*
* \brief HCI core initialization.
*
* \return None.
*/
/*************************************************************************************************/
void HciCoreInit(void)
{
uint8_t i;
WSF_QUEUE_INIT(&hciCoreCb.aclQueue);
for (i = 0; i < DM_CONN_MAX; i++)
{
hciCoreCb.conn[i].handle = HCI_HANDLE_NONE;
}
hciCoreCb.maxRxAclLen = HCI_MAX_RX_ACL_LEN;
hciCoreCb.aclQueueHi = HCI_ACL_QUEUE_HI;
hciCoreCb.aclQueueLo = HCI_ACL_QUEUE_LO;
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
if (APOLLO3_GE_B0)
{
// B0 has only less internal ACL buffers
hciCoreCb.aclQueueHi--;
hciCoreCb.aclQueueLo--;
}
#endif
hciCoreCb.extResetSeq = NULL;
hciCoreInit();
}
/*************************************************************************************************/
/*!
* \fn HciResetSequence
*
* \brief Initiate an HCI reset sequence.
*
* \return None.
*/
/*************************************************************************************************/
void HciResetSequence(void)
{
uint8_t *pBuf;
wsfHandlerId_t handlerId;
uint8_t i;
hciCoreConn_t *pConn = hciCoreCb.conn;
// free any pending incoming packets
while ((pBuf = WsfMsgDeq(&hciCb.rxQueue, &handlerId)) != NULL)
{
/* Free buffer */
WsfMsgFree(pBuf);
}
HCI_TRACE_INFO0("reset sequence");
// free any pending tx packets
/* find connection struct */
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
{
/* free any fragmenting ACL packet */
if (pConn->pTxAclPkt != NULL)
{
WsfMsgFree(pConn->pTxAclPkt);
pConn->pTxAclPkt = NULL;
}
pConn->fragmenting = FALSE;
if (pConn->pRxAclPkt != NULL)
{
WsfMsgFree(pConn->pRxAclPkt);
pConn->pRxAclPkt = NULL;
}
/* free structure */
pConn->handle = HCI_HANDLE_NONE;
/* optional: iterate through tx ACL queue and free any buffers with this handle */
/* outstanding buffers are now available; service TX data path */
hciCoreTxReady(pConn->outBufs);
}
/* set resetting state */
hciCb.resetting = TRUE;
/* start the reset sequence */
hciCoreResetStart();
}
/*************************************************************************************************/
/*!
* \fn HciSetMaxRxAclLen
*
* \brief Set the maximum reassembled RX ACL packet length. Minimum value is 27.
*
* \param len ACL packet length.
*
* \return None.
*/
/*************************************************************************************************/
void HciSetMaxRxAclLen(uint16_t len)
{
hciCoreCb.maxRxAclLen = len;
}
/*************************************************************************************************/
/*!
* \fn HciSetAclQueueWatermarks
*
* \brief Set TX ACL queue high and low watermarks.
*
* \param queueHi Disable flow on a connection when this many ACL buffers are queued.
* queueLo Disable flow on a connection when this many ACL buffers are queued.
*
* \return None.
*/
/*************************************************************************************************/
void HciSetAclQueueWatermarks(uint8_t queueHi, uint8_t queueLo)
{
hciCoreCb.aclQueueHi = queueHi;
hciCoreCb.aclQueueLo = queueLo;
}
/*************************************************************************************************/
/*!
* \fn HciSetLeSupFeat
*
* \brief Set LE supported features configuration mask.
*
* \param feat Feature bit to set or clear
* \param flag TRUE to set feature bit and FALSE to clear it
*
* \return None.
*/
/*************************************************************************************************/
void HciSetLeSupFeat(uint32_t feat, bool_t flag)
{
/* if asked to include feature */
if (flag)
{
/* set feature bit */
hciLeSupFeatCfg |= feat;
}
else
{
/* clear feature bit */
hciLeSupFeatCfg &= ~feat;
}
}
/*************************************************************************************************/
/*!
* \fn HciSendAclData
*
* \brief Send data from the stack to HCI.
*
* \param pData WSF buffer containing an ACL packet
*
* \return None.
*/
/*************************************************************************************************/
void HciSendAclData(uint8_t *pData)
{
uint16_t handle;
uint16_t len;
hciCoreConn_t *pConn;
/* parse handle and length */
BYTES_TO_UINT16(handle, pData);
BYTES_TO_UINT16(len, &pData[2]);
/* look up connection structure */
if ((pConn = hciCoreConnByHandle(handle)) != NULL)
{
/* if queue empty and buffers available */
if (WsfQueueEmpty(&hciCoreCb.aclQueue) && hciCoreCb.availBufs > 0)
{
/* send data */
hciCoreTxAclStart(pConn, len, pData);
}
else
{
/* queue data - message handler ID 'handerId' not used */
WsfMsgEnq(&hciCoreCb.aclQueue, 0, pData);
}
/* increment buffer queue count for this connection with consideration for HCI fragmentation */
pConn->queuedBufs += ((len - 1) / HciGetBufSize()) + 1;
/* manage flow control to stack */
if (pConn->queuedBufs >= hciCoreCb.aclQueueHi && pConn->flowDisabled == FALSE)
{
pConn->flowDisabled = TRUE;
(*hciCb.flowCback)(handle, TRUE);
}
}
/* connection not found, connection must be closed */
else
{
/* discard buffer */
WsfMsgFree(pData);
HCI_TRACE_WARN1("HciSendAclData discarding buffer, handle=%u", handle);
}
}
@@ -0,0 +1,391 @@
/*************************************************************************************************/
/*!
* \file hci_core_ps.c
*
* \brief HCI core platform-specific module for dual-chip.
*
* $Date: 2016-12-28 16:12:14 -0600 (Wed, 28 Dec 2016) $
* $Revision: 10805 $
*
* Copyright (c) 2009-2017 ARM Ltd., all rights reserved.
* ARM Ltd. confidential and proprietary.
*
* IMPORTANT. Your use of this file is governed by a Software License Agreement
* ("Agreement") that must be accepted in order to download or otherwise receive a
* copy of this file. You may not use or copy this file for any purpose other than
* as described in the Agreement. If you do not agree to all of the terms of the
* Agreement do not use this file and delete all copies in your possession or control;
* if you do not have a copy of the Agreement, you must contact ARM Ltd. prior
* to any use, copying or further distribution of this software.
*/
/*************************************************************************************************/
#include <string.h>
#include "wsf_types.h"
#include "wsf_msg.h"
#include "wsf_trace.h"
#include "bda.h"
#include "bstream.h"
#include "hci_core.h"
#include "hci_tr.h"
#include "hci_cmd.h"
#include "hci_evt.h"
#include "hci_api.h"
#include "hci_main.h"
/*************************************************************************************************/
/*!
* \fn hciCoreInit
*
* \brief HCI core initialization.
*
* \return None.
*/
/*************************************************************************************************/
void hciCoreInit(void)
{
hciCmdInit();
}
/*************************************************************************************************/
/*!
* \fn hciCoreNumCmplPkts
*
* \brief Handle an HCI Number of Completed Packets event.
*
* \param pMsg Message containing the HCI Number of Completed Packets event.
*
* \return None.
*/
/*************************************************************************************************/
void hciCoreNumCmplPkts(uint8_t *pMsg)
{
uint8_t numHandles;
uint16_t bufs;
uint16_t handle;
uint8_t availBufs = 0;
hciCoreConn_t *pConn;
/* parse number of handles */
BSTREAM_TO_UINT8(numHandles, pMsg);
/* for each handle in event */
while (numHandles-- > 0)
{
/* parse handle and number of buffers */
BSTREAM_TO_UINT16(handle, pMsg);
BSTREAM_TO_UINT16(bufs, pMsg);
if ((pConn = hciCoreConnByHandle(handle)) != NULL)
{
/* decrement outstanding buffer count to controller */
pConn->outBufs -= (uint8_t) bufs;
/* decrement queued buffer count for this connection */
pConn->queuedBufs -= (uint8_t) bufs;
/* increment available buffer count */
availBufs += (uint8_t) bufs;
/* call flow control callback */
if (pConn->flowDisabled && pConn->queuedBufs <= hciCoreCb.aclQueueLo)
{
pConn->flowDisabled = FALSE;
(*hciCb.flowCback)(handle, FALSE);
}
}
}
/* service TX data path */
hciCoreTxReady(availBufs);
}
/*************************************************************************************************/
/*!
* \fn hciCoreRecv
*
* \brief Send a received HCI event or ACL packet to the HCI event handler.
*
* \param msgType Message type: HCI_ACL_TYPE or HCI_EVT_TYPE.
* \param pCoreRecvMsg Pointer to received message.
*
* \return None.
*/
/*************************************************************************************************/
void hciCoreRecv(uint8_t msgType, uint8_t *pCoreRecvMsg)
{
/* dump event for protocol analysis */
if (msgType == HCI_EVT_TYPE)
{
HCI_PDUMP_EVT(*(pCoreRecvMsg + 1) + HCI_EVT_HDR_LEN, pCoreRecvMsg);
}
else if (msgType == HCI_ACL_TYPE)
{
HCI_PDUMP_RX_ACL(*(pCoreRecvMsg + 2) + HCI_ACL_HDR_LEN, pCoreRecvMsg);
}
/* queue buffer */
WsfMsgEnq(&hciCb.rxQueue, (wsfHandlerId_t) msgType, pCoreRecvMsg);
/* set event */
WsfSetEvent(hciCb.handlerId, HCI_EVT_RX);
}
/*************************************************************************************************/
/*!
* \fn HciCoreHandler
*
* \brief WSF event handler for core HCI.
*
* \param event WSF event mask.
* \param pMsg WSF message.
*
* \return None.
*/
/*************************************************************************************************/
void HciCoreHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
{
uint8_t *pBuf;
wsfHandlerId_t handlerId;
/* Handle message */
if (pMsg != NULL)
{
/* Handle HCI command timeout */
if (pMsg->event == HCI_MSG_CMD_TIMEOUT)
{
hciCmdTimeout(pMsg);
}
}
/* Handle events */
else if (event & HCI_EVT_RX)
{
/* Process rx queue */
while ((pBuf = WsfMsgDeq(&hciCb.rxQueue, &handlerId)) != NULL)
{
/* Handle incoming HCI events */
if (handlerId == HCI_EVT_TYPE)
{
/* Parse/process events */
hciEvtProcessMsg(pBuf);
/* Handle events during reset sequence */
if (hciCb.resetting)
{
hciCoreResetSequence(pBuf);
}
/* Free buffer */
WsfMsgFree(pBuf);
}
/* Handle ACL data */
else
{
/* Reassemble */
if ((pBuf = hciCoreAclReassembly(pBuf)) != NULL)
{
/* Call ACL callback; client will free buffer */
hciCb.aclCback(pBuf);
}
}
}
}
}
/*************************************************************************************************/
/*!
* \fn HciGetBdAddr
*
* \brief Return a pointer to the BD address of this device.
*
* \return Pointer to the BD address.
*/
/*************************************************************************************************/
uint8_t *HciGetBdAddr(void)
{
return hciCoreCb.bdAddr;
}
/*************************************************************************************************/
/*!
* \fn HciGetWhiteListSize
*
* \brief Return the white list size.
*
* \return White list size.
*/
/*************************************************************************************************/
uint8_t HciGetWhiteListSize(void)
{
return hciCoreCb.whiteListSize;
}
/*************************************************************************************************/
/*!
* \fn HciGetAdvTxPwr
*
* \brief Return the advertising transmit power.
*
* \return Advertising transmit power.
*/
/*************************************************************************************************/
int8_t HciGetAdvTxPwr(void)
{
return hciCoreCb.advTxPwr;
}
/*************************************************************************************************/
/*!
* \fn HciGetBufSize
*
* \brief Return the ACL buffer size supported by the controller.
*
* \return ACL buffer size.
*/
/*************************************************************************************************/
uint16_t HciGetBufSize(void)
{
return hciCoreCb.bufSize;
}
/*************************************************************************************************/
/*!
* \fn HciGetNumBufs
*
* \brief Return the number of ACL buffers supported by the controller.
*
* \return Number of ACL buffers.
*/
/*************************************************************************************************/
uint8_t HciGetNumBufs(void)
{
return hciCoreCb.numBufs;
}
/*************************************************************************************************/
/*!
* \fn HciGetSupStates
*
* \brief Return the states supported by the controller.
*
* \return Pointer to the supported states array.
*/
/*************************************************************************************************/
uint8_t *HciGetSupStates(void)
{
return hciCoreCb.leStates;
}
/*************************************************************************************************/
/*!
* \fn HciGetLeSupFeat
*
* \brief Return the LE supported features supported by the controller.
*
* \return Supported features.
*/
/*************************************************************************************************/
uint32_t HciGetLeSupFeat(void)
{
// disable LL connection parameter update feature for a better
// interoperability with Android phones (especially older Android OS).
return hciCoreCb.leSupFeat & ~HCI_LE_SUP_FEAT_CONN_PARAM_REQ_PROC;
}
/*************************************************************************************************/
/*!
* \fn HciGetMaxRxAclLen
*
* \brief Get the maximum reassembled RX ACL packet length.
*
* \return ACL packet length.
*/
/*************************************************************************************************/
uint16_t HciGetMaxRxAclLen(void)
{
return hciCoreCb.maxRxAclLen;
}
/*************************************************************************************************/
/*!
* \fn HciGetResolvingListSize
*
* \brief Return the resolving list size.
*
* \return resolving list size.
*/
/*************************************************************************************************/
uint8_t HciGetResolvingListSize(void)
{
return hciCoreCb.resListSize;
}
/*************************************************************************************************/
/*!
* \fn HciLlPrivacySupported
*
* \brief Whether LL Privacy is supported.
*
* \return TRUE if LL Privacy is supported. FALSE, otherwise.
*/
/*************************************************************************************************/
bool_t HciLlPrivacySupported(void)
{
return (hciCoreCb.resListSize > 0) ? TRUE : FALSE;
}
/*************************************************************************************************/
/*!
* \fn HciGetMaxAdvDataLen
*
* \brief Get the maximum advertisement (or scan response) data length supported by the Controller.
*
* \return Maximum advertisement data length.
*/
/*************************************************************************************************/
uint16_t HciGetMaxAdvDataLen(void)
{
return hciCoreCb.maxAdvDataLen;
}
/*************************************************************************************************/
/*!
* \fn HciGetNumSupAdvSets
*
* \brief Get the maximum number of advertising sets supported by the Controller.
*
* \return Maximum number of advertising sets.
*/
/*************************************************************************************************/
uint8_t HciGetNumSupAdvSets(void)
{
return hciCoreCb.numSupAdvSets;
}
/*************************************************************************************************/
/*!
* \fn HciLeAdvExtSupported
*
* \brief Whether LE Advertising Extensions is supported.
*
* \return TRUE if LE Advertising Extensions is supported. FALSE, otherwise.
*/
/*************************************************************************************************/
bool_t HciLeAdvExtSupported(void)
{
return (hciCoreCb.numSupAdvSets > 0) ? TRUE : FALSE;
}
/*************************************************************************************************/
/*!
* \fn HciGetPerAdvListSize
*
* \brief Return the periodic advertising list size.
*
* \return periodic advertising list size.
*/
/*************************************************************************************************/
uint8_t HciGetPerAdvListSize(void)
{
return hciCoreCb.perAdvListSize;
}
@@ -0,0 +1,42 @@
/*************************************************************************************************/
/*!
* \file hci_core_ps.h
*
* \brief HCI core platform-specific interfaces for dual-chip.
*
* $Date: 2016-12-28 16:12:14 -0600 (Wed, 28 Dec 2016) $
* $Revision: 10805 $
*
* Copyright (c) 2013-2017 ARM Ltd., all rights reserved.
* ARM Ltd. confidential and proprietary.
*
* IMPORTANT. Your use of this file is governed by a Software License Agreement
* ("Agreement") that must be accepted in order to download or otherwise receive a
* copy of this file. You may not use or copy this file for any purpose other than
* as described in the Agreement. If you do not agree to all of the terms of the
* Agreement do not use this file and delete all copies in your possession or control;
* if you do not have a copy of the Agreement, you must contact ARM Ltd. prior
* to any use, copying or further distribution of this software.
*/
/*************************************************************************************************/
#ifndef HCI_CORE_PS_H
#define HCI_CORE_PS_H
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
void hciCoreResetSequence(uint8_t *pMsg);
void hciCoreNumCmplPkts(uint8_t *pMsg);
void hciCoreRecv(uint8_t msgType, uint8_t *pCoreRecvMsg);
uint8_t hciCoreVsCmdCmplRcvd(uint16_t opcode, uint8_t *pMsg, uint8_t len);
#ifdef __cplusplus
};
#endif
#endif /* HCI_CORE_PS_H */
@@ -0,0 +1,68 @@
//*****************************************************************************
//
//! @file hci_drv_apollo.h
//!
//! @brief Additional header information for the Apollo implementation of HCI.
//
//*****************************************************************************
#ifndef HCI_DRV_APOLLO_H
#define HCI_DRV_APOLLO_H
#ifdef __cplusplus
extern "C"
{
#endif
//*****************************************************************************
//
// Errors
//
//*****************************************************************************
#define HCI_DRV_SPECIFIC_ERROR_START 0x09000000
typedef enum
{
HCI_DRV_TRANSMIT_QUEUE_FULL = HCI_DRV_SPECIFIC_ERROR_START,
HCI_DRV_TX_PACKET_TOO_LARGE,
HCI_DRV_RX_PACKET_TOO_LARGE,
HCI_DRV_BLE_STACK_UNABLE_TO_ACCEPT_PACKET,
HCI_DRV_PACKET_TRANSMIT_FAILED,
HCI_DRV_IRQ_STUCK_HIGH,
HCI_DRV_TOO_MANY_PACKETS,
}
hci_drv_error_t;
typedef void (*hci_drv_error_handler_t)(uint32_t ui32Error);
//*****************************************************************************
//
// Function prototypes.
//
//*****************************************************************************
extern void HciDrvUartEnable(void);
extern void HciDrvUartDisable(void);
extern void HciDrvUartFlowOff(void);
extern void HciDrvUartFlowOn(void);
extern void HciDrvUartPause(void);
extern void HciDrvUartUnpause(void);
extern bool HciDrvUartSafeShutdown(void);
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
extern void HciDrvRadioBoot(bool bColdBoot);
#else
extern void HciDrvRadioBoot(uint32_t ui32UartModule);
#endif
extern void HciDrvRadioShutdown(void);
extern void HciDrvUartISR(uint32_t ui32Status);
extern bool_t HciDataReadyISR(void);
extern void HciDrvIntService(void);
extern void HciDrvGPIOService(void);
extern void HciDrvHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
extern void HciDrvErrorHandlerSet(hci_drv_error_handler_t pfnErrorHandler);
#ifdef __cplusplus
};
#endif
#endif // HCI_DRV_APOLLO_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,304 @@
/*************************************************************************************************/
/*!
* \file hci_tr.c
*
* \brief HCI transport module.
*
* $Date: 2017-03-10 14:08:37 -0600 (Fri, 10 Mar 2017) $
* $Revision: 11501 $
*
* Copyright (c) 2011-2017 ARM Ltd., all rights reserved.
* ARM Ltd. confidential and proprietary.
*
* IMPORTANT. Your use of this file is governed by a Software License Agreement
* ("Agreement") that must be accepted in order to download or otherwise receive a
* copy of this file. You may not use or copy this file for any purpose other than
* as described in the Agreement. If you do not agree to all of the terms of the
* Agreement do not use this file and delete all copies in your possession or control;
* if you do not have a copy of the Agreement, you must contact ARM Ltd. prior
* to any use, copying or further distribution of this software.
*/
/*************************************************************************************************/
#include "wsf_types.h"
#include "wsf_msg.h"
#include "wsf_trace.h"
#include "wsf_assert.h"
#include "bstream.h"
#include "hci_api.h"
#include "hci_core.h"
#include "hci_drv.h"
#include "am_mcu_apollo.h"
/**************************************************************************************************
State variable
**************************************************************************************************/
static volatile bool_t g_bHCIReceivingPacket = FALSE;
/**************************************************************************************************
Macros
**************************************************************************************************/
#define HCI_HDR_LEN_MAX HCI_ACL_HDR_LEN
/**************************************************************************************************
Data Types
**************************************************************************************************/
typedef enum
{
HCI_RX_STATE_IDLE,
HCI_RX_STATE_HEADER,
HCI_RX_STATE_DATA,
HCI_RX_STATE_COMPLETE
} hciRxState_t;
/*************************************************************************************************/
/*!
* \fn hciTrSendAclData
*
* \brief Send a complete HCI ACL packet to the transport.
*
* \param pContext Connection context.
* \param pData WSF msg buffer containing an ACL packet.
*
* \return None.
*/
/*************************************************************************************************/
void hciTrSendAclData(void *pContext, uint8_t *pData)
{
uint16_t len;
/* get 16-bit length */
BYTES_TO_UINT16(len, &pData[2]);
len += HCI_ACL_HDR_LEN;
/* dump event for protocol analysis */
HCI_PDUMP_TX_ACL(len, pData);
/* transmit ACL header and data */
if (hciDrvWrite(HCI_ACL_TYPE, len, pData) == len)
{
/* free buffer */
hciCoreTxAclComplete(pContext, pData);
}
}
/*************************************************************************************************/
/*!
* \fn hciTrSendCmd
*
* \brief Send a complete HCI command to the transport.
*
* \param pData WSF msg buffer containing an HCI command.
*
* \return None.
*/
/*************************************************************************************************/
void hciTrSendCmd(uint8_t *pData)
{
uint8_t len;
/* get length */
len = pData[2] + HCI_CMD_HDR_LEN;
/* dump event for protocol analysis */
HCI_PDUMP_CMD(len, pData);
/* transmit ACL header and data */
if (hciDrvWrite(HCI_CMD_TYPE, len, pData) == len)
{
/* free buffer */
WsfMsgFree(pData);
}
}
/*************************************************************************************************/
/*!
* \fn hciSerialRxIncoming
*
* \brief Receive function. Gets called by external code when bytes are received.
*
* \param pBuf Pointer to buffer of incoming bytes.
* \param len Number of bytes in incoming buffer.
*
* \return The number of bytes consumed.
*/
/*************************************************************************************************/
uint16_t hciTrSerialRxIncoming(uint8_t *pBuf, uint16_t len)
{
static uint8_t stateRx = HCI_RX_STATE_IDLE;
static uint8_t pktIndRx;
static uint16_t iRx;
static uint8_t hdrRx[HCI_HDR_LEN_MAX];
static uint8_t *pPktRx;
static uint8_t *pDataRx;
uint8_t dataByte;
uint16_t consumed_bytes;
consumed_bytes = 0;
/* loop until all bytes of incoming buffer are handled */
while (len)
{
/* read single byte from incoming buffer and advance to next byte */
dataByte = *pBuf;
/* --- Idle State --- */
if (stateRx == HCI_RX_STATE_IDLE)
{
/* save the packet type */
pktIndRx = dataByte;
iRx = 0;
stateRx = HCI_RX_STATE_HEADER;
g_bHCIReceivingPacket = TRUE;
pBuf++;
consumed_bytes++;
len--;
}
/* --- Header State --- */
else if (stateRx == HCI_RX_STATE_HEADER)
{
uint8_t hdrLen = 0;
uint16_t dataLen = 0;
/* determine header length based on packet type */
if (pktIndRx == HCI_EVT_TYPE)
{
hdrLen = HCI_EVT_HDR_LEN;
}
else if (pktIndRx == HCI_ACL_TYPE)
{
hdrLen = HCI_ACL_HDR_LEN;
}
else
{
/* invalid packet type */
WSF_ASSERT(0);
return consumed_bytes;
}
if (iRx != hdrLen) {
/* copy current byte into the temp header buffer */
hdrRx[iRx++] = dataByte;
pBuf++;
consumed_bytes++;
len--;
}
/* see if entire header has been read */
if (iRx == hdrLen)
{
/* extract data length from header */
if (pktIndRx == HCI_EVT_TYPE)
{
dataLen = hdrRx[1];
}
else if (pktIndRx == HCI_ACL_TYPE)
{
BYTES_TO_UINT16(dataLen, &hdrRx[2]);
}
/* allocate data buffer to hold entire packet */
if (pktIndRx == HCI_ACL_TYPE)
{
pPktRx = (uint8_t*)WsfMsgDataAlloc(hdrLen + dataLen, 0);
}
else
{
pPktRx = (uint8_t*)WsfMsgAlloc(hdrLen + dataLen);
}
if (pPktRx != NULL)
{
pDataRx = pPktRx;
/* copy header into data packet (note: memcpy is not so portable) */
{
uint8_t i;
for (i = 0; i < hdrLen; i++)
{
*pDataRx++ = hdrRx[i];
}
}
/* save number of bytes left to read */
iRx = dataLen;
if (iRx == 0)
{
stateRx = HCI_RX_STATE_COMPLETE;
}
else
{
stateRx = HCI_RX_STATE_DATA;
}
}
else
{
WSF_ASSERT(0); /* allocate falied */
return consumed_bytes;
}
}
}
/* --- Data State --- */
else if (stateRx == HCI_RX_STATE_DATA)
{
/* write incoming byte to allocated buffer */
*pDataRx++ = dataByte;
/* determine if entire packet has been read */
iRx--;
if (iRx == 0)
{
stateRx = HCI_RX_STATE_COMPLETE;
}
pBuf++;
consumed_bytes++;
len--;
}
/* --- Complete State --- */
/* ( Note Well! There is no else-if construct by design. ) */
if (stateRx == HCI_RX_STATE_COMPLETE)
{
g_bHCIReceivingPacket = FALSE;
/* deliver data */
if (pPktRx != NULL)
{
//am_hal_gpio_out_bit_set(13);
hciCoreRecv(pktIndRx, pPktRx);
//am_hal_gpio_out_bit_clear(13);
}
/* reset state machine */
stateRx = HCI_RX_STATE_IDLE;
}
}
return consumed_bytes;
}
//*****************************************************************************
//
//! @brief Check to see if the state machine has received part of a packet.
//!
//! This function checks the HCI packet-receive state machine to see if it is
//! in the middle of receiving a packet. This information can be useful in
//! determining whether the serial interface should remain enabled.
//!
//! @return TRUE if there is a packet in progress.
//
//*****************************************************************************
bool_t
hciTrReceivingPacket(void)
{
return g_bHCIReceivingPacket;
}
@@ -0,0 +1,29 @@
//*****************************************************************************
//
//! @file hci_tr_apollo.h
//!
//! @brief Additional header information for the Apollo implementation of HCI.
//
//*****************************************************************************
#ifndef HCI_TR_APOLLO_H
#define HCI_TR_APOLLO_H
#ifdef __cplusplus
extern "C"
{
#endif
//*****************************************************************************
//
// Function prototypes.
//
//*****************************************************************************
extern bool_t hciTrReceivingPacket(void);
extern uint16_t hciTrSerialRxIncoming(uint8_t *pBuf, uint16_t len);
#ifdef __cplusplus
};
#endif
#endif // HCI_TR_APOLLO_H

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