1 /*
2 * Copyright Runtime.io 2018. All rights reserved.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @brief A driver for sending and receiving mcumgr packets over UART.
10 */
11
12 #include <string.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/drivers/uart.h>
15 #include <zephyr/mgmt/mcumgr/transport/serial.h>
16 #include <zephyr/drivers/console/uart_mcumgr.h>
17
18 static const struct device *const uart_mcumgr_dev =
19 DEVICE_DT_GET(DT_CHOSEN(zephyr_uart_mcumgr));
20
21 /** Callback to execute when a valid fragment has been received. */
22 static uart_mcumgr_recv_fn *uart_mgumgr_recv_cb;
23
24 /** Contains the fragment currently being received. */
25 static struct uart_mcumgr_rx_buf *uart_mcumgr_cur_buf;
26
27 /**
28 * Whether the line currently being read should be ignored. This is true if
29 * the line is too long or if there is no buffer available to hold it.
30 */
31 static bool uart_mcumgr_ignoring;
32
33 /** Contains buffers to hold incoming request fragments. */
34 K_MEM_SLAB_DEFINE(uart_mcumgr_slab, sizeof(struct uart_mcumgr_rx_buf),
35 CONFIG_UART_MCUMGR_RX_BUF_COUNT, 1);
36
37 #if defined(CONFIG_MCUMGR_TRANSPORT_UART_ASYNC)
38 uint8_t async_buffer[CONFIG_MCUMGR_TRANSPORT_UART_ASYNC_BUFS]
39 [CONFIG_MCUMGR_TRANSPORT_UART_ASYNC_BUF_SIZE];
40 static int async_current;
41 #endif
42
uart_mcumgr_alloc_rx_buf(void)43 static struct uart_mcumgr_rx_buf *uart_mcumgr_alloc_rx_buf(void)
44 {
45 struct uart_mcumgr_rx_buf *rx_buf;
46 void *block;
47 int rc;
48
49 rc = k_mem_slab_alloc(&uart_mcumgr_slab, &block, K_NO_WAIT);
50 if (rc != 0) {
51 return NULL;
52 }
53
54 rx_buf = block;
55 rx_buf->length = 0;
56 return rx_buf;
57 }
58
uart_mcumgr_free_rx_buf(struct uart_mcumgr_rx_buf * rx_buf)59 void uart_mcumgr_free_rx_buf(struct uart_mcumgr_rx_buf *rx_buf)
60 {
61 void *block;
62
63 block = rx_buf;
64 k_mem_slab_free(&uart_mcumgr_slab, block);
65 }
66
67 #if !defined(CONFIG_MCUMGR_TRANSPORT_UART_ASYNC)
68 /**
69 * Reads a chunk of received data from the UART.
70 */
uart_mcumgr_read_chunk(void * buf,int capacity)71 static int uart_mcumgr_read_chunk(void *buf, int capacity)
72 {
73 if (!uart_irq_rx_ready(uart_mcumgr_dev)) {
74 return 0;
75 }
76
77 return uart_fifo_read(uart_mcumgr_dev, buf, capacity);
78 }
79 #endif
80
81 /**
82 * Processes a single incoming byte.
83 */
uart_mcumgr_rx_byte(uint8_t byte)84 static struct uart_mcumgr_rx_buf *uart_mcumgr_rx_byte(uint8_t byte)
85 {
86 struct uart_mcumgr_rx_buf *rx_buf;
87
88 if (!uart_mcumgr_ignoring) {
89 if (uart_mcumgr_cur_buf == NULL) {
90 uart_mcumgr_cur_buf = uart_mcumgr_alloc_rx_buf();
91 if (uart_mcumgr_cur_buf == NULL) {
92 /* Insufficient buffers; drop this fragment. */
93 uart_mcumgr_ignoring = true;
94 }
95 }
96 }
97
98 rx_buf = uart_mcumgr_cur_buf;
99 if (!uart_mcumgr_ignoring) {
100 if (rx_buf->length >= sizeof(rx_buf->data)) {
101 /* Line too long; drop this fragment. */
102 uart_mcumgr_free_rx_buf(uart_mcumgr_cur_buf);
103 uart_mcumgr_cur_buf = NULL;
104 uart_mcumgr_ignoring = true;
105 } else {
106 rx_buf->data[rx_buf->length++] = byte;
107 }
108 }
109
110 if (byte == '\n') {
111 /* Fragment complete. */
112 if (uart_mcumgr_ignoring) {
113 uart_mcumgr_ignoring = false;
114 } else {
115 uart_mcumgr_cur_buf = NULL;
116 return rx_buf;
117 }
118 }
119
120 return NULL;
121 }
122
123 #if defined(CONFIG_MCUMGR_TRANSPORT_UART_ASYNC)
uart_mcumgr_async(const struct device * dev,struct uart_event * evt,void * user_data)124 static void uart_mcumgr_async(const struct device *dev, struct uart_event *evt, void *user_data)
125 {
126 struct uart_mcumgr_rx_buf *rx_buf;
127 uint8_t *p;
128 int len;
129
130 ARG_UNUSED(dev);
131
132 switch (evt->type) {
133 case UART_TX_DONE:
134 case UART_TX_ABORTED:
135 break;
136 case UART_RX_RDY:
137 len = evt->data.rx.len;
138 p = &evt->data.rx.buf[evt->data.rx.offset];
139
140 for (int i = 0; i < len; i++) {
141 rx_buf = uart_mcumgr_rx_byte(p[i]);
142 if (rx_buf != NULL) {
143 uart_mgumgr_recv_cb(rx_buf);
144 }
145 }
146 break;
147 case UART_RX_DISABLED:
148 async_current = 0;
149 break;
150 case UART_RX_BUF_REQUEST:
151 /*
152 * Note that when buffer gets filled, the UART_RX_BUF_RELEASED will be reported,
153 * aside to UART_RX_RDY. The UART_RX_BUF_RELEASED is not processed because
154 * it has been assumed that the mcumgr will be able to consume bytes faster
155 * than UART will receive them and, since there is nothing to release, only
156 * UART_RX_BUF_REQUEST is processed.
157 */
158 ++async_current;
159 async_current %= CONFIG_MCUMGR_TRANSPORT_UART_ASYNC_BUFS;
160 uart_rx_buf_rsp(dev, async_buffer[async_current],
161 sizeof(async_buffer[async_current]));
162 break;
163 case UART_RX_BUF_RELEASED:
164 case UART_RX_STOPPED:
165 break;
166 }
167 }
168 #else
169 /**
170 * ISR that is called when UART bytes are received.
171 */
uart_mcumgr_isr(const struct device * unused,void * user_data)172 static void uart_mcumgr_isr(const struct device *unused, void *user_data)
173 {
174 struct uart_mcumgr_rx_buf *rx_buf;
175 uint8_t buf[32];
176 int chunk_len;
177 int i;
178
179 ARG_UNUSED(unused);
180 ARG_UNUSED(user_data);
181
182 while (uart_irq_update(uart_mcumgr_dev) &&
183 uart_irq_is_pending(uart_mcumgr_dev)) {
184
185 chunk_len = uart_mcumgr_read_chunk(buf, sizeof(buf));
186 if (chunk_len == 0) {
187 continue;
188 }
189
190 for (i = 0; i < chunk_len; i++) {
191 rx_buf = uart_mcumgr_rx_byte(buf[i]);
192 if (rx_buf != NULL) {
193 uart_mgumgr_recv_cb(rx_buf);
194 }
195 }
196 }
197 }
198 #endif
199
200 /**
201 * Sends raw data over the UART.
202 */
uart_mcumgr_send_raw(const void * data,int len)203 static int uart_mcumgr_send_raw(const void *data, int len)
204 {
205 const uint8_t *u8p;
206
207 u8p = data;
208 while (len--) {
209 uart_poll_out(uart_mcumgr_dev, *u8p++);
210 }
211
212 return 0;
213 }
214
uart_mcumgr_send(const uint8_t * data,int len)215 int uart_mcumgr_send(const uint8_t *data, int len)
216 {
217 return mcumgr_serial_tx_pkt(data, len, uart_mcumgr_send_raw);
218 }
219
220
221 #if defined(CONFIG_MCUMGR_TRANSPORT_UART_ASYNC)
uart_mcumgr_setup(const struct device * uart)222 static void uart_mcumgr_setup(const struct device *uart)
223 {
224 uart_callback_set(uart, uart_mcumgr_async, NULL);
225
226 uart_rx_enable(uart, async_buffer[0], sizeof(async_buffer[0]), 0);
227 }
228 #else
uart_mcumgr_setup(const struct device * uart)229 static void uart_mcumgr_setup(const struct device *uart)
230 {
231 uint8_t c;
232
233 uart_irq_rx_disable(uart);
234 uart_irq_tx_disable(uart);
235
236 /* Drain the fifo */
237 while (uart_fifo_read(uart, &c, 1)) {
238 continue;
239 }
240
241 uart_irq_callback_set(uart, uart_mcumgr_isr);
242
243 uart_irq_rx_enable(uart);
244 }
245 #endif
246
uart_mcumgr_register(uart_mcumgr_recv_fn * cb)247 void uart_mcumgr_register(uart_mcumgr_recv_fn *cb)
248 {
249 uart_mgumgr_recv_cb = cb;
250
251 if (device_is_ready(uart_mcumgr_dev)) {
252 uart_mcumgr_setup(uart_mcumgr_dev);
253 }
254 }
255