diff --git a/src/configfile.c b/src/configfile.c index cc21dfb..686cae9 100644 --- a/src/configfile.c +++ b/src/configfile.c @@ -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) { diff --git a/src/options.c b/src/options.c index 67c6ed6..d85a5c6 100644 --- a/src/options.c +++ b/src/options.c @@ -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 Map characters\n"); printf(" -c, --color 0..255|bold|none|list Colorize tio text (default: bold)\n"); printf(" -S, --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 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); diff --git a/src/options.h b/src/options.h index 4f501ae..337768c 100644 --- a/src/options.h +++ b/src/options.h @@ -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); diff --git a/src/script.c b/src/script.c index 269bd69..45e9fea 100644 --- a/src/script.c +++ b/src/script.c @@ -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"; diff --git a/src/tty.c b/src/tty.c index 36a4bac..441ea3d 100644 --- a/src/tty.c +++ b/src/tty.c @@ -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: diff --git a/src/tty.h b/src/tty.h index 31ae00e..5135394 100644 --- a/src/tty.h +++ b/src/tty.h @@ -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); diff --git a/src/xymodem.c b/src/xymodem.c index 5190e40..33b6924 100644 --- a/src/xymodem.c +++ b/src/xymodem.c @@ -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; }