From 26ebd60ef8a3983dcef6dca9d8370d56465be79b Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 13 Dec 2014 10:34:11 -0600 Subject: . --- apps/system/cu/.gitignore | 11 ++ apps/system/cu/Kconfig | 17 ++ apps/system/cu/Makefile | 138 +++++++++++++++ apps/system/cu/cu.h | 80 +++++++++ apps/system/cu/cu_main.c | 430 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 676 insertions(+) create mode 100644 apps/system/cu/.gitignore create mode 100644 apps/system/cu/Kconfig create mode 100644 apps/system/cu/Makefile create mode 100644 apps/system/cu/cu.h create mode 100644 apps/system/cu/cu_main.c (limited to 'apps/system') diff --git a/apps/system/cu/.gitignore b/apps/system/cu/.gitignore new file mode 100644 index 000000000..fa1ec7579 --- /dev/null +++ b/apps/system/cu/.gitignore @@ -0,0 +1,11 @@ +/Make.dep +/.depend +/.built +/*.asm +/*.obj +/*.rel +/*.lst +/*.sym +/*.adb +/*.lib +/*.src diff --git a/apps/system/cu/Kconfig b/apps/system/cu/Kconfig new file mode 100644 index 000000000..22d3dfd9e --- /dev/null +++ b/apps/system/cu/Kconfig @@ -0,0 +1,17 @@ +# +# For a description of the syntax of this configuration file, +# see misc/tools/kconfig-language.txt. +# + +config SYSTEM_CUTERM + bool "CU serial terminal" + default n + ---help--- + Enable the CU serial terminal. This is a minimalistic + implementation of the 'cu' terminal program (part of Taylor UUCP for + ages). Using it, you can simply open a serial port and interact with + it. Using '~.' you can leave the terminal program and drop back to nsh. + + This terminal might come in handy for other people that have e.g. GS + modems, GPS receivers or other devices with text based serial + communications attached to their Nuttx systems. diff --git a/apps/system/cu/Makefile b/apps/system/cu/Makefile new file mode 100644 index 000000000..3a3416f8c --- /dev/null +++ b/apps/system/cu/Makefile @@ -0,0 +1,138 @@ +############################################################################ +# apps/examples/cu/Makefile +# +# Copyright (C) 2011-2013 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# USB terminal example + +ASRCS = +CSRCS = +MAINSRC = cu_main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) +MAINOBJ = $(MAINSRC:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) $(MAINSRC) +OBJS = $(AOBJS) $(COBJS) + +ifneq ($(CONFIG_BUILD_KERNEL),y) + OBJS += $(MAINOBJ) +endif + +ifeq ($(CONFIG_WINDOWS_NATIVE),y) + BIN = ..\..\libapps$(LIBEXT) +else +ifeq ($(WINTOOL),y) + BIN = ..\\..\\libapps$(LIBEXT) +else + BIN = ../../libapps$(LIBEXT) +endif +endif + +ifeq ($(WINTOOL),y) + INSTALL_DIR = "${shell cygpath -w $(BIN_DIR)}" +else + INSTALL_DIR = $(BIN_DIR) +endif + +CONFIG_XYZ_PROGNAME ?= cu$(EXEEXT) +PROGNAME = $(CONFIG_XYZ_PROGNAME) + +ROOTDEPPATH = --dep-path . + +# Built-in application info + +APPNAME = cu +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +# Common build + +VPATH = + +all: .built +.PHONY: context clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS) $(MAINOBJ): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + $(call ARCHIVE, $(BIN), $(OBJS)) + @touch .built + +ifeq ($(CONFIG_BUILD_KERNEL),y) +$(BIN_DIR)$(DELIM)$(PROGNAME): $(OBJS) $(MAINOBJ) + @echo "LD: $(PROGNAME)" + $(Q) $(LD) $(LDELFFLAGS) $(LDLIBPATH) -o $(INSTALL_DIR)$(DELIM)$(PROGNAME) $(ARCHCRT0OBJ) $(MAINOBJ) $(LDLIBS) + $(Q) $(NM) -u $(INSTALL_DIR)$(DELIM)$(PROGNAME) + +install: $(BIN_DIR)$(DELIM)$(PROGNAME) + +else +install: + +endif + +ifeq ($(CONFIG_NSH_BUILTIN_APPS),y) +$(BUILTIN_REGISTRY)$(DELIM)$(APPNAME)_main.bdat: $(DEPCONFIG) Makefile + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + +context: $(BUILTIN_REGISTRY)$(DELIM)$(APPNAME)_main.bdat +else +context: +endif + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + $(call DELFILE, .built) + $(call CLEAN) + +distclean: clean + $(call DELFILE, Make.dep) + $(call DELFILE, .depend) + +-include Make.dep + diff --git a/apps/system/cu/cu.h b/apps/system/cu/cu.h new file mode 100644 index 000000000..98b656f72 --- /dev/null +++ b/apps/system/cu/cu.h @@ -0,0 +1,80 @@ +/**************************************************************************** + * system/cu/cu.h + * + * Copyright (C) 2014 sysmocom - s.f.m.c. GmbH. All rights reserved. + * Author: Harald Welte + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_SYSTEM_CU_CUTERM_H +#define __APPS_SYSTEM_CU_CUTERM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* All terminal state data is packaged in a single structure to minimize + * name conflicts with other global symbols -- a poor man's name space. + */ + +struct cu_globals_s +{ + int infd; /* Incmoming data from serial port */ + int outfd; /* Outgoing data to serial port */ + pthread_t listener; /* Terminal listener thread */ +}; + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/* terminal state data */ + +extern struct cu_globals_s g_cu; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#endif /* __APPS_SYSTEM_CU_CUTERM_H */ diff --git a/apps/system/cu/cu_main.c b/apps/system/cu/cu_main.c new file mode 100644 index 000000000..b4fef578c --- /dev/null +++ b/apps/system/cu/cu_main.c @@ -0,0 +1,430 @@ +/**************************************************************************** + * examples/cu/cu_main.c + * + * Copyright (C) 2014 sysmocom - s.f.m.c. GmbH. All rights reserved. + * Author: Harald Welte + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "cu.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define SIGINT 2 +#define SIGKILL 9 +#define SIGTERM 15 + +enum parity_mode +{ + PARITY_NONE, + PARITY_EVEN, + PARITY_ODD, +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* terminal state data */ + +struct cu_globals_s g_cu; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cu_listener + * + * Description: + * Entry point for the listener thread. + * + ****************************************************************************/ + +static FAR void *cu_listener(FAR void *parameter) +{ + for (;;) + { + int rc; + char ch; + + rc = read(g_cu.infd, &ch, 1); + if (rc <= 0) + { + break; + } + + fputc(ch, stdout); + fflush(stdout); + } + + /* Won't get here */ + + return NULL; +} + +static void sigint(int sig) +{ + pthread_cancel(g_cu.listener); + close(g_cu.outfd); + close(g_cu.infd); + exit(0); +} + +static int enable_crlf_conversion(int fd) +{ +#ifdef CONFIG_SERIAL_TERMIOS + int rc = 0; + int ret; + struct termios tio; + + /* enable \n -> \r\n conversion during write */ + + ret = tcgetattr(fd, &tio); + if (ret) + { + fprintf(stderr, "en_crlf_conv: ERROR during tcgetattr(): %d\n", errno); + rc = -1; + } + + tio.c_oflag = OPOST | ONLCR; + ret = tcsetattr(fd, TCSANOW, &tio); + if (ret) + { + fprintf(stderr, "en_crlf_conv: ERROR during tcsetattr(): %d\n", errno); + rc = -1; + } + + return rc; +#else + return -1; +#endif +} + +static int set_baudrate(int fd, int rate, enum parity_mode parity, int rtscts) +{ +#ifdef CONFIG_SERIAL_TERMIOS + int rc = 0; + int ret; + struct termios tio; + + /* enable \n -> \r\n conversion during write */ + + ret = tcgetattr(fd, &tio); + if (ret) + { + fprintf(stderr, "set_baudrate: ERROR during tcgetattr(): %d\n", errno); + rc = -1; + } + + if (rate != 0) + { + cfsetspeed(&tio, rate); + } + + switch (parity) + { + case PARITY_EVEN: + tio.c_cflag = PARENB; + break; + + case PARITY_ODD: + tio.c_cflag = PARENB | PARODD; + break; + + case PARITY_NONE: + break; + } + + if (rtscts) + { + tio.c_cflag |= CRTS_IFLOW | CCTS_OFLOW; + } + + ret = tcsetattr(fd, TCSANOW, &tio); + if (ret) + { + fprintf(stderr, "set_baudrate: ERROR during tcsetattr(): %d\n", errno); + rc = -1; + } + + return rc; +#else + if (rate == 0) + { + return 0; + } + + return -1; +#endif +} + +static void print_help(void) +{ + printf("Usage: cu [options]\n" + " -l: Use named device (e.g. /dev/ttyS1)\n" + " -e: Set even parity\n" + " -o: Set odd parity\n" + " -s: Use given speed\n" + " -r: Disable RTS/CTS flow control (default: on)\n" + " -?: This help\n"); +} + +static void print_escape_help(void) +{ + printf("[Escape sequences]\n" + "[~. hangup]\n" + ); +} + +static int cu_cmd(char bcmd) +{ + switch (bcmd) + { + case '?': + print_escape_help(); + break; + + case '.': + return 1; + + /* FIXME: implement other commands such as send/receive file */ + } + + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cu_main + * + * Description: + * Main entry point for the serial terminal example. + * + ****************************************************************************/ + +#ifdef CONFIG_BUILD_KERNEL +int main(int argc, FAR char *argv[]) +#else +int cu_main(int argc, FAR char *argv[]) +#endif +{ + pthread_attr_t attr; + struct sigaction sa; + FAR char *devname = NULL; + int baudrate = 0; + enum parity_mode parity = PARITY_NONE; + int rtscts = 1; + int option; + int ret; + int bcmd; + int start_of_line = 1; + + /* Initialize global data */ + + memset(&g_cu, 0, sizeof(struct cu_globals_s)); + + /* Install signal handlers */ + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = sigint; + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGKILL, &sa, NULL); + + while ((option = getopt(argc, argv, "l:s:eor?")) != ERROR) + { + switch (option) + { + case 'l': + devname = optarg; + break; + + case 's': + baudrate = atoi(optarg); + break; + + case 'e': + parity = PARITY_ODD; + break; + + case 'o': + parity = PARITY_EVEN; + break; + + case 'r': + rtscts = 0; + break; + + case '?': + print_help(); + return EXIT_SUCCESS; + + default: + return EXIT_FAILURE; + } + } + + /* Open the serial device for writing */ + + g_cu.outfd = open(devname, O_WRONLY); + if (g_cu.outfd < 0) + { + fprintf(stderr, "cu_main: ERROR: Failed to open %s for writing: %d\n", + devname, errno); + goto errout_with_devinit; + } + + enable_crlf_conversion(g_cu.outfd); + set_baudrate(g_cu.outfd, baudrate, parity, rtscts); + + /* Open the serial device for reading. Since we are already connected, this + * should not fail. + */ + + g_cu.infd = open(devname, O_RDONLY); + if (g_cu.infd < 0) + { + fprintf(stderr, "cu_main: ERROR: Failed to open %s for reading: %d\n", + devname, errno); + goto errout_with_outfd; + } + + /* Start the serial receiver thread */ + + ret = pthread_attr_init(&attr); + if (ret != OK) + { + fprintf(stderr, "cu_main: pthread_attr_init failed: %d\n", ret); + goto errout_with_fds; + } + + ret = pthread_create(&g_cu.listener, &attr, + cu_listener, (pthread_addr_t)0); + if (ret != 0) + { + fprintf(stderr, "cu_main: Error in thread creation: %d\n", ret); + goto errout_with_fds; + } + + /* Send messages and get responses -- forever */ + + for (;;) + { + int ch = getc(stdin); + + if (ch <= 0) + { + break; + } + + if (start_of_line == 1 && ch == '~') + { + /* we've seen and escape (~) character, echo it to local + * terminal and read the next char from serial + */ + + fputc(ch, stdout); + bcmd = getc(stdin); + if (bcmd == ch) + { + /* Escaping a tilde: handle like normal char */ + + write(g_cu.outfd, &ch, 1); + continue; + } + else + { + if (cu_cmd(bcmd) == 1) + { + break; + } + } + } + + /* Normal character */ + + write(g_cu.outfd, &ch, 1); + + /* Determine if we are now at the start of a new line or not */ + + if (ch == '\n' || ch == '\r') + { + start_of_line = 1; + } + else + { + start_of_line = 0; + } + } + + pthread_cancel(g_cu.listener); + pthread_attr_destroy(&attr); + + /* Error exits */ + +errout_with_fds: + close(g_cu.infd); +errout_with_outfd: + close(g_cu.outfd); +errout_with_devinit: + return EXIT_FAILURE; +} -- cgit v1.2.3