mirror of
https://github.com/apache/nuttx-apps.git
synced 2026-08-16 01:43:17 +00:00
system: Add stty utility for terminal control
This commit adds a system utily 'stty' to NuttX, providing a standard Unix-like interface for configuring terminal (TTY) device settings. The command allows runtime configuration of termios attributes for serial ports and other character devices. Usage examples: # Set raw mode on ttyS0 (for binary communication) nsh> stty -F /dev/ttyS0 raw -echo # Set console mode for interactive terminal nsh> stty -F /dev/ttyS0 cooked # Display current settings nsh> stty -F /dev/ttyS0 # Configure stdin (if it's a TTY) nsh> stty echo icanon # Set baudrate (if driver support) nsh> stty -F /dev/ttyS1 speed 115200 Signed-off-by: fangpeina <fangpeina@xiaomi.com>
This commit is contained in:
parent
860815a33a
commit
be038ce406
5 changed files with 505 additions and 0 deletions
33
system/stty/CMakeLists.txt
Normal file
33
system/stty/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# ##############################################################################
|
||||
# apps/system/stty/CMakeLists.txt
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more contributor
|
||||
# license agreements. See the NOTICE file distributed with this work for
|
||||
# additional information regarding copyright ownership. The ASF licenses this
|
||||
# file to you under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy of
|
||||
# the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations under
|
||||
# the License.
|
||||
#
|
||||
# ##############################################################################
|
||||
|
||||
if(CONFIG_SYSTEM_STTY)
|
||||
nuttx_add_application(
|
||||
MODULE
|
||||
${CONFIG_SYSTEM_STTY}
|
||||
NAME
|
||||
stty
|
||||
STACKSIZE
|
||||
${CONFIG_SYSTEM_STTY_STACKSIZE}
|
||||
PRIORITY
|
||||
${CONFIG_SYSTEM_STTY_PRIORITY}
|
||||
SRCS
|
||||
stty_main.c)
|
||||
endif()
|
||||
26
system/stty/Kconfig
Normal file
26
system/stty/Kconfig
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see the file kconfig-language.txt in the NuttX tools repository.
|
||||
#
|
||||
|
||||
menuconfig SYSTEM_STTY
|
||||
tristate "stty - set terminal options"
|
||||
default n
|
||||
depends on SERIAL_TERMIOS
|
||||
---help---
|
||||
Enable the stty command to configure terminal (TTY) settings.
|
||||
This command allows you to view and change terminal attributes
|
||||
such as echo, canonical mode, and line endings.
|
||||
|
||||
if SYSTEM_STTY
|
||||
|
||||
config SYSTEM_STTY_PRIORITY
|
||||
int "stty task priority"
|
||||
default 100
|
||||
|
||||
config SYSTEM_STTY_STACKSIZE
|
||||
int "stty stack size"
|
||||
default DEFAULT_TASK_STACKSIZE
|
||||
|
||||
endif # SYSTEM_STTY
|
||||
|
||||
24
system/stty/Make.defs
Normal file
24
system/stty/Make.defs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
############################################################################
|
||||
# apps/system/stty/Make.defs
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more contributor
|
||||
# license agreements. See the NOTICE file distributed with this work for
|
||||
# additional information regarding copyright ownership. The ASF licenses this
|
||||
# file to you under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy of
|
||||
# the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations under
|
||||
# the License.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
ifneq ($(CONFIG_SYSTEM_STTY),)
|
||||
CONFIGURED_APPS += $(APPDIR)/system/stty
|
||||
endif
|
||||
|
||||
32
system/stty/Makefile
Normal file
32
system/stty/Makefile
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
############################################################################
|
||||
# apps/system/stty/Makefile
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more contributor
|
||||
# license agreements. See the NOTICE file distributed with this work for
|
||||
# additional information regarding copyright ownership. The ASF licenses this
|
||||
# file to you under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy of
|
||||
# the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations under
|
||||
# the License.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
include $(APPDIR)/Make.defs
|
||||
|
||||
# stty - set terminal options
|
||||
|
||||
PROGNAME = stty
|
||||
PRIORITY = $(CONFIG_SYSTEM_STTY_PRIORITY)
|
||||
STACKSIZE = $(CONFIG_SYSTEM_STTY_STACKSIZE)
|
||||
MODULE = $(CONFIG_SYSTEM_STTY)
|
||||
|
||||
MAINSRC = stty_main.c
|
||||
|
||||
include $(APPDIR)/Application.mk
|
||||
390
system/stty/stty_main.c
Normal file
390
system/stty/stty_main.c
Normal file
|
|
@ -0,0 +1,390 @@
|
|||
/****************************************************************************
|
||||
* apps/system/stty/stty_main.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define stty_error(...) dprintf(STDERR_FILENO, __VA_ARGS__)
|
||||
#define FLAG_STR(flags, flag) ((flags) & (flag) ? "" : "-")
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static void print_usage(FAR const char *progname)
|
||||
{
|
||||
printf("Usage: %s [-F device] [settings...]\n", progname);
|
||||
printf("\nSettings:\n");
|
||||
printf(" raw - Set raw mode (no processing)\n");
|
||||
printf(" cooked - Set cooked mode (canonical)\n");
|
||||
printf(" echo - Enable echo\n");
|
||||
printf(" -echo - Disable echo\n");
|
||||
printf(" icanon - Enable canonical mode\n");
|
||||
printf(" -icanon - Disable canonical mode\n");
|
||||
printf(" icrnl - Map CR to NL on input\n");
|
||||
printf(" -icrnl - Don't map CR to NL\n");
|
||||
printf(" onlcr - Map NL to CR-NL on output\n");
|
||||
printf(" -onlcr - Don't map NL to CR-NL\n");
|
||||
printf(" opost - Enable output processing\n");
|
||||
printf(" -opost - Disable output processing\n");
|
||||
printf(" isig - Enable signal characters\n");
|
||||
printf(" -isig - Disable signal characters\n");
|
||||
printf(" speed N - Set baud rate\n");
|
||||
printf(" min N - Set minimum characters for read (0-255)\n");
|
||||
printf(" time N - Set read timeout in 0.1s units (0-255)\n");
|
||||
printf("\nExamples:\n");
|
||||
printf(" %s -F /dev/ttyS0 raw -echo", progname);
|
||||
printf(" # Raw mode, no echo\n");
|
||||
printf(" %s -F /dev/ttyS0 cooked", progname);
|
||||
printf(" # Interactive terminal mode\n");
|
||||
}
|
||||
|
||||
static int parse_numeric_param(int argc, FAR char *argv[], FAR int *idx,
|
||||
int min, int max)
|
||||
{
|
||||
int val;
|
||||
if (*idx + 1 >= argc)
|
||||
{
|
||||
stty_error("ERROR: %s requires a value\n", argv[*idx]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
val = atoi(argv[++(*idx)]);
|
||||
if (val < min || val > max)
|
||||
{
|
||||
stty_error("ERROR: Invalid value: %d (must be %d-%d)\n",
|
||||
val, min, max);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int apply_settings(int fd, int argc, FAR char *argv[], int idx)
|
||||
{
|
||||
struct termios tio;
|
||||
int val;
|
||||
int ret;
|
||||
|
||||
/* Get current settings */
|
||||
|
||||
ret = tcgetattr(fd, &tio);
|
||||
if (ret < 0)
|
||||
{
|
||||
stty_error("ERROR: tcgetattr failed: %d\n", errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* Parse and apply settings */
|
||||
|
||||
for (; idx < argc; idx++)
|
||||
{
|
||||
FAR const char *arg = argv[idx];
|
||||
|
||||
if (strcmp(arg, "raw") == 0)
|
||||
{
|
||||
cfmakeraw(&tio);
|
||||
}
|
||||
else if (strcmp(arg, "cooked") == 0)
|
||||
{
|
||||
/* Set cooked mode (canonical with echo) */
|
||||
|
||||
tio.c_lflag |= ICANON | ECHO | ISIG;
|
||||
tio.c_oflag |= OPOST | ONLCR;
|
||||
tio.c_iflag |= ICRNL;
|
||||
}
|
||||
else if (strcmp(arg, "echo") == 0)
|
||||
{
|
||||
tio.c_lflag |= ECHO;
|
||||
}
|
||||
else if (strcmp(arg, "-echo") == 0)
|
||||
{
|
||||
tio.c_lflag &= ~ECHO;
|
||||
}
|
||||
else if (strcmp(arg, "icanon") == 0)
|
||||
{
|
||||
tio.c_lflag |= ICANON;
|
||||
}
|
||||
else if (strcmp(arg, "-icanon") == 0)
|
||||
{
|
||||
tio.c_lflag &= ~ICANON;
|
||||
}
|
||||
else if (strcmp(arg, "icrnl") == 0)
|
||||
{
|
||||
tio.c_iflag |= ICRNL;
|
||||
}
|
||||
else if (strcmp(arg, "-icrnl") == 0)
|
||||
{
|
||||
tio.c_iflag &= ~ICRNL;
|
||||
}
|
||||
else if (strcmp(arg, "onlcr") == 0)
|
||||
{
|
||||
tio.c_oflag |= ONLCR;
|
||||
}
|
||||
else if (strcmp(arg, "-onlcr") == 0)
|
||||
{
|
||||
tio.c_oflag &= ~ONLCR;
|
||||
}
|
||||
else if (strcmp(arg, "opost") == 0)
|
||||
{
|
||||
tio.c_oflag |= OPOST;
|
||||
}
|
||||
else if (strcmp(arg, "-opost") == 0)
|
||||
{
|
||||
tio.c_oflag &= ~OPOST;
|
||||
}
|
||||
else if (strcmp(arg, "isig") == 0)
|
||||
{
|
||||
tio.c_lflag |= ISIG;
|
||||
}
|
||||
else if (strcmp(arg, "-isig") == 0)
|
||||
{
|
||||
tio.c_lflag &= ~ISIG;
|
||||
}
|
||||
else if (strcmp(arg, "inlcr") == 0)
|
||||
{
|
||||
tio.c_iflag |= INLCR;
|
||||
}
|
||||
else if (strcmp(arg, "-inlcr") == 0)
|
||||
{
|
||||
tio.c_iflag &= ~INLCR;
|
||||
}
|
||||
else if (strcmp(arg, "igncr") == 0)
|
||||
{
|
||||
tio.c_iflag |= IGNCR;
|
||||
}
|
||||
else if (strcmp(arg, "-igncr") == 0)
|
||||
{
|
||||
tio.c_iflag &= ~IGNCR;
|
||||
}
|
||||
else if (strcmp(arg, "ocrnl") == 0)
|
||||
{
|
||||
tio.c_oflag |= OCRNL;
|
||||
}
|
||||
else if (strcmp(arg, "-ocrnl") == 0)
|
||||
{
|
||||
tio.c_oflag &= ~OCRNL;
|
||||
}
|
||||
else if (strcmp(arg, "speed") == 0)
|
||||
{
|
||||
val = parse_numeric_param(argc, argv, &idx, 0, 4000000);
|
||||
if (val < 0)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
if (cfsetspeed(&tio, val) < 0)
|
||||
{
|
||||
stty_error("ERROR: Invalid speed value: %d\n", val);
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
else if (strcmp(arg, "min") == 0)
|
||||
{
|
||||
val = parse_numeric_param(argc, argv, &idx, 0, 255);
|
||||
if (val < 0)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
tio.c_cc[VMIN] = val;
|
||||
}
|
||||
else if (strcmp(arg, "time") == 0)
|
||||
{
|
||||
val = parse_numeric_param(argc, argv, &idx, 0, 255);
|
||||
if (val < 0)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
tio.c_cc[VTIME] = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
stty_error("WARNING: Unknown setting: %s\n", arg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply the new settings */
|
||||
|
||||
ret = tcsetattr(fd, TCSANOW, &tio);
|
||||
if (ret < 0)
|
||||
{
|
||||
stty_error("ERROR: tcsetattr failed: %d\n", errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
int main(int argc, FAR char *argv[])
|
||||
{
|
||||
FAR const char *device = NULL;
|
||||
int fd = STDIN_FILENO;
|
||||
int ret;
|
||||
int opt;
|
||||
int idx;
|
||||
|
||||
/* Parse -F option for device path */
|
||||
|
||||
while ((opt = getopt(argc, argv, "F:h")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'F':
|
||||
device = optarg;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
print_usage(argv[0]);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
print_usage(argv[0]);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
idx = optind;
|
||||
|
||||
/* Open device if specified, or use stdin as default */
|
||||
|
||||
if (device == NULL)
|
||||
{
|
||||
device = "stdin";
|
||||
}
|
||||
else
|
||||
{
|
||||
fd = open(device, O_RDWR | O_NONBLOCK);
|
||||
if (fd < 0)
|
||||
{
|
||||
stty_error("ERROR: Failed to open %s: %d\n", device, errno);
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isatty(fd))
|
||||
{
|
||||
stty_error("ERROR: %s is not a TTY\n", device);
|
||||
if (fd != STDIN_FILENO)
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* If no settings provided, just display current settings */
|
||||
|
||||
if (idx >= argc)
|
||||
{
|
||||
struct termios tio;
|
||||
speed_t speed;
|
||||
|
||||
memset(&tio, 0, sizeof(struct termios));
|
||||
ret = tcgetattr(fd, &tio);
|
||||
if (ret < 0)
|
||||
{
|
||||
stty_error("ERROR: tcgetattr failed: %d\n", errno);
|
||||
if (fd != STDIN_FILENO)
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
speed = cfgetispeed(&tio);
|
||||
|
||||
printf("Terminal settings for %s:\n", device);
|
||||
if (speed <= 0)
|
||||
{
|
||||
printf(" speed unknown or not supported by driver; ");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" speed %lu baud; ", speed);
|
||||
}
|
||||
|
||||
printf("min = %d; time = %d;\n", tio.c_cc[VMIN], tio.c_cc[VTIME]);
|
||||
|
||||
printf(" c_iflag: 0x%08x %sicrnl %signcr %sinlcr\n", tio.c_iflag,
|
||||
FLAG_STR(tio.c_iflag, ICRNL),
|
||||
FLAG_STR(tio.c_iflag, IGNCR),
|
||||
FLAG_STR(tio.c_iflag, INLCR));
|
||||
printf(" c_oflag: 0x%08x %sopost %sonlcr %socrnl\n", tio.c_oflag,
|
||||
FLAG_STR(tio.c_oflag, OPOST),
|
||||
FLAG_STR(tio.c_oflag, ONLCR),
|
||||
FLAG_STR(tio.c_oflag, OCRNL));
|
||||
printf(" c_lflag: 0x%08x %secho %sicanon %sisig\n", tio.c_lflag,
|
||||
FLAG_STR(tio.c_lflag, ECHO),
|
||||
FLAG_STR(tio.c_lflag, ICANON),
|
||||
FLAG_STR(tio.c_lflag, ISIG));
|
||||
printf(" c_cflag: 0x%08x %sclocal %scread %scstopb\n", tio.c_cflag,
|
||||
FLAG_STR(tio.c_cflag, CLOCAL),
|
||||
FLAG_STR(tio.c_cflag, CREAD),
|
||||
FLAG_STR(tio.c_cflag, CSTOPB));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Apply settings */
|
||||
|
||||
ret = apply_settings(fd, argc, argv, idx);
|
||||
if (ret < 0)
|
||||
{
|
||||
if (fd != STDIN_FILENO)
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
printf("Settings applied to %s\n", device);
|
||||
}
|
||||
|
||||
if (fd != STDIN_FILENO)
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue