Embedded System Design 2 - Project
lora_wrappers.c
Go to the documentation of this file.
1 /***************************************************************************//**
2  * @file lora_wrappers.c
3  * @brief LoRa wrapper methods
4  * @version 2.4
5  * @author
6  * Benjamin Van der Smissen@n
7  * Heavily modified by Brecht Van Eeckhoudt
8  *
9  * ******************************************************************************
10  *
11  * @section Versions
12  *
13  * @li v1.0: Started with original code from Benjamin.
14  * @li v1.1: Modified a lot of code, implemented custom LPP data type methods.
15  * @li v1.2: Updated code to use new functionality to add data to the LPP packet.
16  * @li v1.3: Added method to use deprecated methods to test if data gets send correctly.
17  * @li v1.4: Changed error numbering and removed unnecessary variables and definitions.
18  * @li v1.5: Moved `data.index` reset to LoRaWAN sending functionality.
19  * @li v1.6: Moved `data.index` reset back to `main.c` because it doesn't affect the correct variable here.
20  * @li v2.0: Added functionality to exit methods after `error` call and updated version number.
21  * @li v2.1: Added extra dbprint debugging statements.
22  * @li v2.2: Fixed suboptimal buffer logic causing lockups after some runtime.
23  * @li v2.3: Chanced logic to clear the buffer before going to sleep.
24  * @li v2.4: Removed `static` before the local variables (not necessary).
25  *
26  * ******************************************************************************
27  *
28  * @todo
29  * **Future improvements:**@n
30  * - Save LoRaWAN settings during INIT before calling `disableLoRaWAN`?
31  * - Should be possible in ABP (saving to EEPROM? `saveMAC`?) See reference manual!
32  * - Update code where `initLoRaWAN` and other methods are called.
33  * - Fix `sleepLoRaWAN` and `wakeLoRaWAN` methods.
34  * - First separate `ULFRCO` definition in `delay.c`
35  *
36  * ******************************************************************************
37  *
38  * @section License
39  *
40  * **Copyright (C) 2019 - Brecht Van Eeckhoudt**
41  *
42  * This program is free software: you can redistribute it and/or modify
43  * it under the terms of the **GNU General Public License** as published by
44  * the Free Software Foundation, either **version 3** of the License, or
45  * (at your option) any later version.
46  *
47  * This program is distributed in the hope that it will be useful,
48  * but WITHOUT ANY WARRANTY; without even the implied warranty of
49  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
50  * GNU General Public License for more details.
51  *
52  * *A copy of the GNU General Public License can be found in the `LICENSE`
53  * file along with this source code.*
54  *
55  * @n
56  *
57  * Some methods use code obtained from examples from [Silicon Labs' GitHub](https://github.com/SiliconLabs/peripheral_examples).
58  * These sections are licensed under the Silabs License Agreement. See the file
59  * "Silabs_License_Agreement.txt" for details. Before using this software for
60  * any purpose, you must agree to the terms of that agreement.
61  *
62  ******************************************************************************/
63 
64 
65 #include <stdlib.h> /* "round" and memory functionality */
66 #include <stdbool.h> /* "bool", "true", "false" */
67 #include "em_gpio.h" /* General Purpose IO */
68 #include "em_leuart.h" /* Low Energy Universal Asynchronous Receiver/Transmitter Peripheral API */
69 
70 #include "lora.h" /* LoRaWAN functionality */
71 #include "lpp.h" /* Basic Low Power Payload (LPP) functionality */
72 #include "pm.h" /* Power management functionality */
73 #include "lora_settings.h" /* LoRaWAN settings */
74 
75 #include "lora_wrappers.h" /* Corresponding header file */
76 #include "pin_mapping.h" /* PORT and PIN definitions */
77 #include "debug_dbprint.h" /* Enable or disable printing to UART for debugging */
78 #include "datatypes.h" /* Definitions of the custom data-types */
79 #include "util.h" /* Utility functionality */
80 
81 
82 /* Local (application) variables */
86 
87 
88 /**************************************************************************//**
89  * @brief
90  * Initialize LoRaWAN functionality.
91  *****************************************************************************/
92 void initLoRaWAN (void)
93 {
94  // Before: memset(&appData, 0, sizeof(appData));
95  appData.length = 0;
96  appData.fill = 0;
97  appData.buffer = NULL;
98 
99  /* Initialize LoRaWAN communication */
100  loraStatus = LoRa_Init(loraSettings);
101 
102  if (loraStatus != JOINED) error(30);
103 
104 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
105  else dbinfo("LoRaWAN initialized.");
106 #endif /* DEBUG_DBPRINT */
107 
108 }
109 
110 
111 /**************************************************************************//**
112  * @brief
113  * Disable LoRaWAN functionality.
114  *****************************************************************************/
115 void disableLoRaWAN (void)
116 {
117  LEUART_Reset(RN2483_UART);
119  GPIO_PinOutClear(RN2483_RESET_PORT, RN2483_RESET_PIN);
120  GPIO_PinOutClear(RN2483_RX_PORT, RN2483_RX_PIN);
121  GPIO_PinOutClear(RN2483_TX_PORT, RN2483_TX_PIN);
122 
123 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
124  dbinfo("LoRaWAN disabled.");
125 #endif /* DEBUG_DBPRINT */
126 
127 }
128 
129 
130 /**************************************************************************//**
131  * @brief
132  * Let the LoRaWAN module sleep for a specified amount of time.
133  *
134  * @param[in] sSleep
135  * The amount of seconds for the module to go to sleep.
136  *****************************************************************************/
137 void sleepLoRaWAN (uint32_t sSleep)
138 {
139  bool wakeUp = false;
140  LoRa_Sleep((1000*sSleep), &wakeUp); /* "wakeUp" is not used in underlying method */
141 }
142 
143 
144 /**************************************************************************//**
145  * @brief
146  * Wake up the LoRaWAN module early after putting it to sleep using `sleepLoRaWAN`.
147  *****************************************************************************/
148 void wakeLoRaWAN (void)
149 {
150  LoRa_WakeUp();
151 }
152 
153 
154 /**************************************************************************//**
155  * @brief
156  * Send measured battery voltages and internal and external temperatures
157  * to the cloud using LoRaWAN.
158  *
159  * @details
160  * The measurements get added to the LPP packet following the *custom message
161  * convention* to save bytes to send.
162  *
163  * @param[in] data
164  * The struct which contains the measurements to send using LoRaWAN.
165  *****************************************************************************/
167 {
168  /* Initialize LPP-formatted payload
169  * For 6 measurements we need a max amount of 43 bytes (see `LPP_AddMeasurements` method documentation for the calculation) */
170  if (!LPP_InitBuffer(&appData, 43))
171  {
172  error(31);
173  return; /* Exit function */
174  }
175 
176  /* Add measurements to the LPP packet using the custom convention to save bytes send */
177  if (!LPP_AddMeasurements(&appData, data))
178  {
179  error(32);
180  return; /* Exit function */
181  }
182 
183 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
184  dbinfo("Started sending LPP buffer...");
185 #endif /* DEBUG_DBPRINT */
186 
187  /* Send custom LPP-like-formatted payload */
188  if (LoRa_SendLppBuffer(appData, LORA_UNCONFIMED) != SUCCESS)
189  {
190  error(33);
191  return; /* Exit function */
192  }
193 
194 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
195  dbinfo("LPP buffer send.");
196 #endif /* DEBUG_DBPRINT */
197 
198  LPP_FreeBuffer(&appData); // Clear buffer before going to sleep
199 }
200 
201 
202 /**************************************************************************//**
203  * @brief
204  * Send a packet to the cloud using LoRaWAN to indicate that a storm has been detected.
205  *
206  * @details
207  * The value gets added to the LPP packet following the *custom message convention*.
208  *
209  * @param[in] stormDetected
210  * @li `true` - A storm has been detected!
211  * @li `false` - No storm is detected.
212  *****************************************************************************/
213 void sendStormDetected (bool stormDetected)
214 {
215  /* Initialize LPP-formatted payload - We need 4 bytes */
216  if (!LPP_InitBuffer(&appData, 4))
217  {
218  error(34);
219  return; /* Exit function */
220  }
221 
222  /* Add value to the LPP packet using the custom convention */
223  if (!LPP_AddStormDetected(&appData, stormDetected))
224  {
225  error(35);
226  return; /* Exit function */
227  }
228 
229  /* Send custom LPP-like-formatted payload */
230  if (LoRa_SendLppBuffer(appData, LORA_UNCONFIMED) != SUCCESS)
231  {
232  error(36);
233  return; /* Exit function */
234  }
235 
236  LPP_FreeBuffer(&appData); // Clear buffer before going to sleep
237 }
238 
239 
240 /**************************************************************************//**
241  * @brief
242  * Send a packet to the cloud using LoRaWAN to indicate that the cable is broken.
243  *
244  * @details
245  * The value gets added to the LPP packet following the *custom message convention*.
246  *
247  * @param[in] cableBroken
248  * @li `true` - The cable is intact.
249  * @li `false` - The cable is broken!
250  *****************************************************************************/
251 void sendCableBroken (bool cableBroken)
252 {
253  /* Initialize LPP-formatted payload - We need 4 bytes */
254  if (!LPP_InitBuffer(&appData, 4))
255  {
256  error(37);
257  return; /* Exit function */
258  }
259 
260  /* Add value to the LPP packet using the custom convention */
261  if (!LPP_AddCableBroken(&appData, cableBroken))
262  {
263  error(38);
264  return; /* Exit function */
265  }
266 
267 
268  /* Send custom LPP-like-formatted payload */
269  if (LoRa_SendLppBuffer(appData, LORA_UNCONFIMED) != SUCCESS)
270  {
271  error(39);
272  return; /* Exit function */
273  }
274 
275  LPP_FreeBuffer(&appData); // Clear buffer before going to sleep
276 }
277 
278 
279 /**************************************************************************//**
280  * @brief
281  * Send a packet to indicate a *status*.
282  *
283  * @param[in] status
284  * The status value to send.
285  *****************************************************************************/
286 void sendStatus (uint8_t status)
287 {
288  /* Initialize LPP-formatted payload - We need 4 bytes */
289  if (!LPP_InitBuffer(&appData, 4))
290  {
291  error(40);
292  return; /* Exit function */
293  }
294 
295  /* Add value to the LPP packet using the custom convention */
296  if (!LPP_AddStatus(&appData, status))
297  {
298  error(41);
299  return; /* Exit function */
300  }
301 
302  /* Send custom LPP-like-formatted payload */
303  if (LoRa_SendLppBuffer(appData, LORA_UNCONFIMED) != SUCCESS)
304  {
305  error(42);
306  return; /* Exit function */
307  }
308 
309  LPP_FreeBuffer(&appData); // Clear buffer before going to sleep
310 }
311 
312 
313 /**************************************************************************//**
314  * @brief
315  * Send ONE measured battery voltage, internal and external temperature,
316  * `stormDetected`, `cableBroken` and `status` value to the cloud using
317  * LoRaWAN. This method uses the deprecated methods to test if the data
318  * gets send correctly.
319  *
320  * @param[in] data
321  * The struct which contains the measurements to send using LoRaWAN.
322  *****************************************************************************/
324 {
325  /* Initialize LPP-formatted payload - We need 21 bytes */
326  if (!LPP_InitBuffer(&appData, 21))
327  {
328  error(43);
329  return; /* Exit function */
330  }
331 
332  /* Add measurements to the LPP packet */
333  int16_t batteryLPP = (int16_t)(round((float)data.voltage[0]/10));
334  if (!LPP_deprecated_AddVBAT(&appData, batteryLPP))
335  {
336  error(44);
337  return; /* Exit function */
338  }
339 
340  int16_t intTempLPP = (int16_t)(round((float)data.intTemp[0]/100));
341  if (!LPP_deprecated_AddIntTemp(&appData, intTempLPP))
342  {
343  error(45);
344  return; /* Exit function */
345  }
346 
347  int16_t extTempLPP = (int16_t)(round((float)data.extTemp[0]/100));
348  if (!LPP_deprecated_AddExtTemp(&appData, extTempLPP))
349  {
350  error(46);
351  return; /* Exit function */
352  }
353 
354  if (!LPP_deprecated_AddStormDetected(&appData, true))
355  {
356  error(47);
357  return; /* Exit function */
358  }
359 
360  if (!LPP_deprecated_AddCableBroken(&appData, true))
361  {
362  error(48);
363  return; /* Exit function */
364  }
365 
366  if (!LPP_deprecated_AddStatus(&appData, 9))
367  {
368  error(49);
369  return; /* Exit function */
370  }
371 
372  /* Send LPP-formatted payload */
373  if (LoRa_SendLppBuffer(appData, LORA_UNCONFIMED) != SUCCESS)
374  {
375  error(50);
376  return; /* Exit function */
377  }
378 
379  LPP_FreeBuffer(&appData); // Clear buffer before going to sleep
380 }
void disableLoRaWAN(void)
Disable LoRaWAN functionality.
void sendStormDetected(bool stormDetected)
Send a packet to the cloud using LoRaWAN to indicate that a storm has been detected.
void sendCableBroken(bool cableBroken)
Send a packet to the cloud using LoRaWAN to indicate that the cable is broken.
#define RN2483_RESET_PORT
Definition: pin_mapping.h:121
uint8_t fill
Definition: lpp.h:41
LoRaSettings_t loraSettings
Definition: lora_wrappers.c:83
bool LPP_InitBuffer(LPP_Buffer_t *b, uint8_t size)
Definition: lpp.c:84
bool LPP_AddStormDetected(LPP_Buffer_t *b, uint8_t stormDetected)
Add a value to indicate that a storm has been detected to the LPP packet following the custom message...
Definition: lpp.c:274
#define RN2483_RESET_PIN
Definition: pin_mapping.h:122
enum lora_statuses LoRaStatus_t
Basic Low Power Payload (LPP) functionality.
Definitions of the custom data-types used.
MeasurementData_t data
Definition: main.c:189
void sendStatus(uint8_t status)
Send a packet to indicate a status.
#define RN2483_UART
Definition: pin_mapping.h:115
#define RN2483_TX_PIN
Definition: pin_mapping.h:118
#define LORA_UNCONFIMED
Definition: lora.h:23
Definition: lpp.h:38
#define RN2483_RX_PORT
Definition: pin_mapping.h:119
void dbinfo(char *message)
Print an info string (char array) to USARTx and go to the next line.
Definition: dbprint.c:503
#define RN2483_TX_PORT
Definition: pin_mapping.h:117
void LoRa_Sleep(uint32_t durationMs, volatile bool *wakeUp)
Definition: lora.c:76
bool LPP_deprecated_AddCableBroken(LPP_Buffer_t *b, uint8_t cableBroken)
Add a cable break value to the LPP packet, disguised as a Digital Input packet (1 byte)...
Definition: lpp.c:529
Definition: lora.h:34
bool LPP_deprecated_AddStatus(LPP_Buffer_t *b, uint8_t status)
Add a status value to the LPP packet, disguised as a Digital Input packet (1 byte). The channel is defined by LPP_STATUS_CHANNEL and is 0x15.
Definition: lpp.c:560
int32_t intTemp[6]
Definition: datatypes.h:73
void initLoRaWAN(void)
Initialize LoRaWAN functionality.
Definition: lora_wrappers.c:92
void sleepLoRaWAN(uint32_t sSleep)
Let the LoRaWAN module sleep for a specified amount of time.
void error(uint8_t number)
Error method.
Definition: util.c:131
#define RN2483_RX_PIN
Definition: pin_mapping.h:120
uint8_t * buffer
Definition: lpp.h:40
Utility functionality.
void PM_Disable(PM_SubSystem_t pmss)
Definition: pm.c:58
Definition: lora.h:35
The pin definitions for the regular and custom Happy Gecko board.
void wakeLoRaWAN(void)
Wake up the LoRaWAN module early after putting it to sleep using sleepLoRaWAN.
LoRaStatus_t LoRa_Init(LoRaSettings_t init)
Definition: lora.c:37
bool LPP_AddCableBroken(LPP_Buffer_t *b, uint8_t cableBroken)
Add a value to indicate that the cable has been broken to the LPP packet following the custom message...
Definition: lpp.c:317
LoRaStatus_t loraStatus
Definition: lora_wrappers.c:84
void LPP_FreeBuffer(LPP_Buffer_t *b)
Definition: lpp.c:129
LoRa wrapper methods.
Enable or disable printing to UART with dbprint.
void sendMeasurements(MeasurementData_t data)
Send measured battery voltages and internal and external temperatures to the cloud using LoRaWAN...
int32_t extTemp[6]
Definition: datatypes.h:74
bool LPP_deprecated_AddVBAT(LPP_Buffer_t *b, int16_t vbat)
Add a battery voltage measurement to the LPP packet, disguised as an Analog Input packet (2 bytes)...
Definition: lpp.c:400
LoRaStatus_t LoRa_WakeUp(void)
Definition: lora.c:80
bool LPP_AddMeasurements(LPP_Buffer_t *b, MeasurementData_t data)
Add measurement data to the LPP packet following the custom message convention to save bytes to send...
Definition: lpp.c:182
bool LPP_deprecated_AddIntTemp(LPP_Buffer_t *b, int16_t intTemp)
Add an internal temperature measurement (2 bytes) to the LPP packet. The channel is defined by LPP_TE...
Definition: lpp.c:433
LoRaStatus_t LoRa_SendLppBuffer(LPP_Buffer_t b, bool ackNoAck)
Definition: lora.c:61
bool LPP_AddStatus(LPP_Buffer_t *b, uint8_t status)
Add a value to indicate a program status to the LPP packet following the custom message convention...
Definition: lpp.c:360
LPP_Buffer_t appData
Definition: lora_wrappers.c:85
#define LORA_INIT_MY_DEVICE
Definition: lora_settings.h:98
uint8_t length
Definition: lpp.h:42
int32_t voltage[6]
Definition: datatypes.h:72
bool LPP_deprecated_AddStormDetected(LPP_Buffer_t *b, uint8_t stormDetected)
Add a storm value to the LPP packet, disguised as a Digital Input packet (1 byte). The channel is defined by LPP_STORM_CHANNEL and is 0x13.
Definition: lpp.c:498
Definition: pm.h:26
void sendTest(MeasurementData_t data)
Send ONE measured battery voltage, internal and external temperature, stormDetected, cableBroken and status value to the cloud using LoRaWAN. This method uses the deprecated methods to test if the data gets send correctly.
bool LPP_deprecated_AddExtTemp(LPP_Buffer_t *b, int16_t extTemp)
Add an external temperature measurement (2 bytes) to the LPP packet. The channel is defined by LPP_TE...
Definition: lpp.c:466