1 /*
2 * Copyright (c) 2024, Jamie McCrae
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/logging/log.h>
9 #include <zephyr/lorawan/lorawan.h>
10 #include <zephyr/mgmt/mcumgr/smp/smp.h>
11 #include <zephyr/mgmt/mcumgr/transport/smp.h>
12 #include <zephyr/mgmt/mcumgr/mgmt/handlers.h>
13
14 #include <mgmt/mcumgr/transport/smp_internal.h>
15 #include <mgmt/mcumgr/transport/smp_reassembly.h>
16
17 LOG_MODULE_REGISTER(smp_lorawan, CONFIG_MCUMGR_TRANSPORT_LORAWAN_LOG_LEVEL);
18
19 static void smp_lorawan_downlink(uint8_t port, uint8_t flags, int16_t rssi, int8_t snr,
20 uint8_t len, const uint8_t *hex_data);
21
22 static int smp_lorawan_uplink(struct net_buf *nb);
23
24 static uint16_t smp_lorawan_get_mtu(const struct net_buf *nb);
25
26 static struct lorawan_downlink_cb lorawan_smp_downlink_cb = {
27 .port = CONFIG_MCUMGR_TRANSPORT_LORAWAN_FRAME_PORT,
28 .cb = smp_lorawan_downlink,
29 };
30
31 struct smp_transport smp_lorawan_transport = {
32 .functions.output = smp_lorawan_uplink,
33 .functions.get_mtu = smp_lorawan_get_mtu,
34 };
35
36 #ifdef CONFIG_SMP_CLIENT
37 struct smp_client_transport_entry smp_lorawan_client_transport = {
38 .smpt = &smp_lorawan_transport,
39 .smpt_type = SMP_LORAWAN_TRANSPORT,
40 };
41 #endif
42
43 #ifdef CONFIG_MCUMGR_TRANSPORT_LORAWAN_POLL_FOR_DATA
44 static struct k_thread smp_lorawan_thread;
45 K_KERNEL_STACK_MEMBER(smp_lorawan_stack, CONFIG_MCUMGR_TRANSPORT_LORAWAN_POLL_FOR_DATA_STACK_SIZE);
46 K_FIFO_DEFINE(smp_lorawan_fifo);
47
48 struct smp_lorawan_uplink_message_t {
49 void *fifo_reserved;
50 struct net_buf *nb;
51 struct k_sem my_sem;
52 };
53
54 static struct smp_lorawan_uplink_message_t empty_message = {
55 .nb = NULL,
56 };
57
smp_lorawan_uplink_thread(void * p1,void * p2,void * p3)58 static void smp_lorawan_uplink_thread(void *p1, void *p2, void *p3)
59 {
60 struct smp_lorawan_uplink_message_t *msg;
61
62 while (1) {
63 msg = k_fifo_get(&smp_lorawan_fifo, K_FOREVER);
64 uint16_t size = 0;
65 uint16_t pos = 0;
66
67 if (msg->nb != NULL) {
68 size = msg->nb->len;
69 }
70
71 while (pos < size || size == 0) {
72 uint8_t *data = NULL;
73 uint8_t data_size;
74 uint8_t temp;
75 uint8_t tries = CONFIG_MCUMGR_TRANSPORT_LORAWAN_POLL_FOR_DATA_RETRIES;
76
77 lorawan_get_payload_sizes(&data_size, &temp);
78
79 if (data_size > size) {
80 data_size = size;
81 }
82
83 if (size > 0) {
84 if ((data_size + pos) > size) {
85 data_size = size - pos;
86 }
87
88 data = net_buf_pull_mem(msg->nb, data_size);
89 }
90
91 while (tries > 0) {
92 int rc;
93
94 rc = lorawan_send(CONFIG_MCUMGR_TRANSPORT_LORAWAN_FRAME_PORT,
95 data, data_size,
96 #if defined(CONFIG_MCUMGR_TRANSPORT_LORAWAN_CONFIRMED_UPLINKS)
97 LORAWAN_MSG_CONFIRMED
98 #else
99 LORAWAN_MSG_UNCONFIRMED
100 #endif
101 );
102
103 if (rc != 0) {
104 --tries;
105 } else {
106 break;
107 }
108 }
109
110 if (size == 0) {
111 break;
112 }
113
114 pos += data_size;
115 }
116
117 /* For empty packets, do not trigger semaphore */
118 if (size != 0) {
119 k_sem_give(&msg->my_sem);
120 }
121 }
122 }
123 #endif
124
smp_lorawan_downlink(uint8_t port,uint8_t flags,int16_t rssi,int8_t snr,uint8_t len,const uint8_t * hex_data)125 static void smp_lorawan_downlink(uint8_t port, uint8_t flags, int16_t rssi, int8_t snr,
126 uint8_t len, const uint8_t *hex_data)
127 {
128 ARG_UNUSED(flags);
129 ARG_UNUSED(rssi);
130 ARG_UNUSED(snr);
131
132 if (port == CONFIG_MCUMGR_TRANSPORT_LORAWAN_FRAME_PORT) {
133 #ifdef CONFIG_MCUMGR_TRANSPORT_LORAWAN_REASSEMBLY
134 int rc;
135
136 if (len == 0) {
137 /* Empty packet is used to clear partially queued data */
138 (void)smp_reassembly_drop(&smp_lorawan_transport);
139 } else {
140 rc = smp_reassembly_collect(&smp_lorawan_transport, hex_data, len);
141
142 if (rc == 0) {
143 rc = smp_reassembly_complete(&smp_lorawan_transport, false);
144
145 if (rc) {
146 LOG_ERR("LoRaWAN SMP reassembly complete failed: %d", rc);
147 }
148 } else if (rc < 0) {
149 LOG_ERR("LoRaWAN SMP reassembly collect failed: %d", rc);
150 } else {
151 LOG_ERR("LoRaWAN SMP expected data left: %d", rc);
152
153 #ifdef CONFIG_MCUMGR_TRANSPORT_LORAWAN_POLL_FOR_DATA
154 /* Send empty LoRaWAN packet to receive next packet from server */
155 k_fifo_put(&smp_lorawan_fifo, &empty_message);
156 #endif
157 }
158 }
159 #else
160 if (len > sizeof(struct smp_hdr)) {
161 struct net_buf *nb;
162
163 nb = smp_packet_alloc();
164
165 if (!nb) {
166 LOG_ERR("LoRaWAN SMP packet allocation failure");
167 return;
168 }
169
170 net_buf_add_mem(nb, hex_data, len);
171 smp_rx_req(&smp_lorawan_transport, nb);
172 } else {
173 LOG_ERR("Invalid LoRaWAN SMP downlink");
174 }
175 #endif
176 } else {
177 LOG_ERR("Invalid LoRaWAN SMP downlink");
178 }
179 }
180
smp_lorawan_uplink(struct net_buf * nb)181 static int smp_lorawan_uplink(struct net_buf *nb)
182 {
183 int rc = 0;
184
185 #ifdef CONFIG_MCUMGR_TRANSPORT_LORAWAN_FRAGMENTED_UPLINKS
186 struct smp_lorawan_uplink_message_t tx_data = {
187 .nb = nb,
188 };
189
190 k_sem_init(&tx_data.my_sem, 0, 1);
191 k_fifo_put(&smp_lorawan_fifo, &tx_data);
192 k_sem_take(&tx_data.my_sem, K_FOREVER);
193 #else
194 uint8_t data_size;
195 uint8_t temp;
196
197 lorawan_get_payload_sizes(&data_size, &temp);
198
199 if (nb->len > data_size) {
200 LOG_ERR("Cannot send LoRaWAN SMP message, too large. Message: %d, maximum: %d",
201 nb->len, data_size);
202 } else {
203 rc = lorawan_send(CONFIG_MCUMGR_TRANSPORT_LORAWAN_FRAME_PORT, nb->data, nb->len,
204 #if defined(CONFIG_MCUMGR_TRANSPORT_LORAWAN_CONFIRMED_UPLINKS)
205 LORAWAN_MSG_CONFIRMED
206 #else
207 LORAWAN_MSG_UNCONFIRMED
208 #endif
209 );
210
211 if (rc != 0) {
212 LOG_ERR("Failed to send LoRaWAN SMP message: %d", rc);
213 }
214 }
215 #endif
216
217 smp_packet_free(nb);
218
219 return rc;
220 }
221
smp_lorawan_get_mtu(const struct net_buf * nb)222 static uint16_t smp_lorawan_get_mtu(const struct net_buf *nb)
223 {
224 ARG_UNUSED(nb);
225
226 uint8_t max_data_size;
227 uint8_t temp;
228
229 lorawan_get_payload_sizes(&max_data_size, &temp);
230
231 return (uint16_t)max_data_size;
232 }
233
smp_lorawan_start(void)234 static void smp_lorawan_start(void)
235 {
236 int rc;
237
238 rc = smp_transport_init(&smp_lorawan_transport);
239
240 #ifdef CONFIG_SMP_CLIENT
241 if (rc == 0) {
242 smp_client_transport_register(&smp_lorawan_client_transport);
243 }
244 #endif
245
246 if (rc == 0) {
247 lorawan_register_downlink_callback(&lorawan_smp_downlink_cb);
248 } else {
249 LOG_ERR("Failed to init LoRaWAN MCUmgr SMP transport: %d", rc);
250 }
251
252 #ifdef CONFIG_MCUMGR_TRANSPORT_LORAWAN_REASSEMBLY
253 smp_reassembly_init(&smp_lorawan_transport);
254 #endif
255
256 #ifdef CONFIG_MCUMGR_TRANSPORT_LORAWAN_POLL_FOR_DATA
257 k_thread_create(&smp_lorawan_thread, smp_lorawan_stack,
258 K_KERNEL_STACK_SIZEOF(smp_lorawan_stack),
259 smp_lorawan_uplink_thread, NULL, NULL, NULL,
260 CONFIG_MCUMGR_TRANSPORT_LORAWAN_POLL_FOR_DATA_THREAD_PRIORITY, 0,
261 K_FOREVER);
262
263 k_thread_start(&smp_lorawan_thread);
264 #endif
265 }
266
267 MCUMGR_HANDLER_DEFINE(smp_lorawan, smp_lorawan_start);
268