/* * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once #include "esp_err.h" #include "driver/uhci_types.h" #ifdef __cplusplus extern "C" { #endif /** * @brief UHCI controller specific configurations */ typedef struct { uart_port_t uart_port; /*!< UART port that connect to UHCI controller */ size_t tx_trans_queue_depth; /*!< Depth of internal transfer queue, increase this value can support more transfers pending in the background */ size_t max_transmit_size; /*!< Maximum transfer size in one transaction, in bytes. Note that this is the total size of all buffers combined */ size_t max_transmit_buffer_count; /*!< Maximum number of buffers that can be transmitted together in one transaction, via `uhci_multi_buffer_transmit()`. Set to 0 or 1 if only single-buffer transmit (`uhci_transmit()`) is needed. */ size_t max_receive_internal_mem; /*!< Expected maximum buffer size for uhci_receive(). This value determines the number of descriptors in the receive DMA chain. Each DMA descriptor can reference a buffer of up to X bytes (depending on the chip). For large transfers, at least two descriptors are recommended for ping-pong operation. */ size_t dma_burst_size; /*!< DMA burst size, in bytes. Set to 0 to disable data burst. Otherwise, use a power of 2. */ size_t max_packet_receive; /*!< Max receive size, auto stop receiving after reach this value, only valid when `length_eof` set true */ struct { uint16_t rx_brk_eof: 1; /*!< UHCI will end payload receive process when NULL frame is received by UART. */ uint16_t idle_eof: 1; /*!< UHCI will end payload receive process when UART has been in idle state. */ uint16_t length_eof: 1; /*!< UHCI will end payload receive process when the receiving byte count has reached the specific value. */ } rx_eof_flags; /*!< UHCI eof flags */ } uhci_controller_config_t; /** * @brief Structure for defining callback functions for UHCI events. */ typedef struct { uhci_rx_event_callback_t on_rx_trans_event; /*!< Callback function for handling the completion of a reception. */ uhci_tx_done_callback_t on_tx_trans_done; /*!< Callback function for handling the completion of a transmission. */ } uhci_event_callbacks_t; /** * @brief One buffer segment used by `uhci_multi_buffer_transmit()` */ typedef struct { const uint8_t *write_buffer; /*!< Pointer to this buffer segment. Must remain valid until the transmission is complete. */ size_t buffer_size; /*!< Size of this buffer segment, in bytes */ } uhci_transmit_buffer_info_t; /** * @brief Create and initialize a new UHCI controller. * * This function initializes a new UHCI controller instance based on the provided configuration. * It allocates and configures resources required for the UHCI controller, such as DMA and * communication settings. The created controller handle is returned through the output parameter. * * @param[in] config Pointer to a `uhci_controller_config_t` structure containing the * configuration parameters for the UHCI controller. * @param[out] ret_uhci_ctrl Pointer to a variable where the handle to the newly created UHCI controller * will be stored. This handle is used in subsequent operations involving the * controller. * * @return * - `ESP_OK`: Controller successfully created and initialized. * - `ESP_ERR_INVALID_ARG`: One or more arguments are invalid (e.g., null pointers or invalid config). * - `ESP_ERR_NO_MEM`: Memory allocation for the controller failed. * - Other error codes: Indicate failure in the underlying hardware or driver initialization. */ esp_err_t uhci_new_controller(const uhci_controller_config_t *config, uhci_controller_handle_t *ret_uhci_ctrl); /** * @brief Receive data from the UHCI controller. * * This function retrieves data from the UHCI controller into the provided buffer. It is typically * used for receiving data that was transmitted via UART and processed by the UHCI DMA controller. * * @param[in] uhci_ctrl Handle to the UHCI controller, which was previously created using * `uhci_new_controller()`. * @param[out] read_buffer Pointer to the buffer where the received data will be stored. * The buffer must be pre-allocated by the caller. * @param[in] buffer_size The size of read buffer. Should generally not exceed `uhci_controller_config_t.max_receive_internal_mem`. * * @note The function is non-blocking, it just mounts the user buffer to the DMA. * The return from the function doesn't mean a finished receive. You need to register corresponding * callback function to get notification. * * @note This function can be called from the RX-done callback (i.e. ISR context), e.g. to re-arm * reception with a new buffer and minimize the RX gap. To call it while the cache is disabled, * enable CONFIG_UHCI_RECV_FUNC_IN_IRAM so this function is placed in IRAM. * * @return * - `ESP_OK`: The driver is ready for data reception. * - `ESP_ERR_INVALID_STATE`: The controller is not in enable state. * - `ESP_ERR_INVALID_ARG`: Invalid arguments (e.g., invalid controller handle, null buffer, invalid buffer size). */ esp_err_t uhci_receive(uhci_controller_handle_t uhci_ctrl, uint8_t *read_buffer, size_t buffer_size); /** * @brief Start the receive continuously. * * Unlike `uhci_receive()` (which stops the DMA after one frame and must be re-armed), this keeps * the GDMA running across EOFs. `read_buffer` is split across the DMA nodes and used as a circular * ring: each finished frame (UART idle/length EOF) is delivered through the registered * `on_rx_trans_event` callback with `flags.totally_received = true`, and the following frame lands * in the next buffer without any re-arm. Call `uhci_stop_receive()` to end the session. * * @param[in] uhci_ctrl Handle to the UHCI controller. * @param[in] read_buffer Caller-provided storage buffer to receive into. Must stay valid until `uhci_stop_receive()`. * @param[in] buffer_size The size of the storage buffer, in bytes. * * @note The callback delivers a pointer into the storage buffer (zero-copy). The application must * consume the data before the DMA wraps around and overwrites it, so size the storage buffer for the * expected throughput and consumer latency. Overrun protection is not provided in this version. * * @return * - `ESP_OK`: Continuous reception started. * - `ESP_ERR_INVALID_ARG`: Invalid arguments (e.g., null buffer or invalid controller handle). * - `ESP_ERR_INVALID_STATE`: A reception is already in progress. */ esp_err_t uhci_start_receive_continuous(uhci_controller_handle_t uhci_ctrl, uint8_t *read_buffer, size_t buffer_size); /** * @brief Stop an ongoing reception. * * Stops the RX DMA and returns the controller to the idle state so it can be re-armed with * `uhci_receive()` / `uhci_start_receive_continuous()` or deleted with `uhci_del_controller()`. Mainly * used to end a `uhci_start_receive_continuous()` session; it is a no-op if no reception is in progress. * * @param[in] uhci_ctrl Handle to the UHCI controller. * * @return * - `ESP_OK`: Reception stopped (or already idle). * - `ESP_ERR_INVALID_ARG`: The provided `uhci_ctrl` handle is invalid or null. * - `ESP_ERR_INVALID_STATE`: A reception is concurrently being armed; retry after it completes. */ esp_err_t uhci_stop_receive(uhci_controller_handle_t uhci_ctrl); /** * @brief Transmit data using the UHCI controller. * * This function sends data from the provided buffer through the UHCI controller. It uses the DMA * capabilities of UHCI to efficiently handle data transmission via UART. * * @param[in] uhci_ctrl Handle to the UHCI controller, which was previously created using * `uhci_new_controller()`. * @param[in] write_buffer Pointer to the buffer containing the data to be transmitted. * The buffer must remain valid until the transmission is complete. * @param[in] write_size The number of bytes to transmit from the buffer. * Must not exceed `uhci_controller_config_t.max_transmit_size`. * * @note The function is an non-blocking api, which means this function will return immediately. You can * get corresponding event from callbacks. * * @return * - `ESP_OK`: Data successfully queued for transmission. * - `ESP_ERR_INVALID_ARG`: Invalid arguments (e.g., null buffer, invalid handle, zero `write_size`, or * `write_size` exceeds `max_transmit_size`). * - `ESP_ERR_INVALID_STATE`: No free transaction descriptor available. */ esp_err_t uhci_transmit(uhci_controller_handle_t uhci_ctrl, uint8_t *write_buffer, size_t write_size); /** * @brief Transmit several discontinuous buffers as a single UHCI transaction * * Unlike `uhci_transmit()`, this accepts an array of buffer segments instead of a single * contiguous buffer. For `array_size > 1`, the buffers are assembled into one DMA link list in * the given order (only the last segment is marked EOF). * * @note All buffer segments must remain valid until the transmission is complete (same contract as * `uhci_transmit()`). * * @param[in] uhci_ctrl Handle to the UHCI controller, which was previously created using * `uhci_new_controller()`. * @param[in] buffer_info_array Array of buffer segments to transmit, in order. The combined size of * all buffers must not exceed `uhci_controller_config_t.max_transmit_size`. * @param[in] array_size Number of entries in `buffer_info_array`. Must not exceed `max_transmit_buffer_count`. * * @return * - `ESP_OK`: Data successfully queued for transmission. * - `ESP_ERR_INVALID_ARG`: Invalid arguments, `array_size` exceeds `max_transmit_buffer_count`, or the * combined size of all buffers exceeds `max_transmit_size`. * - `ESP_ERR_INVALID_STATE`: No free transaction descriptor available. */ esp_err_t uhci_multi_buffer_transmit(uhci_controller_handle_t uhci_ctrl, const uhci_transmit_buffer_info_t *buffer_info_array, size_t array_size); /** * @brief Uninstall the UHCI (UART Host Controller Interface) driver and release resources. * * This function deinitializes the UHCI controller and frees any resources allocated during its * initialization. It ensures proper cleanup and prevents resource leaks when the UHCI controller * is no longer needed. * * @param[in] uhci_ctrl Handle to the UHCI controller, which was previously created using * `uhci_new_controller()`. Passing an invalid or uninitialized handle * may result in undefined behavior. * * @return * - `ESP_OK`: The UHCI driver was successfully uninstalled, and resources were released. * - `ESP_ERR_INVALID_ARG`: The provided `uhci_ctrl` handle is invalid or null. */ esp_err_t uhci_del_controller(uhci_controller_handle_t uhci_ctrl); /** * @brief Register event callback functions for a UHCI controller. * * This function allows the user to register callback functions to handle specific UHCI events, such as * transmission or reception completion. The callbacks provide a mechanism to handle asynchronous events * generated by the UHCI controller. * * @param[in] uhci_ctrl Handle to the UHCI controller, which was previously created using * `uhci_new_controller()`. * @param[in] cbs Pointer to a `uhci_event_callbacks_t` structure that defines the callback * functions to be registered. This structure includes pointers to the callback * functions for handling UHCI events. * @param[in] user_data Pointer to user-defined data that will be passed to the callback functions * when they are invoked. This can be used to provide context or state information * specific to the application. * * @return * - `ESP_OK`: Event callbacks were successfully registered. * - `ESP_ERR_INVALID_ARG`: Invalid arguments (e.g., null `uhci_ctrl` handle or `cbs` pointer). */ esp_err_t uhci_register_event_callbacks(uhci_controller_handle_t uhci_ctrl, const uhci_event_callbacks_t *cbs, void *user_data); /** * @brief Wait for all pending TX transactions done * * @param[in] uhci_ctrl UHCI controller that created by `uhci_new_controller` * @param[in] timeout_ms Timeout in milliseconds, `-1` means to wait forever * @return * - ESP_OK: All pending TX transactions is finished and recycled * - ESP_ERR_INVALID_ARG: Wait for all pending TX transactions done failed because of invalid argument * - ESP_ERR_TIMEOUT: Wait for all pending TX transactions done timeout * - ESP_FAIL: Wait for all pending TX transactions done failed because of other error */ esp_err_t uhci_wait_all_tx_transaction_done(uhci_controller_handle_t uhci_ctrl, int timeout_ms); #ifdef __cplusplus } #endif