LoRaMacCommands.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. /*
  2. / _____) _ | |
  3. ( (____ _____ ____ _| |_ _____ ____| |__
  4. \____ \| ___ | (_ _) ___ |/ ___) _ \
  5. _____) ) ____| | | || |_| ____( (___| | | |
  6. (______/|_____)_|_|_| \__)_____)\____)_| |_|
  7. (C)2013 Semtech
  8. ___ _____ _ ___ _ _____ ___ ___ ___ ___
  9. / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
  10. \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
  11. |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
  12. embedded.connectivity.solutions===============
  13. Description: LoRa MAC commands
  14. License: Revised BSD License, see LICENSE.TXT file include in the project
  15. Maintainer: Miguel Luis ( Semtech ), Daniel Jaeckle ( STACKFORCE ), Johannes Bruder ( STACKFORCE )
  16. */
  17. #include <stddef.h>
  18. #include "utilities.h"
  19. #include "LoRaMacCommands.h"
  20. #include "LoRaMacConfirmQueue.h"
  21. /*!
  22. * Number of MAC Command slots
  23. */
  24. #define NUM_OF_MAC_COMMANDS 15
  25. /*!
  26. * Size of the CID field of MAC commands
  27. */
  28. #define CID_FIELD_SIZE 1
  29. /*!
  30. * Mac Commands list structure
  31. */
  32. typedef struct sMacCommandsList
  33. {
  34. /*
  35. * First element of MAC command list.
  36. */
  37. MacCommand_t* First;
  38. /*
  39. * Last element of MAC command list.
  40. */
  41. MacCommand_t* Last;
  42. } MacCommandsList_t;
  43. /*!
  44. * LoRaMac Commands Context structure
  45. */
  46. typedef struct sLoRaMacCommandsCtx
  47. {
  48. /*
  49. * List of MAC command elements
  50. */
  51. MacCommandsList_t MacCommandList;
  52. /*
  53. * Buffer to store MAC command elements
  54. */
  55. MacCommand_t MacCommandSlots[NUM_OF_MAC_COMMANDS];
  56. /*
  57. * Size of all MAC commands serialized as buffer
  58. */
  59. size_t SerializedCmdsSize;
  60. } LoRaMacCommandsCtx_t;
  61. /*!
  62. * Callback function to notify the upper layer about context change
  63. */
  64. static LoRaMacCommandsNvmEvent CommandsNvmCtxChanged;
  65. /*!
  66. * Non-volatile module context.
  67. */
  68. static LoRaMacCommandsCtx_t NvmCtx;
  69. /* Memory management functions */
  70. /*!
  71. * \brief Determines if a MAC command slot is free
  72. *
  73. * \param[IN] slot - Slot to check
  74. * \retval - Status of the operation
  75. */
  76. static bool IsSlotFree( const MacCommand_t* slot )
  77. {
  78. uint8_t* mem = ( uint8_t* )slot;
  79. for( uint16_t size = 0; size < sizeof( MacCommand_t ); size++ )
  80. {
  81. if( mem[size] != 0x00 )
  82. {
  83. return false;
  84. }
  85. }
  86. return true;
  87. }
  88. /*!
  89. * \brief Allocates a new MAC command memory slot
  90. *
  91. * \retval - Pointer to slot
  92. */
  93. static MacCommand_t* MallocNewMacCommandSlot( void )
  94. {
  95. uint8_t itr = 0;
  96. while( IsSlotFree( ( const MacCommand_t* )&NvmCtx.MacCommandSlots[itr] ) == false )
  97. {
  98. itr++;
  99. if( itr == NUM_OF_MAC_COMMANDS )
  100. {
  101. return NULL;
  102. }
  103. }
  104. return &NvmCtx.MacCommandSlots[itr];
  105. }
  106. /*!
  107. * \brief Free memory slot
  108. *
  109. * \param[IN] slot - Slot to free
  110. *
  111. * \retval - Status of the operation
  112. */
  113. static bool FreeMacCommandSlot( MacCommand_t* slot )
  114. {
  115. if( slot == NULL )
  116. {
  117. return false;
  118. }
  119. memset1( ( uint8_t* )slot, 0x00, sizeof( MacCommand_t ) );
  120. return true;
  121. }
  122. /* Linked list functions */
  123. /*!
  124. * \brief Initialize list
  125. *
  126. * \param[IN] list - List that shall be initialized
  127. * \retval - Status of the operation
  128. */
  129. static bool LinkedListInit( MacCommandsList_t* list )
  130. {
  131. if( list == NULL )
  132. {
  133. return false;
  134. }
  135. list->First = NULL;
  136. list->Last = NULL;
  137. return true;
  138. }
  139. /*!
  140. * \brief Add an element to the list
  141. *
  142. * \param[IN] list - List where the element shall be added.
  143. * \param[IN] element - Element to add
  144. * \retval - Status of the operation
  145. */
  146. static bool LinkedListAdd( MacCommandsList_t* list, MacCommand_t* element )
  147. {
  148. if( ( list == NULL ) || ( element == NULL ) )
  149. {
  150. return false;
  151. }
  152. // Check if this is the first entry to enter the list.
  153. if( list->First == NULL )
  154. {
  155. list->First = element;
  156. }
  157. // Check if the last entry exists and update its next point.
  158. if( list->Last )
  159. {
  160. list->Last->Next = element;
  161. }
  162. // Update the next point of this entry.
  163. element->Next = NULL;
  164. // Update the last entry of the list.
  165. list->Last = element;
  166. return true;
  167. }
  168. /*!
  169. * \brief Return the previous element in the list.
  170. *
  171. * \param[IN] list - List
  172. * \param[IN] element - Element where the previous element shall be searched
  173. * \retval - Status of the operation
  174. */
  175. static MacCommand_t* LinkedListGetPrevious( MacCommandsList_t* list, MacCommand_t* element )
  176. {
  177. if( ( list == NULL ) || ( element == NULL ) )
  178. {
  179. return NULL;
  180. }
  181. MacCommand_t* curElement;
  182. // Start at the head of the list
  183. curElement = list->First;
  184. // When current element is the first of the list, there's no previous element so we can return NULL immediately.
  185. if( element != curElement )
  186. {
  187. // Loop through all elements until the end is reached or the next of current is the current element.
  188. while( ( curElement != NULL ) && ( curElement->Next != element ) )
  189. {
  190. curElement = curElement->Next;
  191. }
  192. }
  193. else
  194. {
  195. curElement = NULL;
  196. }
  197. return curElement;
  198. }
  199. /*!
  200. * \brief Remove an element from the list
  201. *
  202. * \param[IN] list - List where the element shall be removed from.
  203. * \param[IN] element - Element to remove
  204. * \retval - Status of the operation
  205. */
  206. static bool LinkedListRemove( MacCommandsList_t* list, MacCommand_t* element )
  207. {
  208. if( ( list == NULL ) || ( element == NULL ) )
  209. {
  210. return false;
  211. }
  212. MacCommand_t* PrevElement = LinkedListGetPrevious( list, element );
  213. if( list->First == element )
  214. {
  215. list->First = element->Next;
  216. }
  217. if( list->Last == element )
  218. {
  219. list->Last = PrevElement;
  220. }
  221. if( PrevElement != NULL )
  222. {
  223. PrevElement->Next = element->Next;
  224. }
  225. element->Next = NULL;
  226. return true;
  227. }
  228. /*
  229. * \brief Determines if a MAC command is sticky or not
  230. *
  231. * \param[IN] cid - MAC command identifier
  232. *
  233. * \retval - Status of the operation
  234. */
  235. static bool IsSticky( uint8_t cid )
  236. {
  237. switch( cid )
  238. {
  239. case MOTE_MAC_DL_CHANNEL_ANS:
  240. case MOTE_MAC_RX_PARAM_SETUP_ANS:
  241. case MOTE_MAC_RX_TIMING_SETUP_ANS:
  242. return true;
  243. default:
  244. return false;
  245. }
  246. }
  247. /*
  248. * \brief Wrapper function for the NvmCtx
  249. */
  250. static void NvmCtxCallback( void )
  251. {
  252. if( CommandsNvmCtxChanged != NULL )
  253. {
  254. CommandsNvmCtxChanged( );
  255. }
  256. }
  257. LoRaMacCommandStatus_t LoRaMacCommandsInit( LoRaMacCommandsNvmEvent commandsNvmCtxChanged )
  258. {
  259. // Initialize with default
  260. memset1( ( uint8_t* )&NvmCtx, 0, sizeof( NvmCtx ) );
  261. LinkedListInit( &NvmCtx.MacCommandList );
  262. // Assign callback
  263. CommandsNvmCtxChanged = commandsNvmCtxChanged;
  264. return LORAMAC_COMMANDS_SUCCESS;
  265. }
  266. LoRaMacCommandStatus_t LoRaMacCommandsRestoreNvmCtx( void* commandsNvmCtx )
  267. {
  268. // Restore module context
  269. if( commandsNvmCtx != NULL )
  270. {
  271. memcpy1( ( uint8_t* )&NvmCtx, ( uint8_t* )commandsNvmCtx, sizeof( NvmCtx ) );
  272. return LORAMAC_COMMANDS_SUCCESS;
  273. }
  274. else
  275. {
  276. return LORAMAC_COMMANDS_ERROR_NPE;
  277. }
  278. }
  279. void* LoRaMacCommandsGetNvmCtx( size_t* commandsNvmCtxSize )
  280. {
  281. *commandsNvmCtxSize = sizeof( NvmCtx );
  282. return &NvmCtx;
  283. }
  284. LoRaMacCommandStatus_t LoRaMacCommandsAddCmd( uint8_t cid, uint8_t* payload, size_t payloadSize )
  285. {
  286. if( payload == NULL )
  287. {
  288. return LORAMAC_COMMANDS_ERROR_NPE;
  289. }
  290. MacCommand_t* newCmd;
  291. // Allocate a memory slot
  292. newCmd = MallocNewMacCommandSlot( );
  293. if( newCmd == 0 )
  294. {
  295. return LORAMAC_COMMANDS_ERROR_MEMORY;
  296. }
  297. // Add it to the list of Mac commands
  298. if( LinkedListAdd( &NvmCtx.MacCommandList, newCmd ) == false )
  299. {
  300. return LORAMAC_COMMANDS_ERROR;
  301. }
  302. // Set Values
  303. newCmd->CID = cid;
  304. newCmd->PayloadSize = payloadSize;
  305. memcpy1( ( uint8_t* )newCmd->Payload, payload, payloadSize );
  306. newCmd->IsSticky = IsSticky( cid );
  307. NvmCtx.SerializedCmdsSize += ( CID_FIELD_SIZE + payloadSize );
  308. NvmCtxCallback( );
  309. return LORAMAC_COMMANDS_SUCCESS;
  310. }
  311. LoRaMacCommandStatus_t LoRaMacCommandsRemoveCmd( MacCommand_t* macCmd )
  312. {
  313. if( macCmd == NULL )
  314. {
  315. return LORAMAC_COMMANDS_ERROR_NPE;
  316. }
  317. // Remove the Mac command element from MacCommandList
  318. if( LinkedListRemove( &NvmCtx.MacCommandList, macCmd ) == false )
  319. {
  320. return LORAMAC_COMMANDS_ERROR_CMD_NOT_FOUND;
  321. }
  322. NvmCtx.SerializedCmdsSize -= ( CID_FIELD_SIZE + macCmd->PayloadSize );
  323. // Free the MacCommand Slot
  324. if( FreeMacCommandSlot( macCmd ) == false )
  325. {
  326. return LORAMAC_COMMANDS_ERROR;
  327. }
  328. NvmCtxCallback( );
  329. return LORAMAC_COMMANDS_SUCCESS;
  330. }
  331. LoRaMacCommandStatus_t LoRaMacCommandsGetCmd( uint8_t cid, MacCommand_t** macCmd )
  332. {
  333. MacCommand_t* curElement;
  334. // Start at the head of the list
  335. curElement = NvmCtx.MacCommandList.First;
  336. // Loop through all elements until we find the element with the given CID
  337. while( ( curElement != NULL ) && ( curElement->CID != cid ) )
  338. {
  339. curElement = curElement->Next;
  340. }
  341. // Update the pointer anyway
  342. *macCmd = curElement;
  343. // Handle error in case if we reached the end without finding it.
  344. if( curElement == NULL )
  345. {
  346. return LORAMAC_COMMANDS_ERROR_CMD_NOT_FOUND;
  347. }
  348. return LORAMAC_COMMANDS_SUCCESS;
  349. }
  350. LoRaMacCommandStatus_t LoRaMacCommandsRemoveNoneStickyCmds( void )
  351. {
  352. MacCommand_t* curElement;
  353. MacCommand_t* nexElement;
  354. // Start at the head of the list
  355. curElement = NvmCtx.MacCommandList.First;
  356. // Loop through all elements
  357. while( curElement != NULL )
  358. {
  359. if( curElement->IsSticky == false )
  360. {
  361. nexElement = curElement->Next;
  362. LoRaMacCommandsRemoveCmd( curElement );
  363. curElement = nexElement;
  364. }
  365. else
  366. {
  367. curElement = curElement->Next;
  368. }
  369. }
  370. NvmCtxCallback( );
  371. return LORAMAC_COMMANDS_SUCCESS;
  372. }
  373. LoRaMacCommandStatus_t LoRaMacCommandsRemoveStickyAnsCmds( void )
  374. {
  375. MacCommand_t* curElement;
  376. MacCommand_t* nexElement;
  377. // Start at the head of the list
  378. curElement = NvmCtx.MacCommandList.First;
  379. // Loop through all elements
  380. while( curElement != NULL )
  381. {
  382. nexElement = curElement->Next;
  383. if( IsSticky( curElement->CID ) == true )
  384. {
  385. LoRaMacCommandsRemoveCmd( curElement );
  386. }
  387. curElement = nexElement;
  388. }
  389. NvmCtxCallback( );
  390. return LORAMAC_COMMANDS_SUCCESS;
  391. }
  392. LoRaMacCommandStatus_t LoRaMacCommandsGetSizeSerializedCmds( size_t* size )
  393. {
  394. if( size == NULL )
  395. {
  396. return LORAMAC_COMMANDS_ERROR_NPE;
  397. }
  398. *size = NvmCtx.SerializedCmdsSize;
  399. return LORAMAC_COMMANDS_SUCCESS;
  400. }
  401. LoRaMacCommandStatus_t LoRaMacCommandsSerializeCmds( size_t availableSize, size_t* effectiveSize, uint8_t* buffer )
  402. {
  403. MacCommand_t* curElement = NvmCtx.MacCommandList.First;
  404. MacCommand_t* nextElement;
  405. uint8_t itr = 0;
  406. if( ( buffer == NULL ) || ( effectiveSize == NULL ) )
  407. {
  408. return LORAMAC_COMMANDS_ERROR_NPE;
  409. }
  410. // Loop through all elements which fits into the buffer
  411. while( curElement != NULL )
  412. {
  413. // If the next MAC command still fits into the buffer, add it.
  414. if( ( availableSize - itr ) >= ( CID_FIELD_SIZE + curElement->PayloadSize ) )
  415. {
  416. buffer[itr++] = curElement->CID;
  417. memcpy1( &buffer[itr], curElement->Payload, curElement->PayloadSize );
  418. itr += curElement->PayloadSize;
  419. }
  420. else
  421. {
  422. break;
  423. }
  424. curElement = curElement->Next;
  425. }
  426. // Remove all commands which do not fit into the buffer
  427. while( curElement != NULL )
  428. {
  429. // Store the next element before removing the current one
  430. nextElement = curElement->Next;
  431. LoRaMacCommandsRemoveCmd( curElement );
  432. curElement = nextElement;
  433. }
  434. // Fetch the effective size of the mac commands
  435. LoRaMacCommandsGetSizeSerializedCmds( effectiveSize );
  436. return LORAMAC_COMMANDS_SUCCESS;
  437. }
  438. LoRaMacCommandStatus_t LoRaMacCommandsStickyCmdsPending( bool* cmdsPending )
  439. {
  440. if( cmdsPending == NULL )
  441. {
  442. return LORAMAC_COMMANDS_ERROR_NPE;
  443. }
  444. MacCommand_t* curElement;
  445. curElement = NvmCtx.MacCommandList.First;
  446. *cmdsPending = false;
  447. // Loop through all elements
  448. while( curElement != NULL )
  449. {
  450. if( curElement->IsSticky == true )
  451. {
  452. // Found one sticky MAC command
  453. *cmdsPending = true;
  454. return LORAMAC_COMMANDS_SUCCESS;
  455. }
  456. curElement = curElement->Next;
  457. }
  458. return LORAMAC_COMMANDS_SUCCESS;
  459. }