1 /*
2 * Copyright Runtime.io 2018. All rights reserved.
3 * Copyright Laird Connectivity 2021-2022.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 /** @file
9 * @brief Dummy transport for the mcumgr SMP protocol for unit testing.
10 */
11
12 /* Define required for uart_mcumgr.h functionality reuse */
13 #define CONFIG_UART_MCUMGR_RX_BUF_SIZE CONFIG_MCUMGR_TRANSPORT_DUMMY_RX_BUF_SIZE
14 #define MCUMGR_DUMMY_MAX_FRAME CONFIG_MCUMGR_TRANSPORT_DUMMY_RX_BUF_SIZE
15
16 #include <zephyr/kernel.h>
17 #include <zephyr/init.h>
18 #include <zephyr/sys/crc.h>
19 #include <zephyr/sys/byteorder.h>
20 #include <zephyr/net/buf.h>
21 #include <zephyr/sys/base64.h>
22 #include <zephyr/drivers/console/uart_mcumgr.h>
23 #include <zephyr/mgmt/mcumgr/mgmt/mgmt.h>
24 #include <zephyr/mgmt/mcumgr/smp/smp.h>
25 #include <zephyr/mgmt/mcumgr/transport/smp.h>
26 #include <zephyr/mgmt/mcumgr/transport/smp_dummy.h>
27 #include <zephyr/mgmt/mcumgr/transport/serial.h>
28 #include <string.h>
29
30 #include <mgmt/mcumgr/transport/smp_internal.h>
31
32 BUILD_ASSERT(CONFIG_MCUMGR_TRANSPORT_DUMMY_RX_BUF_SIZE != 0,
33 "CONFIG_MCUMGR_TRANSPORT_DUMMY_RX_BUF_SIZE must be > 0");
34
35 struct device;
36 static struct mcumgr_serial_rx_ctxt smp_dummy_rx_ctxt;
37 static struct mcumgr_serial_rx_ctxt smp_dummy_tx_ctxt;
38 static struct smp_transport smp_dummy_transport;
39 static bool enable_dummy_smp;
40 static struct k_sem smp_data_ready_sem;
41 static uint8_t smp_send_buffer[CONFIG_MCUMGR_TRANSPORT_DUMMY_RX_BUF_SIZE];
42 static uint16_t smp_send_pos;
43 static uint8_t smp_receive_buffer[CONFIG_MCUMGR_TRANSPORT_DUMMY_RX_BUF_SIZE];
44 static uint16_t smp_receive_pos;
45
46 /** Callback to execute when a valid fragment has been received. */
47 static uart_mcumgr_recv_fn *dummy_mgumgr_recv_cb;
48
49 /** Contains the fragment currently being received. */
50 static struct uart_mcumgr_rx_buf *dummy_mcumgr_cur_buf;
51
52 /**
53 * Whether the line currently being read should be ignored. This is true if
54 * the line is too long or if there is no buffer available to hold it.
55 */
56 static bool dummy_mcumgr_ignoring;
57
58 static void smp_dummy_process_rx_queue(struct k_work *work);
59 static void dummy_mcumgr_free_rx_buf(struct uart_mcumgr_rx_buf *rx_buf);
60
61
62 static struct net_buf *mcumgr_dummy_process_frag(
63 struct mcumgr_serial_rx_ctxt *rx_ctxt,
64 const uint8_t *frag, int frag_len);
65
66 static struct net_buf *mcumgr_dummy_process_frag_outgoing(
67 struct mcumgr_serial_rx_ctxt *tx_ctxt,
68 const uint8_t *frag, uint16_t frag_len);
69
70 static int mcumgr_dummy_tx_pkt(const uint8_t *data, int len,
71 mcumgr_serial_tx_cb cb);
72
73 K_FIFO_DEFINE(smp_dummy_rx_fifo);
74 K_WORK_DEFINE(smp_dummy_work, smp_dummy_process_rx_queue);
75 K_MEM_SLAB_DEFINE(dummy_mcumgr_slab, sizeof(struct uart_mcumgr_rx_buf), 1, 1);
76
smp_dummy_clear_state(void)77 void smp_dummy_clear_state(void)
78 {
79 k_sem_reset(&smp_data_ready_sem);
80
81 memset(smp_receive_buffer, 0, sizeof(smp_receive_buffer));
82 smp_receive_pos = 0;
83 memset(smp_send_buffer, 0, sizeof(smp_send_buffer));
84 smp_send_pos = 0;
85 }
86
87 /**
88 * Processes a single line (fragment) coming from the mcumgr UART driver.
89 */
smp_dummy_process_frag(struct uart_mcumgr_rx_buf * rx_buf)90 static void smp_dummy_process_frag(struct uart_mcumgr_rx_buf *rx_buf)
91 {
92 struct net_buf *nb;
93
94 /* Decode the fragment and write the result to the global receive
95 * context.
96 */
97 nb = mcumgr_dummy_process_frag(&smp_dummy_rx_ctxt,
98 rx_buf->data, rx_buf->length);
99
100 /* Release the encoded fragment. */
101 dummy_mcumgr_free_rx_buf(rx_buf);
102
103 /* If a complete packet has been received, pass it to SMP for
104 * processing.
105 */
106 if (nb != NULL) {
107 smp_rx_req(&smp_dummy_transport, nb);
108 }
109 }
110
111 /**
112 * Processes a single line (fragment) coming from the mcumgr response to be
113 * used in tests
114 */
smp_dummy_process_frag_outgoing(uint8_t * buffer,uint16_t buffer_size)115 static struct net_buf *smp_dummy_process_frag_outgoing(uint8_t *buffer,
116 uint16_t buffer_size)
117 {
118 struct net_buf *nb;
119
120 /* Decode the fragment and write the result to the global receive
121 * context.
122 */
123 nb = mcumgr_dummy_process_frag_outgoing(&smp_dummy_tx_ctxt,
124 buffer, buffer_size);
125
126 return nb;
127 }
128
smp_dummy_process_rx_queue(struct k_work * work)129 static void smp_dummy_process_rx_queue(struct k_work *work)
130 {
131 struct uart_mcumgr_rx_buf *rx_buf;
132
133 while ((rx_buf = k_fifo_get(&smp_dummy_rx_fifo, K_NO_WAIT)) != NULL) {
134 smp_dummy_process_frag(rx_buf);
135 }
136 }
137
smp_dummy_get_outgoing(void)138 struct net_buf *smp_dummy_get_outgoing(void)
139 {
140 return smp_dummy_process_frag_outgoing(smp_send_buffer, smp_send_pos);
141 }
142
143 /**
144 * Enqueues a received SMP fragment for later processing. This function
145 * executes in the interrupt context.
146 */
smp_dummy_rx_frag(struct uart_mcumgr_rx_buf * rx_buf)147 static void smp_dummy_rx_frag(struct uart_mcumgr_rx_buf *rx_buf)
148 {
149 k_fifo_put(&smp_dummy_rx_fifo, rx_buf);
150 k_work_submit(&smp_dummy_work);
151 }
152
smp_dummy_get_mtu(const struct net_buf * nb)153 static uint16_t smp_dummy_get_mtu(const struct net_buf *nb)
154 {
155 return CONFIG_MCUMGR_TRANSPORT_DUMMY_RX_BUF_SIZE;
156 }
157
dummy_mcumgr_send_raw(const void * data,int len)158 int dummy_mcumgr_send_raw(const void *data, int len)
159 {
160 uint16_t data_size =
161 MIN(len, (sizeof(smp_send_buffer) - smp_send_pos - 1));
162
163 if (enable_dummy_smp == true) {
164 memcpy(&smp_send_buffer[smp_send_pos], data, data_size);
165 smp_send_pos += data_size;
166
167 if (smp_send_buffer[(smp_send_pos - 1)] == 0x0a) {
168 /* End character of SMP over console message has been
169 * received
170 */
171 k_sem_give(&smp_data_ready_sem);
172 }
173 }
174
175 return 0;
176 }
177
smp_dummy_tx_pkt_int(struct net_buf * nb)178 static int smp_dummy_tx_pkt_int(struct net_buf *nb)
179 {
180 int rc;
181
182 rc = mcumgr_dummy_tx_pkt(nb->data, nb->len, dummy_mcumgr_send_raw);
183 smp_packet_free(nb);
184
185 return rc;
186 }
187
smp_dummy_init(void)188 static int smp_dummy_init(void)
189 {
190 int rc;
191
192 k_sem_init(&smp_data_ready_sem, 0, 1);
193
194 smp_dummy_transport.functions.output = smp_dummy_tx_pkt_int;
195 smp_dummy_transport.functions.get_mtu = smp_dummy_get_mtu;
196
197 rc = smp_transport_init(&smp_dummy_transport);
198
199 if (rc != 0) {
200 return rc;
201 }
202
203 dummy_mgumgr_recv_cb = smp_dummy_rx_frag;
204
205 return 0;
206 }
207
dummy_mcumgr_alloc_rx_buf(void)208 static struct uart_mcumgr_rx_buf *dummy_mcumgr_alloc_rx_buf(void)
209 {
210 struct uart_mcumgr_rx_buf *rx_buf;
211 void *block;
212 int rc;
213
214 rc = k_mem_slab_alloc(&dummy_mcumgr_slab, &block, K_NO_WAIT);
215 if (rc != 0) {
216 return NULL;
217 }
218
219 rx_buf = block;
220 rx_buf->length = 0;
221 return rx_buf;
222 }
223
dummy_mcumgr_free_rx_buf(struct uart_mcumgr_rx_buf * rx_buf)224 static void dummy_mcumgr_free_rx_buf(struct uart_mcumgr_rx_buf *rx_buf)
225 {
226 void *block;
227
228 block = rx_buf;
229 k_mem_slab_free(&dummy_mcumgr_slab, block);
230 }
231
232 /**
233 * Processes a single incoming byte.
234 */
dummy_mcumgr_rx_byte(uint8_t byte)235 static struct uart_mcumgr_rx_buf *dummy_mcumgr_rx_byte(uint8_t byte)
236 {
237 struct uart_mcumgr_rx_buf *rx_buf;
238
239 if (!dummy_mcumgr_ignoring) {
240 if (dummy_mcumgr_cur_buf == NULL) {
241 dummy_mcumgr_cur_buf = dummy_mcumgr_alloc_rx_buf();
242 if (dummy_mcumgr_cur_buf == NULL) {
243 /* Insufficient buffers; drop this fragment. */
244 dummy_mcumgr_ignoring = true;
245 }
246 }
247 }
248
249 rx_buf = dummy_mcumgr_cur_buf;
250 if (!dummy_mcumgr_ignoring) {
251 if (rx_buf->length >= sizeof(rx_buf->data)) {
252 /* Line too long; drop this fragment. */
253 dummy_mcumgr_free_rx_buf(dummy_mcumgr_cur_buf);
254 dummy_mcumgr_cur_buf = NULL;
255 dummy_mcumgr_ignoring = true;
256 } else {
257 rx_buf->data[rx_buf->length++] = byte;
258 }
259 }
260
261 if (byte == '\n') {
262 /* Fragment complete. */
263 if (dummy_mcumgr_ignoring) {
264 dummy_mcumgr_ignoring = false;
265 } else {
266 dummy_mcumgr_cur_buf = NULL;
267 return rx_buf;
268 }
269 }
270
271 return NULL;
272 }
273
dummy_mcumgr_add_data(uint8_t * data,uint16_t data_size)274 void dummy_mcumgr_add_data(uint8_t *data, uint16_t data_size)
275 {
276 struct uart_mcumgr_rx_buf *rx_buf;
277 int i;
278
279 for (i = 0; i < data_size; i++) {
280 rx_buf = dummy_mcumgr_rx_byte(data[i]);
281 if (rx_buf != NULL) {
282 dummy_mgumgr_recv_cb(rx_buf);
283 }
284 }
285 }
286
mcumgr_dummy_free_rx_ctxt(struct mcumgr_serial_rx_ctxt * rx_ctxt)287 static void mcumgr_dummy_free_rx_ctxt(struct mcumgr_serial_rx_ctxt *rx_ctxt)
288 {
289 if (rx_ctxt->nb != NULL) {
290 smp_packet_free(rx_ctxt->nb);
291 rx_ctxt->nb = NULL;
292 }
293 }
294
mcumgr_dummy_calc_crc(const uint8_t * data,int len)295 static uint16_t mcumgr_dummy_calc_crc(const uint8_t *data, int len)
296 {
297 return crc16_itu_t(0x0000, data, len);
298 }
299
mcumgr_dummy_parse_op(const uint8_t * buf,int len)300 static int mcumgr_dummy_parse_op(const uint8_t *buf, int len)
301 {
302 uint16_t op;
303
304 if (len < sizeof(op)) {
305 return -EINVAL;
306 }
307
308 memcpy(&op, buf, sizeof(op));
309 op = sys_be16_to_cpu(op);
310
311 if (op != MCUMGR_SERIAL_HDR_PKT && op != MCUMGR_SERIAL_HDR_FRAG) {
312 return -EINVAL;
313 }
314
315 return op;
316 }
317
mcumgr_dummy_extract_len(struct mcumgr_serial_rx_ctxt * rx_ctxt)318 static int mcumgr_dummy_extract_len(struct mcumgr_serial_rx_ctxt *rx_ctxt)
319 {
320 if (rx_ctxt->nb->len < 2) {
321 return -EINVAL;
322 }
323
324 rx_ctxt->pkt_len = net_buf_pull_be16(rx_ctxt->nb);
325 return 0;
326 }
327
mcumgr_dummy_decode_frag(struct mcumgr_serial_rx_ctxt * rx_ctxt,const uint8_t * frag,int frag_len)328 static int mcumgr_dummy_decode_frag(struct mcumgr_serial_rx_ctxt *rx_ctxt,
329 const uint8_t *frag, int frag_len)
330 {
331 size_t dec_len;
332 int rc;
333
334 rc = base64_decode(rx_ctxt->nb->data + rx_ctxt->nb->len,
335 net_buf_tailroom(rx_ctxt->nb), &dec_len,
336 frag, frag_len);
337 if (rc != 0) {
338 return -EINVAL;
339 }
340
341 rx_ctxt->nb->len += dec_len;
342
343 return 0;
344 }
345
346 /**
347 * Processes a received mcumgr fragment
348 *
349 * @param rx_ctxt The receive context
350 * @param frag The fragment buffer
351 * @param frag_len The size of the fragment
352 *
353 * @return The net buffer if a complete packet was received, NULL if
354 * the frame is invalid or if additional fragments are
355 * expected
356 */
mcumgr_dummy_process_frag(struct mcumgr_serial_rx_ctxt * rx_ctxt,const uint8_t * frag,int frag_len)357 static struct net_buf *mcumgr_dummy_process_frag(
358 struct mcumgr_serial_rx_ctxt *rx_ctxt,
359 const uint8_t *frag, int frag_len)
360 {
361 struct net_buf *nb;
362 uint16_t crc;
363 uint16_t op;
364 int rc;
365
366 if (rx_ctxt->nb == NULL) {
367 rx_ctxt->nb = smp_packet_alloc();
368 if (rx_ctxt->nb == NULL) {
369 return NULL;
370 }
371 }
372
373 op = mcumgr_dummy_parse_op(frag, frag_len);
374 switch (op) {
375 case MCUMGR_SERIAL_HDR_PKT:
376 net_buf_reset(rx_ctxt->nb);
377 break;
378
379 case MCUMGR_SERIAL_HDR_FRAG:
380 if (rx_ctxt->nb->len == 0U) {
381 mcumgr_dummy_free_rx_ctxt(rx_ctxt);
382 return NULL;
383 }
384 break;
385
386 default:
387 return NULL;
388 }
389
390 rc = mcumgr_dummy_decode_frag(rx_ctxt,
391 frag + sizeof(op),
392 frag_len - sizeof(op));
393 if (rc != 0) {
394 mcumgr_dummy_free_rx_ctxt(rx_ctxt);
395 return NULL;
396 }
397
398 if (op == MCUMGR_SERIAL_HDR_PKT) {
399 rc = mcumgr_dummy_extract_len(rx_ctxt);
400 if (rc < 0) {
401 mcumgr_dummy_free_rx_ctxt(rx_ctxt);
402 return NULL;
403 }
404 }
405
406 if (rx_ctxt->nb->len < rx_ctxt->pkt_len) {
407 /* More fragments expected. */
408 return NULL;
409 }
410
411 if (rx_ctxt->nb->len > rx_ctxt->pkt_len) {
412 /* Payload longer than indicated in header. */
413 mcumgr_dummy_free_rx_ctxt(rx_ctxt);
414 return NULL;
415 }
416
417 crc = mcumgr_dummy_calc_crc(rx_ctxt->nb->data, rx_ctxt->nb->len);
418 if (crc != 0U) {
419 mcumgr_dummy_free_rx_ctxt(rx_ctxt);
420 return NULL;
421 }
422
423 /* Packet is complete; strip the CRC. */
424 rx_ctxt->nb->len -= 2U;
425
426 nb = rx_ctxt->nb;
427 rx_ctxt->nb = NULL;
428 return nb;
429 }
430
431 /**
432 * Processes a mcumgr response fragment
433 *
434 * @param tx_ctxt The transmission context
435 * @param frag The fragment buffer
436 * @param frag_len The size of the fragment
437 *
438 * @return The net buffer if a complete packet was received, NULL if
439 * the frame is invalid or if additional fragments are
440 * expected
441 */
mcumgr_dummy_process_frag_outgoing(struct mcumgr_serial_rx_ctxt * tx_ctxt,const uint8_t * frag,uint16_t frag_len)442 static struct net_buf *mcumgr_dummy_process_frag_outgoing(
443 struct mcumgr_serial_rx_ctxt *tx_ctxt,
444 const uint8_t *frag, uint16_t frag_len)
445 {
446 struct net_buf *nb;
447 uint16_t crc;
448 uint16_t op;
449 int rc;
450
451 if (tx_ctxt->nb == NULL) {
452 tx_ctxt->nb = smp_packet_alloc();
453 if (tx_ctxt->nb == NULL) {
454 return NULL;
455 }
456 }
457
458 op = mcumgr_dummy_parse_op(frag, frag_len);
459 switch (op) {
460 case MCUMGR_SERIAL_HDR_PKT:
461 net_buf_reset(tx_ctxt->nb);
462 break;
463
464 case MCUMGR_SERIAL_HDR_FRAG:
465 if (tx_ctxt->nb->len == 0U) {
466 mcumgr_dummy_free_rx_ctxt(tx_ctxt);
467 return NULL;
468 }
469 break;
470
471 default:
472 return NULL;
473 }
474
475 rc = mcumgr_dummy_decode_frag(tx_ctxt,
476 frag + sizeof(op),
477 frag_len - sizeof(op));
478 if (rc != 0) {
479 mcumgr_dummy_free_rx_ctxt(tx_ctxt);
480 return NULL;
481 }
482
483 if (op == MCUMGR_SERIAL_HDR_PKT) {
484 rc = mcumgr_dummy_extract_len(tx_ctxt);
485 if (rc < 0) {
486 mcumgr_dummy_free_rx_ctxt(tx_ctxt);
487 return NULL;
488 }
489 }
490
491 if (tx_ctxt->nb->len < tx_ctxt->pkt_len) {
492 /* More fragments expected. */
493 return NULL;
494 }
495
496 if (tx_ctxt->nb->len > tx_ctxt->pkt_len) {
497 /* Payload longer than indicated in header. */
498 mcumgr_dummy_free_rx_ctxt(tx_ctxt);
499 return NULL;
500 }
501
502 crc = mcumgr_dummy_calc_crc(tx_ctxt->nb->data, tx_ctxt->nb->len);
503 if (crc != 0U) {
504 mcumgr_dummy_free_rx_ctxt(tx_ctxt);
505 return NULL;
506 }
507
508 /* Packet is complete; strip the CRC. */
509 tx_ctxt->nb->len -= 2U;
510
511 nb = tx_ctxt->nb;
512 tx_ctxt->nb = NULL;
513 return nb;
514 }
515
516 /**
517 * Base64-encodes a small chunk of data and transmits it. The data must be no
518 * larger than three bytes.
519 */
mcumgr_dummy_tx_small(const void * data,int len,mcumgr_serial_tx_cb cb)520 static int mcumgr_dummy_tx_small(const void *data, int len,
521 mcumgr_serial_tx_cb cb)
522 {
523 uint8_t b64[4 + 1]; /* +1 required for null terminator. */
524 size_t dst_len;
525 int rc;
526
527 rc = base64_encode(b64, sizeof(b64), &dst_len, data, len);
528 __ASSERT_NO_MSG(rc == 0);
529 __ASSERT_NO_MSG(dst_len == 4);
530
531 return cb(b64, 4);
532 }
533
534 /**
535 * @brief Transmits a single mcumgr frame over serial.
536 *
537 * @param data The frame payload to transmit. This does not
538 * include a header or CRC.
539 * @param first Whether this is the first frame in the packet.
540 * @param len The number of untransmitted data bytes in the
541 * packet.
542 * @param crc The 16-bit CRC of the entire packet.
543 * @param cb A callback used for transmitting raw data.
544 * @param out_data_bytes_txed On success, the number of data bytes
545 * transmitted gets written here.
546 *
547 * @return 0 on success; negative error code on failure.
548 */
mcumgr_dummy_tx_frame(const uint8_t * data,bool first,int len,uint16_t crc,mcumgr_serial_tx_cb cb,int * out_data_bytes_txed)549 int mcumgr_dummy_tx_frame(const uint8_t *data, bool first, int len,
550 uint16_t crc, mcumgr_serial_tx_cb cb,
551 int *out_data_bytes_txed)
552 {
553 uint8_t raw[3];
554 uint16_t u16;
555 int dst_off;
556 int src_off;
557 int rem;
558 int rc;
559
560 src_off = 0;
561 dst_off = 0;
562
563 if (first) {
564 u16 = sys_cpu_to_be16(MCUMGR_SERIAL_HDR_PKT);
565 } else {
566 u16 = sys_cpu_to_be16(MCUMGR_SERIAL_HDR_FRAG);
567 }
568
569 rc = cb(&u16, sizeof(u16));
570 if (rc != 0) {
571 return rc;
572 }
573 dst_off += 2;
574
575 /* Only the first fragment contains the packet length. */
576 if (first) {
577 u16 = sys_cpu_to_be16(len + 2); /* Bug fix to account for CRC */
578 memcpy(raw, &u16, sizeof(u16));
579 raw[2] = data[0];
580
581 rc = mcumgr_dummy_tx_small(raw, 3, cb);
582 if (rc != 0) {
583 return rc;
584 }
585
586 src_off++;
587 dst_off += 4;
588 }
589
590 while (1) {
591 if (dst_off >= MCUMGR_DUMMY_MAX_FRAME - 4) {
592 /* Can't fit any more data in this frame. */
593 break;
594 }
595
596 /* If we have reached the end of the packet, we need to encode
597 * and send the CRC.
598 */
599 rem = len - src_off;
600 if (rem == 0) {
601 raw[0] = (crc & 0xff00) >> 8;
602 raw[1] = crc & 0x00ff;
603 rc = mcumgr_dummy_tx_small(raw, 2, cb);
604 if (rc != 0) {
605 return rc;
606 }
607 break;
608 }
609
610 if (rem == 1) {
611 raw[0] = data[src_off];
612 src_off++;
613
614 raw[1] = (crc & 0xff00) >> 8;
615 raw[2] = crc & 0x00ff;
616 rc = mcumgr_dummy_tx_small(raw, 3, cb);
617 if (rc != 0) {
618 return rc;
619 }
620 break;
621 }
622
623 if (rem == 2) {
624 raw[0] = data[src_off];
625 raw[1] = data[src_off + 1];
626 src_off += 2;
627
628 raw[2] = (crc & 0xff00) >> 8;
629 rc = mcumgr_dummy_tx_small(raw, 3, cb);
630 if (rc != 0) {
631 return rc;
632 }
633
634 raw[0] = crc & 0x00ff;
635 rc = mcumgr_dummy_tx_small(raw, 1, cb);
636 if (rc != 0) {
637 return rc;
638 }
639 break;
640 }
641
642 /* Otherwise, just encode payload data. */
643 memcpy(raw, data + src_off, 3);
644 rc = mcumgr_dummy_tx_small(raw, 3, cb);
645 if (rc != 0) {
646 return rc;
647 }
648 src_off += 3;
649 dst_off += 4;
650 }
651
652 rc = cb("\n", 1);
653 if (rc != 0) {
654 return rc;
655 }
656
657 *out_data_bytes_txed = src_off;
658 return 0;
659 }
660
mcumgr_dummy_tx_pkt(const uint8_t * data,int len,mcumgr_serial_tx_cb cb)661 static int mcumgr_dummy_tx_pkt(const uint8_t *data, int len, mcumgr_serial_tx_cb cb)
662 {
663 uint16_t crc;
664 int data_bytes_txed;
665 int src_off;
666 int rc;
667
668 /* Calculate CRC of entire packet. */
669 crc = mcumgr_dummy_calc_crc(data, len);
670
671 /* Transmit packet as a sequence of frames. */
672 src_off = 0;
673 while (src_off < len) {
674 rc = mcumgr_dummy_tx_frame(data + src_off,
675 src_off == 0,
676 len - src_off,
677 crc, cb,
678 &data_bytes_txed);
679 if (rc != 0) {
680 return rc;
681 }
682
683 src_off += data_bytes_txed;
684 }
685
686 return 0;
687 }
688
smp_receive(const void * data,int len)689 static int smp_receive(const void *data, int len)
690 {
691 uint16_t data_size =
692 MIN(len, (sizeof(smp_receive_buffer) - smp_receive_pos - 1));
693
694 if (enable_dummy_smp == true) {
695 memcpy(&smp_receive_buffer[smp_receive_pos], data, data_size);
696 smp_receive_pos += data_size;
697 }
698
699 return 0;
700 }
701
smp_dummy_wait_for_data(uint32_t wait_time_s)702 bool smp_dummy_wait_for_data(uint32_t wait_time_s)
703 {
704 return k_sem_take(&smp_data_ready_sem, K_SECONDS(wait_time_s)) == 0 ? true : false;
705 }
706
smp_dummy_add_data(void)707 void smp_dummy_add_data(void)
708 {
709 dummy_mcumgr_add_data(smp_receive_buffer, smp_receive_pos);
710 }
711
smp_dummy_get_send_pos(void)712 uint16_t smp_dummy_get_send_pos(void)
713 {
714 return smp_send_pos;
715 }
716
smp_dummy_get_receive_pos(void)717 uint16_t smp_dummy_get_receive_pos(void)
718 {
719 return smp_receive_pos;
720 }
721
smp_dummy_tx_pkt(const uint8_t * data,int len)722 int smp_dummy_tx_pkt(const uint8_t *data, int len)
723 {
724 return mcumgr_dummy_tx_pkt(data, len, smp_receive);
725 }
726
smp_dummy_enable(void)727 void smp_dummy_enable(void)
728 {
729 enable_dummy_smp = true;
730 }
731
smp_dummy_disable(void)732 void smp_dummy_disable(void)
733 {
734 enable_dummy_smp = false;
735 }
736
smp_dummy_get_status(void)737 bool smp_dummy_get_status(void)
738 {
739 return enable_dummy_smp;
740 }
741
742 SYS_INIT(smp_dummy_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
743