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