/* * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief Helper module for receiving using UART Asynchronous API. */ #ifndef ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_RX_H_ #define ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_RX_H_ #ifdef __cplusplus extern "C" { #endif #include /* @brief RX buffer structure which holds the buffer and its state. */ struct uart_async_rx_buf { /* Write index which is incremented whenever new data is reported to be * received to that buffer. */ uint8_t wr_idx:7; /* Set to one if buffer is released by the driver. */ uint8_t completed:1; /* Location which is passed to the UART driver. */ uint8_t buffer[]; }; /** @brief UART asynchronous RX helper structure. */ struct uart_async_rx { /* Pointer to the configuration structure. Structure must be persistent. */ const struct uart_async_rx_config *config; /* Total amount of pending bytes. Bytes may be spread across multiple RX buffers. */ atomic_t pending_bytes; /* Number of buffers which are free. */ atomic_t free_buf_cnt; /* Single buffer size. */ uint8_t buf_len; /* Index of the next buffer to be provided to the driver. */ uint8_t drv_buf_idx; /* Current buffer from which data is being consumed. */ uint8_t rd_buf_idx; /* Current read index in the buffer from which data is being consumed. * Read index which is incremented whenever data is consumed from the buffer. */ uint8_t rd_idx; }; /** @brief UART asynchronous RX helper configuration structure. */ struct uart_async_rx_config { /* Pointer to the buffer. */ uint8_t *buffer; /* Buffer length. */ size_t length; /* Number of buffers into provided space shall be split. */ uint8_t buf_cnt; }; /** @brief Get RX buffer length. * * @param async_rx Pointer to the helper instance. * * @return Buffer length. */ static inline uint8_t uart_async_rx_get_buf_len(struct uart_async_rx *async_rx) { return async_rx->buf_len; } /** @brief Get amount of space dedicated for managing each buffer state. * * User buffer provided during the initialization is split into chunks and each * chunk has overhead. This overhead can be used to calculate actual space used * for UART data. * * @return Overhead space in bytes. */ #define UART_ASYNC_RX_BUF_OVERHEAD offsetof(struct uart_async_rx_buf, buffer) /** @brief Initialize the helper instance. * * @param async_rx Pointer to the helper instance. * @param config Configuration. Must be persistent. * * @retval 0 on successful initialization. */ int uart_async_rx_init(struct uart_async_rx *async_rx, const struct uart_async_rx_config *config); /** @brief Reset state of the helper instance. * * Helper can be reset after RX abort to discard all received data and bring * the helper to its initial state. * * @param async_rx Pointer to the helper instance. */ void uart_async_rx_reset(struct uart_async_rx *async_rx); /** @brief Indicate received data. * * Function shall be called from @ref UART_RX_RDY context. * * @param async_rx Pointer to the helper instance. * @param buffer Buffer received in the UART driver event. * @param length Length received in the UART driver event. */ void uart_async_rx_on_rdy(struct uart_async_rx *async_rx, uint8_t *buffer, size_t length); /** @brief Get next RX buffer. * * Returned pointer shall be provided to @ref uart_rx_buf_rsp or @ref uart_rx_enable. * If null is returned that indicates that there are no available buffers since all * buffers are used by the driver or contain not consumed data. * * @param async_rx Pointer to the helper instance. * * @return Pointer to the next RX buffer or null if no buffer available. */ uint8_t *uart_async_rx_buf_req(struct uart_async_rx *async_rx); /** @brief Indicate that buffer is no longer used by the UART driver. * * Function shall be called on @ref UART_RX_BUF_RELEASED event. * * @param async_rx Pointer to the helper instance. * @param buf Buffer pointer received in the UART driver event. */ void uart_async_rx_on_buf_rel(struct uart_async_rx *async_rx, uint8_t *buf); /** @brief Claim received data for processing. * * Helper module works in the zero copy mode. It provides a pointer to the buffer * that was directly used by the UART driver. Since received data is spread across * multiple buffers there is no possibility to read all data at once. It can only be * consumed in chunks. After data is processed, @ref uart_async_rx_data_consume is * used to indicate that data is consumed. * * @param async_rx Pointer to the helper instance. * @param data Location where address to the buffer is written. Untouched if no data to claim. * @param length Amount of requested data. * * @return Amount valid of data in the @p data buffer. 0 is returned when there is no data. */ size_t uart_async_rx_data_claim(struct uart_async_rx *async_rx, uint8_t **data, size_t length); /** @brief Consume claimed data. * * It pairs with @ref uart_async_rx_data_claim. * * @param async_rx Pointer to the helper instance. * @param length Amount of data to consume. It must be less or equal than amount of claimed data. * * @retval true If there are free buffers in the pool after data got consumed. * @retval false If there are no free buffers. */ bool uart_async_rx_data_consume(struct uart_async_rx *async_rx, size_t length); #ifdef __cplusplus } #endif #endif /* ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_RX_H_ */