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 <zephyr/device.h>
10 #include <zephyr/lorawan/lorawan.h>
11 #include <zephyr/kernel.h>
12 
13 /* Customize based on network configuration */
14 #define LORAWAN_DEV_EUI			{ 0xDD, 0xEE, 0xAA, 0xDD, 0xBB, 0xEE,\
15 					  0xEE, 0xFF }
16 #define LORAWAN_JOIN_EUI		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
17 					  0x00, 0x00 }
18 #define LORAWAN_APP_KEY			{ 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE,\
19 					  0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88,\
20 					  0x09, 0xCF, 0x4F, 0x3C }
21 
22 #define DELAY K_MSEC(10000)
23 
24 #define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
25 #include <zephyr/logging/log.h>
26 LOG_MODULE_REGISTER(lorawan_class_a);
27 
28 char data[] = {'h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd'};
29 
dl_callback(uint8_t port,bool data_pending,int16_t rssi,int8_t snr,uint8_t len,const uint8_t * hex_data)30 static void dl_callback(uint8_t port, bool data_pending,
31 			int16_t rssi, int8_t snr,
32 			uint8_t len, const uint8_t *hex_data)
33 {
34 	LOG_INF("Port %d, Pending %d, RSSI %ddB, SNR %ddBm", port, data_pending, rssi, snr);
35 	if (hex_data) {
36 		LOG_HEXDUMP_INF(hex_data, len, "Payload: ");
37 	}
38 }
39 
lorwan_datarate_changed(enum lorawan_datarate dr)40 static void lorwan_datarate_changed(enum lorawan_datarate dr)
41 {
42 	uint8_t unused, max_size;
43 
44 	lorawan_get_payload_sizes(&unused, &max_size);
45 	LOG_INF("New Datarate: DR_%d, Max Payload %d", dr, max_size);
46 }
47 
main(void)48 int main(void)
49 {
50 	const struct device *lora_dev;
51 	struct lorawan_join_config join_cfg;
52 	uint8_t dev_eui[] = LORAWAN_DEV_EUI;
53 	uint8_t join_eui[] = LORAWAN_JOIN_EUI;
54 	uint8_t app_key[] = LORAWAN_APP_KEY;
55 	int ret;
56 
57 	struct lorawan_downlink_cb downlink_cb = {
58 		.port = LW_RECV_PORT_ANY,
59 		.cb = dl_callback
60 	};
61 
62 	lora_dev = DEVICE_DT_GET(DT_ALIAS(lora0));
63 	if (!device_is_ready(lora_dev)) {
64 		LOG_ERR("%s: device not ready.", lora_dev->name);
65 		return 0;
66 	}
67 
68 #if defined(CONFIG_LORAMAC_REGION_EU868)
69 	/* If more than one region Kconfig is selected, app should set region
70 	 * before calling lorawan_start()
71 	 */
72 	ret = lorawan_set_region(LORAWAN_REGION_EU868);
73 	if (ret < 0) {
74 		LOG_ERR("lorawan_set_region failed: %d", ret);
75 		return 0;
76 	}
77 #endif
78 
79 	ret = lorawan_start();
80 	if (ret < 0) {
81 		LOG_ERR("lorawan_start failed: %d", ret);
82 		return 0;
83 	}
84 
85 	lorawan_register_downlink_callback(&downlink_cb);
86 	lorawan_register_dr_changed_callback(lorwan_datarate_changed);
87 
88 	join_cfg.mode = LORAWAN_ACT_OTAA;
89 	join_cfg.dev_eui = dev_eui;
90 	join_cfg.otaa.join_eui = join_eui;
91 	join_cfg.otaa.app_key = app_key;
92 	join_cfg.otaa.nwk_key = app_key;
93 	join_cfg.otaa.dev_nonce = 0u;
94 
95 	LOG_INF("Joining network over OTAA");
96 	ret = lorawan_join(&join_cfg);
97 	if (ret < 0) {
98 		LOG_ERR("lorawan_join_network failed: %d", ret);
99 		return 0;
100 	}
101 
102 #ifdef CONFIG_LORAWAN_APP_CLOCK_SYNC
103 	lorawan_clock_sync_run();
104 #endif
105 
106 	LOG_INF("Sending data...");
107 	while (1) {
108 		ret = lorawan_send(2, data, sizeof(data),
109 				   LORAWAN_MSG_CONFIRMED);
110 
111 		/*
112 		 * Note: The stack may return -EAGAIN if the provided data
113 		 * length exceeds the maximum possible one for the region and
114 		 * datarate. But since we are just sending the same data here,
115 		 * we'll just continue.
116 		 */
117 		if (ret == -EAGAIN) {
118 			LOG_ERR("lorawan_send failed: %d. Continuing...", ret);
119 			k_sleep(DELAY);
120 			continue;
121 		}
122 
123 		if (ret < 0) {
124 			LOG_ERR("lorawan_send failed: %d", ret);
125 			return 0;
126 		}
127 
128 		LOG_INF("Data sent!");
129 		k_sleep(DELAY);
130 	}
131 }
132