1 /*
2  * Class A LoRaWAN sample application
3  *
4  * Copyright (c) 2020 Manivannan Sadhasivam <mani@kernel.org>
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #include <device.h>
10 #include <lorawan/lorawan.h>
11 #include <zephyr.h>
12 
13 #define DEFAULT_RADIO_NODE DT_ALIAS(lora0)
14 BUILD_ASSERT(DT_NODE_HAS_STATUS(DEFAULT_RADIO_NODE, okay),
15 	     "No default LoRa radio specified in DT");
16 #define DEFAULT_RADIO DT_LABEL(DEFAULT_RADIO_NODE)
17 
18 /* Customize based on network configuration */
19 #define LORAWAN_DEV_EUI			{ 0xDD, 0xEE, 0xAA, 0xDD, 0xBB, 0xEE,\
20 					  0xEE, 0xFF }
21 #define LORAWAN_JOIN_EUI		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
22 					  0x00, 0x00 }
23 #define LORAWAN_APP_KEY			{ 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE,\
24 					  0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88,\
25 					  0x09, 0xCF, 0x4F, 0x3C }
26 
27 #define DELAY K_MSEC(10000)
28 
29 #define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
30 #include <logging/log.h>
31 LOG_MODULE_REGISTER(lorawan_class_a);
32 
33 char data[] = {'h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd'};
34 
dl_callback(uint8_t port,bool data_pending,int16_t rssi,int8_t snr,uint8_t len,const uint8_t * data)35 static void dl_callback(uint8_t port, bool data_pending,
36 			int16_t rssi, int8_t snr,
37 			uint8_t len, const uint8_t *data)
38 {
39 	LOG_INF("Port %d, Pending %d, RSSI %ddB, SNR %ddBm", port, data_pending, rssi, snr);
40 	if (data) {
41 		LOG_HEXDUMP_INF(data, len, "Payload: ");
42 	}
43 }
44 
lorwan_datarate_changed(enum lorawan_datarate dr)45 static void lorwan_datarate_changed(enum lorawan_datarate dr)
46 {
47 	uint8_t unused, max_size;
48 
49 	lorawan_get_payload_sizes(&unused, &max_size);
50 	LOG_INF("New Datarate: DR_%d, Max Payload %d", dr, max_size);
51 }
52 
main(void)53 void main(void)
54 {
55 	const struct device *lora_dev;
56 	struct lorawan_join_config join_cfg;
57 	uint8_t dev_eui[] = LORAWAN_DEV_EUI;
58 	uint8_t join_eui[] = LORAWAN_JOIN_EUI;
59 	uint8_t app_key[] = LORAWAN_APP_KEY;
60 	int ret;
61 
62 	struct lorawan_downlink_cb downlink_cb = {
63 		.port = LW_RECV_PORT_ANY,
64 		.cb = dl_callback
65 	};
66 
67 	lora_dev = device_get_binding(DEFAULT_RADIO);
68 	if (!lora_dev) {
69 		LOG_ERR("%s Device not found", DEFAULT_RADIO);
70 		return;
71 	}
72 
73 	ret = lorawan_start();
74 	if (ret < 0) {
75 		LOG_ERR("lorawan_start failed: %d", ret);
76 		return;
77 	}
78 
79 	lorawan_register_downlink_callback(&downlink_cb);
80 	lorawan_register_dr_changed_callback(lorwan_datarate_changed);
81 
82 	join_cfg.mode = LORAWAN_ACT_OTAA;
83 	join_cfg.dev_eui = dev_eui;
84 	join_cfg.otaa.join_eui = join_eui;
85 	join_cfg.otaa.app_key = app_key;
86 	join_cfg.otaa.nwk_key = app_key;
87 
88 	LOG_INF("Joining network over OTAA");
89 	ret = lorawan_join(&join_cfg);
90 	if (ret < 0) {
91 		LOG_ERR("lorawan_join_network failed: %d", ret);
92 		return;
93 	}
94 
95 	LOG_INF("Sending data...");
96 	while (1) {
97 		ret = lorawan_send(2, data, sizeof(data),
98 				   LORAWAN_MSG_CONFIRMED);
99 
100 		/*
101 		 * Note: The stack may return -EAGAIN if the provided data
102 		 * length exceeds the maximum possible one for the region and
103 		 * datarate. But since we are just sending the same data here,
104 		 * we'll just continue.
105 		 */
106 		if (ret == -EAGAIN) {
107 			LOG_ERR("lorawan_send failed: %d. Continuing...", ret);
108 			k_sleep(DELAY);
109 			continue;
110 		}
111 
112 		if (ret < 0) {
113 			LOG_ERR("lorawan_send failed: %d", ret);
114 			return;
115 		}
116 
117 		LOG_INF("Data sent!");
118 		k_sleep(DELAY);
119 	}
120 }
121