diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..60663b5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# Prerequisites +*.d + +# Object files +*.o + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.so +*.so.* + +# qt-creator +*.config +*.cflags +*.cxxflags +*.creator* +*.files +*.includes diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..eb946aa --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,69 @@ +cmake_minimum_required(VERSION 3.0) +set(PROJ tty_term) +set(MINOR_VERSION "1") +set(MID_VERSION "0") +set(MAJOR_VERSION "0") +set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}") + +project(${PROJ} VERSION ${PROJ_VERSION} LANGUAGES C) +#enable_language(C) + +message("VER: ${VERSION}") + +# default flags +set(CMAKE_C_FLAGS_RELEASE "") +set(CMAKE_C_FLAGS_DEBUG "") +set(CMAKE_C_FLAGS "-O2 -std=gnu99") + +set(CMAKE_COLOR_MAKEFILE ON) + +# here is one of two variants: all .c in directory or .c files in list +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} SOURCES) + +# cmake -DDEBUG=1 -> debugging +if(DEFINED EBUG) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra -Wall -Werror -W") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra -Wall -Werror -W") + set(CMAKE_BUILD_TYPE DEBUG) + set(CMAKE_VERBOSE_MAKEFILE "ON") + add_definitions(-DEBUG) +else() + set(CMAKE_BUILD_TYPE RELEASE) +endif() + +###### pkgconfig ###### +# pkg-config modules (for pkg-check-modules) +set(MODULES usefull_macros) + +# find packages: +find_package(PkgConfig REQUIRED) +pkg_check_modules(${PROJ} REQUIRED ${MODULES}) + +###### additional flags ###### +#list(APPEND ${PROJ}_LIBRARIES "-lfftw3_threads") + +# change wrong behaviour with install prefix +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT AND CMAKE_INSTALL_PREFIX MATCHES "/usr/local") +else() + message("Change default install path to /usr/local") + set(CMAKE_INSTALL_PREFIX "/usr/local") +endif() +message("Install dir prefix: ${CMAKE_INSTALL_PREFIX}") + +# exe file +add_executable(${PROJ} ${SOURCES}) +# -I +include_directories(${${PROJ}_INCLUDE_DIRS}) +# -L +link_directories(${${PROJ}_LIBRARY_DIRS}) +# -D +add_definitions(${CFLAGS} -DLOCALEDIR=\"${LOCALEDIR}\" + -DPACKAGE_VERSION=\"${VERSION}\" -DGETTEXT_PACKAGE=\"${PROJ}\" + -DMINOR_VERSION=\"${MINOR_VERSION}\" -DMID_VERSION=\"${MID_VERSION}\" + -DMAJOR_VERSION=\"${MAJOR_VESION}\") + +# -l +target_link_libraries(${PROJ} ${${PROJ}_LIBRARIES} -lm) + +# Installation of the program +INSTALL(TARGETS ${PROJ} DESTINATION "bin") diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..1115f3c --- /dev/null +++ b/Readme.md @@ -0,0 +1,11 @@ +Very simple terminal client +=========================== + + Usage: tty_term [args] + + Where args are: + + -d, --devname=arg serial device name + -e, --eol=arg end of line: n, r or rn + -h, --help show this help + -s, --speed=arg baudrate (default: 9600) diff --git a/cmdlnopts.c b/cmdlnopts.c new file mode 100644 index 0000000..12c9ab8 --- /dev/null +++ b/cmdlnopts.c @@ -0,0 +1,75 @@ +/* + * This file is part of the ttyterm project. + * Copyright 2020 Edward V. Emelianov . + * + * 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 3 of the License, 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 // assert +#include // printf +#include // memcpy +#include +#include "cmdlnopts.h" + +/* + * here are global parameters initialisation + */ +static int help; +static glob_pars G; + +// DEFAULTS +// default global parameters +glob_pars const Gdefault = { + .speed = 9600, + .ttyname = "/dev/ttyUSB0", + .eol = "n", +}; + +/* + * Define command line options by filling structure: + * name has_arg flag val type argptr help +*/ +static myoption cmdlnopts[] = { + // set 1 to param despite of its repeating number: + {"help", NO_ARGS, NULL, 'h', arg_int, APTR(&help), _("show this help")}, + {"speed", NEED_ARG, NULL, 's', arg_int, APTR(&G.speed), _("baudrate (default: 9600)")}, + {"devname", NEED_ARG, NULL, 'd', arg_string, APTR(&G.ttyname), _("serial device name")}, + {"eol", NEED_ARG, NULL, 'e', arg_string, APTR(&G.eol), _("end of line: n, r or rn")}, + end_option +}; + +/** + * Parse command line options and return dynamically allocated structure + * to global parameters + * @param argc - copy of argc from main + * @param argv - copy of argv from main + * @return allocated structure with global parameters + */ +glob_pars *parse_args(int argc, char **argv){ + void *ptr = memcpy(&G, &Gdefault, sizeof(G)); assert(ptr); + // format of help: "Usage: progname [args]\n" + change_helpstring(_("Usage: %s [args]\n\n\tWhere args are:\n")); + // parse arguments + parseargs(&argc, &argv, cmdlnopts); + if(help) showhelp(-1, cmdlnopts); + if(argc > 0){ + WARNX("Wrong arguments:\n"); + for(int i = 0; i < argc; i++) + fprintf(stderr, "\t%s\n", argv[i]); + signals(9); + } + return &G; +} + diff --git a/cmdlnopts.h b/cmdlnopts.h new file mode 100644 index 0000000..2ffac8f --- /dev/null +++ b/cmdlnopts.h @@ -0,0 +1,37 @@ +/* + * This file is part of the ttyterm project. + * Copyright 2020 Edward V. Emelianov . + * + * 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 3 of the License, 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 . + */ + +#pragma once +#ifndef CMDLNOPTS_H__ +#define CMDLNOPTS_H__ + +/* + * here are some typedef's for global data + */ +typedef struct{ + int speed; // baudrate + char *ttyname; // device name + char *eol; // end of line: \r (CR), \rn (CR+LF) or \n (LF): "r", "rn", "n" +} glob_pars; + + +// default & global parameters +extern glob_pars const Gdefault; + +glob_pars *parse_args(int argc, char **argv); +#endif // CMDLNOPTS_H__ diff --git a/main.c b/main.c new file mode 100644 index 0000000..fb51e2e --- /dev/null +++ b/main.c @@ -0,0 +1,83 @@ +/* + * This file is part of the ttyterm project. + * Copyright 2020 Edward V. Emelianov . + * + * 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 3 of the License, 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 // strcmp +#include +#include "cmdlnopts.h" +#include "tty.h" + +// we don't need more than 64 bytes for TTY input buffer - USB CDC can't transmit more in one packet +#define BUFLEN 65 + +static TTY_descr *dev = NULL; + +void signals(int signo){ + restore_console(); + if(dev) close_tty(&dev); + exit(signo); +} + +typedef enum{ + EOL_N = 0, + EOL_R, + EOL_RN +} eol_t; + +int main(int argc, char **argv){ + glob_pars *G = NULL; // default parameters see in cmdlnopts.c + initial_setup(); + G = parse_args(argc, argv); + dev = new_tty(G->ttyname, G->speed, BUFLEN); + if(!dev || !(dev = tty_open(dev, 1))) return 1; // open exclusively + eol_t eol = EOL_N; + if(strcmp(G->eol, "n")){ // change eol + if(strcmp(G->eol, "r") == 0) eol = EOL_R; + else if(strcmp(G->eol, "rn") == 0) eol = EOL_RN; + else ERRX("End of line should be \"r\", \"n\" or \"rn\""); + } + signal(SIGTERM, signals); // kill (-15) - quit + signal(SIGHUP, signals); // hup - quit + signal(SIGINT, signals); // ctrl+C - quit + signal(SIGQUIT, signals); // ctrl+\ - quit + signal(SIGTSTP, SIG_IGN); // ignore ctrl+Z + setup_con(); + const char r = '\r'; + while(1){ + int b; + int l = read_ttyX(dev, &b); + if(l < 0) signals(9); + if(b > -1){ + char c = (char)b; + if(c == '\n' && eol != EOL_N){ // !\n + if(eol == EOL_R) c = '\r'; // \r + else if(write_tty(dev->comfd, &r, 1)) WARN("write_tty()"); // \r\n + } + if(write_tty(dev->comfd, &c, 1)) WARN("write_tty()"); + } + if(l){ + printf("%s", dev->buf); + fflush(stdout); + // if(fout) copy_buf_to_file(buff, &oldcmd); + } + } + // never reached + return 0; +} + diff --git a/tty.c b/tty.c new file mode 100644 index 0000000..e2a9990 --- /dev/null +++ b/tty.c @@ -0,0 +1,97 @@ +/* + * This file is part of the ttyterm project. + * Copyright 2020 Edward V. Emelianov . + * + * 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 3 of the License, 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 // getchar +#include +#include "tty.h" + +/** + * @brief read_ttyX- read data from TTY & console with 1ms timeout WITH disconnect detection + * @param buff (o) - buffer for data read + * @param length - buffer len + * @param rb (o) - byte read from console or -1 + * @return amount of bytes read on tty or -1 if disconnected + */ +int read_ttyX(TTY_descr *d, int *rb){ + if(!d || d->comfd < 0) return -1; + ssize_t L = 0; + fd_set rfds; + struct timeval tv; + int retval; + if(rb) *rb = -1; + FD_ZERO(&rfds); + FD_SET(STDIN_FILENO, &rfds); + FD_SET(d->comfd, &rfds); + // wait for 1ms + tv.tv_sec = 0; tv.tv_usec = 1000; + retval = select(d->comfd + 1, &rfds, NULL, NULL, &tv); + if(!retval) return 0; + if(retval < 0){ + WARN("select()"); + return -1; + } + if(FD_ISSET(STDIN_FILENO, &rfds) && rb){ + *rb = getchar(); + } + if(FD_ISSET(d->comfd, &rfds)){ + if((L = read(d->comfd, d->buf, d->bufsz)) < 1){ + WARN("read()"); + return -1; // disconnect or other error - close TTY & die + } + } + d->buflen = (size_t)L; + d->buf[L] = 0; + return (int)L; +} + + +#if 0 +/** + * Copy line by line buffer buff to file removing cmd starting from newline + * @param buffer - data to put into file + * @param cmd - symbol to remove from line startint (if found, change *cmd to (-1) + * or NULL, (-1) if no command to remove + */ +void copy_buf_to_file(char *buffer, int *cmd){ + char *buff, *line, *ptr; + if(!cmd || *cmd < 0){ + fprintf(fout, "%s", buffer); + return; + } + buff = strdup(buffer), ptr = buff; + do{ + if(!*ptr) break; + if(ptr[0] == (char)*cmd){ + *cmd = -1; + ptr++; + if(ptr[0] == '\n') ptr++; + if(!*ptr) break; + } + line = ptr; + ptr = strchr(buff, '\n'); + if(ptr){ + *ptr++ = 0; + fprintf(fout, "%s\n", line); + }else + fprintf(fout, "%s", line); // no newline found in buffer +// fprintf(fout, "%s\n", line); + }while(ptr); + free(buff); +} + +#endif diff --git a/tty.h b/tty.h new file mode 100644 index 0000000..fb00a0b --- /dev/null +++ b/tty.h @@ -0,0 +1,27 @@ +/* + * This file is part of the ttyterm project. + * Copyright 2020 Edward V. Emelianov . + * + * 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 3 of the License, 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 . + */ + +#pragma once +#ifndef TTY_H__ +#define TTY_H__ + +#include + +int read_ttyX(TTY_descr *d, int *rb); + +#endif // TTY_H__