1 /*
2  / _____)             _              | |
3 ( (____  _____ ____ _| |_ _____  ____| |__
4  \____ \| ___ |    (_   _) ___ |/ ___)  _ \
5  _____) ) ____| | | || |_| ____( (___| | | |
6 (______/|_____)_|_|_| \__)_____)\____)_| |_|
7     (C)2013 Semtech
8  ___ _____ _   ___ _  _____ ___  ___  ___ ___
9 / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
10 \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
11 |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
12 embedded.connectivity.solutions===============
13 
14 Description: LoRa MAC confirm queue implementation
15 
16 License: Revised BSD License, see LICENSE.TXT file include in the project
17 
18 Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE )
19 */
20 #include <stdint.h>
21 #include <stdbool.h>
22 #include <stddef.h>
23 
24 #include "timer.h"
25 #include "utilities.h"
26 #include "LoRaMac.h"
27 #include "LoRaMacConfirmQueue.h"
28 
29 
30 /*
31  * LoRaMac Confirm Queue Context NVM structure
32  */
33 typedef struct sLoRaMacConfirmQueueNvmData
34 {
35     /*!
36     * MlmeConfirm queue data structure
37     */
38     MlmeConfirmQueue_t MlmeConfirmQueue[LORA_MAC_MLME_CONFIRM_QUEUE_LEN];
39     /*!
40     * Counts the number of MlmeConfirms to process
41     */
42     uint8_t MlmeConfirmQueueCnt;
43     /*!
44     * Variable which holds a common status
45     */
46     LoRaMacEventInfoStatus_t CommonStatus;
47 } LoRaMacConfirmQueueNvmData_t;
48 
49 /*
50  * LoRaMac Confirm Queue Context structure
51  */
52 typedef struct sLoRaMacConfirmQueueCtx
53 {
54     /*!
55     * LoRaMac callback function primitives
56     */
57     LoRaMacPrimitives_t* Primitives;
58     /*!
59     * Pointer to the first element of the ring buffer
60     */
61     MlmeConfirmQueue_t* BufferStart;
62     /*!
63     * Pointer to the last element of the ring buffer
64     */
65     MlmeConfirmQueue_t* BufferEnd;
66     /*!
67     * Non-volatile module context.
68     */
69     LoRaMacConfirmQueueNvmData_t Nvm;
70 } LoRaMacConfirmQueueCtx_t;
71 
72 /*
73  * Module context.
74  */
75 static LoRaMacConfirmQueueCtx_t ConfirmQueueCtx;
76 
IncreaseBufferPointer(MlmeConfirmQueue_t * bufferPointer)77 static MlmeConfirmQueue_t* IncreaseBufferPointer( MlmeConfirmQueue_t* bufferPointer )
78 {
79     if( bufferPointer == &ConfirmQueueCtx.Nvm.MlmeConfirmQueue[LORA_MAC_MLME_CONFIRM_QUEUE_LEN - 1] )
80     {
81         // Reset to the first element
82         bufferPointer = ConfirmQueueCtx.Nvm.MlmeConfirmQueue;
83     }
84     else
85     {
86         // Increase
87         bufferPointer++;
88     }
89     return bufferPointer;
90 }
91 
DecreaseBufferPointer(MlmeConfirmQueue_t * bufferPointer)92 static MlmeConfirmQueue_t* DecreaseBufferPointer( MlmeConfirmQueue_t* bufferPointer )
93 {
94     if( bufferPointer == ConfirmQueueCtx.Nvm.MlmeConfirmQueue )
95     {
96         // Reset to the last element
97         bufferPointer = &ConfirmQueueCtx.Nvm.MlmeConfirmQueue[LORA_MAC_MLME_CONFIRM_QUEUE_LEN - 1];
98     }
99     else
100     {
101         bufferPointer--;
102     }
103     return bufferPointer;
104 }
105 
IsListEmpty(uint8_t count)106 static bool IsListEmpty( uint8_t count )
107 {
108     if( count == 0 )
109     {
110         return true;
111     }
112     return false;
113 }
114 
IsListFull(uint8_t count)115 static bool IsListFull( uint8_t count )
116 {
117     if( count >= LORA_MAC_MLME_CONFIRM_QUEUE_LEN )
118     {
119         return true;
120     }
121     return false;
122 }
123 
GetElement(Mlme_t request,MlmeConfirmQueue_t * bufferStart,MlmeConfirmQueue_t * bufferEnd)124 static MlmeConfirmQueue_t* GetElement( Mlme_t request, MlmeConfirmQueue_t* bufferStart, MlmeConfirmQueue_t* bufferEnd )
125 {
126     MlmeConfirmQueue_t* element = bufferStart;
127 
128     if( IsListEmpty( ConfirmQueueCtx.Nvm.MlmeConfirmQueueCnt ) == true )
129     {
130         return NULL;
131     }
132 
133     for( uint8_t elementCnt = 0; elementCnt < ConfirmQueueCtx.Nvm.MlmeConfirmQueueCnt; elementCnt++ )
134     {
135         if( element->Request == request )
136         {
137             // We have found the element
138             return element;
139         }
140         element = IncreaseBufferPointer( element );
141     }
142 
143     return NULL;
144 }
145 
LoRaMacConfirmQueueInit(LoRaMacPrimitives_t * primitives)146 void LoRaMacConfirmQueueInit( LoRaMacPrimitives_t* primitives )
147 {
148     ConfirmQueueCtx.Primitives = primitives;
149 
150     // Init counter
151     ConfirmQueueCtx.Nvm.MlmeConfirmQueueCnt = 0;
152 
153     // Init buffer
154     ConfirmQueueCtx.BufferStart = ConfirmQueueCtx.Nvm.MlmeConfirmQueue;
155     ConfirmQueueCtx.BufferEnd = ConfirmQueueCtx.Nvm.MlmeConfirmQueue;
156 
157     memset1( ( uint8_t* )ConfirmQueueCtx.Nvm.MlmeConfirmQueue, 0xFF, sizeof( ConfirmQueueCtx.Nvm.MlmeConfirmQueue ) );
158 
159     // Common status
160     ConfirmQueueCtx.Nvm.CommonStatus = LORAMAC_EVENT_INFO_STATUS_ERROR;
161 }
162 
LoRaMacConfirmQueueAdd(MlmeConfirmQueue_t * mlmeConfirm)163 bool LoRaMacConfirmQueueAdd( MlmeConfirmQueue_t* mlmeConfirm )
164 {
165     if( IsListFull( ConfirmQueueCtx.Nvm.MlmeConfirmQueueCnt ) == true )
166     {
167         // Protect the buffer against overwrites
168         return false;
169     }
170 
171     // Add the element to the ring buffer
172     ConfirmQueueCtx.BufferEnd->Request = mlmeConfirm->Request;
173     ConfirmQueueCtx.BufferEnd->Status = mlmeConfirm->Status;
174     ConfirmQueueCtx.BufferEnd->RestrictCommonReadyToHandle = mlmeConfirm->RestrictCommonReadyToHandle;
175     ConfirmQueueCtx.BufferEnd->ReadyToHandle = mlmeConfirm->ReadyToHandle;
176     // Increase counter
177     ConfirmQueueCtx.Nvm.MlmeConfirmQueueCnt++;
178     // Update end pointer
179     ConfirmQueueCtx.BufferEnd = IncreaseBufferPointer( ConfirmQueueCtx.BufferEnd );
180 
181     return true;
182 }
183 
LoRaMacConfirmQueueRemoveLast(void)184 bool LoRaMacConfirmQueueRemoveLast( void )
185 {
186     if( IsListEmpty( ConfirmQueueCtx.Nvm.MlmeConfirmQueueCnt ) == true )
187     {
188         return false;
189     }
190 
191     // Increase counter
192     ConfirmQueueCtx.Nvm.MlmeConfirmQueueCnt--;
193     // Update start pointer
194     ConfirmQueueCtx.BufferEnd = DecreaseBufferPointer( ConfirmQueueCtx.BufferEnd );
195 
196     return true;
197 }
198 
LoRaMacConfirmQueueRemoveFirst(void)199 bool LoRaMacConfirmQueueRemoveFirst( void )
200 {
201     if( IsListEmpty( ConfirmQueueCtx.Nvm.MlmeConfirmQueueCnt ) == true )
202     {
203         return false;
204     }
205 
206     // Increase counter
207     ConfirmQueueCtx.Nvm.MlmeConfirmQueueCnt--;
208     // Update start pointer
209     ConfirmQueueCtx.BufferStart = IncreaseBufferPointer( ConfirmQueueCtx.BufferStart );
210 
211     return true;
212 }
213 
LoRaMacConfirmQueueSetStatus(LoRaMacEventInfoStatus_t status,Mlme_t request)214 void LoRaMacConfirmQueueSetStatus( LoRaMacEventInfoStatus_t status, Mlme_t request )
215 {
216     MlmeConfirmQueue_t* element = NULL;
217 
218     if( IsListEmpty( ConfirmQueueCtx.Nvm.MlmeConfirmQueueCnt ) == false )
219     {
220         element = GetElement( request, ConfirmQueueCtx.BufferStart, ConfirmQueueCtx.BufferEnd );
221         if( element != NULL )
222         {
223             element->Status = status;
224             element->ReadyToHandle = true;
225         }
226     }
227 }
228 
LoRaMacConfirmQueueGetStatus(Mlme_t request)229 LoRaMacEventInfoStatus_t LoRaMacConfirmQueueGetStatus( Mlme_t request )
230 {
231     MlmeConfirmQueue_t* element = NULL;
232 
233     if( IsListEmpty( ConfirmQueueCtx.Nvm.MlmeConfirmQueueCnt ) == false )
234     {
235         element = GetElement( request, ConfirmQueueCtx.BufferStart, ConfirmQueueCtx.BufferEnd );
236         if( element != NULL )
237         {
238             return element->Status;
239         }
240     }
241     return LORAMAC_EVENT_INFO_STATUS_ERROR;
242 }
243 
LoRaMacConfirmQueueSetStatusCmn(LoRaMacEventInfoStatus_t status)244 void LoRaMacConfirmQueueSetStatusCmn( LoRaMacEventInfoStatus_t status )
245 {
246     MlmeConfirmQueue_t* element = ConfirmQueueCtx.BufferStart;
247 
248     ConfirmQueueCtx.Nvm.CommonStatus = status;
249 
250     if( IsListEmpty( ConfirmQueueCtx.Nvm.MlmeConfirmQueueCnt ) == false )
251     {
252         do
253         {
254             element->Status = status;
255             // Set the status if it is allowed to set it with a call to
256             // LoRaMacConfirmQueueSetStatusCmn.
257             if( element->RestrictCommonReadyToHandle == false )
258             {
259                 element->ReadyToHandle = true;
260             }
261             element = IncreaseBufferPointer( element );
262         }while( element != ConfirmQueueCtx.BufferEnd );
263     }
264 }
265 
LoRaMacConfirmQueueGetStatusCmn(void)266 LoRaMacEventInfoStatus_t LoRaMacConfirmQueueGetStatusCmn( void )
267 {
268     return ConfirmQueueCtx.Nvm.CommonStatus;
269 }
270 
LoRaMacConfirmQueueIsCmdActive(Mlme_t request)271 bool LoRaMacConfirmQueueIsCmdActive( Mlme_t request )
272 {
273     if( GetElement( request, ConfirmQueueCtx.BufferStart, ConfirmQueueCtx.BufferEnd ) != NULL )
274     {
275         return true;
276     }
277     return false;
278 }
279 
LoRaMacConfirmQueueHandleCb(MlmeConfirm_t * mlmeConfirm)280 void LoRaMacConfirmQueueHandleCb( MlmeConfirm_t* mlmeConfirm )
281 {
282     uint8_t nbElements = ConfirmQueueCtx.Nvm.MlmeConfirmQueueCnt;
283     bool readyToHandle = false;
284     MlmeConfirmQueue_t mlmeConfirmToStore;
285 
286     for( uint8_t i = 0; i < nbElements; i++ )
287     {
288         mlmeConfirm->MlmeRequest = ConfirmQueueCtx.BufferStart->Request;
289         mlmeConfirm->Status = ConfirmQueueCtx.BufferStart->Status;
290         readyToHandle = ConfirmQueueCtx.BufferStart->ReadyToHandle;
291 
292         if( readyToHandle == true )
293         {
294             ConfirmQueueCtx.Primitives->MacMlmeConfirm( mlmeConfirm );
295         }
296         else
297         {
298             // The request is not processed yet. Store the state.
299             mlmeConfirmToStore.Request = ConfirmQueueCtx.BufferStart->Request;
300             mlmeConfirmToStore.Status = ConfirmQueueCtx.BufferStart->Status;
301             mlmeConfirmToStore.RestrictCommonReadyToHandle = ConfirmQueueCtx.BufferStart->RestrictCommonReadyToHandle;
302         }
303 
304         // Increase the pointer afterwards to prevent overwrites
305         LoRaMacConfirmQueueRemoveFirst( );
306 
307         if( readyToHandle == false )
308         {
309             // Add a request which has not been finished again to the queue
310             LoRaMacConfirmQueueAdd( &mlmeConfirmToStore );
311         }
312     }
313 }
314 
LoRaMacConfirmQueueGetCnt(void)315 uint8_t LoRaMacConfirmQueueGetCnt( void )
316 {
317     return ConfirmQueueCtx.Nvm.MlmeConfirmQueueCnt;
318 }
319 
LoRaMacConfirmQueueIsFull(void)320 bool LoRaMacConfirmQueueIsFull( void )
321 {
322     if( IsListFull( ConfirmQueueCtx.Nvm.MlmeConfirmQueueCnt ) == true )
323     {
324         return true;
325     }
326     else
327     {
328         return false;
329     }
330 }
331