1 /*
2 * Copyright Runtime.io 2018. All rights reserved.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /** @file
8 * @brief UART transport for the mcumgr SMP protocol.
9 */
10
11 #include <string.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/init.h>
14 #include <zephyr/net_buf.h>
15 #include <zephyr/drivers/console/uart_mcumgr.h>
16 #include <zephyr/mgmt/mcumgr/mgmt/mgmt.h>
17 #include <zephyr/mgmt/mcumgr/smp/smp.h>
18 #include <zephyr/mgmt/mcumgr/transport/smp.h>
19 #include <zephyr/mgmt/mcumgr/transport/serial.h>
20
21 #include <mgmt/mcumgr/transport/smp_internal.h>
22
23 BUILD_ASSERT(CONFIG_MCUMGR_TRANSPORT_UART_MTU != 0, "CONFIG_MCUMGR_TRANSPORT_UART_MTU must be > 0");
24
25 struct device;
26
27 static void smp_uart_process_rx_queue(struct k_work *work);
28
29 K_FIFO_DEFINE(smp_uart_rx_fifo);
30 K_WORK_DEFINE(smp_uart_work, smp_uart_process_rx_queue);
31
32 static struct mcumgr_serial_rx_ctxt smp_uart_rx_ctxt;
33 static struct smp_transport smp_uart_transport;
34 #ifdef CONFIG_SMP_CLIENT
35 static struct smp_client_transport_entry smp_client_transport;
36 #endif
37
38 /**
39 * Processes a single line (fragment) coming from the mcumgr UART driver.
40 */
smp_uart_process_frag(struct uart_mcumgr_rx_buf * rx_buf)41 static void smp_uart_process_frag(struct uart_mcumgr_rx_buf *rx_buf)
42 {
43 struct net_buf *nb;
44
45 /* Decode the fragment and write the result to the global receive
46 * context.
47 */
48 nb = mcumgr_serial_process_frag(&smp_uart_rx_ctxt,
49 rx_buf->data, rx_buf->length);
50
51 /* Release the encoded fragment. */
52 uart_mcumgr_free_rx_buf(rx_buf);
53
54 /* If a complete packet has been received, pass it to SMP for
55 * processing.
56 */
57 if (nb != NULL) {
58 smp_rx_req(&smp_uart_transport, nb);
59 }
60 }
61
smp_uart_process_rx_queue(struct k_work * work)62 static void smp_uart_process_rx_queue(struct k_work *work)
63 {
64 struct uart_mcumgr_rx_buf *rx_buf;
65
66 while ((rx_buf = k_fifo_get(&smp_uart_rx_fifo, K_NO_WAIT)) != NULL) {
67 smp_uart_process_frag(rx_buf);
68 }
69 }
70
71 /**
72 * Enqueues a received SMP fragment for later processing. This function
73 * executes in the interrupt context.
74 */
smp_uart_rx_frag(struct uart_mcumgr_rx_buf * rx_buf)75 static void smp_uart_rx_frag(struct uart_mcumgr_rx_buf *rx_buf)
76 {
77 k_fifo_put(&smp_uart_rx_fifo, rx_buf);
78 k_work_submit(&smp_uart_work);
79 }
80
smp_uart_get_mtu(const struct net_buf * nb)81 static uint16_t smp_uart_get_mtu(const struct net_buf *nb)
82 {
83 return CONFIG_MCUMGR_TRANSPORT_UART_MTU;
84 }
85
smp_uart_tx_pkt(struct net_buf * nb)86 static int smp_uart_tx_pkt(struct net_buf *nb)
87 {
88 int rc;
89
90 rc = uart_mcumgr_send(nb->data, nb->len);
91 smp_packet_free(nb);
92
93 return rc;
94 }
95
smp_uart_init(void)96 static int smp_uart_init(void)
97 {
98 int rc;
99
100 smp_uart_transport.functions.output = smp_uart_tx_pkt;
101 smp_uart_transport.functions.get_mtu = smp_uart_get_mtu;
102
103 rc = smp_transport_init(&smp_uart_transport);
104
105 if (rc == 0) {
106 uart_mcumgr_register(smp_uart_rx_frag);
107 #ifdef CONFIG_SMP_CLIENT
108 smp_client_transport.smpt = &smp_uart_transport;
109 smp_client_transport.smpt_type = SMP_SERIAL_TRANSPORT;
110 smp_client_transport_register(&smp_client_transport);
111 #endif
112 }
113
114 return rc;
115 }
116
117 SYS_INIT(smp_uart_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
118