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