1 /*
2 * Copyright (c) 2020 Manivannan Sadhasivam <mani@kernel.org>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/init.h>
9 #include <errno.h>
10 #include <zephyr/lorawan/lorawan.h>
11
12 #include "lw_priv.h"
13
14 #include <LoRaMac.h>
15 #include <Region.h>
16 #include "nvm/lorawan_nvm.h"
17
18 #ifdef CONFIG_LORAMAC_REGION_AS923
19 #define DEFAULT_LORAWAN_REGION LORAMAC_REGION_AS923
20 #elif CONFIG_LORAMAC_REGION_AU915
21 #define DEFAULT_LORAWAN_REGION LORAMAC_REGION_AU915
22 #elif CONFIG_LORAMAC_REGION_CN470
23 #define DEFAULT_LORAWAN_REGION LORAMAC_REGION_CN470
24 #elif CONFIG_LORAMAC_REGION_CN779
25 #define DEFAULT_LORAWAN_REGION LORAMAC_REGION_CN779
26 #elif CONFIG_LORAMAC_REGION_EU433
27 #define DEFAULT_LORAWAN_REGION LORAMAC_REGION_EU433
28 #elif CONFIG_LORAMAC_REGION_EU868
29 #define DEFAULT_LORAWAN_REGION LORAMAC_REGION_EU868
30 #elif CONFIG_LORAMAC_REGION_KR920
31 #define DEFAULT_LORAWAN_REGION LORAMAC_REGION_KR920
32 #elif CONFIG_LORAMAC_REGION_IN865
33 #define DEFAULT_LORAWAN_REGION LORAMAC_REGION_IN865
34 #elif CONFIG_LORAMAC_REGION_US915
35 #define DEFAULT_LORAWAN_REGION LORAMAC_REGION_US915
36 #elif CONFIG_LORAMAC_REGION_RU864
37 #define DEFAULT_LORAWAN_REGION LORAMAC_REGION_RU864
38 #else
39 #error "At least one LoRaWAN region should be selected"
40 #endif
41
42 /* Use version 1.0.3.0 for ABP */
43 #define LORAWAN_ABP_VERSION 0x01000300
44
45 #define LOG_LEVEL CONFIG_LORAWAN_LOG_LEVEL
46 #include <zephyr/logging/log.h>
47 LOG_MODULE_REGISTER(lorawan);
48
49 K_SEM_DEFINE(mlme_confirm_sem, 0, 1);
50 K_SEM_DEFINE(mcps_confirm_sem, 0, 1);
51
52 K_MUTEX_DEFINE(lorawan_join_mutex);
53 K_MUTEX_DEFINE(lorawan_send_mutex);
54
55 /* We store both the default datarate requested through lorawan_set_datarate
56 * and the current datarate so that we can use the default datarate for all
57 * join requests, even as the current datarate changes due to ADR.
58 */
59 static enum lorawan_datarate default_datarate;
60 static enum lorawan_datarate current_datarate;
61 static bool lorawan_adr_enable;
62
63 static sys_slist_t dl_callbacks;
64
65 static LoRaMacPrimitives_t mac_primitives;
66 static LoRaMacCallback_t mac_callbacks;
67
68 static LoRaMacEventInfoStatus_t last_mcps_confirm_status;
69 static LoRaMacEventInfoStatus_t last_mlme_confirm_status;
70 static LoRaMacEventInfoStatus_t last_mcps_indication_status;
71 static LoRaMacEventInfoStatus_t last_mlme_indication_status;
72
73 static LoRaMacRegion_t selected_region = DEFAULT_LORAWAN_REGION;
74
75 static uint8_t (*get_battery_level_user)(void);
76 static void (*dr_change_cb)(enum lorawan_datarate dr);
77
78 /* implementation required by the soft-se (software secure element) */
BoardGetUniqueId(uint8_t * id)79 void BoardGetUniqueId(uint8_t *id)
80 {
81 /* Do not change the default value */
82 }
83
get_battery_level(void)84 static uint8_t get_battery_level(void)
85 {
86 if (get_battery_level_user != NULL) {
87 return get_battery_level_user();
88 }
89
90 return 255;
91 }
92
mac_process_notify(void)93 static void mac_process_notify(void)
94 {
95 LoRaMacProcess();
96 }
97
datarate_observe(bool force_notification)98 static void datarate_observe(bool force_notification)
99 {
100 MibRequestConfirm_t mib_req;
101
102 mib_req.Type = MIB_CHANNELS_DATARATE;
103 LoRaMacMibGetRequestConfirm(&mib_req);
104
105 if ((mib_req.Param.ChannelsDatarate != current_datarate) ||
106 (force_notification)) {
107 current_datarate = mib_req.Param.ChannelsDatarate;
108 if (dr_change_cb) {
109 dr_change_cb(current_datarate);
110 }
111 LOG_INF("Datarate changed: DR_%d", current_datarate);
112 }
113 }
114
mcps_confirm_handler(McpsConfirm_t * mcps_confirm)115 static void mcps_confirm_handler(McpsConfirm_t *mcps_confirm)
116 {
117 LOG_DBG("Received McpsConfirm (for McpsRequest %d)",
118 mcps_confirm->McpsRequest);
119
120 if (mcps_confirm->Status != LORAMAC_EVENT_INFO_STATUS_OK) {
121 LOG_ERR("McpsRequest failed : %s",
122 lorawan_eventinfo2str(mcps_confirm->Status));
123 } else {
124 LOG_DBG("McpsRequest success!");
125 }
126
127 /* Datarate may have changed due to a missed ADRACK */
128 if (lorawan_adr_enable) {
129 datarate_observe(false);
130 }
131
132 last_mcps_confirm_status = mcps_confirm->Status;
133 k_sem_give(&mcps_confirm_sem);
134 }
135
mcps_indication_handler(McpsIndication_t * mcps_indication)136 static void mcps_indication_handler(McpsIndication_t *mcps_indication)
137 {
138 struct lorawan_downlink_cb *cb;
139
140 LOG_DBG("Received McpsIndication %d", mcps_indication->McpsIndication);
141
142 if (mcps_indication->Status != LORAMAC_EVENT_INFO_STATUS_OK) {
143 LOG_ERR("McpsIndication failed : %s",
144 lorawan_eventinfo2str(mcps_indication->Status));
145 return;
146 }
147
148 /* Datarate can change as result of ADR command from server */
149 if (lorawan_adr_enable) {
150 datarate_observe(false);
151 }
152
153 /* Iterate over all registered downlink callbacks */
154 SYS_SLIST_FOR_EACH_CONTAINER(&dl_callbacks, cb, node) {
155 if ((cb->port == LW_RECV_PORT_ANY) ||
156 (cb->port == mcps_indication->Port)) {
157 cb->cb(mcps_indication->Port,
158 /* IsUplinkTxPending also indicates pending downlinks */
159 mcps_indication->IsUplinkTxPending == 1,
160 mcps_indication->Rssi, mcps_indication->Snr,
161 mcps_indication->BufferSize,
162 mcps_indication->Buffer);
163 }
164 }
165
166 last_mcps_indication_status = mcps_indication->Status;
167 }
168
mlme_confirm_handler(MlmeConfirm_t * mlme_confirm)169 static void mlme_confirm_handler(MlmeConfirm_t *mlme_confirm)
170 {
171 MibRequestConfirm_t mib_req;
172
173 LOG_DBG("Received MlmeConfirm (for MlmeRequest %d)",
174 mlme_confirm->MlmeRequest);
175
176 if (mlme_confirm->Status != LORAMAC_EVENT_INFO_STATUS_OK) {
177 LOG_ERR("MlmeConfirm failed : %s",
178 lorawan_eventinfo2str(mlme_confirm->Status));
179 goto out_sem;
180 }
181
182 switch (mlme_confirm->MlmeRequest) {
183 case MLME_JOIN:
184 mib_req.Type = MIB_DEV_ADDR;
185 LoRaMacMibGetRequestConfirm(&mib_req);
186 LOG_INF("Joined network! DevAddr: %08x", mib_req.Param.DevAddr);
187 break;
188 case MLME_LINK_CHECK:
189 /* Not implemented */
190 LOG_INF("Link check not implemented yet!");
191 break;
192 default:
193 break;
194 }
195
196 out_sem:
197 last_mlme_confirm_status = mlme_confirm->Status;
198 k_sem_give(&mlme_confirm_sem);
199 }
200
mlme_indication_handler(MlmeIndication_t * mlme_indication)201 static void mlme_indication_handler(MlmeIndication_t *mlme_indication)
202 {
203 LOG_DBG("Received MlmeIndication %d", mlme_indication->MlmeIndication);
204 last_mlme_indication_status = mlme_indication->Status;
205 }
206
lorawan_join_otaa(const struct lorawan_join_config * join_cfg)207 static LoRaMacStatus_t lorawan_join_otaa(
208 const struct lorawan_join_config *join_cfg)
209 {
210 MlmeReq_t mlme_req;
211 MibRequestConfirm_t mib_req;
212
213 mlme_req.Type = MLME_JOIN;
214 mlme_req.Req.Join.Datarate = default_datarate;
215 mlme_req.Req.Join.NetworkActivation = ACTIVATION_TYPE_OTAA;
216
217 if (IS_ENABLED(CONFIG_LORAWAN_NVM_NONE)) {
218 /* Retrieve the NVM context to store device nonce */
219 mib_req.Type = MIB_NVM_CTXS;
220 if (LoRaMacMibGetRequestConfirm(&mib_req) !=
221 LORAMAC_STATUS_OK) {
222 LOG_ERR("Could not get NVM context");
223 return -EINVAL;
224 }
225 mib_req.Param.Contexts->Crypto.DevNonce =
226 join_cfg->otaa.dev_nonce;
227 }
228
229 mib_req.Type = MIB_DEV_EUI;
230 mib_req.Param.DevEui = join_cfg->dev_eui;
231 LoRaMacMibSetRequestConfirm(&mib_req);
232
233 mib_req.Type = MIB_JOIN_EUI;
234 mib_req.Param.JoinEui = join_cfg->otaa.join_eui;
235 LoRaMacMibSetRequestConfirm(&mib_req);
236
237 mib_req.Type = MIB_NWK_KEY;
238 mib_req.Param.NwkKey = join_cfg->otaa.nwk_key;
239 LoRaMacMibSetRequestConfirm(&mib_req);
240
241 mib_req.Type = MIB_APP_KEY;
242 mib_req.Param.AppKey = join_cfg->otaa.app_key;
243 LoRaMacMibSetRequestConfirm(&mib_req);
244
245 return LoRaMacMlmeRequest(&mlme_req);
246 }
247
lorawan_join_abp(const struct lorawan_join_config * join_cfg)248 static LoRaMacStatus_t lorawan_join_abp(
249 const struct lorawan_join_config *join_cfg)
250 {
251 MibRequestConfirm_t mib_req;
252
253 mib_req.Type = MIB_ABP_LORAWAN_VERSION;
254 mib_req.Param.AbpLrWanVersion.Value = LORAWAN_ABP_VERSION;
255 LoRaMacMibSetRequestConfirm(&mib_req);
256
257 mib_req.Type = MIB_NET_ID;
258 mib_req.Param.NetID = 0;
259 LoRaMacMibSetRequestConfirm(&mib_req);
260
261 mib_req.Type = MIB_DEV_ADDR;
262 mib_req.Param.DevAddr = join_cfg->abp.dev_addr;
263 LoRaMacMibSetRequestConfirm(&mib_req);
264
265 mib_req.Type = MIB_F_NWK_S_INT_KEY;
266 mib_req.Param.FNwkSIntKey = join_cfg->abp.nwk_skey;
267 LoRaMacMibSetRequestConfirm(&mib_req);
268
269 mib_req.Type = MIB_S_NWK_S_INT_KEY;
270 mib_req.Param.SNwkSIntKey = join_cfg->abp.nwk_skey;
271 LoRaMacMibSetRequestConfirm(&mib_req);
272
273 mib_req.Type = MIB_NWK_S_ENC_KEY;
274 mib_req.Param.NwkSEncKey = join_cfg->abp.nwk_skey;
275 LoRaMacMibSetRequestConfirm(&mib_req);
276
277 mib_req.Type = MIB_APP_S_KEY;
278 mib_req.Param.AppSKey = join_cfg->abp.app_skey;
279 LoRaMacMibSetRequestConfirm(&mib_req);
280
281 mib_req.Type = MIB_NETWORK_ACTIVATION;
282 mib_req.Param.NetworkActivation = ACTIVATION_TYPE_ABP;
283 LoRaMacMibSetRequestConfirm(&mib_req);
284
285 return LORAMAC_STATUS_OK;
286 }
287
lorawan_set_region(enum lorawan_region region)288 int lorawan_set_region(enum lorawan_region region)
289 {
290 switch (region) {
291
292 #if defined(CONFIG_LORAMAC_REGION_AS923)
293 case LORAWAN_REGION_AS923:
294 selected_region = LORAMAC_REGION_AS923;
295 break;
296 #endif
297
298 #if defined(CONFIG_LORAMAC_REGION_AU915)
299 case LORAWAN_REGION_AU915:
300 selected_region = LORAMAC_REGION_AU915;
301 break;
302 #endif
303
304 #if defined(CONFIG_LORAMAC_REGION_CN470)
305 case LORAWAN_REGION_CN470:
306 selected_region = LORAMAC_REGION_CN470;
307 break;
308 #endif
309
310 #if defined(CONFIG_LORAMAC_REGION_CN779)
311 case LORAWAN_REGION_CN779:
312 selected_region = LORAMAC_REGION_CN779;
313 break;
314 #endif
315
316 #if defined(CONFIG_LORAMAC_REGION_EU433)
317 case LORAWAN_REGION_EU433:
318 selected_region = LORAMAC_REGION_EU433;
319 break;
320 #endif
321
322 #if defined(CONFIG_LORAMAC_REGION_EU868)
323 case LORAWAN_REGION_EU868:
324 selected_region = LORAMAC_REGION_EU868;
325 break;
326 #endif
327
328 #if defined(CONFIG_LORAMAC_REGION_KR920)
329 case LORAWAN_REGION_KR920:
330 selected_region = LORAMAC_REGION_KR920;
331 break;
332 #endif
333
334 #if defined(CONFIG_LORAMAC_REGION_IN865)
335 case LORAWAN_REGION_IN865:
336 selected_region = LORAMAC_REGION_IN865;
337 break;
338 #endif
339
340 #if defined(CONFIG_LORAMAC_REGION_US915)
341 case LORAWAN_REGION_US915:
342 selected_region = LORAMAC_REGION_US915;
343 break;
344 #endif
345
346 #if defined(CONFIG_LORAMAC_REGION_RU864)
347 case LORAWAN_REGION_RU864:
348 selected_region = LORAMAC_REGION_RU864;
349 break;
350 #endif
351
352 default:
353 LOG_ERR("No support for region %d!", region);
354 return -ENOTSUP;
355 }
356
357 LOG_DBG("Selected region %d", region);
358
359 return 0;
360 }
361
lorawan_join(const struct lorawan_join_config * join_cfg)362 int lorawan_join(const struct lorawan_join_config *join_cfg)
363 {
364 MibRequestConfirm_t mib_req;
365 LoRaMacStatus_t status;
366 int ret = 0;
367
368 k_mutex_lock(&lorawan_join_mutex, K_FOREVER);
369
370 /* MIB_PUBLIC_NETWORK powers on the radio and does not turn it off */
371 mib_req.Type = MIB_PUBLIC_NETWORK;
372 mib_req.Param.EnablePublicNetwork = IS_ENABLED(CONFIG_LORAWAN_PUBLIC_NETWORK);
373 LoRaMacMibSetRequestConfirm(&mib_req);
374
375 if (join_cfg->mode == LORAWAN_ACT_OTAA) {
376 status = lorawan_join_otaa(join_cfg);
377 if (status != LORAMAC_STATUS_OK) {
378 LOG_ERR("OTAA join failed: %s",
379 lorawan_status2str(status));
380 ret = lorawan_status2errno(status);
381 goto out;
382 }
383
384 LOG_DBG("Network join request sent!");
385
386 /*
387 * We can be sure that the semaphore will be released for
388 * both success and failure cases after a specific time period.
389 * So we can use K_FOREVER and no need to check the return val.
390 */
391 k_sem_take(&mlme_confirm_sem, K_FOREVER);
392 if (last_mlme_confirm_status != LORAMAC_EVENT_INFO_STATUS_OK) {
393 ret = lorawan_eventinfo2errno(last_mlme_confirm_status);
394 goto out;
395 }
396 } else if (join_cfg->mode == LORAWAN_ACT_ABP) {
397 status = lorawan_join_abp(join_cfg);
398 if (status != LORAMAC_STATUS_OK) {
399 LOG_ERR("ABP join failed: %s",
400 lorawan_status2str(status));
401 ret = lorawan_status2errno(status);
402 goto out;
403 }
404 } else {
405 ret = -EINVAL;
406 }
407
408 out:
409 /* If the join succeeded */
410 if (ret == 0) {
411 /*
412 * Several regions (AS923, AU915, US915) overwrite the
413 * datarate as part of the join process. Reset the datarate
414 * to the value requested (and validated) in
415 * lorawan_set_datarate so that the MAC layer is aware of the
416 * set datarate for LoRaMacQueryTxPossible. This is only
417 * performed when ADR is disabled as it the network servers
418 * responsibility to increase datarates when ADR is enabled.
419 */
420 if (!lorawan_adr_enable) {
421 MibRequestConfirm_t mib_req2;
422
423 mib_req2.Type = MIB_CHANNELS_DATARATE;
424 mib_req2.Param.ChannelsDatarate = default_datarate;
425 LoRaMacMibSetRequestConfirm(&mib_req2);
426 }
427
428 /*
429 * Force a notification of the datarate on network join as the
430 * user may not have explicitly set a datarate to use.
431 */
432 datarate_observe(true);
433 }
434
435 k_mutex_unlock(&lorawan_join_mutex);
436 return ret;
437 }
438
lorawan_set_class(enum lorawan_class dev_class)439 int lorawan_set_class(enum lorawan_class dev_class)
440 {
441 MibRequestConfirm_t mib_req;
442 DeviceClass_t current_class;
443 LoRaMacStatus_t status;
444
445 mib_req.Type = MIB_DEVICE_CLASS;
446 LoRaMacMibGetRequestConfirm(&mib_req);
447 current_class = mib_req.Param.Class;
448
449 switch (dev_class) {
450 case LORAWAN_CLASS_A:
451 mib_req.Param.Class = CLASS_A;
452 break;
453 case LORAWAN_CLASS_B:
454 LOG_ERR("Class B not supported yet!");
455 return -ENOTSUP;
456 case LORAWAN_CLASS_C:
457 mib_req.Param.Class = CLASS_C;
458 break;
459 default:
460 return -EINVAL;
461 }
462
463 if (mib_req.Param.Class != current_class) {
464 status = LoRaMacMibSetRequestConfirm(&mib_req);
465 if (status != LORAMAC_STATUS_OK) {
466 LOG_ERR("Failed to set device class: %s",
467 lorawan_status2str(status));
468 return lorawan_status2errno(status);
469 }
470 }
471
472 return 0;
473 }
474
lorawan_set_datarate(enum lorawan_datarate dr)475 int lorawan_set_datarate(enum lorawan_datarate dr)
476 {
477 MibRequestConfirm_t mib_req;
478
479 /* Bail out if using ADR */
480 if (lorawan_adr_enable) {
481 return -EINVAL;
482 }
483
484 /* Notify MAC layer of the requested datarate */
485 mib_req.Type = MIB_CHANNELS_DATARATE;
486 mib_req.Param.ChannelsDatarate = dr;
487 if (LoRaMacMibSetRequestConfirm(&mib_req) != LORAMAC_STATUS_OK) {
488 /* Datarate is invalid for this region */
489 return -EINVAL;
490 }
491
492 default_datarate = dr;
493 current_datarate = dr;
494
495 return 0;
496 }
497
lorawan_get_payload_sizes(uint8_t * max_next_payload_size,uint8_t * max_payload_size)498 void lorawan_get_payload_sizes(uint8_t *max_next_payload_size,
499 uint8_t *max_payload_size)
500 {
501 LoRaMacTxInfo_t tx_info;
502
503 /* QueryTxPossible cannot fail */
504 (void) LoRaMacQueryTxPossible(0, &tx_info);
505
506 *max_next_payload_size = tx_info.MaxPossibleApplicationDataSize;
507 *max_payload_size = tx_info.CurrentPossiblePayloadSize;
508 }
509
lorawan_get_min_datarate(void)510 enum lorawan_datarate lorawan_get_min_datarate(void)
511 {
512 MibRequestConfirm_t mib_req;
513
514 mib_req.Type = MIB_CHANNELS_MIN_TX_DATARATE;
515 LoRaMacMibGetRequestConfirm(&mib_req);
516
517 return mib_req.Param.ChannelsMinTxDatarate;
518 }
519
lorawan_enable_adr(bool enable)520 void lorawan_enable_adr(bool enable)
521 {
522 MibRequestConfirm_t mib_req;
523
524 if (enable != lorawan_adr_enable) {
525 lorawan_adr_enable = enable;
526
527 mib_req.Type = MIB_ADR;
528 mib_req.Param.AdrEnable = lorawan_adr_enable;
529 LoRaMacMibSetRequestConfirm(&mib_req);
530 }
531 }
532
lorawan_set_conf_msg_tries(uint8_t tries)533 int lorawan_set_conf_msg_tries(uint8_t tries)
534 {
535 MibRequestConfirm_t mib_req;
536
537 mib_req.Type = MIB_CHANNELS_NB_TRANS;
538 mib_req.Param.ChannelsNbTrans = tries;
539 if (LoRaMacMibSetRequestConfirm(&mib_req) != LORAMAC_STATUS_OK) {
540 return -EINVAL;
541 }
542
543 return 0;
544 }
545
lorawan_send(uint8_t port,uint8_t * data,uint8_t len,enum lorawan_message_type type)546 int lorawan_send(uint8_t port, uint8_t *data, uint8_t len,
547 enum lorawan_message_type type)
548 {
549 LoRaMacStatus_t status;
550 McpsReq_t mcps_req;
551 LoRaMacTxInfo_t tx_info;
552 int ret = 0;
553 bool empty_frame = false;
554
555 if (data == NULL) {
556 return -EINVAL;
557 }
558
559 k_mutex_lock(&lorawan_send_mutex, K_FOREVER);
560
561 status = LoRaMacQueryTxPossible(len, &tx_info);
562 if (status != LORAMAC_STATUS_OK) {
563 /*
564 * If status indicates an error, then most likely the payload
565 * has exceeded the maximum possible length for the current
566 * region and datarate. We can't do much other than sending
567 * empty frame in order to flush MAC commands in stack and
568 * hoping the application to lower the payload size for
569 * next try.
570 */
571 LOG_ERR("LoRaWAN Query Tx Possible Failed: %s",
572 lorawan_status2str(status));
573 empty_frame = true;
574 mcps_req.Type = MCPS_UNCONFIRMED;
575 mcps_req.Req.Unconfirmed.fBuffer = NULL;
576 mcps_req.Req.Unconfirmed.fBufferSize = 0;
577 mcps_req.Req.Unconfirmed.Datarate = DR_0;
578 } else {
579 switch (type) {
580 case LORAWAN_MSG_UNCONFIRMED:
581 mcps_req.Type = MCPS_UNCONFIRMED;
582 break;
583 case LORAWAN_MSG_CONFIRMED:
584 mcps_req.Type = MCPS_CONFIRMED;
585 break;
586 }
587 mcps_req.Req.Unconfirmed.fPort = port;
588 mcps_req.Req.Unconfirmed.fBuffer = data;
589 mcps_req.Req.Unconfirmed.fBufferSize = len;
590 mcps_req.Req.Unconfirmed.Datarate = current_datarate;
591 }
592
593 status = LoRaMacMcpsRequest(&mcps_req);
594 if (status != LORAMAC_STATUS_OK) {
595 LOG_ERR("LoRaWAN Send failed: %s", lorawan_status2str(status));
596 ret = lorawan_status2errno(status);
597 goto out;
598 }
599
600 /*
601 * Always wait for MAC operations to complete.
602 * We can be sure that the semaphore will be released for
603 * both success and failure cases after a specific time period.
604 * So we can use K_FOREVER and no need to check the return val.
605 */
606 k_sem_take(&mcps_confirm_sem, K_FOREVER);
607 if (last_mcps_confirm_status != LORAMAC_EVENT_INFO_STATUS_OK) {
608 ret = lorawan_eventinfo2errno(last_mcps_confirm_status);
609 }
610
611 /*
612 * Indicate to the application that the provided data was not sent and
613 * it has to resend the packet.
614 */
615 if (empty_frame) {
616 ret = -EAGAIN;
617 }
618
619 out:
620 k_mutex_unlock(&lorawan_send_mutex);
621 return ret;
622 }
623
lorawan_set_battery_level_callback(uint8_t (* battery_lvl_cb)(void))624 int lorawan_set_battery_level_callback(uint8_t (*battery_lvl_cb)(void))
625 {
626 if (battery_lvl_cb == NULL) {
627 return -EINVAL;
628 }
629
630 get_battery_level_user = battery_lvl_cb;
631
632 return 0;
633 }
634
lorawan_register_downlink_callback(struct lorawan_downlink_cb * cb)635 void lorawan_register_downlink_callback(struct lorawan_downlink_cb *cb)
636 {
637 sys_slist_append(&dl_callbacks, &cb->node);
638 }
639
lorawan_register_dr_changed_callback(void (* cb)(enum lorawan_datarate))640 void lorawan_register_dr_changed_callback(void (*cb)(enum lorawan_datarate))
641 {
642 dr_change_cb = cb;
643 }
644
lorawan_start(void)645 int lorawan_start(void)
646 {
647 LoRaMacStatus_t status;
648 MibRequestConfirm_t mib_req;
649 GetPhyParams_t phy_params;
650 PhyParam_t phy_param;
651
652 status = LoRaMacInitialization(&mac_primitives, &mac_callbacks,
653 selected_region);
654 if (status != LORAMAC_STATUS_OK) {
655 LOG_ERR("LoRaMacInitialization failed: %s",
656 lorawan_status2str(status));
657 return -EINVAL;
658 }
659
660 LOG_DBG("LoRaMAC Initialized");
661
662 if (!IS_ENABLED(CONFIG_LORAWAN_NVM_NONE)) {
663 lorawan_nvm_init();
664 lorawan_nvm_data_restore();
665 }
666
667 status = LoRaMacStart();
668 if (status != LORAMAC_STATUS_OK) {
669 LOG_ERR("Failed to start the LoRaMAC stack: %s",
670 lorawan_status2str(status));
671 return -EINVAL;
672 }
673
674 /* Retrieve the default TX datarate for selected region */
675 phy_params.Attribute = PHY_DEF_TX_DR;
676 phy_param = RegionGetPhyParam(selected_region, &phy_params);
677 default_datarate = phy_param.Value;
678 current_datarate = default_datarate;
679
680 /* TODO: Move these to a proper location */
681 mib_req.Type = MIB_SYSTEM_MAX_RX_ERROR;
682 mib_req.Param.SystemMaxRxError = CONFIG_LORAWAN_SYSTEM_MAX_RX_ERROR;
683 LoRaMacMibSetRequestConfirm(&mib_req);
684
685 return 0;
686 }
687
lorawan_init(void)688 static int lorawan_init(void)
689 {
690
691 sys_slist_init(&dl_callbacks);
692
693 mac_primitives.MacMcpsConfirm = mcps_confirm_handler;
694 mac_primitives.MacMcpsIndication = mcps_indication_handler;
695 mac_primitives.MacMlmeConfirm = mlme_confirm_handler;
696 mac_primitives.MacMlmeIndication = mlme_indication_handler;
697 mac_callbacks.GetBatteryLevel = get_battery_level;
698 mac_callbacks.GetTemperatureLevel = NULL;
699
700 if (IS_ENABLED(CONFIG_LORAWAN_NVM_NONE)) {
701 mac_callbacks.NvmDataChange = NULL;
702 } else {
703 mac_callbacks.NvmDataChange = lorawan_nvm_data_mgmt_event;
704 }
705
706 mac_callbacks.MacProcessNotify = mac_process_notify;
707
708 return 0;
709 }
710
711 SYS_INIT(lorawan_init, POST_KERNEL, 0);
712