mirror of
https://github.com/tio/tio.git
synced 2026-05-01 14:57:59 +02:00
Add independent input and output mode
Replaces -x, --hexadecimal option with --intput-mode and --output-mode so it is possible to select hex or normal mode for both input and output independently. To obtain same behaviour as -x, --hexadecimal use the following configuration: input-mode = hex output-mode = hex
This commit is contained in:
parent
fd6a246908
commit
2fff4d36d0
9 changed files with 254 additions and 78 deletions
|
|
@ -46,9 +46,8 @@ when used in combination with [tmux](https://tmux.github.io).
|
|||
* Line timestamps
|
||||
* Support for delayed output per character
|
||||
* Support for delayed output per line
|
||||
* Hexadecimal mode
|
||||
* Log to file
|
||||
* Autogeneration of log filename
|
||||
* Switchable independent input and output mode (normal vs hex)
|
||||
* Log to file with automatic or manual naming of log file
|
||||
* Configuration file support
|
||||
* Activate sub-configurations by name or pattern
|
||||
* Redirect I/O to UNIX socket or IPv4/v6 network socket for scripting or TTY sharing
|
||||
|
|
|
|||
36
man/tio.1.in
36
man/tio.1.in
|
|
@ -191,9 +191,20 @@ If defining more than one flag, the flags must be comma separated.
|
|||
.RE
|
||||
|
||||
.TP
|
||||
.BR \-x ", " \-\-hexadecimal
|
||||
.BR " \-\-input\-mode " \fInormal|hex
|
||||
|
||||
Enable hexadecimal mode.
|
||||
Set input mode. In hex input mode bytes can be sent 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.
|
||||
|
||||
Default value is "normal".
|
||||
|
||||
.TP
|
||||
.BR " \-\-output\-mode " \fInormal|hex
|
||||
|
||||
Set output mode. In hex mode each incoming byte is printed out as a hex value.
|
||||
|
||||
Default value is "normal".
|
||||
|
||||
.TP
|
||||
.BR \-c ", " "\-\-color " \fI0..255|bold|none|list
|
||||
|
|
@ -329,14 +340,16 @@ Toggle log to file
|
|||
Flush data I/O buffers (discard data written but not transmitted and data received but not read)
|
||||
.IP "\fBctrl-t g"
|
||||
Toggle serial port line
|
||||
.IP "\fBctrl-t h"
|
||||
Toggle hexadecimal mode
|
||||
.IP "\fBctrl-t i"
|
||||
Toggle input mode
|
||||
.IP "\fBctrl-t l"
|
||||
Clear screen
|
||||
.IP "\fBctrl-t L"
|
||||
Show line states (DTR, RTS, CTS, DSR, DCD, RI)
|
||||
.IP "\fBctrl-t m"
|
||||
Toggle MSB to LSB bit order
|
||||
.IP "\fBctrl-t o"
|
||||
Toggle output mode
|
||||
.IP "\fBctrl-t p"
|
||||
Pulse serial port line
|
||||
.IP "\fBctrl-t q"
|
||||
|
|
@ -360,15 +373,6 @@ Send a file using the YMODEM protocol (prompts for file name)
|
|||
.IP "\fBctrl-t ctrl-t"
|
||||
Send ctrl-t character
|
||||
|
||||
.SH "HEXADECIMAL MODE"
|
||||
.PP
|
||||
In hexadecimal mode each incoming byte is printed out as a hexadecimal value.
|
||||
|
||||
.PP
|
||||
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
|
||||
|
|
@ -470,8 +474,10 @@ Set timestamp format
|
|||
Map characters on input or output
|
||||
.IP "\fBcolor"
|
||||
Colorize tio text using ANSI color code ranging from 0 to 255
|
||||
.IP "\fBhexadecimal"
|
||||
Enable hexadecimal mode
|
||||
.IP "\fBinput-mode"
|
||||
Set input mode.
|
||||
.IP "\fBoutput-mode"
|
||||
Set output mode.
|
||||
.IP "\fBsocket"
|
||||
Set socket to redirect I/O to
|
||||
.IP "\fBprefix-ctrl-key"
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ _tio()
|
|||
-L --list-devices \
|
||||
-c --color \
|
||||
-S --socket \
|
||||
-x --hexadecimal \
|
||||
--input-mode \
|
||||
--output-mode \
|
||||
-r --response-wait \
|
||||
--response-timeout \
|
||||
--rs-485 \
|
||||
|
|
@ -131,8 +132,12 @@ _tio()
|
|||
COMPREPLY=( $(compgen -W "unix: inet: inet6:" -- ${cur}) )
|
||||
return 0
|
||||
;;
|
||||
-x | --hexadecimal)
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
--input-mode)
|
||||
COMPREPLY=( $(compgen -W "normal hex" -- ${cur}) )
|
||||
return 0
|
||||
;;
|
||||
--output-mode)
|
||||
COMPREPLY=( $(compgen -W "normal hex" -- ${cur}) )
|
||||
return 0
|
||||
;;
|
||||
-r | --response-wait)
|
||||
|
|
|
|||
|
|
@ -213,9 +213,13 @@ static int data_handler(void *user, const char *section, const char *name,
|
|||
{
|
||||
option.local_echo = read_boolean(value, name);
|
||||
}
|
||||
else if (!strcmp(name, "hexadecimal"))
|
||||
else if (!strcmp(name, "input-mode"))
|
||||
{
|
||||
option.hex_mode = read_boolean(value, name);
|
||||
option.input_mode = input_mode_option_parse(value);
|
||||
}
|
||||
else if (!strcmp(name, "output-mode"))
|
||||
{
|
||||
option.output_mode = output_mode_option_parse(value);
|
||||
}
|
||||
else if (!strcmp(name, "timestamp"))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ enum opt_t
|
|||
OPT_SCRIPT,
|
||||
OPT_SCRIPT_FILE,
|
||||
OPT_SCRIPT_RUN,
|
||||
OPT_INPUT_MODE,
|
||||
OPT_OUTPUT_MODE,
|
||||
};
|
||||
|
||||
/* Default options */
|
||||
|
|
@ -89,7 +91,8 @@ struct option_t option =
|
|||
.socket = NULL,
|
||||
.map = "",
|
||||
.color = 256, // Bold
|
||||
.hex_mode = false,
|
||||
.input_mode = INPUT_MODE_NORMAL,
|
||||
.output_mode = OUTPUT_MODE_NORMAL,
|
||||
.prefix_code = 20, // ctrl-t
|
||||
.prefix_key = 't',
|
||||
.prefix_enabled = true,
|
||||
|
|
@ -137,7 +140,8 @@ void print_help(char *argv[])
|
|||
printf(" -m, --map <flags> Map characters\n");
|
||||
printf(" -c, --color 0..255|bold|none|list Colorize tio text (default: bold)\n");
|
||||
printf(" -S, --socket <socket> Redirect I/O to socket\n");
|
||||
printf(" -x, --hexadecimal Enable hexadecimal mode\n");
|
||||
printf(" --input-mode normal|hex Select input mode (default: normal)\n");
|
||||
printf(" --output-mode normal|hex Select output mode (default: normal)\n");
|
||||
printf(" -r, --response-wait Wait for line response then quit\n");
|
||||
printf(" --response-timeout <ms> Response timeout (default: 100)\n");
|
||||
printf(" --rs-485 Enable RS-485 mode\n");
|
||||
|
|
@ -215,6 +219,70 @@ void line_pulse_duration_option_parse(const char *arg)
|
|||
free(buffer);
|
||||
}
|
||||
|
||||
input_mode_t input_mode_option_parse(const char *arg)
|
||||
{
|
||||
if (strcmp("normal", arg) == 0)
|
||||
{
|
||||
return INPUT_MODE_NORMAL;
|
||||
}
|
||||
else if (strcmp("hex", arg) == 0)
|
||||
{
|
||||
return INPUT_MODE_HEX;
|
||||
}
|
||||
else
|
||||
{
|
||||
tio_error_printf("Invalid input mode option");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
output_mode_t output_mode_option_parse(const char *arg)
|
||||
{
|
||||
if (strcmp("normal", arg) == 0)
|
||||
{
|
||||
return OUTPUT_MODE_NORMAL;
|
||||
}
|
||||
else if (strcmp("hex", arg) == 0)
|
||||
{
|
||||
return OUTPUT_MODE_HEX;
|
||||
}
|
||||
else
|
||||
{
|
||||
tio_error_printf("Invalid output mode option");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
const char *input_mode_by_string(input_mode_t mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case INPUT_MODE_NORMAL:
|
||||
return "normal";
|
||||
case INPUT_MODE_HEX:
|
||||
return "hex";
|
||||
case INPUT_MODE_END:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *output_mode_by_string(output_mode_t mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case OUTPUT_MODE_NORMAL:
|
||||
return "normal";
|
||||
case OUTPUT_MODE_HEX:
|
||||
return "hex";
|
||||
case OUTPUT_MODE_END:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
enum script_run_t script_run_option_parse(const char *arg)
|
||||
{
|
||||
if (strcmp("once", arg) == 0)
|
||||
|
|
@ -255,7 +323,8 @@ void options_print()
|
|||
option.dsr_pulse_duration,
|
||||
option.dcd_pulse_duration,
|
||||
option.ri_pulse_duration);
|
||||
tio_printf(" Hexadecimal mode: %s", option.hex_mode ? "enabled" : "disabled");
|
||||
tio_printf(" Input mode: %s", input_mode_by_string(option.input_mode));
|
||||
tio_printf(" Output mode: %s", output_mode_by_string(option.output_mode));
|
||||
if (option.map[0] != 0)
|
||||
tio_printf(" Map flags: %s", option.map);
|
||||
if (option.log)
|
||||
|
|
@ -304,7 +373,8 @@ void options_parse(int argc, char *argv[])
|
|||
{"socket", required_argument, 0, 'S' },
|
||||
{"map", required_argument, 0, 'm' },
|
||||
{"color", required_argument, 0, 'c' },
|
||||
{"hexadecimal", no_argument, 0, 'x' },
|
||||
{"input-mode", required_argument, 0, OPT_INPUT_MODE },
|
||||
{"output-mode", required_argument, 0, OPT_OUTPUT_MODE },
|
||||
{"response-wait", no_argument, 0, 'r' },
|
||||
{"response-timeout", required_argument, 0, OPT_RESPONSE_TIMEOUT },
|
||||
{"rs-485", no_argument, 0, OPT_RS485 },
|
||||
|
|
@ -453,8 +523,12 @@ void options_parse(int argc, char *argv[])
|
|||
}
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
option.hex_mode = true;
|
||||
case OPT_INPUT_MODE:
|
||||
option.input_mode = input_mode_option_parse(optarg);
|
||||
break;
|
||||
|
||||
case OPT_OUTPUT_MODE:
|
||||
option.output_mode = output_mode_option_parse(optarg);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
|
|
|
|||
|
|
@ -30,6 +30,20 @@
|
|||
#include "timestamp.h"
|
||||
#include "alert.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
INPUT_MODE_NORMAL,
|
||||
INPUT_MODE_HEX,
|
||||
INPUT_MODE_END,
|
||||
} input_mode_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
OUTPUT_MODE_NORMAL,
|
||||
OUTPUT_MODE_HEX,
|
||||
OUTPUT_MODE_END,
|
||||
} output_mode_t;
|
||||
|
||||
/* Options */
|
||||
struct option_t
|
||||
{
|
||||
|
|
@ -58,7 +72,8 @@ struct option_t
|
|||
const char *map;
|
||||
const char *socket;
|
||||
int color;
|
||||
bool hex_mode;
|
||||
input_mode_t input_mode;
|
||||
output_mode_t output_mode;
|
||||
unsigned char prefix_code;
|
||||
unsigned char prefix_key;
|
||||
bool prefix_enabled;
|
||||
|
|
@ -84,3 +99,6 @@ 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);
|
||||
|
||||
input_mode_t input_mode_option_parse(const char *arg);
|
||||
output_mode_t output_mode_option_parse(const char *arg);
|
||||
|
|
|
|||
|
|
@ -73,3 +73,8 @@ void tio_printf_array(const char *array)
|
|||
}
|
||||
tio_printf("");
|
||||
}
|
||||
|
||||
void print_tainted_set()
|
||||
{
|
||||
print_tainted = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,3 +116,4 @@ void print_hex(char c);
|
|||
void print_normal(char c);
|
||||
void print_init_ansi_formatting(void);
|
||||
void tio_printf_array(const char *array);
|
||||
void print_tainted_set(void);
|
||||
|
|
|
|||
118
src/tty.c
118
src/tty.c
|
|
@ -98,10 +98,11 @@
|
|||
#define KEY_F 0x66
|
||||
#define KEY_SHIFT_F 0x46
|
||||
#define KEY_G 0x67
|
||||
#define KEY_H 0x68
|
||||
#define KEY_I 0x69
|
||||
#define KEY_L 0x6C
|
||||
#define KEY_SHIFT_L 0x4C
|
||||
#define KEY_M 0x6D
|
||||
#define KEY_O 0x6F
|
||||
#define KEY_P 0x70
|
||||
#define KEY_Q 0x71
|
||||
#define KEY_R 0x72
|
||||
|
|
@ -180,11 +181,15 @@ static void optional_local_echo(char c)
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
print(c);
|
||||
|
||||
if (option.log)
|
||||
{
|
||||
log_putc(c);
|
||||
}
|
||||
|
||||
print_tainted_set();
|
||||
}
|
||||
|
||||
inline static bool is_valid_hex(char c)
|
||||
|
|
@ -407,23 +412,29 @@ void tty_input_thread_wait_ready(void)
|
|||
pthread_mutex_lock(&mutex_input_ready);
|
||||
}
|
||||
|
||||
static void output_hex(char c)
|
||||
static void handle_hex_prompt(char c)
|
||||
{
|
||||
hex_chars[hex_char_index++] = c;
|
||||
|
||||
printf("%c", c);
|
||||
print_tainted_set();
|
||||
|
||||
if (hex_char_index == 2)
|
||||
{
|
||||
usleep(100*1000);
|
||||
if (option.local_echo == false)
|
||||
{
|
||||
printf("\b \b");
|
||||
printf("\b \b");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
unsigned char hex_value = char_to_nibble(hex_chars[0]) << 4 | (char_to_nibble(hex_chars[1]) & 0x0F);
|
||||
hex_char_index = 0;
|
||||
|
||||
optional_local_echo(hex_value);
|
||||
|
||||
ssize_t status = tty_write(fd, &hex_value, 1);
|
||||
if (status < 0)
|
||||
{
|
||||
|
|
@ -629,6 +640,23 @@ static int tio_readln(void)
|
|||
return (p - line);
|
||||
}
|
||||
|
||||
void tty_output_mode_set(output_mode_t mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case OUTPUT_MODE_NORMAL:
|
||||
print = print_normal;
|
||||
break;
|
||||
|
||||
case OUTPUT_MODE_HEX:
|
||||
print = print_hex;
|
||||
break;
|
||||
|
||||
case OUTPUT_MODE_END:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void handle_command_sequence(char input_char, char *output_char, bool *forward)
|
||||
{
|
||||
char unused_char;
|
||||
|
|
@ -709,10 +737,11 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward)
|
|||
tio_printf(" ctrl-%c f Toggle log to file", option.prefix_key);
|
||||
tio_printf(" ctrl-%c F Flush data I/O buffers", option.prefix_key);
|
||||
tio_printf(" ctrl-%c g Toggle serial port line", option.prefix_key);
|
||||
tio_printf(" ctrl-%c h Toggle hexadecimal mode", option.prefix_key);
|
||||
tio_printf(" ctrl-%c i Toggle input mode", option.prefix_key);
|
||||
tio_printf(" ctrl-%c l Clear screen", option.prefix_key);
|
||||
tio_printf(" ctrl-%c L Show line states", option.prefix_key);
|
||||
tio_printf(" ctrl-%c m Toggle MSB to LSB bit order", option.prefix_key);
|
||||
tio_printf(" ctrl-%c o Toggle output mode", 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);
|
||||
|
|
@ -803,19 +832,42 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward)
|
|||
tio_printf("Switched local echo %s", option.local_echo ? "on" : "off");
|
||||
break;
|
||||
|
||||
case KEY_H:
|
||||
/* Toggle hexadecimal printing mode */
|
||||
if (!option.hex_mode)
|
||||
case KEY_I:
|
||||
option.input_mode += 1;
|
||||
switch (option.input_mode)
|
||||
{
|
||||
print = print_hex;
|
||||
option.hex_mode = true;
|
||||
tio_printf("Switched to hexadecimal mode");
|
||||
case INPUT_MODE_NORMAL:
|
||||
break;
|
||||
|
||||
case INPUT_MODE_HEX:
|
||||
option.input_mode = INPUT_MODE_HEX;
|
||||
tio_printf("Switched to hex input mode");
|
||||
break;
|
||||
|
||||
case INPUT_MODE_END:
|
||||
option.input_mode = INPUT_MODE_NORMAL;
|
||||
tio_printf("Switched to normal input mode");
|
||||
break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
case KEY_O:
|
||||
option.output_mode += 1;
|
||||
switch (option.output_mode)
|
||||
{
|
||||
print = print_normal;
|
||||
option.hex_mode = false;
|
||||
tio_printf("Switched to normal mode");
|
||||
case OUTPUT_MODE_NORMAL:
|
||||
break;
|
||||
|
||||
case OUTPUT_MODE_HEX:
|
||||
tty_output_mode_set(OUTPUT_MODE_HEX);
|
||||
tio_printf("Switched to hex output mode");
|
||||
break;
|
||||
|
||||
case OUTPUT_MODE_END:
|
||||
option.output_mode = OUTPUT_MODE_NORMAL;
|
||||
tty_output_mode_set(OUTPUT_MODE_NORMAL);
|
||||
tio_printf("Switched to normal output mode");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -1379,9 +1431,12 @@ void forward_to_tty(int fd, char output_char)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (option.hex_mode)
|
||||
switch (option.output_mode)
|
||||
{
|
||||
output_hex(output_char);
|
||||
case OUTPUT_MODE_NORMAL:
|
||||
if (option.input_mode == INPUT_MODE_HEX)
|
||||
{
|
||||
handle_hex_prompt(output_char);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1403,6 +1458,22 @@ void forward_to_tty(int fd, char output_char)
|
|||
/* Update transmit statistics */
|
||||
tx_total++;
|
||||
}
|
||||
break;
|
||||
|
||||
case OUTPUT_MODE_HEX:
|
||||
if (option.input_mode == INPUT_MODE_HEX)
|
||||
{
|
||||
handle_hex_prompt(output_char);
|
||||
}
|
||||
else
|
||||
{
|
||||
optional_local_echo(output_char);
|
||||
}
|
||||
break;
|
||||
|
||||
case OUTPUT_MODE_END:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1460,14 +1531,7 @@ int tty_connect(void)
|
|||
}
|
||||
|
||||
/* Manage print output mode */
|
||||
if (option.hex_mode)
|
||||
{
|
||||
print = print_hex;
|
||||
}
|
||||
else
|
||||
{
|
||||
print = print_normal;
|
||||
}
|
||||
tty_output_mode_set(option.output_mode);
|
||||
|
||||
/* Save current port settings */
|
||||
if (tcgetattr(fd, &tio_old) < 0)
|
||||
|
|
@ -1577,7 +1641,7 @@ int tty_connect(void)
|
|||
input_char = input_buffer[i];
|
||||
|
||||
/* Print timestamp on new line if enabled */
|
||||
if ((next_timestamp && input_char != '\n' && input_char != '\r') && !option.hex_mode)
|
||||
if ((next_timestamp && input_char != '\n' && input_char != '\r') && (option.output_mode == OUTPUT_MODE_NORMAL))
|
||||
{
|
||||
now = timestamp_current_time();
|
||||
if (now)
|
||||
|
|
@ -1697,7 +1761,7 @@ int tty_connect(void)
|
|||
/* Handle commands */
|
||||
handle_command_sequence(input_char, &output_char, &forward);
|
||||
|
||||
if ((option.hex_mode) && (forward))
|
||||
if ((option.input_mode == INPUT_MODE_HEX) && (forward))
|
||||
{
|
||||
if (!is_valid_hex(input_char))
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue