Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 | /*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_TO_IRQ_H_
#define ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_TO_IRQ_H_
#include <zephyr/drivers/uart.h>
#include <zephyr/logging/log.h>
#include <zephyr/spinlock.h>
#include <zephyr/sys/util.h>
#include <zephyr/drivers/serial/uart_async_rx.h>
/**
* @brief UART Asynchronous to Interrupt driven API adaptation layer
* @ingroup uart_interface
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
/* Forward declarations. */
/** @brief Data structure used by the adaptation layer.
*
* Pointer to that data must be the first element of the UART device data structure.
*/
struct uart_async_to_irq_data;
/** @brief Configuration structure used by the adaptation layer.
*
* Pointer to this data must be the first element of the UART device configuration structure.
*/
struct uart_async_to_irq_config;
/* @brief Function that triggers trampoline to the interrupt context.
*
* This context is used to call user UART interrupt handler. It is to used to
* fulfill the requirement that UART interrupt driven API shall be called from
* the UART interrupt. Trampoline context shall have the same priority as UART.
*
* One option may be to use k_timer configured to expire immediately.
*/
typedef void (*uart_async_to_irq_trampoline)(const struct device *dev);
/** @brief Callback to be called from trampoline context.
*
* @param dev UART device.
*/
void uart_async_to_irq_trampoline_cb(const struct device *dev);
/** @brief Interrupt driven API initializer.
*
* It should be used in the initialization of the UART API structure in the
* driver to provide interrupt driven API functions.
*/
#define UART_ASYNC_TO_IRQ_API_INIT() \
.fifo_fill = z_uart_async_to_irq_fifo_fill, \
.fifo_read = z_uart_async_to_irq_fifo_read, \
.irq_tx_enable = z_uart_async_to_irq_irq_tx_enable, \
.irq_tx_disable = z_uart_async_to_irq_irq_tx_disable, \
.irq_tx_ready = z_uart_async_to_irq_irq_tx_ready, \
.irq_rx_enable = z_uart_async_to_irq_irq_rx_enable, \
.irq_rx_disable = z_uart_async_to_irq_irq_rx_disable, \
.irq_tx_complete = z_uart_async_to_irq_irq_tx_complete,\
.irq_rx_ready = z_uart_async_to_irq_irq_rx_ready, \
.irq_err_enable = z_uart_async_to_irq_irq_err_enable, \
.irq_err_disable = z_uart_async_to_irq_irq_err_disable,\
.irq_is_pending = z_uart_async_to_irq_irq_is_pending, \
.irq_update = z_uart_async_to_irq_irq_update, \
.irq_callback_set = z_uart_async_to_irq_irq_callback_set
/** @brief Configuration structure initializer.
*
* @param _api Structure with UART asynchronous API.
* @param _trampoline Function that trampolines to the interrupt context.
* @param _baudrate UART baudrate.
* @param _tx_buf TX buffer.
* @param _tx_len TX buffer length.
* @param _rx_buf RX buffer.
* @param _rx_len RX buffer length.
* @param _rx_cnt Number of chunks into which RX buffer is divided.
* @param _log Logging instance, if not provided (empty) then default is used.
*/
#define UART_ASYNC_TO_IRQ_API_CONFIG_INITIALIZER(_api, _trampoline, _baudrate, _tx_buf, \
_tx_len, _rx_buf, _rx_len, _rx_cnt, _log) \
{ \
.tx_buf = _tx_buf, \
.tx_len = _tx_len, \
.async_rx = { \
.buffer = _rx_buf, \
.length = _rx_len, \
.buf_cnt = _rx_cnt \
}, \
.api = _api, \
.trampoline = _trampoline, \
.baudrate = _baudrate, \
LOG_OBJECT_PTR_INIT(log, \
COND_CODE_1(IS_EMPTY(_log), \
(LOG_OBJECT_PTR(UART_ASYNC_TO_IRQ_LOG_NAME)), \
(_log) \
) \
) \
}
/** @brief Initialize the adaptation layer.
*
* @param data Data associated with the given adaptation layer instance.
* @param config Configuration structure. Must be persistent.
*
* @retval 0 On successful initialization.
*/
int uart_async_to_irq_init(struct uart_async_to_irq_data *data,
const struct uart_async_to_irq_config *config);
/* @brief Enable RX for interrupt driven API.
*
* @param dev UART device. Device must support asynchronous API.
*
* @retval 0 on successful operation.
* @retval -EINVAL if adaption layer has wrong configuration.
* @retval negative value Error reported by the UART API.
*/
int uart_async_to_irq_rx_enable(const struct device *dev);
/* @brief Disable RX for interrupt driven API.
*
* @param dev UART device. Device must support asynchronous API.
*
* @retval 0 on successful operation.
* @retval -EINVAL if adaption layer has wrong configuration.
* @retval negative value Error reported by the UART API.
*/
int uart_async_to_irq_rx_disable(const struct device *dev);
/* Starting from here API is internal only. */
/** @cond INTERNAL_HIDDEN
* @brief Structure used by the adaptation layer.
*/
struct uart_async_to_irq_config {
/** Pointer to the TX buffer. */
uint8_t *tx_buf;
/** TX buffer length. */
size_t tx_len;
/** UART Asynchronous RX helper configuration. */
struct uart_async_rx_config async_rx;
/** Async API used by the a2i layer. */
const struct uart_async_to_irq_async_api *api;
/** Trampoline callback. */
uart_async_to_irq_trampoline trampoline;
/** Initial baudrate. */
uint32_t baudrate;
/** Instance logging handler. */
LOG_INSTANCE_PTR_DECLARE(log);
};
/** @brief Asynchronous API used by the adaptation layer. */
struct uart_async_to_irq_async_api {
int (*callback_set)(const struct device *dev,
uart_callback_t callback,
void *user_data);
int (*tx)(const struct device *dev, const uint8_t *buf, size_t len,
int32_t timeout);
int (*tx_abort)(const struct device *dev);
int (*rx_enable)(const struct device *dev, uint8_t *buf, size_t len,
int32_t timeout);
int (*rx_buf_rsp)(const struct device *dev, uint8_t *buf, size_t len);
int (*rx_disable)(const struct device *dev);
};
/** @brief Structure holding receiver data. */
struct uart_async_to_irq_rx_data {
/** Asynchronous RX helper data. */
struct uart_async_rx async_rx;
/** Semaphore for pending on RX disable. */
struct k_sem sem;
/** Number of pending buffer requests which weren't handled because lack of free buffers. */
atomic_t pending_buf_req;
};
/** @brief Structure holding transmitter data. */
struct uart_async_to_irq_tx_data {
/** TX buffer. */
uint8_t *buf;
/** Length of the buffer. */
size_t len;
};
/** @briref Data associated with the asynchronous to the interrupt driven API adaptation layer. */
struct uart_async_to_irq_data {
/** User callback for interrupt driven API. */
uart_irq_callback_user_data_t callback;
/** User data. */
void *user_data;
/** Interrupt request counter. */
atomic_t irq_req;
/** RX specific data. */
struct uart_async_to_irq_rx_data rx;
/** TX specific data. */
struct uart_async_to_irq_tx_data tx;
/** Spinlock. */
struct k_spinlock lock;
/** Internally used flags for holding the state of the a2i layer. */
atomic_t flags;
};
/** Interrupt driven FIFO fill function. */
int z_uart_async_to_irq_fifo_fill(const struct device *dev,
const uint8_t *buf,
int len);
/** Interrupt driven FIFO read function. */
int z_uart_async_to_irq_fifo_read(const struct device *dev,
uint8_t *buf,
const int len);
/** Interrupt driven transfer enabling function. */
void z_uart_async_to_irq_irq_tx_enable(const struct device *dev);
/** Interrupt driven transfer disabling function */
void z_uart_async_to_irq_irq_tx_disable(const struct device *dev);
/** Interrupt driven transfer ready function */
int z_uart_async_to_irq_irq_tx_ready(const struct device *dev);
/** Interrupt driven receiver enabling function */
void z_uart_async_to_irq_irq_rx_enable(const struct device *dev);
/** Interrupt driven receiver disabling function */
void z_uart_async_to_irq_irq_rx_disable(const struct device *dev);
/** Interrupt driven transfer complete function */
int z_uart_async_to_irq_irq_tx_complete(const struct device *dev);
/** Interrupt driven receiver ready function */
int z_uart_async_to_irq_irq_rx_ready(const struct device *dev);
/** Interrupt driven error enabling function */
void z_uart_async_to_irq_irq_err_enable(const struct device *dev);
/** Interrupt driven error disabling function */
void z_uart_async_to_irq_irq_err_disable(const struct device *dev);
/** Interrupt driven pending status function */
int z_uart_async_to_irq_irq_is_pending(const struct device *dev);
/** Interrupt driven interrupt update function */
int z_uart_async_to_irq_irq_update(const struct device *dev);
/** Set the irq callback function */
void z_uart_async_to_irq_irq_callback_set(const struct device *dev,
uart_irq_callback_user_data_t cb,
void *user_data);
/** @endcond */
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_TO_IRQ_H_ */
|