mirror of
https://github.com/tio/tio.git
synced 2026-05-01 23:07:58 +02:00
Extended hexadecimal mode.
While in hex mode (ctrl-t h) you can output hexadecimal values. E.g.: to send 0x0A you have to type 0A (always 2 characters). Added option -x, --hex to start in hexadecimal mode. Added option --newline-in-hex to interpret newline characters in hex mode. This is disabled by default, because, in my opinion, hex stream is fundamentally different from text, so a "new line" is meaningless in this context.
This commit is contained in:
parent
0f0279bd3f
commit
7fc8e278ed
4 changed files with 131 additions and 23 deletions
26
man/tio.1
26
man/tio.1
|
|
@ -1,4 +1,4 @@
|
||||||
.TH "tio" "1" "June 2018"
|
.TH "tio" "1" "July 2021"
|
||||||
|
|
||||||
.SH "NAME"
|
.SH "NAME"
|
||||||
tio \- a simple TTY terminal I/O application
|
tio \- a simple TTY terminal I/O application
|
||||||
|
|
@ -56,6 +56,11 @@ option is provided, tio will exit if the device is not present or an established
|
||||||
|
|
||||||
Enable local echo.
|
Enable local echo.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.BR \-t ", " "\-\-timestamp
|
||||||
|
|
||||||
|
Prefix each new line with a timestamp.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BR \-l ", " "\-\-log " \fI<filename>
|
.BR \-l ", " "\-\-log " \fI<filename>
|
||||||
|
|
||||||
|
|
@ -86,10 +91,21 @@ Map NL to CR-NL on output.
|
||||||
If defining more than one flag, the flags must be comma separated.
|
If defining more than one flag, the flags must be comma separated.
|
||||||
.RE
|
.RE
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.BR \-x ", " \-\-hex
|
||||||
|
|
||||||
|
Start in hexadecimal mode.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.BR \-\-newline-in-hex
|
||||||
|
|
||||||
|
Interpret new line characters ('\\r', '\\n') in hexadecimal mode.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BR \-v ", " \-\-version
|
.BR \-v ", " \-\-version
|
||||||
|
|
||||||
Display program version.
|
Display program version.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BR \-h ", " \-\-help
|
.BR \-h ", " \-\-help
|
||||||
|
|
||||||
|
|
@ -126,6 +142,14 @@ Toggle RTS
|
||||||
.IP "\fBctrl-t v"
|
.IP "\fBctrl-t v"
|
||||||
Show version
|
Show version
|
||||||
|
|
||||||
|
.SH "HEXADECIMAL MODE"
|
||||||
|
.TP
|
||||||
|
In hexadecimal mode each incoming byte is printed out as a hexadecimal value.
|
||||||
|
.TP
|
||||||
|
By default there is \fBno new line\fR in this mode, but it can be turned on using the \fB--newline-in-hex\fR option.
|
||||||
|
.TP
|
||||||
|
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 "EXAMPLES"
|
.SH "EXAMPLES"
|
||||||
.TP
|
.TP
|
||||||
Typical use is without options. For example:
|
Typical use is without options. For example:
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
#define OPT_NEWLINE_IN_HEX 1000 // "short" option for --newline-in-hex
|
||||||
|
|
||||||
/* Options */
|
/* Options */
|
||||||
struct option_t
|
struct option_t
|
||||||
{
|
{
|
||||||
|
|
@ -41,6 +43,8 @@ struct option_t
|
||||||
bool log;
|
bool log;
|
||||||
bool local_echo;
|
bool local_echo;
|
||||||
bool timestamp;
|
bool timestamp;
|
||||||
|
bool hex_mode;
|
||||||
|
bool newline_in_hex;
|
||||||
const char *log_filename;
|
const char *log_filename;
|
||||||
const char *map;
|
const char *map;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,8 @@ struct option_t option =
|
||||||
false, // No log
|
false, // No log
|
||||||
false, // No local echo
|
false, // No local echo
|
||||||
false, // No timestamp
|
false, // No timestamp
|
||||||
|
false, // Not starting in hex mode
|
||||||
|
false, // No newlines in hex mode
|
||||||
"", // Log filename
|
"", // Log filename
|
||||||
"" // Map string
|
"" // Map string
|
||||||
};
|
};
|
||||||
|
|
@ -67,6 +69,8 @@ void print_help(char *argv[])
|
||||||
printf(" -t, --timestamp Prefix each new line with a timestamp\n");
|
printf(" -t, --timestamp Prefix each new line with a timestamp\n");
|
||||||
printf(" -l, --log <filename> Log to file\n");
|
printf(" -l, --log <filename> Log to file\n");
|
||||||
printf(" -m, --map <flags> Map special characters\n");
|
printf(" -m, --map <flags> Map special characters\n");
|
||||||
|
printf(" -x, --hex Start in hexadecimal mode\n");
|
||||||
|
printf(" --newline-in-hex Interpret new line characters in hex mode\n");
|
||||||
printf(" -v, --version Display version\n");
|
printf(" -v, --version Display version\n");
|
||||||
printf(" -h, --help Display help\n");
|
printf(" -h, --help Display help\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
@ -117,6 +121,8 @@ void parse_options(int argc, char *argv[])
|
||||||
{"timestamp", no_argument, 0, 't'},
|
{"timestamp", no_argument, 0, 't'},
|
||||||
{"log", required_argument, 0, 'l'},
|
{"log", required_argument, 0, 'l'},
|
||||||
{"map", required_argument, 0, 'm'},
|
{"map", required_argument, 0, 'm'},
|
||||||
|
{"hex", no_argument, 0, 'x'},
|
||||||
|
{"newline-in-hex", no_argument, 0, OPT_NEWLINE_IN_HEX },
|
||||||
{"version", no_argument, 0, 'v'},
|
{"version", no_argument, 0, 'v'},
|
||||||
{"help", no_argument, 0, 'h'},
|
{"help", no_argument, 0, 'h'},
|
||||||
{0, 0, 0, 0 }
|
{0, 0, 0, 0 }
|
||||||
|
|
@ -126,7 +132,7 @@ void parse_options(int argc, char *argv[])
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
|
|
||||||
/* Parse argument using getopt_long */
|
/* Parse argument using getopt_long */
|
||||||
c = getopt_long(argc, argv, "b:d:f:s:p:o:netl:m:vh", long_options, &option_index);
|
c = getopt_long(argc, argv, "b:d:f:s:p:o:netl:m:xvh", long_options, &option_index);
|
||||||
|
|
||||||
/* Detect the end of the options */
|
/* Detect the end of the options */
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
|
|
@ -189,6 +195,14 @@ void parse_options(int argc, char *argv[])
|
||||||
option.map = optarg;
|
option.map = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'x':
|
||||||
|
option.hex_mode = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPT_NEWLINE_IN_HEX:
|
||||||
|
option.newline_in_hex = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'v':
|
case 'v':
|
||||||
printf("tio v%s\n", VERSION);
|
printf("tio v%s\n", VERSION);
|
||||||
printf("Copyright (c) 2014-2018 Martin Lund\n");
|
printf("Copyright (c) 2014-2018 Martin Lund\n");
|
||||||
|
|
|
||||||
90
src/tty.c
90
src/tty.c
|
|
@ -60,6 +60,8 @@ static bool map_i_nl_crnl = false;
|
||||||
static bool map_o_cr_nl = false;
|
static bool map_o_cr_nl = false;
|
||||||
static bool map_o_nl_crnl = false;
|
static bool map_o_nl_crnl = false;
|
||||||
static bool map_o_del_bs = false;
|
static bool map_o_del_bs = false;
|
||||||
|
static char hex_chars[2];
|
||||||
|
static unsigned char hex_char_index = 0;
|
||||||
|
|
||||||
#define tio_printf(format, args...) \
|
#define tio_printf(format, args...) \
|
||||||
{ \
|
{ \
|
||||||
|
|
@ -68,10 +70,58 @@ static bool map_o_del_bs = false;
|
||||||
tainted = false; \
|
tainted = false; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void optional_local_echo(char c)
|
||||||
|
{
|
||||||
|
if (!option.local_echo)
|
||||||
|
return;
|
||||||
|
print(c);
|
||||||
|
fflush(stdout);
|
||||||
|
if (option.log)
|
||||||
|
log_write(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static bool is_valid_hex(char c)
|
||||||
|
{
|
||||||
|
return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static unsigned char char_to_nibble(char c)
|
||||||
|
{
|
||||||
|
if(c >= '0' && c <= '9'){
|
||||||
|
return c - '0';
|
||||||
|
} else if(c >= 'a' && c <= 'f'){
|
||||||
|
return c - 'a' + 10;
|
||||||
|
} else if(c >= 'A' && c <= 'F'){
|
||||||
|
return c - 'A' + 10;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void output_hex(char c)
|
||||||
|
{
|
||||||
|
hex_chars[hex_char_index++] = c;
|
||||||
|
|
||||||
|
if(hex_char_index == 2){
|
||||||
|
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 = write(fd, &hex_value, 1);
|
||||||
|
if (status < 0){
|
||||||
|
warning_printf("Could not write to tty device");
|
||||||
|
} else {
|
||||||
|
tx_total++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fsync(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void print_hex(char c)
|
static void print_hex(char c)
|
||||||
{
|
{
|
||||||
|
if (((c == '\n') || (c == '\r')) && option.newline_in_hex)
|
||||||
if ((c == '\n') || (c == '\r'))
|
|
||||||
printf("%c", c);
|
printf("%c", c);
|
||||||
else
|
else
|
||||||
printf("%02x ", (unsigned char) c);
|
printf("%02x ", (unsigned char) c);
|
||||||
|
|
@ -601,16 +651,6 @@ void tty_restore(void)
|
||||||
tty_disconnect();
|
tty_disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void optional_local_echo(char c)
|
|
||||||
{
|
|
||||||
if (!option.local_echo)
|
|
||||||
return;
|
|
||||||
print(c);
|
|
||||||
fflush(stdout);
|
|
||||||
if (option.log)
|
|
||||||
log_write(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
int tty_connect(void)
|
int tty_connect(void)
|
||||||
{
|
{
|
||||||
fd_set rdfs; /* Read file descriptor set */
|
fd_set rdfs; /* Read file descriptor set */
|
||||||
|
|
@ -660,6 +700,19 @@ int tty_connect(void)
|
||||||
if (option.timestamp)
|
if (option.timestamp)
|
||||||
next_timestamp = time(NULL);
|
next_timestamp = time(NULL);
|
||||||
|
|
||||||
|
if (option.hex_mode)
|
||||||
|
{
|
||||||
|
print = print_hex;
|
||||||
|
print_mode = HEX;
|
||||||
|
tio_printf("Switched to hexadecimal mode");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
print = print_normal;
|
||||||
|
print_mode = NORMAL;
|
||||||
|
tio_printf("Switched to normal mode");
|
||||||
|
}
|
||||||
|
|
||||||
/* Save current port settings */
|
/* Save current port settings */
|
||||||
if (tcgetattr(fd, &tio_old) < 0)
|
if (tcgetattr(fd, &tio_old) < 0)
|
||||||
goto error_tcgetattr;
|
goto error_tcgetattr;
|
||||||
|
|
@ -759,6 +812,7 @@ int tty_connect(void)
|
||||||
goto error_read;
|
goto error_read;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FD_ISSET(STDIN_FILENO, &rdfs))
|
if (FD_ISSET(STDIN_FILENO, &rdfs))
|
||||||
{
|
{
|
||||||
bool forward = true;
|
bool forward = true;
|
||||||
|
|
@ -781,6 +835,13 @@ int tty_connect(void)
|
||||||
|
|
||||||
if (forward)
|
if (forward)
|
||||||
{
|
{
|
||||||
|
if(print_mode == HEX){
|
||||||
|
if(!is_valid_hex(input_char)){
|
||||||
|
warning_printf("Invalid hex character: '%c' (0x%02x)", input_char, input_char);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Map output character */
|
/* Map output character */
|
||||||
if ((output_char == 127) && (map_o_del_bs))
|
if ((output_char == 127) && (map_o_del_bs))
|
||||||
output_char = '\b';
|
output_char = '\b';
|
||||||
|
|
@ -800,8 +861,12 @@ int tty_connect(void)
|
||||||
delay(option.output_delay);
|
delay(option.output_delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(print_mode == HEX){
|
||||||
|
output_hex(output_char);
|
||||||
|
} else {
|
||||||
/* Send output to tty device */
|
/* Send output to tty device */
|
||||||
optional_local_echo(output_char);
|
optional_local_echo(output_char);
|
||||||
|
|
||||||
status = write(fd, &output_char, 1);
|
status = write(fd, &output_char, 1);
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
warning_printf("Could not write to tty device");
|
warning_printf("Could not write to tty device");
|
||||||
|
|
@ -809,6 +874,7 @@ int tty_connect(void)
|
||||||
|
|
||||||
/* Update transmit statistics */
|
/* Update transmit statistics */
|
||||||
tx_total++;
|
tx_total++;
|
||||||
|
}
|
||||||
|
|
||||||
/* Insert output delay */
|
/* Insert output delay */
|
||||||
delay(option.output_delay);
|
delay(option.output_delay);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue