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/cu_main.c | 430 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 430 insertions(+) create mode 100644 apps/system/cu/cu_main.c (limited to 'apps/system/cu/cu_main.c') 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