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 lorawan_battery_level_cb_t battery_level_cb;
76 static lorawan_dr_changed_cb_t dr_changed_cb;
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 (battery_level_cb != NULL) {
87 		return battery_level_cb();
88 	} else {
89 		return 255;
90 	}
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_changed_cb != NULL) {
109 			dr_changed_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_register_battery_level_callback(lorawan_battery_level_cb_t cb)624 void lorawan_register_battery_level_callback(lorawan_battery_level_cb_t cb)
625 {
626 	battery_level_cb = cb;
627 }
628 
lorawan_register_downlink_callback(struct lorawan_downlink_cb * cb)629 void lorawan_register_downlink_callback(struct lorawan_downlink_cb *cb)
630 {
631 	sys_slist_append(&dl_callbacks, &cb->node);
632 }
633 
lorawan_register_dr_changed_callback(lorawan_dr_changed_cb_t cb)634 void lorawan_register_dr_changed_callback(lorawan_dr_changed_cb_t cb)
635 {
636 	dr_changed_cb = cb;
637 }
638 
lorawan_start(void)639 int lorawan_start(void)
640 {
641 	LoRaMacStatus_t status;
642 	MibRequestConfirm_t mib_req;
643 	GetPhyParams_t phy_params;
644 	PhyParam_t phy_param;
645 
646 	status = LoRaMacInitialization(&mac_primitives, &mac_callbacks,
647 				       selected_region);
648 	if (status != LORAMAC_STATUS_OK) {
649 		LOG_ERR("LoRaMacInitialization failed: %s",
650 			lorawan_status2str(status));
651 		return -EINVAL;
652 	}
653 
654 	LOG_DBG("LoRaMAC Initialized");
655 
656 	if (!IS_ENABLED(CONFIG_LORAWAN_NVM_NONE)) {
657 		lorawan_nvm_init();
658 		lorawan_nvm_data_restore();
659 	}
660 
661 	status = LoRaMacStart();
662 	if (status != LORAMAC_STATUS_OK) {
663 		LOG_ERR("Failed to start the LoRaMAC stack: %s",
664 			lorawan_status2str(status));
665 		return -EINVAL;
666 	}
667 
668 	/* Retrieve the default TX datarate for selected region */
669 	phy_params.Attribute = PHY_DEF_TX_DR;
670 	phy_param = RegionGetPhyParam(selected_region, &phy_params);
671 	default_datarate = phy_param.Value;
672 	current_datarate = default_datarate;
673 
674 	/* TODO: Move these to a proper location */
675 	mib_req.Type = MIB_SYSTEM_MAX_RX_ERROR;
676 	mib_req.Param.SystemMaxRxError = CONFIG_LORAWAN_SYSTEM_MAX_RX_ERROR;
677 	LoRaMacMibSetRequestConfirm(&mib_req);
678 
679 	return 0;
680 }
681 
lorawan_init(void)682 static int lorawan_init(void)
683 {
684 
685 	sys_slist_init(&dl_callbacks);
686 
687 	mac_primitives.MacMcpsConfirm = mcps_confirm_handler;
688 	mac_primitives.MacMcpsIndication = mcps_indication_handler;
689 	mac_primitives.MacMlmeConfirm = mlme_confirm_handler;
690 	mac_primitives.MacMlmeIndication = mlme_indication_handler;
691 	mac_callbacks.GetBatteryLevel = get_battery_level;
692 	mac_callbacks.GetTemperatureLevel = NULL;
693 
694 	if (IS_ENABLED(CONFIG_LORAWAN_NVM_NONE)) {
695 		mac_callbacks.NvmDataChange = NULL;
696 	} else {
697 		mac_callbacks.NvmDataChange = lorawan_nvm_data_mgmt_event;
698 	}
699 
700 	mac_callbacks.MacProcessNotify = mac_process_notify;
701 
702 	return 0;
703 }
704 
705 SYS_INIT(lorawan_init, POST_KERNEL, 0);
706