1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Helper module for receiving using UART Asynchronous API.
10  */
11 
12 #ifndef ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_RX_H_
13 #define ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_RX_H_
14 
15 #ifdef __cplusplus
16 extern "C" {
17 #endif
18 
19 #include <zephyr/kernel.h>
20 
21 /* @brief RX buffer structure which holds the buffer and its state. */
22 struct uart_async_rx_buf {
23 	/* Write index which is incremented whenever new data is reported to be
24 	 * received to that buffer.
25 	 */
26 	uint8_t wr_idx:7;
27 
28 	/* Set to one if buffer is released by the driver. */
29 	uint8_t completed:1;
30 
31 	/* Location which is passed to the UART driver. */
32 	uint8_t buffer[];
33 };
34 
35 /** @brief UART asynchronous RX helper structure. */
36 struct uart_async_rx {
37 	/* Pointer to the configuration structure. Structure must be persistent. */
38 	const struct uart_async_rx_config *config;
39 
40 	/* Total amount of pending bytes. Bytes may be spread across multiple RX buffers. */
41 	atomic_t pending_bytes;
42 
43 	/* Number of buffers which are free. */
44 	atomic_t free_buf_cnt;
45 
46 	/* Single buffer size. */
47 	uint8_t buf_len;
48 
49 	/* Index of the next buffer to be provided to the driver. */
50 	uint8_t drv_buf_idx;
51 
52 	/* Current buffer from which data is being consumed. */
53 	uint8_t rd_buf_idx;
54 
55 	/* Current read index in the buffer from which data is being consumed.
56 	 * Read index which is incremented whenever data is consumed from the buffer.
57 	 */
58 	uint8_t rd_idx;
59 };
60 
61 /** @brief UART asynchronous RX helper configuration structure. */
62 struct uart_async_rx_config {
63 	/* Pointer to the buffer. */
64 	uint8_t *buffer;
65 
66 	/* Buffer length. */
67 	size_t length;
68 
69 	/* Number of buffers into provided space shall be split. */
70 	uint8_t buf_cnt;
71 };
72 
73 /** @brief Get RX buffer length.
74  *
75  * @param async_rx Pointer to the helper instance.
76  *
77  * @return Buffer length.
78  */
uart_async_rx_get_buf_len(struct uart_async_rx * async_rx)79 static inline uint8_t uart_async_rx_get_buf_len(struct uart_async_rx *async_rx)
80 {
81 	return async_rx->buf_len;
82 }
83 
84 /** @brief Get amount of space dedicated for managing each buffer state.
85  *
86  * User buffer provided during the initialization is split into chunks and each
87  * chunk has overhead. This overhead can be used to calculate actual space used
88  * for UART data.
89  *
90  * @return Overhead space in bytes.
91  */
92 #define UART_ASYNC_RX_BUF_OVERHEAD offsetof(struct uart_async_rx_buf, buffer)
93 
94 /** @brief Initialize the helper instance.
95  *
96  * @param async_rx Pointer to the helper instance.
97  * @param config   Configuration. Must be persistent.
98  *
99  * @retval 0 on successful initialization.
100  */
101 int uart_async_rx_init(struct uart_async_rx *async_rx,
102 		       const struct uart_async_rx_config *config);
103 
104 /** @brief Reset state of the helper instance.
105  *
106  * Helper can be reset after RX abort to discard all received data and bring
107  * the helper to its initial state.
108  *
109  * @param async_rx Pointer to the helper instance.
110  */
111 void uart_async_rx_reset(struct uart_async_rx *async_rx);
112 
113 /** @brief Indicate received data.
114  *
115  * Function shall be called from @ref UART_RX_RDY context.
116  *
117  * @param async_rx Pointer to the helper instance.
118  * @param buffer Buffer received in the UART driver event.
119  * @param length Length received in the UART driver event.
120  */
121 void uart_async_rx_on_rdy(struct uart_async_rx *async_rx, uint8_t *buffer, size_t length);
122 
123 /** @brief Get next RX buffer.
124  *
125  * Returned pointer shall be provided to @ref uart_rx_buf_rsp or @ref uart_rx_enable.
126  * If null is returned that indicates that there are no available buffers since all
127  * buffers are used by the driver or contain not consumed data.
128  *
129  * @param async_rx Pointer to the helper instance.
130  *
131  * @return Pointer to the next RX buffer or null if no buffer available.
132  */
133 uint8_t *uart_async_rx_buf_req(struct uart_async_rx *async_rx);
134 
135 /** @brief Indicate that buffer is no longer used by the UART driver.
136  *
137  * Function shall be called on @ref UART_RX_BUF_RELEASED event.
138  *
139  * @param async_rx Pointer to the helper instance.
140  * @param buf Buffer pointer received in the UART driver event.
141  */
142 void uart_async_rx_on_buf_rel(struct uart_async_rx *async_rx, uint8_t *buf);
143 
144 /** @brief Claim received data for processing.
145  *
146  * Helper module works in the zero copy mode. It provides a pointer to the buffer
147  * that was directly used by the UART driver. Since received data is spread across
148  * multiple buffers there is no possibility to read all data at once. It can only be
149  * consumed in chunks. After data is processed, @ref uart_async_rx_data_consume is
150  * used to indicate that data is consumed.
151  *
152  * @param async_rx Pointer to the helper instance.
153  * @param data Location where address to the buffer is written. Untouched if no data to claim.
154  * @param length Amount of requested data.
155  *
156  * @return Amount valid of data in the @p data buffer. 0 is returned when there is no data.
157  */
158 size_t uart_async_rx_data_claim(struct uart_async_rx *async_rx, uint8_t **data, size_t length);
159 
160 /** @brief Consume claimed data.
161  *
162  * It pairs with @ref uart_async_rx_data_claim.
163  *
164  * @param async_rx Pointer to the helper instance.
165  * @param length Amount of data to consume. It must be less or equal than amount of claimed data.
166  *
167  * @retval true If there are free buffers in the pool after data got consumed.
168  * @retval false If there are no free buffers.
169  */
170 bool uart_async_rx_data_consume(struct uart_async_rx *async_rx, size_t length);
171 
172 #ifdef __cplusplus
173 }
174 #endif
175 
176 #endif /* ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_RX_H_ */
177