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)79static 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