Add option --raw/--raw-interactive and Ctrl-t j/J subcommand

Non-interactive operations (input from a pipe, running a shell command,
XYMODEM transfers) often fail when mapping, soft flow control, or output
delay are enabled.

To reduce the hassle of switching settings, add the function shown in
the title.

The raw option can be set to one of the following:
- off ... no effects
- on ... soft-flow off, character mapping off, output delay enabled
- on-nodelay ... soft-flow off, character mapping off, output delay
disable

raw option is for Piped-input / Shell command execution / XYMODEM
transfering. default is on.
raw-interactive option is for socket-mode and normal terminal use.
default is off.

You can type Ctrl-t j if you need to change raw setting for
non-interactive case. it toggles the raw setting.

You can type Ctrl-t J if you need to change raw setting of interactive
case. it toggles the raw setting.
It is useful when transferring files in socket mode.
This commit is contained in:
yabu76 2026-01-17 11:41:10 +09:00
parent 3b7fe3d258
commit 321494b4e6
7 changed files with 357 additions and 102 deletions

View file

@ -212,6 +212,20 @@ static void config_parse_keys(GKeyFile *key_file, char *group)
g_free((void *)string);
string = NULL;
}
config_get_string(key_file, group, "raw", &string, NULL);
if (string != NULL)
{
option_parse_raw(string, &option.raw);
g_free((void *)string);
string = NULL;
}
config_get_string(key_file, group, "raw-interactive", &string, NULL);
if (string != NULL)
{
option_parse_raw(string, &option.raw_interactive);
g_free((void *)string);
string = NULL;
}
config_get_bool(key_file, group, "timestamp", (bool*) &option.timestamp);
if (option.timestamp != TIMESTAMP_NONE)
{

View file

@ -60,6 +60,8 @@ enum opt_t
OPT_EXCLUDE_DRIVERS,
OPT_EXCLUDE_TIDS,
OPT_EXEC,
OPT_RAW,
OPT_RAW_INTERACTIVE,
};
// clang-format off
@ -128,6 +130,8 @@ struct option_t option =
.map_o_nulbrk = false,
.map_i_msb2lsb = false,
.map_o_ign_cr = false,
.raw = RAW_ON_DELAY,
.raw_interactive = RAW_OFF,
};
// clang-format on
@ -170,6 +174,8 @@ void option_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(" --raw off|on|on-nodelay Select raw mode for non-interactive use (default: on)\n");
printf(" --raw-interactive off|on|on-nodelay Select raw mode for interactive use (default: off)\n");
printf(" --rs-485 Enable RS-485 mode\n");
printf(" --rs-485-config <config> Set RS-485 configuration\n");
printf(" --alert bell|blink|none Alert on connect/disconnect (default: none)\n");
@ -453,9 +459,9 @@ void option_parse_timestamp(const char *arg, timestamp_t *timestamp)
}
}
const char *option_alert_state_to_string(alert_t state)
const char *option_alert_state_to_string(alert_t alert_state)
{
switch (state)
switch (alert_state)
{
case ALERT_NONE:
return "none";
@ -729,6 +735,44 @@ const char *option_output_mode_to_string(output_mode_t mode)
return NULL;
}
void option_parse_raw(const char *arg, raw_t *raw)
{
assert(arg != NULL);
if (strcmp("off", arg) == 0)
{
*raw = RAW_OFF;
}
else if (strcmp("on", arg) == 0)
{
*raw = RAW_ON_DELAY;
}
else if (strcmp("on-nodelay", arg) == 0)
{
*raw = RAW_ON_NODELAY;
}
else
{
tio_error_print("Invalid raw option '%s'", arg);
exit(EXIT_FAILURE);
}
}
const char *option_raw_to_string(raw_t raw)
{
switch (raw)
{
case RAW_OFF:
return "off";
case RAW_ON_DELAY:
return "on";
case RAW_ON_NODELAY:
return "on-nodelay";
}
return NULL;
}
void option_parse_script_run(const char *arg, script_run_t *script_run)
{
assert(arg != NULL);
@ -872,6 +916,8 @@ void options_print()
// clang-format on
tio_printf(" Input mode: %s", option_input_mode_to_string(option.input_mode));
tio_printf(" Output mode: %s", option_output_mode_to_string(option.output_mode));
tio_printf(" Raw (non-interactive): %s", option_raw_to_string(option.raw));
tio_printf(" Raw interactive: %s", option_raw_to_string(option.raw_interactive));
tio_printf(" Alert: %s", option_alert_state_to_string(option.alert));
if (option.log)
{
@ -953,6 +999,8 @@ void options_parse(int argc, char *argv[])
{"color", required_argument, 0, 'c' },
{"input-mode", required_argument, 0, OPT_INPUT_MODE },
{"output-mode", required_argument, 0, OPT_OUTPUT_MODE },
{"raw", required_argument, 0, OPT_RAW },
{"raw-interactive", required_argument, 0, OPT_RAW_INTERACTIVE },
{"rs-485", no_argument, 0, OPT_RS485 },
{"rs-485-config", required_argument, 0, OPT_RS485_CONFIG },
{"alert", required_argument, 0, OPT_ALERT },
@ -1147,6 +1195,14 @@ void options_parse(int argc, char *argv[])
option.exec = optarg;
break;
case OPT_RAW:
option_parse_raw(optarg, &option.raw);
break;
case OPT_RAW_INTERACTIVE:
option_parse_raw(optarg, &option.raw_interactive);
break;
case 'v':
printf("tio %s\n", VERSION);
exit(EXIT_SUCCESS);

View file

@ -43,6 +43,13 @@ typedef enum
OUTPUT_MODE_END,
} output_mode_t;
typedef enum
{
RAW_OFF,
RAW_ON_DELAY,
RAW_ON_NODELAY,
} raw_t;
/* Options */
struct option_t
{
@ -75,6 +82,8 @@ struct option_t
int color;
input_mode_t input_mode;
output_mode_t output_mode;
raw_t raw;
raw_t raw_interactive;
char prefix_code;
char prefix_key;
bool prefix_enabled;
@ -123,6 +132,7 @@ void option_parse_parity(const char *arg, parity_t *parity);
void option_parse_output_mode(const char *arg, output_mode_t *mode);
void option_parse_input_mode(const char *arg, input_mode_t *mode);
void option_parse_raw(const char *arg, raw_t *raw);
void option_parse_output_line_delay_char(const char *arg);
void option_parse_line_pulse_duration(const char *arg);
@ -136,3 +146,5 @@ void option_parse_timestamp(const char *arg, timestamp_t *timestamp);
const char* option_timestamp_format_to_string(timestamp_t timestamp);
void option_parse_mappings(const char *map);
const char* option_raw_to_string(raw_t raw);

View file

@ -267,6 +267,10 @@ static int api_send(lua_State *L)
return 0;
}
state_t state_orig = state;
state = STATE_XYMODEM;
tty_tcsetattr(device_fd);
switch (protocol)
{
case XMODEM_1K:
@ -294,6 +298,9 @@ static int api_send(lua_State *L)
break;
}
state = state_orig;
tty_tcsetattr(device_fd);
return 0;
}
@ -704,9 +711,9 @@ void script_run_as_specified_by_options(void)
}
}
const char *script_run_state_to_string(script_run_t state)
const char *script_run_state_to_string(script_run_t run_state)
{
switch (state)
switch (run_state)
{
case SCRIPT_RUN_ONCE:
return "once";

310
src/tty.c
View file

@ -117,6 +117,8 @@
#define KEY_SHIFT_F 0x46
#define KEY_G 0x67
#define KEY_I 0x69
#define KEY_J 0x6A
#define KEY_SHIFT_J 0x4A
#define KEY_L 0x6C
#define KEY_SHIFT_L 0x4C
#define KEY_M 0x6D
@ -166,12 +168,13 @@ const char random_array[] =
// clang-format on
bool interactive_mode = true;
state_t state = STATE_STARTING;
char key_hit = 0xff;
const char* device_name = NULL;
GList *device_list = NULL;
static struct termios tio, tio_old, stdout_new, stdout_old, stdin_new, stdin_old;
static struct termios tio, tio_raw, tio_old, stdout_new, stdout_old, stdin_new, stdin_old;
static unsigned long rx_total = 0, tx_total = 0;
static bool connected = false;
static bool standard_baudrate = true;
@ -236,6 +239,59 @@ inline static unsigned char char_to_nibble(char c)
}
}
raw_t tty_get_raw_mode(void)
{
switch (state)
{
case STATE_INTERACTIVE:
return option.raw_interactive;
case STATE_STARTING:
case STATE_PIPED_INPUT:
case STATE_EXEC_SHELL_COMMAND:
case STATE_XYMODEM:
default:
return option.raw;
}
}
int tty_tcsetattr(int fd)
{
if ( ! connected )
{
return -1;
}
/* Activate or change port settings */
int status;
raw_t raw = tty_get_raw_mode();
if (raw == RAW_OFF)
{
status = tcsetattr(fd, TCSANOW, &tio);
}
else
{
status = tcsetattr(fd, TCSANOW, &tio_raw);
}
if (status == -1)
{
tio_error_printf_silent("Could not apply port settings (%s)", strerror(errno));
return -1;
}
/* Set arbitrary baudrate (only works on supported platforms) */
if (!standard_baudrate)
{
if (setspeed(device_fd, option.baudrate) != 0)
{
tio_error_printf_silent("Could not set baudrate speed (%s)", strerror(errno));
return -1;
}
}
return 0;
}
void tty_sync(int fd)
{
/* If output_delay is valid, tty_buffer should be already empty.
@ -279,7 +335,10 @@ void tty_sync(int fd)
static ssize_t tty_raw_write(int fd)
{
if ( ! (option.output_delay || option.output_line_delay || option.map_o_nulbrk) )
raw_t raw = tty_get_raw_mode();
if ((raw == RAW_ON_NODELAY) ||
((raw == RAW_ON_DELAY) && ( ! option.output_delay )) ||
((raw == RAW_OFF) && ( ! (option.output_delay || option.output_line_delay || option.map_o_nulbrk) )))
{
return 0; // No-op in this function, write in tty_sync()
}
@ -290,7 +349,7 @@ static ssize_t tty_raw_write(int fd)
for (i = 0; i < tty_buffer_count; i++)
{
if ((tty_buffer[i] == 0) && (option.map_o_nulbrk))
if ((raw == RAW_OFF) && (tty_buffer[i] == 0) && (option.map_o_nulbrk))
{
retval = tcsendbreak(fd, 0);
if (retval < 0)
@ -315,7 +374,7 @@ static ssize_t tty_raw_write(int fd)
// Update transmit statistics
tx_total++;
if (option.output_line_delay && tty_buffer[i] == option.output_line_delay_char)
if ((raw == RAW_OFF) && (option.output_line_delay) && (tty_buffer[i] == option.output_line_delay_char))
{
delay(option.output_line_delay);
}
@ -340,55 +399,79 @@ ssize_t tty_write(int fd, const void *buffer, size_t count)
int status;
const char *cp = (char *)buffer;
size_t i;
for (i = 0; i < count; i++, cp++)
raw_t raw = tty_get_raw_mode();
if (raw != RAW_OFF)
{
char *tp;
int bytes_add;
if (tty_buffer_count >= BUFSIZ)
/* RAW mode */
for (i = 0; i < count; i++, cp++)
{
status = tty_raw_write(fd);
if (status < 0)
if (tty_buffer_count >= BUFSIZ)
{
return status;
status = tty_raw_write(fd);
if (status < 0)
{
return status;
}
tty_sync(fd);
}
tty_sync(fd);
}
/* Map output character */
bytes_add = -1; /* negative value means "not mapped yet" */
tp = tty_buffer_write_ptr;
if ((*cp == 127) && (option.map_o_del_bs))
{
*tp = '\b';
bytes_add = 1;
*tty_buffer_write_ptr = *cp;
tty_buffer_write_ptr++;
tty_buffer_count++;
}
if ((*cp == '\r') && (option.map_o_cr_nl))
}
else
{
/* not RAW mode */
for (i = 0; i < count; i++, cp++)
{
*tp = '\n';
bytes_add = 1;
}
if ((*cp == '\r') && (option.map_o_ign_cr))
{
bytes_add = 0;
}
if ((*cp == '\n' || *cp == '\r') && (option.map_o_nl_crnl))
{
*tp = '\r';
*(tp + 1) = '\n';
bytes_add = 2;
}
if (bytes_add < 0)
{
*tp = (option.map_o_ltu) ? toupper(*cp) : *cp;
bytes_add = 1;
}
if (tty_buffer_count >= BUFSIZ)
{
status = tty_raw_write(fd);
if (status < 0)
{
return status;
}
tty_sync(fd);
}
if (bytes_add > 0)
{
tty_buffer_write_ptr += bytes_add;
tty_buffer_count += bytes_add;
/* Map output character */
char *tp;
int bytes_add;
bytes_add = -1; /* negative value means "not mapped yet" */
tp = tty_buffer_write_ptr;
if ((*cp == 127) && (option.map_o_del_bs))
{
*tp = '\b';
bytes_add = 1;
}
if ((*cp == '\r') && (option.map_o_cr_nl))
{
*tp = '\n';
bytes_add = 1;
}
if ((*cp == '\r') && (option.map_o_ign_cr))
{
bytes_add = 0;
}
if ((*cp == '\n' || *cp == '\r') && (option.map_o_nl_crnl))
{
*tp = '\r';
*(tp + 1) = '\n';
bytes_add = 2;
}
if (bytes_add < 0)
{
*tp = (option.map_o_ltu) ? toupper(*cp) : *cp;
bytes_add = 1;
}
if (bytes_add > 0)
{
tty_buffer_write_ptr += bytes_add;
tty_buffer_count += bytes_add;
}
}
}
@ -568,10 +651,10 @@ static const char *tty_line_name(int mask)
void tty_line_set(int fd, tty_line_config_t line_config[])
{
static int state;
static int line_state;
int i = 0;
if (ioctl(fd, TIOCMGET, &state) < 0)
if (ioctl(fd, TIOCMGET, &line_state) < 0)
{
tio_warning_printf("Could not get line state (%s)", strerror(errno));
return;
@ -584,21 +667,21 @@ void tty_line_set(int fd, tty_line_config_t line_config[])
if (line_config[i].value == 0)
{
// Low
state |= line_config[i].mask;
line_state |= line_config[i].mask;
tio_printf("Setting %s to LOW", tty_line_name(line_config[i].mask));
}
else if (line_config[i].value == 1)
{
// High
state &= ~line_config[i].mask;
line_state &= ~line_config[i].mask;
tio_printf("Setting %s to HIGH", tty_line_name(line_config[i].mask));
}
else if (line_config[i].value == 2)
{
// Toggle
state ^= line_config[i].mask;
line_state ^= line_config[i].mask;
if (state & line_config[i].mask)
if (line_state & line_config[i].mask)
{
tio_printf("Setting %s to LOW", tty_line_name(line_config[i].mask));
}
@ -610,7 +693,7 @@ void tty_line_set(int fd, tty_line_config_t line_config[])
}
}
if (ioctl(fd, TIOCMSET, &state) < 0)
if (ioctl(fd, TIOCMSET, &line_state) < 0)
{
tio_warning_printf("Could not set line state (%s)", strerror(errno));
}
@ -618,26 +701,26 @@ void tty_line_set(int fd, tty_line_config_t line_config[])
void tty_line_toggle(int fd, int mask)
{
int state;
int line_state;
if (ioctl(fd, TIOCMGET, &state) < 0)
if (ioctl(fd, TIOCMGET, &line_state) < 0)
{
tio_warning_printf("Could not get line state (%s)", strerror(errno));
return;
}
if (state & mask)
if (line_state & mask)
{
state &= ~mask;
line_state &= ~mask;
tio_printf("Setting %s to HIGH", tty_line_name(mask));
}
else
{
state |= mask;
line_state |= mask;
tio_printf("Setting %s to LOW", tty_line_name(mask));
}
if (ioctl(fd, TIOCMSET, &state) < 0)
if (ioctl(fd, TIOCMSET, &line_state) < 0)
{
tio_warning_printf("Could not set line state (%s)", strerror(errno));
}
@ -789,7 +872,7 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward)
{
char unused_char;
bool unused_bool;
int state;
int line_state;
static tty_line_mode_t line_mode;
static sub_command_t sub_command = SUBCOMMAND_NONE;
static char previous_char = 0;
@ -844,6 +927,9 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward)
break;
case SUBCOMMAND_XMODEM:
state_t state_orig = state;
state = STATE_XYMODEM;
tty_tcsetattr(device_fd);
switch (input_char)
{
case KEY_0:
@ -915,6 +1001,8 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward)
tio_error_print("Invalid protocol option");
break;
}
state = state_orig;
tty_tcsetattr(device_fd);
break;
case SUBCOMMAND_MAP:
@ -1015,6 +1103,8 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward)
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 i Toggle input mode", option.prefix_key);
tio_printf(" ctrl-%c j Toggle raw mode for non-interactive use", option.prefix_key);
tio_printf(" ctrl-%c J Toggle raw mode for interactive use", 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 Change mapping of characters on input or output", option.prefix_key);
@ -1032,18 +1122,18 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward)
break;
case KEY_SHIFT_L:
if (ioctl(device_fd, TIOCMGET, &state) < 0)
if (ioctl(device_fd, TIOCMGET, &line_state) < 0)
{
tio_warning_printf("Could not get line state (%s)", strerror(errno));
break;
}
tio_printf("Line states:");
tio_printf(" DTR: %s", (state & TIOCM_DTR) ? "LOW" : "HIGH");
tio_printf(" RTS: %s", (state & TIOCM_RTS) ? "LOW" : "HIGH");
tio_printf(" CTS: %s", (state & TIOCM_CTS) ? "LOW" : "HIGH");
tio_printf(" DSR: %s", (state & TIOCM_DSR) ? "LOW" : "HIGH");
tio_printf(" DCD: %s", (state & TIOCM_CD) ? "LOW" : "HIGH");
tio_printf(" RI : %s", (state & TIOCM_RI) ? "LOW" : "HIGH");
tio_printf(" DTR: %s", (line_state & TIOCM_DTR) ? "LOW" : "HIGH");
tio_printf(" RTS: %s", (line_state & TIOCM_RTS) ? "LOW" : "HIGH");
tio_printf(" CTS: %s", (line_state & TIOCM_CTS) ? "LOW" : "HIGH");
tio_printf(" DSR: %s", (line_state & TIOCM_DSR) ? "LOW" : "HIGH");
tio_printf(" DCD: %s", (line_state & TIOCM_CD) ? "LOW" : "HIGH");
tio_printf(" RI : %s", (line_state & TIOCM_RI) ? "LOW" : "HIGH");
break;
case KEY_F:
@ -1155,6 +1245,42 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward)
}
break;
case KEY_J:
option.raw += 1;
switch (option.raw)
{
case RAW_ON_DELAY:
tio_printf("Turn on raw mode for non-interactive use");
break;
case RAW_ON_NODELAY:
tio_printf("Turn on raw-nodelay mode for non-interactive use");
break;
case RAW_OFF:
default:
option.raw = RAW_OFF;
tio_printf("Turn off raw mode for non-interactive use");
break;
}
break;
case KEY_SHIFT_J:
option.raw_interactive += 1;
switch (option.raw_interactive)
{
case RAW_ON_DELAY:
tio_printf("Turn on raw mode for interactive use");
break;
case RAW_ON_NODELAY:
tio_printf("Turn on raw-nodelay mode for interactive use");
break;
case RAW_OFF:
default:
option.raw_interactive = RAW_OFF;
tio_printf("Turn off raw mode for interactive use");
break;
}
break;
case KEY_L:
/* Clear screen using ANSI/VT100 escape code */
printf("\033c");
@ -1219,7 +1345,14 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward)
/* Execute shell command */
tio_printf("Execute shell command with I/O redirected to device");
if (tio_subcmd_readln("Enter command: "))
{
state_t state_orig = state;
state = STATE_EXEC_SHELL_COMMAND;
tty_tcsetattr(device_fd);
execute_shell_command(device_fd, line);
state = state_orig;
tty_tcsetattr(device_fd);
}
break;
case KEY_S:
@ -1280,10 +1413,15 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward)
if (tio_subcmd_readln("Enter file name: "))
{
int ret;
state_t state_orig = state;
tio_printf("Sending file '%s' ", line);
tio_printf("Press any key to abort transfer");
state = STATE_XYMODEM;
tty_tcsetattr(device_fd);
ret = xymodem_send(device_fd, line, YMODEM);
state = state_orig;
tty_tcsetattr(device_fd);
tio_printf("%s", ret < 0 ? "Aborted" : "Done");
}
break;
@ -1560,6 +1698,14 @@ void tty_configure(void)
{
tio.c_iflag |= ICRNL;
}
/* Create raw-mode configuration */
memcpy(&tio_raw, &tio, sizeof(tio_raw));
if (option.flow == FLOW_SOFT)
{
tio_raw.c_iflag &= ~(IXON | IXOFF | IXANY);
tio_raw.c_iflag &= ~(INLCR | IGNCR | ICRNL);
}
}
void tty_reconfigure(void)
@ -2680,6 +2826,8 @@ int tty_connect(void)
char* now = NULL;
struct timeval tval_before = {}, tval_now, tval_result;
state = STATE_STARTING;
/* Open tty device */
device_fd = open(device_name, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (device_fd < 0)
@ -2692,7 +2840,7 @@ int tty_connect(void)
if (!isatty(device_fd))
{
tio_error_printf("Not a tty device");
exit(EXIT_FAILURE);;
exit(EXIT_FAILURE);
}
/* Lock device file */
@ -2754,27 +2902,17 @@ int tty_connect(void)
first = false;
}
/* Activate new port settings */
status = tcsetattr(device_fd, TCSANOW, &tio);
/* Activate new port settings and set speed for non-interactive phase */
status = tty_tcsetattr(device_fd);
if (status == -1)
{
tio_error_printf_silent("Could not apply port settings (%s)", strerror(errno));
goto error_tcsetattr;
}
/* Set arbitrary baudrate (only works on supported platforms) */
if (!standard_baudrate)
{
if (setspeed(device_fd, option.baudrate) != 0)
{
tio_error_printf_silent("Could not set baudrate speed (%s)", strerror(errno));
goto error_setspeed;
}
}
/* If stdin is a pipe forward all input to tty device */
if (interactive_mode == false)
{
state = STATE_PIPED_INPUT;
while (true)
{
int ret = read(pipefd[0], input_buffer, BUFSIZ);
@ -2815,7 +2953,7 @@ int tty_connect(void)
}
}
// Exit if piped input
// Exit if piped input or given execute option
if (interactive_mode == false)
{
exit(EXIT_SUCCESS);
@ -2823,10 +2961,19 @@ int tty_connect(void)
if (option.exec != NULL)
{
state = STATE_EXEC_SHELL_COMMAND;
status = execute_shell_command(device_fd, option.exec);
exit(status);
}
/* Activate new port settings for interactive phase */
state = STATE_INTERACTIVE;
status = tty_tcsetattr(device_fd);
if (status == -1)
{
goto error_tcsetattr;
}
/* Input loop */
while (true)
{
@ -3149,7 +3296,6 @@ int tty_connect(void)
return TIO_SUCCESS;
error_setspeed:
error_tcsetattr:
error_tcgetattr:
error_read:

View file

@ -69,8 +69,18 @@ typedef struct
bool reserved;
} tty_line_config_t;
typedef enum
{
STATE_INTERACTIVE,
STATE_STARTING,
STATE_PIPED_INPUT,
STATE_EXEC_SHELL_COMMAND,
STATE_XYMODEM,
} state_t;
extern const char *device_name;
extern bool interactive_mode;
extern state_t state;
void stdout_configure(void);
void stdin_configure(void);
@ -88,3 +98,4 @@ GList *tty_search_for_serial_devices(void);
void forward_to_tty(int fd, char output_char);
ssize_t tty_write(int fd, const void *buffer, size_t count);
void tty_sync(int fd);
int tty_tcsetattr(int fd);

View file

@ -185,6 +185,15 @@ static int xmsend_wait_response(int sio, char *resp, char tmo_resp)
return OK;
}
static ssize_t xmodem_tty_write(int sio, const void *buf, size_t bufsiz)
{
ssize_t ret = tty_write(sio, buf, bufsiz);
if (ret >= 0) {
tty_sync(sio);
}
return ret;
}
/*
* Send EOT at 1 Hz until ACK or CAN received
*/
@ -198,7 +207,7 @@ static int xmsend_repeat_eot_and_wait_response(int sio)
if (key_hit)
return ERR_USER_CAN;
if (write(sio, EOT_STR, 1) < 0)
if (xmodem_tty_write(sio, EOT_STR, 1) < 0)
{
tio_error_print("Write EOT to serial failed");
return ERR;
@ -265,7 +274,7 @@ static int xmodem_send_1k(int sio, const void *data, size_t len, int seq)
if (key_hit)
return ERR_USER_CAN;
if ((rc = write(sio, from, sz)) < 0 )
if ((rc = xmodem_tty_write(sio, from, sz)) < 0 )
{
if (errno == EWOULDBLOCK)
{
@ -398,7 +407,7 @@ static int xmodem_send_128b(int sio, const void *data, size_t len, bool use_crc)
if (key_hit)
return ERR_USER_CAN;
if ((rc = write(sio, from, sz)) < 0 )
if ((rc = xmodem_tty_write(sio, from, sz)) < 0 )
{
if (errno == EWOULDBLOCK)
{
@ -524,9 +533,9 @@ static int xmrecv_start_receive(int sio, bool use_crc)
seconds. If nothing is received in that time then return false to indicate
that the transfer did not start. */
if (use_crc)
rc = write(sio, "C", 1);
rc = xmodem_tty_write(sio, "C", 1);
else
rc = write(sio, NAK_STR, 1);
rc = xmodem_tty_write(sio, NAK_STR, 1);
if (rc < 0)
{
@ -611,7 +620,7 @@ static int xmrecv_receive_packet(int sio, struct xpacket_128b_crc *packet, int f
if (rc == 0)
{
tio_error_print("Timeout waiting for next packet char");
rc = write(sio, CAN_STR, 1);
rc = xmodem_tty_write(sio, CAN_STR, 1);
if (rc < 0)
{
tio_error_print("Write cancel packet to serial failed");
@ -622,7 +631,7 @@ static int xmrecv_receive_packet(int sio, struct xpacket_128b_crc *packet, int f
else if (rc < 0)
{
tio_error_print("Error reading next packet char");
rc = write(sio, CAN_STR, 1);
rc = xmodem_tty_write(sio, CAN_STR, 1);
if (rc < 0)
{
tio_error_print("Write cancel packet to serial failed");
@ -702,7 +711,7 @@ static int xmrecv_receive_packet(int sio, struct xpacket_128b_crc *packet, int f
{
tio_error_print("%s", strerror(errno));
tio_error_print("Poll check error after packet finish");
rc = write(sio, CAN_STR, 1);
rc = xmodem_tty_write(sio, CAN_STR, 1);
if (rc < 0)
{
tio_error_print("Write cancel packet to serial failed");
@ -732,7 +741,7 @@ static int xmrecv_receive_packet(int sio, struct xpacket_128b_crc *packet, int f
if ((calcCrc == rxCrc) && (seq1 == packet->hdr.seq - 1) && ((seq1 ^ seq2) == tester))
{
/* Resend of previously processed packet. */
rc = write(sio, ACK_STR, 1);
rc = xmodem_tty_write(sio, ACK_STR, 1);
if (rc < 0)
{
tio_error_print("Write acknowlegdement packet to serial failed");
@ -755,18 +764,18 @@ static int xmrecv_receive_packet(int sio, struct xpacket_128b_crc *packet, int f
else
{
/* The data is good. Process the packet then ACK it to the sender. */
rc = write(fd, packet->data, sizeof(packet->data));
rc = xmodem_tty_write(fd, packet->data, sizeof(packet->data));
if (rc < 0)
{
tio_error_print("Problem writing to file");
rc = write(sio, CAN_STR, 1);
rc = xmodem_tty_write(sio, CAN_STR, 1);
if (rc < 0)
{
tio_error_print("Write cancel packet to serial failed");
}
return ERR_FATAL;
}
rc = write(sio, ACK_STR, 1);
rc = xmodem_tty_write(sio, ACK_STR, 1);
if (rc < 0)
{
tio_error_print("Write acknowlegdement packet to serial failed");
@ -840,7 +849,7 @@ int xmodem_receive(int sio, int fd, bool use_crc)
}
else if (err == ERR || err == ERR_TMO)
{
rc = write(sio, NAK_STR, 1);
rc = xmodem_tty_write(sio, NAK_STR, 1);
if (rc < 0)
{
tio_error_print("Writing not acknowledge packet to serial failed");
@ -855,7 +864,7 @@ int xmodem_receive(int sio, int fd, bool use_crc)
}
else if (err == ERR_USER_CAN)
{
rc = write(sio, CAN_STR, 1);
rc = xmodem_tty_write(sio, CAN_STR, 1);
if (rc < 0)
{
tio_error_print("Writing cancel to serial failed");
@ -871,7 +880,7 @@ int xmodem_receive(int sio, int fd, bool use_crc)
case EOT:
/* End of Transfer */
rc = write(sio, ACK_STR, 1);
rc = xmodem_tty_write(sio, ACK_STR, 1);
if (rc < 0)
{
tio_error_print("Write acknowlegdement packet to serial failed");
@ -889,7 +898,7 @@ int xmodem_receive(int sio, int fd, bool use_crc)
break;
default:
tio_error_print("Unexpected character received waiting for next packet");
tio_error_print("Unexpected character received waiting for next packet (0x%02x)", resp);
return ERR;
break;
}