diff --git a/Documentation/components/drivers/character/serial.rst b/Documentation/components/drivers/character/serial.rst index f45e45aa8be..ea259fdb88e 100644 --- a/Documentation/components/drivers/character/serial.rst +++ b/Documentation/components/drivers/character/serial.rst @@ -19,6 +19,22 @@ Serial Device Drivers ``/dev/ttyS0``, ``/dev/ttyS1``, etc. See the ``uart_register()`` implementation in ``drivers/serial.c``. +- **TTY_LAUNCH** this depends on ``CONFIG_TTY_LAUNCH``, this feature + allow user launch a new program with a special char input. + + e.g. use ctrl+R to start a nuttx shell. + e.g. use ctrl+E to start user entry. + + You can use ``TTY_LAUNCH_CHAR`` to customize which special char. + + You can choose launch method: + ``TTY_LAUNCH_ENTRY`` or ``TTY_LAUNCH_FILE``, + If``TTY_LAUNCH_ENTRY`` you can set program entery by ``TTY_LAUNCH_ENTRYPOINT``. + If``TTY_LAUNCH_FILE`` you can set file path by ``TTY_LAUNCH_FILEPATH``. + + Also, you can customize: + ``TTY_LAUNCH_ARGS`` ``TTY_LAUNCH_PRIORITY`` ``TTY_LAUNCH_STACKSIZE`` + - **User Access**. Serial drivers are, ultimately, normal `character drivers <#chardrivers>`__ and are accessed as other character drivers. diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 0a2f7adb078..6361321b173 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -173,6 +173,69 @@ config SERIAL_TERMIOS If this is not defined, then the terminal settings (baud, parity, etc). are not configurable at runtime; serial streams cannot be flushed, etc.. +config TTY_LAUNCH + bool "Enable feature TTY launch program" + default n + ---help--- + If select this, then user can launch a program with a special input. + +if TTY_LAUNCH + +config TTY_LAUNCH_CHAR + hex "TTY launch program characters" + default 0x12 + ---help--- + Use Ctrl-R 0x12 inputs to determine whether launch a program + +config TTY_LAUNCH_ARGS + string "TTY launch argument list" + default INIT_ARGS + ---help--- + The argument list for user applications. e.g.: + "\"arg1\",\"arg2\",\"arg3\"" + +config TTY_LAUNCH_PRIORITY + int "TTY launch program priority" + default INIT_PRIORITY + +config TTY_LAUNCH_STACKSIZE + hex "TTY launch program stack size" + default INIT_STACKSIZE + +choice + prompt "TTY launch method" + default TTY_LAUNCH_ENTRY + +config TTY_LAUNCH_ENTRY + bool "TTY launch program" + +config TTY_LAUNCH_FILE + bool "TTY launch file" + depends on !BINFMT_DISABLE + +endchoice + +config TTY_LAUNCH_ENTRYPOINT + string "TTY launch program entry" + depends on TTY_LAUNCH_ENTRY + default INIT_ENTRYPOINT + +config TTY_LAUNCH_ENTRYNAME + string "TTY launch program name" + depends on TTY_LAUNCH_ENTRY + default TTY_LAUNCH_ENTRYPOINT + +config TTY_LAUNCH_FILEPATH + string "TTY launch file path" + depends on TTY_LAUNCH_FILE + default INIT_FILEPATH + ---help--- + The name of the entry point for user applications. For the example + applications this is of the form 'app_main' where 'app' is the application + name. If not defined, USER_ENTRYPOINT defaults to "main". + +endif # TTY_LAUNCH + config TTY_FORCE_PANIC bool "Enable TTY force crash" default n diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index f02316ba602..84c58a770fe 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -45,6 +45,8 @@ #include #include #include +#include +#include /**************************************************************************** * Pre-processor Definitions @@ -105,6 +107,16 @@ static int uart_ioctl(FAR struct file *filep, static int uart_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup); +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_TTY_LAUNCH_ENTRY +/* Lanch program entry, this must be supplied by the application. */ + +int CONFIG_TTY_LAUNCH_ENTRYPOINT(int argc, char *argv[]); +#endif + /**************************************************************************** * Private Data ****************************************************************************/ @@ -123,6 +135,10 @@ static const struct file_operations g_serialops = #endif }; +#ifdef CONFIG_TTY_LAUNCH +static struct work_s g_serial_work; +#endif + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -1609,6 +1625,58 @@ errout: return ret; } +/**************************************************************************** + * Name: uart_nxsched_foreach_cb + ****************************************************************************/ + +#ifdef CONFIG_TTY_LAUNCH +static void uart_launch_foreach(FAR struct tcb_s *tcb, FAR void *arg) +{ +#ifdef CONFIG_TTY_LAUNCH_ENTRY + if (!strcmp(tcb->name, CONFIG_TTY_LAUNCH_ENTRYNAME)) +#else + if (!strcmp(tcb->name, CONFIG_TTY_LAUNCH_FILEPATH)) +#endif + { + *(int *)arg = 1; + } +} + +static void uart_launch_worker(void *arg) +{ +#ifdef CONFIG_TTY_LAUNCH_ARGS + FAR char *const argv[] = + { + CONFIG_TTY_LAUNCH_ARGS, + NULL, + }; +#else + FAR char *const *argv = NULL; +#endif + int found = 0; + + nxsched_foreach(uart_launch_foreach, &found); + if (!found) + { +#ifdef CONFIG_TTY_LAUNCH_ENTRY + nxtask_create(CONFIG_TTY_LAUNCH_ENTRYNAME, + CONFIG_TTY_LAUNCH_PRIORITY, + CONFIG_TTY_LAUNCH_STACKSIZE, + (main_t)CONFIG_TTY_LAUNCH_ENTRYPOINT, + argv); +#else + posix_spawnattr_t attr; + + posix_spawnattr_init(&attr); + + attr.priority = CONFIG_TTY_LAUNCH_PRIORITY; + attr.stacksize = CONFIG_TTY_LAUNCH_STACKSIZE; + exec_spawn(CONFIG_TTY_LAUNCH_FILEPATH, argv, NULL, 0, &attr); +#endif + } +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -1817,3 +1885,19 @@ void uart_reset_sem(FAR uart_dev_t *dev) nxsem_reset(&dev->recv.sem, 1); nxsem_reset(&dev->pollsem, 1); } + +/**************************************************************************** + * Name: uart_launch + * + * Description: + * This function is called when user want launch a new program by + * using a special char. + * + ****************************************************************************/ + +#ifdef CONFIG_TTY_LAUNCH +void uart_launch(void) +{ + work_queue(HPWORK, &g_serial_work, uart_launch_worker, NULL, 0); +} +#endif diff --git a/drivers/serial/serial_dma.c b/drivers/serial/serial_dma.c index b328c5d9875..4a0cbb8c9a1 100644 --- a/drivers/serial/serial_dma.c +++ b/drivers/serial/serial_dma.c @@ -57,7 +57,7 @@ ****************************************************************************/ #if defined(CONFIG_TTY_SIGINT) || defined(CONFIG_TTY_SIGTSTP) || \ - defined(CONFIG_TTY_FORCE_PANIC) + defined(CONFIG_TTY_FORCE_PANIC) || defined(CONFIG_TTY_LAUNCH) static int uart_check_signo(int pid, const char *buf, size_t size) { size_t i; @@ -72,6 +72,14 @@ static int uart_check_signo(int pid, const char *buf, size_t size) } #endif +#ifdef CONFIG_TTY_LAUNCH + if (buf[i] == CONFIG_TTY_LAUNCH_CHAR) + { + uart_launch(); + return 0; + } +#endif + #ifdef CONFIG_TTY_SIGINT if (pid > 0 && buf[i] == CONFIG_TTY_SIGINT_CHAR) { @@ -105,7 +113,7 @@ static int uart_check_signo(int pid, const char *buf, size_t size) #if defined(CONFIG_SERIAL_RXDMA) && \ (defined(CONFIG_TTY_SIGINT) || defined(CONFIG_TTY_SIGTSTP) || \ - defined(CONFIG_TTY_FORCE_PANIC)) + defined(CONFIG_TTY_FORCE_PANIC) || defined(CONFIG_TTY_LAUNCH)) static int uart_recvchars_signo(FAR uart_dev_t *dev) { FAR struct uart_dmaxfer_s *xfer = &dev->dmarx; @@ -369,7 +377,7 @@ void uart_recvchars_done(FAR uart_dev_t *dev) FAR struct uart_buffer_s *rxbuf = &dev->recv; size_t nbytes = xfer->nbytes; #if defined(CONFIG_TTY_SIGINT) || defined(CONFIG_TTY_SIGTSTP) || \ - defined(CONFIG_TTY_FORCE_PANIC) + defined(CONFIG_TTY_FORCE_PANIC) || defined(CONFIG_TTY_LAUNCH) int signo = 0; /* Check if the SIGINT character is anywhere in the newly received DMA diff --git a/drivers/serial/serial_io.c b/drivers/serial/serial_io.c index 3add7e9edcd..35cf83e4c02 100644 --- a/drivers/serial/serial_io.c +++ b/drivers/serial/serial_io.c @@ -252,6 +252,17 @@ void uart_recvchars(FAR uart_dev_t *dev) } else #endif +#ifdef CONFIG_TTY_LAUNCH + /* Is this the special character that will generate the SIGTSTP + * signal? + */ + + if ((dev->tc_lflag & ISIG) && ch == CONFIG_TTY_LAUNCH_CHAR) + { + uart_launch(); + } + else +#endif /* If the RX buffer becomes full, then the serial data is discarded. * This is necessary because on most serial hardware, you must read diff --git a/include/nuttx/serial/serial.h b/include/nuttx/serial/serial.h index d5aa79313d8..293a1c935ca 100644 --- a/include/nuttx/serial/serial.h +++ b/include/nuttx/serial/serial.h @@ -495,6 +495,19 @@ void uart_recvchars_done(FAR uart_dev_t *dev); void uart_reset_sem(FAR uart_dev_t *dev); +/**************************************************************************** + * Name: uart_lanch + * + * Description: + * This function is called when user want lanch a new program by + * using a special char. + * + ****************************************************************************/ + +#ifdef CONFIG_TTY_LAUNCH +void uart_launch(void); +#endif + #undef EXTERN #if defined(__cplusplus) } diff --git a/tools/cfgdefine.c b/tools/cfgdefine.c index 87ecb87d9e4..0405584dfb5 100644 --- a/tools/cfgdefine.c +++ b/tools/cfgdefine.c @@ -60,6 +60,8 @@ static const char *dequote_list[] = "CONFIG_PASS1_BUILDIR", /* Pass1 build directory */ "CONFIG_PASS1_TARGET", /* Pass1 build target */ "CONFIG_PASS1_OBJECT", /* Pass1 build object */ + "CONFIG_TTY_LAUNCH_ENTRYPOINT", /* Name of entry point from tty launch */ + "CONFIG_TTY_LAUNCH_ARGS", /* Argument list of entry point from tty launch */ /* NxWidgets/NxWM */