diff --git a/Documentation/platforms/sim/sim/boards/sim/index.rst b/Documentation/platforms/sim/sim/boards/sim/index.rst index 3f080122eb799..01c82908f9e1a 100644 --- a/Documentation/platforms/sim/sim/boards/sim/index.rst +++ b/Documentation/platforms/sim/sim/boards/sim/index.rst @@ -2173,10 +2173,23 @@ nxscope Configuration demonstrating NxScope stream over simulated UART interface. -The simulated UART must be created on host before running NuttX:: +If ``CONFIG_SIM_UART_PTY`` is disabled, the simulated UART peer must be +created on the host before running NuttX:: socat PTY,link=/dev/ttySIM0 PTY,link=/dev/ttyNX0 +In that mode ``CONFIG_SIM_UART0_NAME`` is both the NuttX device name and +the host path that the sim UART backend opens. This works when the host +path is stable, but it is inconvenient for automated tests and generated +PTYs: the peer device must exist before the UART is opened, and changing +the host path requires changing the NuttX configuration. + +If ``CONFIG_SIM_UART_PTY`` is enabled, NuttX creates the host +pseudoterminal when the simulated UART is opened and prints the host +PTY slave path. The configured ``SIM_UARTx_NAME`` remains the NuttX +device name, while the host PTY path is allocated at runtime and can be +passed to the external simulator or test program. + See :doc:`/applications/examples/nxscope/index` and :doc:`/applications/logging/nxscope/index` for more details. diff --git a/arch/sim/Kconfig b/arch/sim/Kconfig index 7ad1e801c28be..b1e78e1b60e22 100644 --- a/arch/sim/Kconfig +++ b/arch/sim/Kconfig @@ -774,6 +774,11 @@ config SIM_UART_NUMBER Anything sent to the one of these ports will be relayed automatically to the other, and vice-versa. + If SIM_UART_PTY is enabled, NuttX creates the simulated + host pseudoterminal itself. In that mode SIM_UARTx_NAME is + only the NuttX device name, and the host pseudoterminal path + is printed when the port is opened. + config SIM_UART_BUFFER_SIZE int "UART buffer size" default 256 @@ -784,16 +789,41 @@ config SIM_UART_BUFFER_SIZE Note that all ports will have the same buffer size. +config SIM_UART_PTY + bool "Create host pseudoterminals for simulated UART ports" + default n + depends on HOST_LINUX && SIM_UART_NUMBER >= 1 + ---help--- + Open a new host pseudoterminal for each simulated UART + instead of opening an existing host serial device. The + UART remains registered in NuttX using SIM_UARTx_NAME, and + the host PTY slave path is printed when the port is opened. + + The existing behavior requires the host endpoint named by + SIM_UARTx_NAME to exist before the simulated UART is opened. + This makes automated tests awkward when the peer endpoint is + a generated PTY with a host-dependent path, because the host + path must be prepared up front and encoded in the NuttX + configuration. With this option enabled, the sim UART + backend owns the host PTY allocation and reports the actual + slave path at runtime, while keeping the NuttX device name + stable for applications. + + If disabled, SIM UART keeps the existing behavior and opens + the host device path specified by SIM_UARTx_NAME directly. + config SIM_UART0_NAME string "UART port 0 name" default "/dev/ttySIM0" depends on SIM_UART_NUMBER >= 1 ---help--- This is the name of the simulated UART port. - The port will be mounted in NuttX under this name. + The port will be registered in NuttX under this name. - A UART port must also exist on the host system - with the exact same name specified here. + If SIM_UART_PTY is disabled, a UART port must also exist on + the host system with the exact same name specified here. If + SIM_UART_PTY is enabled, the host pseudoterminal is allocated + automatically and printed when this port is opened. config SIM_UART1_NAME string "UART port 1 name" @@ -801,10 +831,12 @@ config SIM_UART1_NAME depends on SIM_UART_NUMBER >= 2 ---help--- This is the name of the simulated UART port. - The port will be mounted in NuttX under this name. + The port will be registered in NuttX under this name. - A UART port must also exist on the host system - with the exact same name specified here. + If SIM_UART_PTY is disabled, a UART port must also exist on + the host system with the exact same name specified here. If + SIM_UART_PTY is enabled, the host pseudoterminal is allocated + automatically and printed when this port is opened. config SIM_UART2_NAME string "UART port 2 name" @@ -812,10 +844,12 @@ config SIM_UART2_NAME depends on SIM_UART_NUMBER >= 3 ---help--- This is the name of the simulated UART port. - The port will be mounted in NuttX under this name. + The port will be registered in NuttX under this name. - A UART port must also exist on the host system - with the exact same name specified here. + If SIM_UART_PTY is disabled, a UART port must also exist on + the host system with the exact same name specified here. If + SIM_UART_PTY is enabled, the host pseudoterminal is allocated + automatically and printed when this port is opened. config SIM_UART3_NAME string "UART port 3 name" @@ -823,10 +857,12 @@ config SIM_UART3_NAME depends on SIM_UART_NUMBER >= 4 ---help--- This is the name of the simulated UART port. - The port will be mounted in NuttX under this name. + The port will be registered in NuttX under this name. - A UART port must also exist on the host system - with the exact same name specified here. + If SIM_UART_PTY is disabled, a UART port must also exist on + the host system with the exact same name specified here. If + SIM_UART_PTY is enabled, the host pseudoterminal is allocated + automatically and printed when this port is opened. config SIM_RAM_UART bool "SIM RAM UART Device" diff --git a/arch/sim/src/sim/posix/sim_hostuart.c b/arch/sim/src/sim/posix/sim_hostuart.c index facc21e467e0e..04254bc882848 100644 --- a/arch/sim/src/sim/posix/sim_hostuart.c +++ b/arch/sim/src/sim/posix/sim_hostuart.c @@ -24,6 +24,7 @@ * Included Files ****************************************************************************/ +#include #include #include #include @@ -130,6 +131,58 @@ int host_uart_open(const char *pathname) return fd; } +/**************************************************************************** + * Name: host_uart_openpty + ****************************************************************************/ + +int host_uart_openpty(const char *name) +{ +#ifdef CONFIG_HOST_LINUX + unsigned int ptyno; + int lock = 0; + int oflags; + int ret; + int fd; + + oflags = O_RDWR | O_NOCTTY | O_NONBLOCK; +#ifdef O_CLOEXEC + oflags |= O_CLOEXEC; +#endif + fd = open("/dev/ptmx", oflags); + if (fd < 0) + { + return -errno; + } + + ret = ioctl(fd, TIOCGPTN, &ptyno); + if (ret < 0) + { + ret = -errno; + goto errout; + } + + ret = ioctl(fd, TIOCSPTLCK, &lock); + if (ret < 0) + { + ret = -errno; + goto errout; + } + + setrawmode(fd); + + printf("%s connected to pseudotty: /dev/pts/%u\n", name, ptyno); + + return fd; + +errout: + close(fd); + return ret; +#else + (void)name; + return -ENOSYS; +#endif +} + /**************************************************************************** * Name: host_uart_close ****************************************************************************/ @@ -229,7 +282,7 @@ bool host_uart_checkin(int fd) pfd.fd = fd; pfd.events = POLLIN; - return poll(&pfd, 1, 0) == 1; + return poll(&pfd, 1, 0) == 1 && (pfd.revents & POLLIN) != 0; } /**************************************************************************** @@ -242,7 +295,7 @@ bool host_uart_checkout(int fd) pfd.fd = fd; pfd.events = POLLOUT; - return poll(&pfd, 1, 0) == 1; + return poll(&pfd, 1, 0) == 1 && (pfd.revents & POLLOUT) != 0; } /**************************************************************************** diff --git a/arch/sim/src/sim/sim_internal.h b/arch/sim/src/sim/sim_internal.h index 3ca70b65e9421..82349ada14c29 100644 --- a/arch/sim/src/sim/sim_internal.h +++ b/arch/sim/src/sim/sim_internal.h @@ -284,6 +284,7 @@ void sim_uartinit(void); void host_uart_start(void); int host_uart_open(const char *pathname); +int host_uart_openpty(const char *name); void host_uart_close(int fd); int host_uart_puts(int fd, const char *buf, size_t size); int host_uart_gets(int fd, char *buf, size_t size); diff --git a/arch/sim/src/sim/sim_uart.c b/arch/sim/src/sim/sim_uart.c index 4f8a3b6de0b80..98e5ed53c65ff 100644 --- a/arch/sim/src/sim/sim_uart.c +++ b/arch/sim/src/sim/sim_uart.c @@ -307,9 +307,8 @@ static void uart_nputs(int fd, const char *buf, size_t size) * Name: tty_setup * * Description: - * Configure the UART baud, bits, parity, fifos, etc. This - * method is called the first time that the serial port is - * opened. + * Open and configure the host endpoint for the simulated UART. + * This method is called the first time that the serial port is opened. * ****************************************************************************/ @@ -317,7 +316,17 @@ static int tty_setup(struct uart_dev_s *dev) { struct tty_priv_s *priv = dev->priv; - priv->fd = host_uart_open(priv->path); +#ifdef CONFIG_SIM_UART_PTY + if (!dev->isconsole) + { + priv->fd = host_uart_openpty(priv->path); + } + else +#endif + { + priv->fd = host_uart_open(priv->path); + } + return priv->fd; } diff --git a/arch/sim/src/sim/win/sim_hostuart.c b/arch/sim/src/sim/win/sim_hostuart.c index 331daa7ad8ee2..220fa997f2e30 100644 --- a/arch/sim/src/sim/win/sim_hostuart.c +++ b/arch/sim/src/sim/win/sim_hostuart.c @@ -74,6 +74,16 @@ int host_uart_open(const char *pathname) return -ENOSYS; } +/**************************************************************************** + * Name: host_uart_openpty + ****************************************************************************/ + +int host_uart_openpty(const char *name) +{ + (void)name; + return -ENOSYS; +} + /**************************************************************************** * Name: host_uart_close ****************************************************************************/