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