ENTS-tock
Environmental NeTworked Sensor firmware on Tock OS
Loading...
Searching...
No Matches
lorawan.cc
Go to the documentation of this file.
1
8#include "lorawan.h"
9
11#include <libents/util/time.h>
12#include <libtock-sync/services/alarm.h>
13#include <libtock/net/eui64.h>
14#include <ulog.h>
15
16#include "RadioLib.h"
17#include "config.h"
18
19// address in fram to store persistant buffer
20#define LORAWAN_NONCES_ADDR 2200
21
22// Amount of time between connection retries
23static const int retry_ms = 15000;
24
25// LoRaWAN upload port
26static const uint8_t upload_fport = 2;
27static const uint8_t heartbeat_fport = 3;
28static const uint8_t reset_fport = 4;
29static const uint8_t timesync_fport = 202;
30
31static TockRadioLibHal* hal;
32static Module* mod;
33static SX1262* tock_module;
34static LoRaWANNode* node;
35
36int lorawan_upload_fport(uint8_t* buffer, int length, int fport);
37
38// the entry point for the program
39int lorawan_init(void) {
40 ulog_trace("lorawan_setup");
41
42 hal = new TockRadioLibHal();
43 mod = new Module(hal, RADIOLIB_RADIO_NSS, RADIOLIB_RADIO_DIO_1,
44 RADIOLIB_RADIO_RESET, RADIOLIB_RADIO_BUSY);
45 tock_module = new SX1262(mod);
46
47 // print const LoRaWANBand_t US915
48 ulog_info("Region: %d\t Sub Band: %d", Region->txSpans->numChannels,
49 Region->freqMin);
50
51 // create the LoRaWAN node
52 node = new LoRaWANNode(tock_module, Region, subBand);
53 // now we can create the radio module
54 // pinout corresponds to the SparkFun LoRa Thing Plus - expLoRaBLE
55 // NSS pin: 0
56 // DIO1 pin: 2
57 // NRST pin: 4
58 // BUSY pin: 1
59
60 // Setup the radio
61 if (tock_module == nullptr) {
62 ulog_fatal("Error when initializing tock module.");
63 return -1;
64 }
65 int state = tock_module->begin();
66
67 // check node?
68 if (node == nullptr) {
69 ulog_fatal("Error when initializing node.");
70 return -1;
71 }
72
73 // check final state
74 if (state != RADIOLIB_ERR_NONE) {
75 ulog_fatal("Initialization failed. State = %d.", state);
76 return -1;
77 }
78
79 return 0;
80}
81
82int lorawan_join(void) {
83 ulog_trace("lorawan_join");
84
85 // lorawan state codes
86 int state = 0;
87
88 // status code
89 int status = 0;
90
91#ifdef STATIC_DEV_EUI
92 ulog_info("Using DevEUI from #define.");
93
94 static const uint8_t devEUI_bytes[8] = FORMAT32_KEY(RADIOLIB_LORAWAN_DEV_EUI);
95 static const uint64_t devEUI = bytes_to_u64_be(devEUI_bytes);
96#else
97 ulog_info("Using DevEUI from flash.");
98
99 // check driver exists
100 if (!libtock_eui64_exists()) {
101 ulog_error("EUI64 driver does not exist!");
102 }
103
104 // get devEUI from flash
105 uint64_t devEUI = 0;
106 libtock_eui64_get(&devEUI);
107
108 uint8_t devEUI_bytes[8] = {};
109 u64_to_bytes_be(devEUI, devEUI_bytes);
110#endif // RADIOLIB_LORAWAN_DEV_EUI
111
112 ulog_info("DevEUI: %02x %02x %02x %02x %02x %02x %02x %02x", devEUI_bytes[0],
113 devEUI_bytes[1], devEUI_bytes[2], devEUI_bytes[3], devEUI_bytes[4],
114 devEUI_bytes[5], devEUI_bytes[6], devEUI_bytes[7]);
115
116 uint8_t appKey[16] = FORMAT_KEY(RADIOLIB_LORAWAN_APP_KEY);
117 static const uint8_t joinEUI_bytes[8] =
119 static const uint64_t joinEUI = bytes_to_u64_be(joinEUI_bytes);
120
121 static const uint8_t nwkKey[16] = FORMAT_KEY(RADIOLIB_LORAWAN_NWK_KEY);
122
123 node->scanGuard = 100;
124
125 //
126 // Setup the OTAA session info
127 //
128 state = node->beginOTAA(joinEUI, devEUI, nwkKey, appKey);
129
130 if (state != RADIOLIB_ERR_NONE) {
131 ulog_fatal("LoRaWAN OTAA setup failed, code %d", state);
132 return 1;
133 }
134 ulog_debug("LoRaWAN OTAA setup success!");
135
136 // get pointer to the buffer
137 uint8_t persistant_nonces[RADIOLIB_LORAWAN_NONCES_BUF_SIZE];
138 status = fram_read(LORAWAN_NONCES_ADDR, RADIOLIB_LORAWAN_NONCES_BUF_SIZE,
139 persistant_nonces);
140
141 if (status < 0) {
142 ulog_error("Could not read nonces data from persistant storage.");
143 } else {
144 if (persistant_nonces[0] == 0x00) {
145 ulog_info("No nonces set");
146 } else {
147 state = node->setBufferNonces(persistant_nonces);
148 if (state < 0) {
149 if (state == RADIOLIB_ERR_NONCES_DISCARDED) {
150 ulog_error("LoRaWAN nonces is invalid. Resetting to 0.");
151 memset(persistant_nonces, 0, sizeof(persistant_nonces));
152 } else {
153 ulog_error("Could not set LoRaWAN nonces buffer. RadioLib state = %d",
154 state);
155 }
156 }
157 }
158 }
159
160 //
161 // Initiate join request
162 //
163 state = node->activateOTAA();
164 while (state != RADIOLIB_ERR_NONE && state != RADIOLIB_LORAWAN_NEW_SESSION) {
165 ulog_error(
166 "LoRaWAN OTAA activation failed, code %d. Delaying %d seconds, then "
167 "retrying.",
168 state, retry_ms / 1000);
169 hal->delay(retry_ms);
170 }
171
172 ulog_debug("LoRaWAN OTAA activation success!");
173
174 uint8_t* current_nonces = node->getBufferNonces();
175 status = fram_write(LORAWAN_NONCES_ADDR, current_nonces,
176 RADIOLIB_LORAWAN_NONCES_BUF_SIZE);
177 if (status < 0) {
178 ulog_error("Could not write nonces data from persistant storage.");
179 }
180
181 // set configuration for future uploads
182
183 // use ADR but set initial data rate
184 node->setADR(true);
185 node->setDatarate(2);
186
187 // TTN fair use
188 // node->setDutyCycle(true, 1250);
189 // dwell time limit for US
190 node->setDwellTime(true, 400);
191
192 return 0;
193}
194
196 ulog_trace("lorawan_timesync");
197
198 int state = 0;
199
200 state = node->sendMacCommandReq(RADIOLIB_LORAWAN_MAC_DEVICE_TIME);
201 if (state < 0) {
202 ulog_error("Failed to queue DeviceTimeReq: %d", state);
203 return state;
204 }
205
206 state = node->sendReceive(nullptr, (size_t)0, timesync_fport);
207 if (state < 0) {
208 ulog_error("Timesync uplink failed: %d", state);
209 return state;
210 }
211
212 uint32_t unix_epoch = 0;
213 uint16_t ms = 0;
214 state = node->getMacDeviceTimeAns(&unix_epoch, &ms);
215 if (state < 0) {
216 ulog_error("No DeviceTimeAns received: %d", state);
217 return state;
218 }
219
220 ulog_info("Current unix epoch is %d", unix_epoch);
221 set_epoch(unix_epoch);
222
223 return 0;
224}
225
226int lorawan_upload_fport(uint8_t* buffer, int length, int fport) {
227 ulog_trace("lorawan_upload_fport");
228
229 int state = 0;
230
231 // Ensure there are no pending callbacks
232 yield_no_wait();
233
234 // Form payload to send
235 ulog_debug("Sending uplink of %lu bytes.", length, buffer);
236
237 // downlink data
238 uint8_t recv_data[16] = {};
239 size_t len_recv_data = 0;
240
241 // packet information
242 LoRaWANEvent_t up_event = {};
243 LoRaWANEvent_t down_event = {};
244
245 // state indicates there was a downlink received
246 state = node->sendReceive(buffer, (size_t)length, (uint8_t)fport, recv_data,
247 &len_recv_data, false, &up_event, &down_event);
248 ulog_debug("LoRaWAN send/receive code %d.", state);
249 if (state < 0) {
250 ulog_error("Upload failed. LoRaWAN state %d", state);
251 } else if (state > 0) {
252 int down_fport = down_event.fPort;
253 ulog_debug("Received downlink (window number = %d, bytes = %d, fport = %d)",
254 state, len_recv_data, down_fport);
255 ulog_info("recv_data: %u", recv_data[0]);
256
257 // handle downlinks
258 switch (down_fport) {
259 case reset_fport:
260 ulog_info("Restarting");
261 tock_restart(0);
262 ulog_info("Failed to restart.");
263 break;
264 default:
265 ulog_warn("Downlink fport = %d not implemented", down_fport);
266 break;
267 }
268 } else {
269 ulog_debug("No downlink received");
270 }
271
272 return state;
273}
274
275int lorawan_upload(uint8_t* buffer, int length) {
276 ulog_trace("lorawan_upload");
277
278 return lorawan_upload_fport(buffer, length, upload_fport);
279}
280
282 ulog_trace("lorawan_heartbeat");
283
284 return lorawan_upload_fport(NULL, 0, heartbeat_fport);
285}
const LoRaWANBand_t * Region
Definition config.h:47
const uint8_t subBand
Definition config.h:51
#define FORMAT_KEY(...)
Definition config.h:61
#define RADIOLIB_LORAWAN_APP_KEY
Definition config.h:34
#define RADIOLIB_LORAWAN_NWK_KEY
Definition config.h:38
#define RADIOLIB_LORAWAN_DEV_EUI
Definition config.h:31
#define RADIOLIB_LORAWAN_JOIN_EUI
Definition config.h:26
#define FORMAT32_KEY(...)
Definition config.h:63
uint8_t buffer[32]
Storage interface for onboard FRAM chips.
fram_status fram_write(fram_addr addr, const uint8_t *data, size_t len)
Write bytes at the given address.
Definition fram.c:20
fram_status fram_read(fram_addr addr, size_t len, uint8_t *data)
Read bytes at the given address.
Definition fram.c:28
int lorawan_timesync(void)
Definition lorawan.cc:195
int lorawan_upload(uint8_t *buffer, int length)
Definition lorawan.cc:275
int lorawan_upload_fport(uint8_t *buffer, int length, int fport)
Definition lorawan.cc:226
int lorawan_heartbeat(void)
Definition lorawan.cc:281
#define LORAWAN_NONCES_ADDR
Definition lorawan.cc:20
int lorawan_join(void)
Definition lorawan.cc:82
int lorawan_init(void)
Definition lorawan.cc:39
void set_epoch(uint32_t epoch)
Sets the current unix epoch timestamp.
Definition time.c:25
UserConfigState state