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