| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548 |
- /*
- / _____) _ | |
- ( (____ _____ ____ _| |_ _____ ____| |__
- \____ \| ___ | (_ _) ___ |/ ___) _ \
- _____) ) ____| | | || |_| ____( (___| | | |
- (______/|_____)_|_|_| \__)_____)\____)_| |_|
- (C)2013 Semtech
- ___ _____ _ ___ _ _____ ___ ___ ___ ___
- / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
- \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
- |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
- embedded.connectivity.solutions===============
- Description: LoRa MAC commands
- License: Revised BSD License, see LICENSE.TXT file include in the project
- Maintainer: Miguel Luis ( Semtech ), Daniel Jaeckle ( STACKFORCE ), Johannes Bruder ( STACKFORCE )
- */
- #include <stddef.h>
- #include "utilities.h"
- #include "LoRaMacCommands.h"
- #include "LoRaMacConfirmQueue.h"
- /*!
- * Number of MAC Command slots
- */
- #define NUM_OF_MAC_COMMANDS 15
- /*!
- * Size of the CID field of MAC commands
- */
- #define CID_FIELD_SIZE 1
- /*!
- * Mac Commands list structure
- */
- typedef struct sMacCommandsList
- {
- /*
- * First element of MAC command list.
- */
- MacCommand_t* First;
- /*
- * Last element of MAC command list.
- */
- MacCommand_t* Last;
- } MacCommandsList_t;
- /*!
- * LoRaMac Commands Context structure
- */
- typedef struct sLoRaMacCommandsCtx
- {
- /*
- * List of MAC command elements
- */
- MacCommandsList_t MacCommandList;
- /*
- * Buffer to store MAC command elements
- */
- MacCommand_t MacCommandSlots[NUM_OF_MAC_COMMANDS];
- /*
- * Size of all MAC commands serialized as buffer
- */
- size_t SerializedCmdsSize;
- } LoRaMacCommandsCtx_t;
- /*!
- * Callback function to notify the upper layer about context change
- */
- static LoRaMacCommandsNvmEvent CommandsNvmCtxChanged;
- /*!
- * Non-volatile module context.
- */
- static LoRaMacCommandsCtx_t NvmCtx;
- /* Memory management functions */
- /*!
- * \brief Determines if a MAC command slot is free
- *
- * \param[IN] slot - Slot to check
- * \retval - Status of the operation
- */
- static bool IsSlotFree( const MacCommand_t* slot )
- {
- uint8_t* mem = ( uint8_t* )slot;
- for( uint16_t size = 0; size < sizeof( MacCommand_t ); size++ )
- {
- if( mem[size] != 0x00 )
- {
- return false;
- }
- }
- return true;
- }
- /*!
- * \brief Allocates a new MAC command memory slot
- *
- * \retval - Pointer to slot
- */
- static MacCommand_t* MallocNewMacCommandSlot( void )
- {
- uint8_t itr = 0;
- while( IsSlotFree( ( const MacCommand_t* )&NvmCtx.MacCommandSlots[itr] ) == false )
- {
- itr++;
- if( itr == NUM_OF_MAC_COMMANDS )
- {
- return NULL;
- }
- }
- return &NvmCtx.MacCommandSlots[itr];
- }
- /*!
- * \brief Free memory slot
- *
- * \param[IN] slot - Slot to free
- *
- * \retval - Status of the operation
- */
- static bool FreeMacCommandSlot( MacCommand_t* slot )
- {
- if( slot == NULL )
- {
- return false;
- }
- memset1( ( uint8_t* )slot, 0x00, sizeof( MacCommand_t ) );
- return true;
- }
- /* Linked list functions */
- /*!
- * \brief Initialize list
- *
- * \param[IN] list - List that shall be initialized
- * \retval - Status of the operation
- */
- static bool LinkedListInit( MacCommandsList_t* list )
- {
- if( list == NULL )
- {
- return false;
- }
- list->First = NULL;
- list->Last = NULL;
- return true;
- }
- /*!
- * \brief Add an element to the list
- *
- * \param[IN] list - List where the element shall be added.
- * \param[IN] element - Element to add
- * \retval - Status of the operation
- */
- static bool LinkedListAdd( MacCommandsList_t* list, MacCommand_t* element )
- {
- if( ( list == NULL ) || ( element == NULL ) )
- {
- return false;
- }
- // Check if this is the first entry to enter the list.
- if( list->First == NULL )
- {
- list->First = element;
- }
- // Check if the last entry exists and update its next point.
- if( list->Last )
- {
- list->Last->Next = element;
- }
- // Update the next point of this entry.
- element->Next = NULL;
- // Update the last entry of the list.
- list->Last = element;
- return true;
- }
- /*!
- * \brief Return the previous element in the list.
- *
- * \param[IN] list - List
- * \param[IN] element - Element where the previous element shall be searched
- * \retval - Status of the operation
- */
- static MacCommand_t* LinkedListGetPrevious( MacCommandsList_t* list, MacCommand_t* element )
- {
- if( ( list == NULL ) || ( element == NULL ) )
- {
- return NULL;
- }
- MacCommand_t* curElement;
- // Start at the head of the list
- curElement = list->First;
- // When current element is the first of the list, there's no previous element so we can return NULL immediately.
- if( element != curElement )
- {
- // Loop through all elements until the end is reached or the next of current is the current element.
- while( ( curElement != NULL ) && ( curElement->Next != element ) )
- {
- curElement = curElement->Next;
- }
- }
- else
- {
- curElement = NULL;
- }
- return curElement;
- }
- /*!
- * \brief Remove an element from the list
- *
- * \param[IN] list - List where the element shall be removed from.
- * \param[IN] element - Element to remove
- * \retval - Status of the operation
- */
- static bool LinkedListRemove( MacCommandsList_t* list, MacCommand_t* element )
- {
- if( ( list == NULL ) || ( element == NULL ) )
- {
- return false;
- }
- MacCommand_t* PrevElement = LinkedListGetPrevious( list, element );
- if( list->First == element )
- {
- list->First = element->Next;
- }
- if( list->Last == element )
- {
- list->Last = PrevElement;
- }
- if( PrevElement != NULL )
- {
- PrevElement->Next = element->Next;
- }
- element->Next = NULL;
- return true;
- }
- /*
- * \brief Determines if a MAC command is sticky or not
- *
- * \param[IN] cid - MAC command identifier
- *
- * \retval - Status of the operation
- */
- static bool IsSticky( uint8_t cid )
- {
- switch( cid )
- {
- case MOTE_MAC_DL_CHANNEL_ANS:
- case MOTE_MAC_RX_PARAM_SETUP_ANS:
- case MOTE_MAC_RX_TIMING_SETUP_ANS:
- return true;
- default:
- return false;
- }
- }
- /*
- * \brief Wrapper function for the NvmCtx
- */
- static void NvmCtxCallback( void )
- {
- if( CommandsNvmCtxChanged != NULL )
- {
- CommandsNvmCtxChanged( );
- }
- }
- LoRaMacCommandStatus_t LoRaMacCommandsInit( LoRaMacCommandsNvmEvent commandsNvmCtxChanged )
- {
- // Initialize with default
- memset1( ( uint8_t* )&NvmCtx, 0, sizeof( NvmCtx ) );
- LinkedListInit( &NvmCtx.MacCommandList );
- // Assign callback
- CommandsNvmCtxChanged = commandsNvmCtxChanged;
- return LORAMAC_COMMANDS_SUCCESS;
- }
- LoRaMacCommandStatus_t LoRaMacCommandsRestoreNvmCtx( void* commandsNvmCtx )
- {
- // Restore module context
- if( commandsNvmCtx != NULL )
- {
- memcpy1( ( uint8_t* )&NvmCtx, ( uint8_t* )commandsNvmCtx, sizeof( NvmCtx ) );
- return LORAMAC_COMMANDS_SUCCESS;
- }
- else
- {
- return LORAMAC_COMMANDS_ERROR_NPE;
- }
- }
- void* LoRaMacCommandsGetNvmCtx( size_t* commandsNvmCtxSize )
- {
- *commandsNvmCtxSize = sizeof( NvmCtx );
- return &NvmCtx;
- }
- LoRaMacCommandStatus_t LoRaMacCommandsAddCmd( uint8_t cid, uint8_t* payload, size_t payloadSize )
- {
- if( payload == NULL )
- {
- return LORAMAC_COMMANDS_ERROR_NPE;
- }
- MacCommand_t* newCmd;
- // Allocate a memory slot
- newCmd = MallocNewMacCommandSlot( );
- if( newCmd == 0 )
- {
- return LORAMAC_COMMANDS_ERROR_MEMORY;
- }
- // Add it to the list of Mac commands
- if( LinkedListAdd( &NvmCtx.MacCommandList, newCmd ) == false )
- {
- return LORAMAC_COMMANDS_ERROR;
- }
- // Set Values
- newCmd->CID = cid;
- newCmd->PayloadSize = payloadSize;
- memcpy1( ( uint8_t* )newCmd->Payload, payload, payloadSize );
- newCmd->IsSticky = IsSticky( cid );
- NvmCtx.SerializedCmdsSize += ( CID_FIELD_SIZE + payloadSize );
- NvmCtxCallback( );
- return LORAMAC_COMMANDS_SUCCESS;
- }
- LoRaMacCommandStatus_t LoRaMacCommandsRemoveCmd( MacCommand_t* macCmd )
- {
- if( macCmd == NULL )
- {
- return LORAMAC_COMMANDS_ERROR_NPE;
- }
- // Remove the Mac command element from MacCommandList
- if( LinkedListRemove( &NvmCtx.MacCommandList, macCmd ) == false )
- {
- return LORAMAC_COMMANDS_ERROR_CMD_NOT_FOUND;
- }
- NvmCtx.SerializedCmdsSize -= ( CID_FIELD_SIZE + macCmd->PayloadSize );
- // Free the MacCommand Slot
- if( FreeMacCommandSlot( macCmd ) == false )
- {
- return LORAMAC_COMMANDS_ERROR;
- }
- NvmCtxCallback( );
- return LORAMAC_COMMANDS_SUCCESS;
- }
- LoRaMacCommandStatus_t LoRaMacCommandsGetCmd( uint8_t cid, MacCommand_t** macCmd )
- {
- MacCommand_t* curElement;
- // Start at the head of the list
- curElement = NvmCtx.MacCommandList.First;
- // Loop through all elements until we find the element with the given CID
- while( ( curElement != NULL ) && ( curElement->CID != cid ) )
- {
- curElement = curElement->Next;
- }
- // Update the pointer anyway
- *macCmd = curElement;
- // Handle error in case if we reached the end without finding it.
- if( curElement == NULL )
- {
- return LORAMAC_COMMANDS_ERROR_CMD_NOT_FOUND;
- }
- return LORAMAC_COMMANDS_SUCCESS;
- }
- LoRaMacCommandStatus_t LoRaMacCommandsRemoveNoneStickyCmds( void )
- {
- MacCommand_t* curElement;
- MacCommand_t* nexElement;
- // Start at the head of the list
- curElement = NvmCtx.MacCommandList.First;
- // Loop through all elements
- while( curElement != NULL )
- {
- if( curElement->IsSticky == false )
- {
- nexElement = curElement->Next;
- LoRaMacCommandsRemoveCmd( curElement );
- curElement = nexElement;
- }
- else
- {
- curElement = curElement->Next;
- }
- }
- NvmCtxCallback( );
- return LORAMAC_COMMANDS_SUCCESS;
- }
- LoRaMacCommandStatus_t LoRaMacCommandsRemoveStickyAnsCmds( void )
- {
- MacCommand_t* curElement;
- MacCommand_t* nexElement;
- // Start at the head of the list
- curElement = NvmCtx.MacCommandList.First;
- // Loop through all elements
- while( curElement != NULL )
- {
- nexElement = curElement->Next;
- if( IsSticky( curElement->CID ) == true )
- {
- LoRaMacCommandsRemoveCmd( curElement );
- }
- curElement = nexElement;
- }
- NvmCtxCallback( );
- return LORAMAC_COMMANDS_SUCCESS;
- }
- LoRaMacCommandStatus_t LoRaMacCommandsGetSizeSerializedCmds( size_t* size )
- {
- if( size == NULL )
- {
- return LORAMAC_COMMANDS_ERROR_NPE;
- }
- *size = NvmCtx.SerializedCmdsSize;
- return LORAMAC_COMMANDS_SUCCESS;
- }
- LoRaMacCommandStatus_t LoRaMacCommandsSerializeCmds( size_t availableSize, size_t* effectiveSize, uint8_t* buffer )
- {
- MacCommand_t* curElement = NvmCtx.MacCommandList.First;
- MacCommand_t* nextElement;
- uint8_t itr = 0;
- if( ( buffer == NULL ) || ( effectiveSize == NULL ) )
- {
- return LORAMAC_COMMANDS_ERROR_NPE;
- }
- // Loop through all elements which fits into the buffer
- while( curElement != NULL )
- {
- // If the next MAC command still fits into the buffer, add it.
- if( ( availableSize - itr ) >= ( CID_FIELD_SIZE + curElement->PayloadSize ) )
- {
- buffer[itr++] = curElement->CID;
- memcpy1( &buffer[itr], curElement->Payload, curElement->PayloadSize );
- itr += curElement->PayloadSize;
- }
- else
- {
- break;
- }
- curElement = curElement->Next;
- }
- // Remove all commands which do not fit into the buffer
- while( curElement != NULL )
- {
- // Store the next element before removing the current one
- nextElement = curElement->Next;
- LoRaMacCommandsRemoveCmd( curElement );
- curElement = nextElement;
- }
- // Fetch the effective size of the mac commands
- LoRaMacCommandsGetSizeSerializedCmds( effectiveSize );
- return LORAMAC_COMMANDS_SUCCESS;
- }
- LoRaMacCommandStatus_t LoRaMacCommandsStickyCmdsPending( bool* cmdsPending )
- {
- if( cmdsPending == NULL )
- {
- return LORAMAC_COMMANDS_ERROR_NPE;
- }
- MacCommand_t* curElement;
- curElement = NvmCtx.MacCommandList.First;
- *cmdsPending = false;
- // Loop through all elements
- while( curElement != NULL )
- {
- if( curElement->IsSticky == true )
- {
- // Found one sticky MAC command
- *cmdsPending = true;
- return LORAMAC_COMMANDS_SUCCESS;
- }
- curElement = curElement->Next;
- }
- return LORAMAC_COMMANDS_SUCCESS;
- }
|