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