1 /*
2  * Copyright (c) 2023 Trackunit Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "modem_backend_uart_async.h"
8 
9 #include <zephyr/logging/log.h>
10 LOG_MODULE_REGISTER(modem_backend_uart_async, CONFIG_MODEM_MODULES_LOG_LEVEL);
11 
12 #include <zephyr/kernel.h>
13 #include <string.h>
14 
15 enum {
16 	MODEM_BACKEND_UART_ASYNC_STATE_TRANSMITTING_BIT,
17 	MODEM_BACKEND_UART_ASYNC_STATE_RECEIVING_BIT,
18 	MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT,
19 	MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF1_USED_BIT,
20 	MODEM_BACKEND_UART_ASYNC_STATE_OPEN_BIT,
21 };
22 
modem_backend_uart_async_is_uart_stopped(struct modem_backend_uart * backend)23 static bool modem_backend_uart_async_is_uart_stopped(struct modem_backend_uart *backend)
24 {
25 	if (!atomic_test_bit(&backend->async.common.state,
26 			    MODEM_BACKEND_UART_ASYNC_STATE_TRANSMITTING_BIT) &&
27 	    !atomic_test_bit(&backend->async.common.state,
28 			    MODEM_BACKEND_UART_ASYNC_STATE_RECEIVING_BIT) &&
29 	    !atomic_test_bit(&backend->async.common.state,
30 			    MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT) &&
31 	    !atomic_test_bit(&backend->async.common.state,
32 			    MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF1_USED_BIT)) {
33 		return true;
34 	}
35 
36 	return false;
37 }
38 
modem_backend_uart_async_is_open(struct modem_backend_uart * backend)39 static bool modem_backend_uart_async_is_open(struct modem_backend_uart *backend)
40 {
41 	return atomic_test_bit(&backend->async.common.state,
42 			       MODEM_BACKEND_UART_ASYNC_STATE_OPEN_BIT);
43 }
44 
get_receive_buf_length(struct modem_backend_uart * backend)45 static uint32_t get_receive_buf_length(struct modem_backend_uart *backend)
46 {
47 	return ring_buf_size_get(&backend->async.receive_rb);
48 }
49 
modem_backend_uart_async_event_handler(const struct device * dev,struct uart_event * evt,void * user_data)50 static void modem_backend_uart_async_event_handler(const struct device *dev,
51 						   struct uart_event *evt, void *user_data)
52 {
53 	struct modem_backend_uart *backend = (struct modem_backend_uart *) user_data;
54 	k_spinlock_key_t key;
55 	uint32_t received;
56 
57 	switch (evt->type) {
58 	case UART_TX_DONE:
59 		atomic_clear_bit(&backend->async.common.state,
60 				 MODEM_BACKEND_UART_ASYNC_STATE_TRANSMITTING_BIT);
61 		k_work_submit(&backend->transmit_idle_work);
62 		break;
63 
64 	case UART_TX_ABORTED:
65 		if (modem_backend_uart_async_is_open(backend)) {
66 			LOG_WRN("Transmit aborted (%zu sent)", evt->data.tx.len);
67 		}
68 		atomic_clear_bit(&backend->async.common.state,
69 				 MODEM_BACKEND_UART_ASYNC_STATE_TRANSMITTING_BIT);
70 		k_work_submit(&backend->transmit_idle_work);
71 
72 		break;
73 
74 	case UART_RX_BUF_REQUEST:
75 		if (!atomic_test_and_set_bit(&backend->async.common.state,
76 					     MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT)) {
77 			uart_rx_buf_rsp(backend->uart, backend->async.receive_bufs[0],
78 					backend->async.receive_buf_size);
79 
80 			break;
81 		}
82 
83 		if (!atomic_test_and_set_bit(&backend->async.common.state,
84 					     MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF1_USED_BIT)) {
85 			uart_rx_buf_rsp(backend->uart, backend->async.receive_bufs[1],
86 					backend->async.receive_buf_size);
87 
88 			break;
89 		}
90 
91 		LOG_WRN("No receive buffer available");
92 		break;
93 
94 	case UART_RX_BUF_RELEASED:
95 		if (evt->data.rx_buf.buf == backend->async.receive_bufs[0]) {
96 			atomic_clear_bit(&backend->async.common.state,
97 					 MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT);
98 
99 			break;
100 		}
101 
102 		if (evt->data.rx_buf.buf == backend->async.receive_bufs[1]) {
103 			atomic_clear_bit(&backend->async.common.state,
104 					 MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF1_USED_BIT);
105 
106 			break;
107 		}
108 
109 		LOG_WRN("Unknown receive buffer released");
110 		break;
111 
112 	case UART_RX_RDY:
113 		key = k_spin_lock(&backend->async.receive_rb_lock);
114 		received = ring_buf_put(&backend->async.receive_rb,
115 					&evt->data.rx.buf[evt->data.rx.offset],
116 					evt->data.rx.len);
117 
118 		if (received < evt->data.rx.len) {
119 			const unsigned int buf_size = get_receive_buf_length(backend);
120 
121 			ring_buf_reset(&backend->async.receive_rb);
122 			k_spin_unlock(&backend->async.receive_rb_lock, key);
123 
124 			LOG_WRN("Receive buffer overrun (dropped %u + %u)",
125 				buf_size - received, (unsigned int)evt->data.rx.len);
126 			break;
127 		}
128 
129 		k_spin_unlock(&backend->async.receive_rb_lock, key);
130 		k_work_schedule(&backend->receive_ready_work, K_NO_WAIT);
131 		break;
132 
133 	case UART_RX_DISABLED:
134 		atomic_clear_bit(&backend->async.common.state,
135 				 MODEM_BACKEND_UART_ASYNC_STATE_RECEIVING_BIT);
136 		break;
137 
138 	case UART_RX_STOPPED:
139 		LOG_WRN("Receive stopped for reasons: %u", (uint8_t)evt->data.rx_stop.reason);
140 		break;
141 
142 	default:
143 		break;
144 	}
145 
146 	if (modem_backend_uart_async_is_uart_stopped(backend)) {
147 		k_work_submit(&backend->async.common.rx_disabled_work);
148 	}
149 }
150 
modem_backend_uart_async_open(void * data)151 static int modem_backend_uart_async_open(void *data)
152 {
153 	struct modem_backend_uart *backend = (struct modem_backend_uart *)data;
154 	int ret;
155 
156 	atomic_clear(&backend->async.common.state);
157 	ring_buf_reset(&backend->async.receive_rb);
158 
159 	atomic_set_bit(&backend->async.common.state,
160 		       MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT);
161 	atomic_set_bit(&backend->async.common.state, MODEM_BACKEND_UART_ASYNC_STATE_RECEIVING_BIT);
162 	atomic_set_bit(&backend->async.common.state, MODEM_BACKEND_UART_ASYNC_STATE_OPEN_BIT);
163 
164 	/* Receive buffers are used internally by UART, receive ring buffer is
165 	 * used to store received data.
166 	 */
167 	ret = uart_rx_enable(backend->uart, backend->async.receive_bufs[0],
168 			     backend->async.receive_buf_size,
169 			     CONFIG_MODEM_BACKEND_UART_ASYNC_RECEIVE_IDLE_TIMEOUT_MS * 1000L);
170 	if (ret < 0) {
171 		atomic_clear(&backend->async.common.state);
172 		return ret;
173 	}
174 
175 	modem_pipe_notify_opened(&backend->pipe);
176 	return 0;
177 }
178 
179 #if CONFIG_MODEM_STATS
get_receive_buf_size(struct modem_backend_uart * backend)180 static uint32_t get_receive_buf_size(struct modem_backend_uart *backend)
181 {
182 	return ring_buf_capacity_get(&backend->async.receive_rb);
183 }
184 
advertise_transmit_buf_stats(struct modem_backend_uart * backend,uint32_t length)185 static void advertise_transmit_buf_stats(struct modem_backend_uart *backend, uint32_t length)
186 {
187 	modem_stats_buffer_advertise_length(&backend->transmit_buf_stats, length);
188 }
189 
advertise_receive_buf_stats(struct modem_backend_uart * backend)190 static void advertise_receive_buf_stats(struct modem_backend_uart *backend)
191 {
192 	uint32_t length;
193 
194 	length = get_receive_buf_length(backend);
195 	modem_stats_buffer_advertise_length(&backend->receive_buf_stats, length);
196 }
197 #endif
198 
get_transmit_buf_size(struct modem_backend_uart * backend)199 static uint32_t get_transmit_buf_size(struct modem_backend_uart *backend)
200 {
201 	return backend->async.common.transmit_buf_size;
202 }
203 
modem_backend_uart_async_transmit(void * data,const uint8_t * buf,size_t size)204 static int modem_backend_uart_async_transmit(void *data, const uint8_t *buf, size_t size)
205 {
206 	struct modem_backend_uart *backend = (struct modem_backend_uart *)data;
207 	bool transmitting;
208 	uint32_t bytes_to_transmit;
209 	int ret;
210 
211 	transmitting = atomic_test_and_set_bit(&backend->async.common.state,
212 					       MODEM_BACKEND_UART_ASYNC_STATE_TRANSMITTING_BIT);
213 	if (transmitting) {
214 		return 0;
215 	}
216 
217 	/* Determine amount of bytes to transmit */
218 	bytes_to_transmit = MIN(size, get_transmit_buf_size(backend));
219 
220 	/* Copy buf to transmit buffer which is passed to UART */
221 	memcpy(backend->async.common.transmit_buf, buf, bytes_to_transmit);
222 
223 	ret = uart_tx(backend->uart, backend->async.common.transmit_buf, bytes_to_transmit,
224 		      CONFIG_MODEM_BACKEND_UART_ASYNC_TRANSMIT_TIMEOUT_MS * 1000L);
225 
226 #if CONFIG_MODEM_STATS
227 	advertise_transmit_buf_stats(backend, bytes_to_transmit);
228 #endif
229 
230 	if (ret != 0) {
231 		LOG_ERR("Failed to %s %u bytes. (%d)",
232 			"start async transmit for", bytes_to_transmit, ret);
233 		return ret;
234 	}
235 
236 	return (int)bytes_to_transmit;
237 }
238 
modem_backend_uart_async_receive(void * data,uint8_t * buf,size_t size)239 static int modem_backend_uart_async_receive(void *data, uint8_t *buf, size_t size)
240 {
241 	struct modem_backend_uart *backend = (struct modem_backend_uart *)data;
242 	k_spinlock_key_t key;
243 	uint32_t received;
244 	bool empty;
245 
246 	key = k_spin_lock(&backend->async.receive_rb_lock);
247 
248 #if CONFIG_MODEM_STATS
249 	advertise_receive_buf_stats(backend);
250 #endif
251 
252 	received = ring_buf_get(&backend->async.receive_rb, buf, size);
253 	empty = ring_buf_is_empty(&backend->async.receive_rb);
254 	k_spin_unlock(&backend->async.receive_rb_lock, key);
255 
256 	if (!empty) {
257 		k_work_schedule(&backend->receive_ready_work, K_NO_WAIT);
258 	}
259 
260 	return (int)received;
261 }
262 
modem_backend_uart_async_close(void * data)263 static int modem_backend_uart_async_close(void *data)
264 {
265 	struct modem_backend_uart *backend = (struct modem_backend_uart *)data;
266 
267 	atomic_clear_bit(&backend->async.common.state, MODEM_BACKEND_UART_ASYNC_STATE_OPEN_BIT);
268 	uart_tx_abort(backend->uart);
269 	uart_rx_disable(backend->uart);
270 	return 0;
271 }
272 
273 static const struct modem_pipe_api modem_backend_uart_async_api = {
274 	.open = modem_backend_uart_async_open,
275 	.transmit = modem_backend_uart_async_transmit,
276 	.receive = modem_backend_uart_async_receive,
277 	.close = modem_backend_uart_async_close,
278 };
279 
modem_backend_uart_async_is_supported(struct modem_backend_uart * backend)280 bool modem_backend_uart_async_is_supported(struct modem_backend_uart *backend)
281 {
282 	return uart_callback_set(backend->uart, modem_backend_uart_async_event_handler,
283 				 backend) == 0;
284 }
285 
modem_backend_uart_async_notify_closed(struct k_work * item)286 static void modem_backend_uart_async_notify_closed(struct k_work *item)
287 {
288 	struct modem_backend_uart_async_common *common =
289 		CONTAINER_OF(item, struct modem_backend_uart_async_common, rx_disabled_work);
290 
291 	struct modem_backend_uart_async *async =
292 		CONTAINER_OF(common, struct modem_backend_uart_async, common);
293 
294 	struct modem_backend_uart *backend =
295 		CONTAINER_OF(async, struct modem_backend_uart, async);
296 
297 	modem_pipe_notify_closed(&backend->pipe);
298 }
299 
300 #if CONFIG_MODEM_STATS
init_stats(struct modem_backend_uart * backend)301 static void init_stats(struct modem_backend_uart *backend)
302 {
303 	char name[CONFIG_MODEM_STATS_BUFFER_NAME_SIZE];
304 	uint32_t receive_buf_size;
305 	uint32_t transmit_buf_size;
306 
307 	receive_buf_size = get_receive_buf_size(backend);
308 	transmit_buf_size = get_transmit_buf_size(backend);
309 
310 	snprintk(name, sizeof(name), "%s_%s", backend->uart->name, "rx");
311 	modem_stats_buffer_init(&backend->receive_buf_stats, name, receive_buf_size);
312 	snprintk(name, sizeof(name), "%s_%s", backend->uart->name, "tx");
313 	modem_stats_buffer_init(&backend->transmit_buf_stats, name, transmit_buf_size);
314 }
315 #endif
316 
modem_backend_uart_async_init(struct modem_backend_uart * backend,const struct modem_backend_uart_config * config)317 int modem_backend_uart_async_init(struct modem_backend_uart *backend,
318 				  const struct modem_backend_uart_config *config)
319 {
320 	uint32_t receive_buf_size_quarter = config->receive_buf_size / 4;
321 
322 	/* Use half the receive buffer for UART receive buffers */
323 	backend->async.receive_buf_size = receive_buf_size_quarter;
324 	backend->async.receive_bufs[0] = &config->receive_buf[0];
325 	backend->async.receive_bufs[1] = &config->receive_buf[receive_buf_size_quarter];
326 
327 	/* Use half the receive buffer for the received data ring buffer */
328 	ring_buf_init(&backend->async.receive_rb, (receive_buf_size_quarter * 2),
329 		      &config->receive_buf[receive_buf_size_quarter * 2]);
330 
331 	backend->async.common.transmit_buf = config->transmit_buf;
332 	backend->async.common.transmit_buf_size = config->transmit_buf_size;
333 	k_work_init(&backend->async.common.rx_disabled_work,
334 		    modem_backend_uart_async_notify_closed);
335 	modem_pipe_init(&backend->pipe, backend, &modem_backend_uart_async_api);
336 
337 #if CONFIG_MODEM_STATS
338 	init_stats(backend);
339 #endif
340 
341 	return 0;
342 }
343