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