This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
The following commit(s) were added to refs/heads/master by this push:
new be038ce40 system: Add stty utility for terminal control
be038ce40 is described below
commit be038ce406beb630efb2f29e2837eac33beebc85
Author: fangpeina <[email protected]>
AuthorDate: Tue Dec 16 23:27:53 2025 +0800
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 <[email protected]>
---
system/stty/CMakeLists.txt | 33 ++++
system/stty/Kconfig | 26 +++
system/stty/Make.defs | 24 +++
system/stty/Makefile | 32 ++++
system/stty/stty_main.c | 390 +++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 505 insertions(+)
diff --git a/system/stty/CMakeLists.txt b/system/stty/CMakeLists.txt
new file mode 100644
index 000000000..55108d2e1
--- /dev/null
+++ b/system/stty/CMakeLists.txt
@@ -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()
diff --git a/system/stty/Kconfig b/system/stty/Kconfig
new file mode 100644
index 000000000..29bb3045b
--- /dev/null
+++ b/system/stty/Kconfig
@@ -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
+
diff --git a/system/stty/Make.defs b/system/stty/Make.defs
new file mode 100644
index 000000000..b149ed6d5
--- /dev/null
+++ b/system/stty/Make.defs
@@ -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
+
diff --git a/system/stty/Makefile b/system/stty/Makefile
new file mode 100644
index 000000000..2e6cd2ee1
--- /dev/null
+++ b/system/stty/Makefile
@@ -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
diff --git a/system/stty/stty_main.c b/system/stty/stty_main.c
new file mode 100644
index 000000000..57d0e6052
--- /dev/null
+++ b/system/stty/stty_main.c
@@ -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;
+}