serial: uart_native_pty: ASYNC TX support
Add support for transmitting using the asynchronous API. The asynchronous portion is simulated through the system workqueue. Signed-off-by: Jordan Yates <jordan@embeint.com>
This commit is contained in:
parent
3d344186fc
commit
5536e5b5cd
@ -6,6 +6,7 @@ config UART_NATIVE_PTY
|
||||
default y
|
||||
depends on (DT_HAS_ZEPHYR_NATIVE_PTY_UART_ENABLED || DT_HAS_ZEPHYR_NATIVE_POSIX_UART_ENABLED)
|
||||
select SERIAL_HAS_DRIVER
|
||||
select SERIAL_SUPPORT_ASYNC
|
||||
help
|
||||
This enables a PTY based UART driver for the POSIX ARCH with up to 2 UARTs.
|
||||
For the first UART port, the driver can be configured
|
||||
|
||||
@ -48,15 +48,38 @@ struct native_pty_status {
|
||||
char *auto_attach_cmd; /* If auto_attach, which command to launch the terminal emulator */
|
||||
bool wait_pts; /* Hold writes to the uart/pts until a client is connected/ready */
|
||||
bool cmd_request_stdinout; /* User requested to connect this UART to the stdin/out */
|
||||
#ifdef CONFIG_UART_ASYNC_API
|
||||
struct {
|
||||
const struct device *dev;
|
||||
struct k_work_delayable tx_done;
|
||||
uart_callback_t user_callback;
|
||||
void *user_data;
|
||||
const uint8_t *tx_buf;
|
||||
size_t tx_len;
|
||||
} async;
|
||||
#endif /* CONFIG_UART_ASYNC_API */
|
||||
};
|
||||
|
||||
static void np_uart_poll_out(const struct device *dev, unsigned char out_char);
|
||||
static int np_uart_poll_in(const struct device *dev, unsigned char *p_char);
|
||||
static int np_uart_init(const struct device *dev);
|
||||
|
||||
#ifdef CONFIG_UART_ASYNC_API
|
||||
static void np_uart_tx_done_work(struct k_work *work);
|
||||
static int np_uart_callback_set(const struct device *dev, uart_callback_t callback,
|
||||
void *user_data);
|
||||
static int np_uart_tx(const struct device *dev, const uint8_t *buf, size_t len, int32_t timeout);
|
||||
static int np_uart_tx_abort(const struct device *dev);
|
||||
#endif /* CONFIG_UART_ASYNC_API */
|
||||
|
||||
static DEVICE_API(uart, np_uart_driver_api) = {
|
||||
.poll_out = np_uart_poll_out,
|
||||
.poll_in = np_uart_poll_in,
|
||||
#ifdef CONFIG_UART_ASYNC_API
|
||||
.callback_set = np_uart_callback_set,
|
||||
.tx = np_uart_tx,
|
||||
.tx_abort = np_uart_tx_abort,
|
||||
#endif /* CONFIG_UART_ASYNC_API */
|
||||
};
|
||||
|
||||
#define NATIVE_PTY_INSTANCE(inst) \
|
||||
@ -119,6 +142,11 @@ static int np_uart_init(const struct device *dev)
|
||||
d->out_fd = tty_fn;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UART_ASYNC_API
|
||||
k_work_init_delayable(&d->async.tx_done, np_uart_tx_done_work);
|
||||
d->async.dev = dev;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -207,6 +235,85 @@ static int np_uart_poll_in(const struct device *dev, unsigned char *p_char)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UART_ASYNC_API
|
||||
|
||||
static int np_uart_callback_set(const struct device *dev, uart_callback_t callback, void *user_data)
|
||||
{
|
||||
struct native_pty_status *data = dev->data;
|
||||
|
||||
data->async.user_callback = callback;
|
||||
data->async.user_data = user_data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void np_uart_tx_done_work(struct k_work *work)
|
||||
{
|
||||
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
|
||||
struct native_pty_status *data =
|
||||
CONTAINER_OF(dwork, struct native_pty_status, async.tx_done);
|
||||
struct uart_event evt;
|
||||
unsigned int key = irq_lock();
|
||||
|
||||
evt.type = UART_TX_DONE;
|
||||
evt.data.tx.buf = data->async.tx_buf;
|
||||
evt.data.tx.len = data->async.tx_len;
|
||||
|
||||
(void)nsi_host_write(data->out_fd, evt.data.tx.buf, evt.data.tx.len);
|
||||
|
||||
data->async.tx_buf = NULL;
|
||||
|
||||
if (data->async.user_callback) {
|
||||
data->async.user_callback(data->async.dev, &evt, data->async.user_data);
|
||||
}
|
||||
irq_unlock(key);
|
||||
}
|
||||
|
||||
static int np_uart_tx(const struct device *dev, const uint8_t *buf, size_t len, int32_t timeout)
|
||||
{
|
||||
struct native_pty_status *data = dev->data;
|
||||
|
||||
if (data->async.tx_buf) {
|
||||
/* Port is busy */
|
||||
return -EBUSY;
|
||||
}
|
||||
data->async.tx_buf = buf;
|
||||
data->async.tx_len = len;
|
||||
|
||||
/* Run the callback on the next tick to give the caller time to use the return value */
|
||||
k_work_reschedule(&data->async.tx_done, K_TICKS(1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int np_uart_tx_abort(const struct device *dev)
|
||||
{
|
||||
struct native_pty_status *data = dev->data;
|
||||
struct k_work_sync sync;
|
||||
struct uart_event evt;
|
||||
bool not_idle;
|
||||
|
||||
/* Cancel the callback */
|
||||
not_idle = k_work_cancel_delayable_sync(&data->async.tx_done, &sync);
|
||||
if (!not_idle) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* Generate TX_DONE event with number of bytes transmitted */
|
||||
evt.type = UART_TX_DONE;
|
||||
evt.data.tx.buf = data->async.tx_buf;
|
||||
evt.data.tx.len = 0;
|
||||
if (data->async.user_callback) {
|
||||
data->async.user_callback(data->async.dev, &evt, data->async.user_data);
|
||||
}
|
||||
|
||||
/* Reset state */
|
||||
data->async.tx_buf = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_UART_ASYNC_API */
|
||||
|
||||
|
||||
#define NATIVE_PTY_SET_AUTO_ATTACH_CMD(inst, cmd) \
|
||||
native_pty_status_##inst.auto_attach_cmd = cmd;
|
||||
#define NATIVE_PTY_SET_AUTO_ATTACH(inst, value) \
|
||||
|
||||
Loading…
Reference in New Issue
Block a user