diff --git a/example/config b/example/config index c208fba..2c01505 100644 --- a/example/config +++ b/example/config @@ -29,6 +29,7 @@ color = bold rs-485 = disable response-wait = disable alert = none +script-run = always # Sub-configurations @@ -63,3 +64,10 @@ device = /dev/ttyUSB0 rs-485 = enable rs-485-config = RTS_ON_SEND=1,RTS_AFTER_SEND=1,RTS_DELAY_BEFORE_SEND=60,RTS_DELAY_AFTER_SEND=80,RX_DURING_TX color = 13 + +[esp32] +device = /dev/ttyUSB0 +color = 14 +script = high(DTR); low(RTS); msleep(100); low(DTR); high(RTS); msleep(100); low(RTS) +script-run = always + diff --git a/example/control-lines-test.lua b/example/control-lines-test.lua new file mode 100644 index 0000000..9f0d493 --- /dev/null +++ b/example/control-lines-test.lua @@ -0,0 +1,7 @@ +high(DTR) +low(RTS) +msleep(100) +low(DTR) +high(RTS) +msleep(100) +low(RTS) diff --git a/man/tio.1.in b/man/tio.1.in index 97ef873..41138de 100644 --- a/man/tio.1.in +++ b/man/tio.1.in @@ -103,7 +103,7 @@ Enable local echo. Enable line timestamp. .TP -.BR " \-\-timestamp-format \fI +.BR " \-\-timestamp\-format \fI Set timestamp format to any of the following timestamp formats: .RS @@ -137,12 +137,12 @@ tio_DEVICE_YYYY-MM-DDTHH:MM:SS.log. The filename can be manually set using the \-\-log-file option. .TP -.BR " \-\-log-file \fI +.BR " \-\-log\-file \fI Set log filename. .TP -.BR " \-\-log-append +.BR " \-\-log\-append Append to log file. @@ -228,7 +228,7 @@ At present there is a hardcoded limit of 16 clients connected at one time. .RE .TP -.BR \-r ", " \-\-response-wait +.BR \-r ", " \-\-response\-wait Wait for line response then quit. A line is considered any string terminated with a NL character. If no line is received tio will quit after response @@ -279,6 +279,23 @@ will sound the bell twice or blink twice on disconnect. Default value is "none". +.TP +.BR "\-\-script \fI + +Run script from string. + +.TP +.BR "\-\-script\-file \fI + +Run script from file with filename. + +.TP +.BR "\-\-script\-run once|always|never" + +Run script on connect once, always, or never. + +Default value is "always". + .TP .BR \-v ", " \-\-version @@ -317,6 +334,8 @@ Toggle MSB to LSB bit order Pulse serial port line .IP "\fBctrl-t q" Quit +.IP "\fBctrl-t r" +Run script .IP "\fBctrl-t s" Show TX/RX statistics .IP "\fBctrl-t t" @@ -341,6 +360,26 @@ Bytes can be sent in this mode by typing the \fBtwo-character hexadecimal\fR representation of the value, e.g.: to send \fI0xA\fR you must type \fI0a\fR or \fI0A\fR. +.SH "SCRIPT API" +.PP +Tio suppots Lua scripting for manipulating the tty device. In addition to the +Lua API tio makes the following functions available: + +.TP 6n +.IP "\fBhigh(line)" +Set tty line high. +.IP "\fBlow(line)" +Set tty line low. +.IP "\fBtoggle(line)" +Toggle the tty line. +.IP "\fBsleep(seconds)" +Sleep for seconds. +.IP "\fBmsleep(ms)" +Sleep for miliseconds. + +.TP 0n +Note: Line can be any of DTR, RTS, CTS, DSR, CD, RI + .SH "CONFIGURATION FILE" .PP Options can be set via configuration file using the INI format. \fBtio\fR uses @@ -428,6 +467,12 @@ Enable RS-485 mode Set RS-485 configuration .IP "\fBalert" Set alert action on connect/disconnect +.IP "\fBscript" +Run script from string +.IP "\fBscript-file" +Run script from file +.IP "\fBscript-run" +Run script on connect. .SH "CONFIGURATION FILE EXAMPLES" @@ -582,6 +627,12 @@ Enable RS-485 mode: $ tio --rs-485 --rs-485-config=RTS_ON_SEND=1,RX_DURING_TX /dev/ttyUSB0 +.TP +Script manipulation of DTR and RTS lines upon first connect: + +$ tio --script "high(DTR); low(RTS); msleep(100); toggle(DTR)" --script-run once /dev/ttyUSB0 + + .SH "WEBSITE" .PP Visit https://tio.github.io diff --git a/src/bash-completion/tio.in b/src/bash-completion/tio.in index 908f7a3..6466db1 100644 --- a/src/bash-completion/tio.in +++ b/src/bash-completion/tio.in @@ -37,6 +37,9 @@ _tio() --rs-485-config \ --alert \ --mute \ + --script \ + --script-file \ + --script-run \ -v --version \ -h --help" @@ -151,6 +154,18 @@ _tio() COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) return 0 ;; + --script) + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + ;; + --script-file) + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + ;; + --script-run) + COMPREPLY=( $(compgen -W "once always never" -- ${cur}) ) + return 0 + ;; -v | --version) COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) return 0 diff --git a/src/configfile.c b/src/configfile.c index ef97f31..2e50e05 100644 --- a/src/configfile.c +++ b/src/configfile.c @@ -60,6 +60,9 @@ struct config_t char *log_filename; char *socket; char *map; + char *script; + char *script_filename; + bool script_run; }; static struct config_t c; @@ -297,6 +300,20 @@ static int data_handler(void *user, const char *section, const char *name, { // Do nothing } + else if (!strcmp(name, "script")) + { + asprintf(&c.script, "%s", value); + option.script = c.script; + } + else if (!strcmp(name, "script-file")) + { + asprintf(&c.script_filename, "%s", value); + option.script_filename = c.script_filename; + } + else if (!strcmp(name, "script-run")) + { + option.script_run = script_run_option_parse(value); + } else { tio_warning_printf("Unknown option '%s' in configuration file, ignored", name); diff --git a/src/meson.build b/src/meson.build index 2b4a0fe..dddddd5 100644 --- a/src/meson.build +++ b/src/meson.build @@ -18,14 +18,27 @@ tio_sources = [ 'rs485.c', 'timestamp.c', 'alert.c', - 'xymodem.c' + 'xymodem.c', + 'script.c' ] + +foreach name: ['lua-5.4', 'lua-5.3', 'lua-5.2', 'lua-5.1', 'lua'] + lua_dep = dependency(name, version: '>=5.1', required: false) + if lua_dep.found() + break + endif +endforeach +if not lua_dep.found() + error('Lua could not be found!') +endif + tio_dep = [ dependency('threads', required: true), dependency('inih', required: true, fallback : ['libinih', 'inih_dep'], - default_options: ['default_library=static', 'distro_install=false']) + default_options: ['default_library=static', 'distro_install=false']), + lua_dep ] tio_c_args = ['-Wno-unused-result'] diff --git a/src/options.c b/src/options.c index 88e2379..1f70122 100644 --- a/src/options.c +++ b/src/options.c @@ -39,6 +39,7 @@ #include "timestamp.h" #include "alert.h" #include "log.h" +#include "script.h" enum opt_t { @@ -54,6 +55,9 @@ enum opt_t OPT_ALERT, OPT_COMPLETE_SUB_CONFIGS, OPT_MUTE, + OPT_SCRIPT, + OPT_SCRIPT_FILE, + OPT_SCRIPT_RUN, }; /* Default options */ @@ -96,6 +100,9 @@ struct option_t option = .rs485_delay_rts_after_send = -1, .alert = ALERT_NONE, .complete_sub_configs = false, + .script = NULL, + .script_filename = NULL, + .script_run = SCRIPT_RUN_ALWAYS, }; void print_help(char *argv[]) @@ -134,6 +141,9 @@ void print_help(char *argv[]) printf(" --rs-485-config Set RS-485 configuration\n"); printf(" --alert bell|blink|none Alert on connect/disconnect (default: none)\n"); printf(" --mute Mute tio\n"); + printf(" --script Run script from string\n"); + printf(" --script-file Run script from file\n"); + printf(" --script-run once|always|never Run script on connect (default: always)\n"); printf(" -v, --version Display version\n"); printf(" -h, --help Display help\n"); printf("\n"); @@ -202,6 +212,27 @@ void line_pulse_duration_option_parse(const char *arg) free(buffer); } +enum script_run_t script_run_option_parse(const char *arg) +{ + if (strcmp("once", arg) == 0) + { + return SCRIPT_RUN_ONCE; + } + else if (strcmp("always", arg) == 0) + { + return SCRIPT_RUN_ALWAYS; + } + else if (strcmp("never", arg) == 0) + { + return SCRIPT_RUN_NEVER; + } + else + { + tio_error_printf("Invalid script run option"); + exit(EXIT_FAILURE); + } +} + void options_print() { tio_printf(" Device: %s", option.tty_device); @@ -276,6 +307,9 @@ void options_parse(int argc, char *argv[]) {"rs-485-config", required_argument, 0, OPT_RS485_CONFIG }, {"alert", required_argument, 0, OPT_ALERT }, {"mute", no_argument, 0, OPT_MUTE }, + {"script", required_argument, 0, OPT_SCRIPT }, + {"script-file", required_argument, 0, OPT_SCRIPT_FILE }, + {"script-run", required_argument, 0, OPT_SCRIPT_RUN }, {"version", no_argument, 0, 'v' }, {"help", no_argument, 0, 'h' }, {"complete-sub-configs", no_argument, 0, OPT_COMPLETE_SUB_CONFIGS}, @@ -439,6 +473,18 @@ void options_parse(int argc, char *argv[]) option.mute = true; break; + case OPT_SCRIPT: + option.script = optarg; + break; + + case OPT_SCRIPT_FILE: + option.script_filename = optarg; + break; + + case OPT_SCRIPT_RUN: + option.script_run = script_run_option_parse(optarg); + break; + case 'v': printf("tio v%s\n", VERSION); exit(EXIT_SUCCESS); diff --git a/src/options.h b/src/options.h index f1f2f73..e909b98 100644 --- a/src/options.h +++ b/src/options.h @@ -26,6 +26,7 @@ #include #include #include +#include "script.h" #include "timestamp.h" #include "alert.h" @@ -69,6 +70,9 @@ struct option_t int32_t rs485_delay_rts_after_send; enum alert_t alert; bool complete_sub_configs; + const char *script; + const char *script_filename; + enum script_run_t script_run; }; extern struct option_t option; @@ -78,3 +82,4 @@ void options_parse(int argc, char *argv[]); void options_parse_final(int argc, char *argv[]); void line_pulse_duration_option_parse(const char *arg); +enum script_run_t script_run_option_parse(const char *arg); diff --git a/src/script.c b/src/script.c new file mode 100644 index 0000000..c736a50 --- /dev/null +++ b/src/script.c @@ -0,0 +1,280 @@ +/* + * tio - a simple serial terminal I/O tool + * + * Copyright (c) 2014-2024 Martin Lund + * + * 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 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "print.h" +#include "options.h" +#include "tty.h" + +static int serial_fd; + +// lua: sleep(seconds) +static int sleep_(lua_State *L) +{ + long seconds = lua_tointeger(L, 1); + + if (seconds < 0) + { + return 0; + } + + tio_printf("Sleeping %ld seconds", seconds); + + sleep(seconds); + + return 0; +} + +// lua: msleep(miliseconds) +static int msleep(lua_State *L) +{ + long mseconds = lua_tointeger(L, 1); + long useconds = mseconds * 1000; + + if (useconds < 0) + { + return 0; + } + + tio_printf("Sleeping %ld ms", mseconds); + usleep(useconds); + + return 0; +} + +static void script_line_set(int line, bool value) +{ + switch (line) + { + case TIOCM_DTR: + tty_line_set(serial_fd, "DTR", line, value); + break; + case TIOCM_RTS: + tty_line_set(serial_fd, "RTS", line, value); + break; + case TIOCM_CTS: + tty_line_set(serial_fd, "CTS", line, value); + break; + case TIOCM_DSR: + tty_line_set(serial_fd, "DSR", line, value); + break; + case TIOCM_CD: + tty_line_set(serial_fd, "CD", line, value); + break; + case TIOCM_RI: + tty_line_set(serial_fd, "RI", line, value); + break; + default: + break; + } +} + +static void script_line_toggle(int line) +{ + switch (line) + { + case TIOCM_DTR: + tty_line_toggle(serial_fd, "DTR", line); + break; + case TIOCM_RTS: + tty_line_toggle(serial_fd, "RTS", line); + break; + case TIOCM_CTS: + tty_line_toggle(serial_fd, "CTS", line); + break; + case TIOCM_DSR: + tty_line_toggle(serial_fd, "DSR", line); + break; + case TIOCM_CD: + tty_line_toggle(serial_fd, "CD", line); + break; + case TIOCM_RI: + tty_line_toggle(serial_fd, "RI", line); + break; + default: + break; + } +} + +// lua: high(line) +static int high(lua_State *L) +{ + long line = lua_tointeger(L, 1); + + if (line < 0) + { + return 0; + } + + script_line_set(line, LINE_HIGH); + + return 0; +} + +// lua: low(line) +static int low(lua_State *L) +{ + long line = lua_tointeger(L, 1); + + if (line < 0) + { + return 0; + } + + script_line_set(line, LINE_LOW); + + return 0; +} + +// lua: toggle(line) +static int toggle(lua_State *L) +{ + long line = lua_tointeger(L, 1); + + if (line < 0) + { + return 0; + } + + script_line_toggle(line); + + return 0; +} + +static void script_buffer_run(lua_State *L, const char *script_buffer) +{ + int error; + + error = luaL_loadbuffer(L, script_buffer, strlen(script_buffer), "tio") || + lua_pcall(L, 0, 0, 0); + if (error) + { + tio_warning_printf("%s\n", lua_tostring(L, -1)); + lua_pop(L, 1); /* pop error message from the stack */ + } +} + +static const struct luaL_Reg tio_lib[] = +{ + { "sleep", sleep_}, + { "msleep", msleep}, + { "high", high}, + { "low", low}, + { "toggle", toggle}, + {NULL, NULL} +}; + +#if !defined LUA_VERSION_NUM || LUA_VERSION_NUM==501 +/* +** Adapted from Lua 5.2.0 (for backwards compatibility) +*/ +static void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) +{ + luaL_checkstack(L, nup+1, "too many upvalues"); + for (; l->name != NULL; l++) { /* fill the table with given functions */ + int i; + lua_pushstring(L, l->name); + for (i = 0; i < nup; i++) /* copy upvalues to the top */ + lua_pushvalue(L, -(nup+1)); + lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ + lua_settable(L, -(nup + 3)); + } + lua_pop(L, nup); /* remove upvalues */ +} +#endif + +int lua_register_tio(lua_State *L) +{ + // Register lxi functions + lua_getglobal(L, "_G"); + luaL_setfuncs(L, tio_lib, 0); + lua_pop(L, 1); + + return 0; +} + +void script_file_run(lua_State *L, const char *filename) +{ + if (strlen(filename) == 0) + { + tio_warning_printf("Missing script filename\n"); + return; + } + + if (luaL_dofile(L, filename)) + { + tio_warning_printf("%s\n", lua_tostring(L, -1)); + lua_pop(L, 1); /* pop error message from the stack */ + return; + } +} + +void script_set_global(lua_State *L, const char *name, long value) +{ + lua_pushnumber(L, value); + lua_setglobal(L, name); +} + +void script_set_globals(lua_State *L) +{ + script_set_global(L, "DTR", TIOCM_DTR); + script_set_global(L, "RTS", TIOCM_RTS); + script_set_global(L, "CTS", TIOCM_CTS); + script_set_global(L, "DSR", TIOCM_DSR); + script_set_global(L, "CD", TIOCM_CD); + script_set_global(L, "RI", TIOCM_RI); +} + +void script_run(int fd) +{ + lua_State *L; + + serial_fd = fd; + + L = luaL_newstate(); + luaL_openlibs(L); + + // Bind tio functions + lua_register_tio(L); + + // Initialize globals + script_set_globals(L); + + if (option.script_filename != NULL) + { + tio_printf("Running script %s", option.script_filename); + script_file_run(L, option.script_filename); + } + else if (option.script != NULL) + { + tio_printf("Running script"); + script_buffer_run(L, option.script); + } + + lua_close(L); +} diff --git a/src/script.h b/src/script.h new file mode 100644 index 0000000..0ea0faf --- /dev/null +++ b/src/script.h @@ -0,0 +1,32 @@ +/* + * tio - a simple serial terminal I/O tool + * + * Copyright (c) 2014-2024 Martin Lund + * + * 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 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#pragma once + +enum script_run_t +{ + SCRIPT_RUN_ONCE, + SCRIPT_RUN_ALWAYS, + SCRIPT_RUN_NEVER, + SCRIPT_RUN_END, +}; + +void script_run(int fd); diff --git a/src/tty.c b/src/tty.c index e8ba150..6921d04 100644 --- a/src/tty.c +++ b/src/tty.c @@ -55,6 +55,7 @@ #include "alert.h" #include "timestamp.h" #include "misc.h" +#include "script.h" /* tty device listing configuration */ @@ -103,6 +104,7 @@ #define KEY_M 0x6D #define KEY_P 0x70 #define KEY_Q 0x71 +#define KEY_R 0x72 #define KEY_S 0x73 #define KEY_T 0x74 #define KEY_U 0x55 @@ -111,12 +113,12 @@ #define KEY_Y 0x79 #define KEY_Z 0x7a -enum line_mode_t +typedef enum { LINE_OFF, LINE_TOGGLE, LINE_PULSE -}; +} tty_line_mode_t; const char random_array[] = { @@ -424,67 +426,87 @@ static void output_hex(char c) } } -static void toggle_line(const char *line_name, int mask, enum line_mode_t line_mode) +void tty_line_set(int fd, const char *name, int mask, bool value) { int state; - if (line_mode == LINE_TOGGLE) + if (ioctl(fd, TIOCMGET, &state) < 0) { - // Toggle line - if (ioctl(fd, TIOCMGET, &state) < 0) - { - tio_warning_printf("Could not get line state (%s)", strerror(errno)); - } - else - { - if (state & mask) - { - state &= ~mask; - tio_printf("Setting %s to HIGH", line_name); - } - else - { - state |= mask; - tio_printf("Setting %s to LOW", line_name); - } - if (ioctl(fd, TIOCMSET, &state) < 0) - tio_warning_printf("Could not set line state (%s)", strerror(errno)); - } - } else if (line_mode == LINE_PULSE) + tio_warning_printf("Could not get line state (%s)", strerror(errno)); + return; + } + + if (value) { - int duration = 0; - // Pulse line - toggle_line(line_name, mask, LINE_TOGGLE); - switch (mask) - { - case TIOCM_DTR: - duration = option.dtr_pulse_duration; - break; - case TIOCM_RTS: - duration = option.rts_pulse_duration; - break; - case TIOCM_CTS: - duration = option.cts_pulse_duration; - break; - case TIOCM_DSR: - duration = option.dsr_pulse_duration; - break; - case TIOCM_CD: - duration = option.dcd_pulse_duration; - break; - case TIOCM_RI: - duration = option.ri_pulse_duration; - break; - default: - duration = 0; - break; - } - if (duration > 0) - { - tio_printf("Waiting %d ms", duration); - delay(duration); - } - toggle_line(line_name, mask, LINE_TOGGLE); + state &= ~mask; + tio_printf("Setting %s to HIGH", name); + } + else + { + state |= mask; + tio_printf("Setting %s to LOW", name); + } + + if (ioctl(fd, TIOCMSET, &state) < 0) + { + tio_warning_printf("Could not set line state (%s)", strerror(errno)); + } +} + +void tty_line_toggle(int fd, const char *line_name, int mask) +{ + int state; + + if (ioctl(fd, TIOCMGET, &state) < 0) + { + tio_warning_printf("Could not get line state (%s)", strerror(errno)); + return; + } + + if (state & mask) + { + state &= ~mask; + tio_printf("Setting %s to HIGH", line_name); + } + else + { + state |= mask; + tio_printf("Setting %s to LOW", line_name); + } + + if (ioctl(fd, TIOCMSET, &state) < 0) + { + tio_warning_printf("Could not set line state (%s)", strerror(errno)); + } +} + +static void tty_line_pulse(int fd, const char *line_name, int mask, unsigned int duration) +{ + tty_line_toggle(fd, line_name, mask); + + if (duration > 0) + { + tio_printf("Waiting %d ms", duration); + delay(duration); + } + + tty_line_toggle(fd, line_name, mask); +} + +static void tty_line_poke(int fd, const char *name, int mask, tty_line_mode_t mode, unsigned int duration) +{ + switch (mode) + { + case LINE_TOGGLE: + tty_line_toggle(fd, name, mask); + break; + + case LINE_PULSE: + tty_line_pulse(fd, name, mask, duration); + break; + + case LINE_OFF: + break; } } @@ -520,7 +542,7 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward) char unused_char; bool unused_bool; int state; - static enum line_mode_t line_mode = LINE_OFF; + static tty_line_mode_t line_mode = LINE_OFF; static char previous_char = 0; /* Ignore unused arguments */ @@ -534,29 +556,29 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward) forward = &unused_bool; } + // Handle tty line toggle and pulse action if (line_mode) { - // Handle line toggle number action *forward = false; switch (input_char) { case KEY_0: - toggle_line("DTR", TIOCM_DTR, line_mode); + tty_line_poke(fd, "DTR", TIOCM_DTR, line_mode, option.dtr_pulse_duration); break; case KEY_1: - toggle_line("RTS", TIOCM_RTS, line_mode); + tty_line_poke(fd, "RTS", TIOCM_RTS, line_mode, option.rts_pulse_duration); break; case KEY_2: - toggle_line("CTS", TIOCM_CTS, line_mode); + tty_line_poke(fd, "CTS", TIOCM_CTS, line_mode, option.cts_pulse_duration); break; case KEY_3: - toggle_line("DSR", TIOCM_DSR, line_mode); + tty_line_poke(fd, "DSR", TIOCM_DSR, line_mode, option.dsr_pulse_duration); break; case KEY_4: - toggle_line("DCD", TIOCM_CD, line_mode); + tty_line_poke(fd, "DCD", TIOCM_CD, line_mode, option.dcd_pulse_duration); break; case KEY_5: - toggle_line("RI", TIOCM_RI, line_mode); + tty_line_poke(fd, "RI", TIOCM_RI, line_mode, option.ri_pulse_duration); break; default: tio_warning_printf("Invalid line number"); @@ -601,6 +623,7 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward) tio_printf(" ctrl-%c m Toggle MSB to LSB bit order", option.prefix_key); tio_printf(" ctrl-%c p Pulse serial port line", option.prefix_key); tio_printf(" ctrl-%c q Quit", option.prefix_key); + tio_printf(" ctrl-%c r Run script", option.prefix_key); tio_printf(" ctrl-%c s Show statistics", option.prefix_key); tio_printf(" ctrl-%c t Toggle line timestamp mode", option.prefix_key); tio_printf(" ctrl-%c U Toggle conversion to uppercase on output", option.prefix_key); @@ -726,6 +749,11 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward) /* Exit upon ctrl-t q sequence */ exit(EXIT_SUCCESS); + case KEY_R: + /* Run script */ + script_run(fd); + break; + case KEY_S: /* Show tx/rx statistics upon ctrl-t s sequence */ tio_printf("Statistics:"); @@ -1383,6 +1411,17 @@ int tty_connect(void) } } + /* Manage script activation */ + if (option.script_run != SCRIPT_RUN_NEVER) + { + script_run(fd); + + if (option.script_run == SCRIPT_RUN_ONCE) + { + option.script_run = SCRIPT_RUN_NEVER; + } + } + /* Input loop */ while (true) { diff --git a/src/tty.h b/src/tty.h index add8bf1..4c667ef 100644 --- a/src/tty.h +++ b/src/tty.h @@ -23,6 +23,9 @@ #include +#define LINE_HIGH true +#define LINE_LOW false + extern bool interactive_mode; extern bool map_i_nl_cr; extern bool map_i_cr_nl; @@ -36,3 +39,5 @@ void tty_wait_for_device(void); void list_serial_devices(void); void tty_input_thread_create(void); void tty_input_thread_wait_ready(void); +void tty_line_set(int fd, const char *name, int mask, bool value); +void tty_line_toggle(int fd, const char *name, int mask);