From d94449ac8bbc4e0833aa014cb30b67552327f2c1 Mon Sep 17 00:00:00 2001 From: Yaroslav Veremenko Date: Mon, 14 Oct 2024 20:54:42 -0600 Subject: [PATCH] util: ucom - micro serial console --- Applications/util/Makefile.generic | 1 + Applications/util/fuzix-util.pkg | 2 + Applications/util/ucom.1 | 49 +++++++ Applications/util/ucom.c | 223 +++++++++++++++++++++++++++++ 4 files changed, 275 insertions(+) create mode 100644 Applications/util/ucom.1 create mode 100644 Applications/util/ucom.c diff --git a/Applications/util/Makefile.generic b/Applications/util/Makefile.generic index a1f9b43d76..d110f37186 100644 --- a/Applications/util/Makefile.generic +++ b/Applications/util/Makefile.generic @@ -72,6 +72,7 @@ SRCS = \ mail.c \ man.c \ manscan.c \ + ucom.c \ mkfs.c \ mode.c \ more.c \ diff --git a/Applications/util/fuzix-util.pkg b/Applications/util/fuzix-util.pkg index 858fe31b5f..14cca04de5 100644 --- a/Applications/util/fuzix-util.pkg +++ b/Applications/util/fuzix-util.pkg @@ -119,6 +119,7 @@ f 0755 /bin/uniq uniq f 0755 /bin/uptime uptime f 0755 /bin/uud uud f 0755 /bin/uue uue +f 0755 /bin/ucom ucom f 0755 /bin/vile vile l /bin/vile /bin/vi f 0755 /bin/wc wc @@ -130,3 +131,4 @@ f 0755 /bin/write write f 0755 /bin/xargs xargs f 0755 /bin/yes yes +f 0655 /usr/man/man1/ucom.1 ucom.1 diff --git a/Applications/util/ucom.1 b/Applications/util/ucom.1 new file mode 100644 index 0000000000..2fdff04d51 --- /dev/null +++ b/Applications/util/ucom.1 @@ -0,0 +1,49 @@ +.TH ucom 1 "FUZIX System Utilities" "FUZIX" +.SH NAME +ucom \- simple serial console. +.SH SYNOPSIS +.B ucom +[\-s speed] device +.SH DESCRIPTION +Simple and minimal terminal emulator program, to use with modems and alike. +.P +Just like other terminal emulator progrms +.B ucom +supports escape sequence to execute a command in +.B ucom +itself. +.SH OPTIONS +.TP +.B "-s speed" +Set speed of the +.B device +in baud before connecting. + +.SH COMMANDS +Commands are executed by first inputing +.I escape character +( +.B ESC +) which by default is +.B ^A. + +.TP +.B "ESC q" +Quit program and restore +.B device termios +to the previous settings. + +.TP +.B "ESC ESC" +Print escape character verbatim. + +.SH EXAMPLES +.P +ucom /dev/tty2 +.P +man -s 300 /dev/tty2 +.SH BUGS +To be found. +.SH AUTHORS +Yaroslav Veremenko +.SH SEE ALSO diff --git a/Applications/util/ucom.c b/Applications/util/ucom.c new file mode 100644 index 0000000000..546d75f2d2 --- /dev/null +++ b/Applications/util/ucom.c @@ -0,0 +1,223 @@ +/* ucom.c - Simple serial console. + * + * Copyright (C) 2024 Yaroslav Veremenko, All rights reserved. + * + * This file is part of FUZIX Operating System. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct termios termsave[2]; +static struct termios termcur[2]; +static int remotefd = -1; +static speed_t speed = 0; +static char escape = 1; +static int opt, i; +static char buf[2]; +static pid_t child; +static char *remotename; + +static int baud[] = { + 50, /* B50 */ + 75, /* B75 */ + 110, /* B110 */ + 134, /* B134 */ + 150, /* B150 */ + 300, /* B300 */ + 600, /* B600 */ + 1200, /* B1200 */ + 2400, /* B2400 */ + 4800, /* B4800 */ + 9600, /* B9600 */ + 19200, /* B19200 */ + 38400, /* B38400 */ + 57600, /* B57600 */ + 115200, /* B115200 */ +}; + +static speed_t baudflg[] = { + B50, + B75, + B110, + B134, + B150, + B300, + B600, + B1200, + B2400, + B4800, + B9600, + B19200, + B38400, + B57600, + B115200, +}; + +#ifndef uint_fast8_t +#define uint_fast8_t char +#endif + +#define TTY 0 +#define REMOTE 1 + +static void term_raw(int fd, int type) +{ + tcgetattr(fd, &termsave[type]); + memcpy(&termcur[type], &termsave[type], sizeof(struct termios)); + cfmakeraw(&termcur[type]); + termcur[type].c_cc[VMIN] = 1; + termcur[type].c_cc[VTIME] = 0; + tcsetattr(fd, TCSAFLUSH, &termcur[type]); +} + +static void restore() +{ + tcsetattr(0, TCSAFLUSH, &termsave[TTY]); + if (remotefd >= 0) + { + tcsetattr(remotefd, TCSAFLUSH, &termsave[REMOTE]); + close(remotefd); + } +} + +static void quit() +{ + int status; + kill(child, SIGHUP); + wait(&status); +} + +static void usage() +{ + fputs("Micro terminal program.\n" + "Usage: ucom [-s SPEED] DEVICE\n\n" + " DEVICE\t- tty or other character device\n" + " -s SPEED\t- set device speed in baud\n" + " ^A\t\t- default escape character\n" + " ESC q\t\t- exit terminal\n", stderr); +} + +int main(int argc, char *argv[]) +{ + if (isatty(0) != 1) + { + fputs("fd 0 is not tty\n", stderr); + exit(1); + } + + while ((opt = getopt(argc, argv, "s:")) != -1) + { + switch (opt) + { + case 's': + speed = atoi(optarg); + for (i = 0; i < sizeof(baud); i++) + { + if (baud[i] == speed) + { + speed = baudflg[i]; + break; + } + } + break; + default: + usage(); + exit(1); + break; + } + } + + argv += optind; + argc -= optind; + + if (argc != 1) + { + usage(); + exit(1); + } + + remotename = *argv; + remotefd = open(remotename, O_RDWR | O_NOCTTY); + + if (remotefd < 0) + { + perror(remotename); + exit(1); + } + + term_raw(0, TTY); + term_raw(remotefd, REMOTE); + + if (speed > 0) + { + if (cfsetospeed(&termcur[REMOTE], (speed_t)speed) < 0 || + tcsetattr(remotefd, TCSAFLUSH, &termcur[REMOTE]) < 0) + { + restore(); + perror("speed"); + exit(1); + } + } + + child = fork(); + if (child < 0) + { + restore(); + perror("fork"); + exit(1); + } + if (child == 0) + { + while (read(remotefd, &buf[0], 1) > 0) + { + write(0, &buf[0], 1); + } + fputs("Disconnected\r\n", stderr); + } + else + { + uint_fast8_t isEscape = 0; + atexit(restore); + fprintf(stderr, "Connected. Escape character ^%c\r\n", '@' + escape); + while (read(0, &buf[1], 1) > 0) + { + if (!isEscape && buf[1] == escape) + { + isEscape = 1; + continue; + } + if (isEscape && buf[1] == 'q') + { + break; + } + isEscape = 0; + write(remotefd, &buf[1], 1); + } + quit(); + } +} \ No newline at end of file