serial: add CONFIG_TTY_LAUNCH support

this allow user start new program from tty

Signed-off-by: ligd <liguiding1@xiaomi.com>
This commit is contained in:
ligd 2021-12-15 13:40:45 +08:00 committed by Xiang Xiao
parent cff2bc05e0
commit 75aec04330
7 changed files with 200 additions and 3 deletions

View File

@ -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.

View File

@ -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

View File

@ -45,6 +45,8 @@
#include <nuttx/serial/serial.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/power/pm.h>
#include <nuttx/wqueue.h>
#include <nuttx/kthread.h>
/****************************************************************************
* 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

View File

@ -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

View File

@ -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

View File

@ -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)
}

View File

@ -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 */