Skip to content

Commit 95f5aab

Browse files
committed
serial: uart_native_pty: ASYNC RX support
Add support for receiving using the asynchronous API. This is achieved through registering a handler for the SIGIO signal, and polling data off the file descriptors inside the event. Signed-off-by: Jordan Yates <[email protected]>
1 parent d704a68 commit 95f5aab

File tree

3 files changed

+123
-0
lines changed

3 files changed

+123
-0
lines changed

drivers/serial/uart_native_pty.c

+101
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#endif
1515

1616
#include <stdbool.h>
17+
#include <signal.h>
1718
#include <zephyr/drivers/uart.h>
1819
#include <zephyr/kernel.h>
1920
#include <cmdline.h> /* native_sim command line options header */
@@ -56,6 +57,8 @@ struct native_pty_status {
5657
void *user_data;
5758
const uint8_t *tx_buf;
5859
size_t tx_len;
60+
uint8_t *rx_buf;
61+
size_t rx_len;
5962
} async;
6063
#endif /* CONFIG_UART_ASYNC_API */
6164
};
@@ -70,6 +73,10 @@ static int np_uart_callback_set(const struct device *dev, uart_callback_t callba
7073
void *user_data);
7174
static int np_uart_tx(const struct device *dev, const uint8_t *buf, size_t len, int32_t timeout);
7275
static int np_uart_tx_abort(const struct device *dev);
76+
static int np_uart_rx_buf_rsp(const struct device *dev, uint8_t *buf, size_t len);
77+
static int np_uart_rx_enable(const struct device *dev, uint8_t *buf, size_t len, int32_t timeout);
78+
static int np_uart_rx_disable(const struct device *dev);
79+
static void sigio_handler(int status);
7380
#endif /* CONFIG_UART_ASYNC_API */
7481

7582
static DEVICE_API(uart, np_uart_driver_api) = {
@@ -79,6 +86,9 @@ static DEVICE_API(uart, np_uart_driver_api) = {
7986
.callback_set = np_uart_callback_set,
8087
.tx = np_uart_tx,
8188
.tx_abort = np_uart_tx_abort,
89+
.rx_buf_rsp = np_uart_rx_buf_rsp,
90+
.rx_enable = np_uart_rx_enable,
91+
.rx_disable = np_uart_rx_disable,
8292
#endif /* CONFIG_UART_ASYNC_API */
8393
};
8494

@@ -143,7 +153,16 @@ static int np_uart_init(const struct device *dev)
143153
}
144154

145155
#ifdef CONFIG_UART_ASYNC_API
156+
static bool handler_installed;
157+
158+
if (!handler_installed) {
159+
/* Install global SIGIO handler */
160+
nsi_signal_handler_install(SIGIO, sigio_handler);
161+
handler_installed = true;
162+
}
146163
k_work_init_delayable(&d->async.tx_done, np_uart_tx_done_work);
164+
/* Mark the file descriptor as async */
165+
nsi_fd_async(d->in_fd);
147166
#endif
148167

149168
return 0;
@@ -296,6 +315,88 @@ static int np_uart_tx_abort(const struct device *dev)
296315
return k_work_cancel_delayable_sync(&data->async.tx_done, &sync) ? 0 : -EFAULT;
297316
}
298317

318+
static void sigio_handler_dev(const struct device *dev)
319+
{
320+
struct native_pty_status *data = dev->data;
321+
unsigned char fallback[8];
322+
struct uart_event event;
323+
unsigned char *buf;
324+
long read;
325+
int len;
326+
327+
/* Read data from the file even if it is disabled.
328+
* This prevents data that was received while disabled from
329+
* appearing at the output if it is enabled later.
330+
*/
331+
if (data->async.rx_len == 0) {
332+
buf = fallback;
333+
len = sizeof(fallback);
334+
} else {
335+
buf = data->async.rx_buf;
336+
len = data->async.rx_len;
337+
}
338+
339+
/* Loop until there is no more data to be read */
340+
while (1) {
341+
read = np_uart_stdin_poll_in_bottom(data->in_fd, buf, len);
342+
if (read <= 0) {
343+
break;
344+
}
345+
if (data->async.rx_len == 0) {
346+
/* RX disabled, drop data */
347+
continue;
348+
}
349+
350+
event.type = UART_RX_RDY;
351+
event.data.rx.buf = buf;
352+
event.data.rx.len = len;
353+
event.data.rx.offset = 0;
354+
355+
data->async.user_callback(data->async.dev, &event, data->async.user_data);
356+
}
357+
}
358+
359+
#define NATIVE_PTY_SIGIO_HANDLER(inst) \
360+
sigio_handler_dev(DEVICE_DT_GET(DT_DRV_INST(inst)));
361+
362+
static void sigio_handler(int status)
363+
{
364+
DT_INST_FOREACH_STATUS_OKAY(NATIVE_PTY_SIGIO_HANDLER)
365+
}
366+
367+
static int np_uart_rx_buf_rsp(const struct device *dev, uint8_t *buf, size_t len)
368+
{
369+
/* Driver never requests additional buffers */
370+
return -ENOTSUP;
371+
}
372+
373+
static int np_uart_rx_enable(const struct device *dev, uint8_t *buf, size_t len,
374+
int32_t timeout)
375+
{
376+
struct native_pty_status *data = dev->data;
377+
378+
ARG_UNUSED(timeout);
379+
380+
data->async.rx_buf = buf;
381+
data->async.rx_len = len;
382+
383+
return 0;
384+
}
385+
386+
static int np_uart_rx_disable(const struct device *dev)
387+
{
388+
struct native_pty_status *data = dev->data;
389+
390+
if (data->async.rx_buf == NULL) {
391+
return -EFAULT;
392+
}
393+
394+
data->async.rx_buf = NULL;
395+
data->async.rx_len = 0;
396+
397+
return 0;
398+
}
399+
299400
#endif /* CONFIG_UART_ASYNC_API */
300401

301402

scripts/native_simulator/common/src/include/nsi_host_trampolines.h

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ void *nsi_host_realloc(void *ptr, unsigned long size);
3737
void nsi_host_srandom(unsigned int seed);
3838
char *nsi_host_strdup(const char *s);
3939
long nsi_host_write(int fd, const void *buffer, unsigned long size);
40+
void nsi_signal_handler_install(int signal, void (*handler)(int status));
41+
void nsi_fd_async(int fd);
4042

4143
#ifdef __cplusplus
4244
}

scripts/native_simulator/common/src/nsi_host_trampolines.c

+20
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <unistd.h>
1111
#include <fcntl.h>
1212
#include <string.h>
13+
#include <signal.h>
1314

1415
void *nsi_host_calloc(unsigned long nmemb, unsigned long size)
1516
{
@@ -75,3 +76,22 @@ long nsi_host_write(int fd, const void *buffer, unsigned long size)
7576
{
7677
return write(fd, buffer, size);
7778
}
79+
80+
void nsi_signal_handler_install(int signal, void (*handler)(int status))
81+
{
82+
struct sigaction saio;
83+
84+
/* Install the signal handler */
85+
saio.sa_handler = handler;
86+
saio.sa_flags = 0;
87+
saio.sa_restorer = NULL;
88+
sigaction(signal, &saio, NULL);
89+
}
90+
91+
void nsi_fd_async(int fd)
92+
{
93+
/* Set the file descriptor owner so we can receive events */
94+
fcntl(fd, F_SETOWN, getpid());
95+
/* Make the file descriptor asynchronous */
96+
fcntl(fd, F_SETFL, O_ASYNC);
97+
}

0 commit comments

Comments
 (0)