From e458b02771b02fe9768c3cd3fda618bd802d047b Mon Sep 17 00:00:00 2001 From: yabu76 Date: Sat, 16 Aug 2025 10:52:31 +0900 Subject: [PATCH] Add Xmodem-SUM support. --- src/script.c | 7 ++ src/tty.c | 30 ++++++++ src/xymodem.c | 206 ++++++++++++++++++++++++++++++++++++-------------- src/xymodem.h | 1 + 4 files changed, 189 insertions(+), 55 deletions(-) diff --git a/src/script.c b/src/script.c index e050af6..cb104bd 100644 --- a/src/script.c +++ b/src/script.c @@ -241,6 +241,12 @@ static int api_send(lua_State *L) tio_printf("%s", ret < 0 ? "Aborted" : "Done"); break; + case XMODEM_SUM: + tio_printf("Sending file '%s' using XMODEM-SUM", file); + ret = xymodem_send(device_fd, file, XMODEM_SUM); + tio_printf("%s", ret < 0 ? "Aborted" : "Done"); + break; + case YMODEM: tio_printf("Sending file '%s' using YMODEM", file); ret = xymodem_send(device_fd, file, YMODEM); @@ -486,6 +492,7 @@ static void script_set_globals(lua_State *L) script_set_global(L, "toggle", 2); script_set_global(L, "high", 1); script_set_global(L, "low", 0); + script_set_global(L, "XMODEM_SUM", XMODEM_SUM); script_set_global(L, "XMODEM_CRC", XMODEM_CRC); script_set_global(L, "XMODEM_1K", XMODEM_1K); script_set_global(L, "YMODEM", YMODEM); diff --git a/src/tty.c b/src/tty.c index 70c5277..d59c7c1 100644 --- a/src/tty.c +++ b/src/tty.c @@ -767,6 +767,34 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward) } break; + case KEY_3: + tio_printf("Send file with XMODEM-SUM"); + tio_printf_raw("Enter file name: "); + if (tio_readln()) + { + int ret; + + tio_printf("Sending file '%s' ", line); + tio_printf("Press any key to abort transfer"); + ret = xymodem_send(device_fd, line, XMODEM_SUM); + tio_printf("%s", ret < 0 ? "Aborted" : "Done"); + } + break; + + case KEY_4: + tio_printf("Receive file with XMODEM-SUM"); + tio_printf_raw("Enter file name: "); + if (tio_readln()) + { + int ret; + + tio_printf("Ready to receiving file '%s' ", line); + tio_printf("Press any key to abort transfer"); + ret = xymodem_receive(device_fd, line, XMODEM_SUM); + tio_printf("%s", ret < 0 ? "Aborted" : "Done"); + } + break; + default: tio_error_print("Invalid protocol option"); break; @@ -1127,6 +1155,8 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward) tio_printf(" (0) XMODEM-1K send"); tio_printf(" (1) XMODEM-CRC send"); tio_printf(" (2) XMODEM-CRC receive"); + tio_printf(" (3) XMODEM-SUM send"); + tio_printf(" (4) XMODEM-SUM receive"); // Process next input character as sub command sub_command = SUBCOMMAND_XMODEM; break; diff --git a/src/xymodem.c b/src/xymodem.c index cbc7834..5190e40 100644 --- a/src/xymodem.c +++ b/src/xymodem.c @@ -54,6 +54,11 @@ struct xpkt_ftr_crc uint8_t crc_lo; } __attribute__((packed)); +struct xpkt_ftr_sum +{ + uint8_t cksum; +} __attribute__((packed)); + struct xpacket_1k { struct xpkt_hdr hdr; @@ -61,13 +66,20 @@ struct xpacket_1k struct xpkt_ftr_crc ftr; } __attribute__((packed)); -struct xpacket_128b +struct xpacket_128b_crc { struct xpkt_hdr hdr; uint8_t data[128]; struct xpkt_ftr_crc ftr; } __attribute__((packed)); +struct xpacket_128b_sum +{ + struct xpkt_hdr hdr; + uint8_t data[128]; + struct xpkt_ftr_sum ftr; +} __attribute__((packed)); + /* See https://en.wikipedia.org/wiki/Computation_of_cyclic_redundancy_checks */ static uint16_t calculate_crc16(const uint8_t *data, uint16_t size) { @@ -101,6 +113,15 @@ static uint16_t update_crc16(uint16_t crc, char data_char) return crc; } +static uint8_t calculate_cksum8(const uint8_t *data, uint16_t size) +{ + uint8_t sum; + for (sum = 0; size > 0; size--) { + sum += *data++; + } + return sum; +} + /* * Drain pending characters from serial line. Insist on the * last drained character being initial character 'C':CRC,1K @@ -303,40 +324,75 @@ static int xmodem_send_1k(int sio, const void *data, size_t len, int seq) return OK; } -static int xmodem_send_128b(int sio, const void *data, size_t len) +static int xmodem_send_128b(int sio, const void *data, size_t len, bool use_crc) { - struct xpacket_128b packet; + union + { + struct xpacket_128b_crc c; + struct xpacket_128b_sum s; + } packet; const uint8_t *buf = data; char resp = 0, tmo_resp; int rc, crc, err; /* Drain pending characters from serial line. Insist on the last drained character being 'C' */ - err = xmsend_initial_handshake(sio, 'C'); + if (use_crc) + { + err = xmsend_initial_handshake(sio, 'C'); + } + else + { + err = xmsend_initial_handshake(sio, NAK); + } if (err != OK) return err; /* Always work with 128b packets */ - packet.hdr.seq = 1; - packet.hdr.type = SOH; + if (use_crc) + { + packet.c.hdr.seq = 1; + packet.c.hdr.type = SOH; + } + else + { + packet.s.hdr.seq = 1; + packet.s.hdr.type = SOH; + } while (len) { size_t sz, z = 0; char *from, status; - /* Build next packet, pad with 0 to full seq */ - z = min(len, sizeof(packet.data)); - memcpy(packet.data, buf, z); - memset(packet.data + z, 0, sizeof(packet.data) - z); - crc = calculate_crc16(packet.data, sizeof(packet.data)); - packet.ftr.crc_hi = crc >> 8; - packet.ftr.crc_lo = crc; - packet.hdr.nseq = 0xff - packet.hdr.seq; + if (use_crc) + { + /* Build next packet, pad with 0 to full seq */ + z = min(len, sizeof(packet.c.data)); + memcpy(packet.c.data, buf, z); + memset(packet.c.data + z, 0, sizeof(packet.c.data) - z); + crc = calculate_crc16(packet.c.data, sizeof(packet.c.data)); + packet.c.ftr.crc_hi = crc >> 8; + packet.c.ftr.crc_lo = crc; + packet.c.hdr.nseq = 0xff - packet.c.hdr.seq; + + from = (char *) &packet.c; + sz = sizeof(packet.c); + } + else + { + /* Build next packet, pad with 0 to full seq */ + z = min(len, sizeof(packet.s.data)); + memcpy(packet.s.data, buf, z); + memset(packet.s.data + z, 0, sizeof(packet.s.data) - z); + packet.s.ftr.cksum = calculate_cksum8(packet.s.data, sizeof(packet.s.data)); + packet.s.hdr.nseq = 0xff - packet.s.hdr.seq; + + from = (char *) &packet.s; + sz = sizeof(packet.s); + } /* Send packet */ - from = (char *) &packet; - sz = sizeof(packet); while (sz) { if (key_hit) @@ -380,7 +436,11 @@ static int xmodem_send_128b(int sio, const void *data, size_t len) /* Move to next block after ACK */ if (resp == ACK) { - packet.hdr.seq++; + if (use_crc) + packet.c.hdr.seq++; + else + packet.s.hdr.seq++; + len -= z; buf += z; } @@ -450,7 +510,7 @@ static int xmrecv_drain_pending_chars(int sio) /* * Start Receive */ -static int xmrecv_start_receive(int sio) +static int xmrecv_start_receive(int sio, bool use_crc) { int rc; struct pollfd fds; @@ -463,7 +523,11 @@ static int xmrecv_start_receive(int sio) something. The start character will be sent once a second for a number of seconds. If nothing is received in that time then return false to indicate that the transfer did not start. */ - rc = write(sio, "C", 1); + if (use_crc) + rc = write(sio, "C", 1); + else + rc = write(sio, NAK_STR, 1); + if (rc < 0) { if (errno == EWOULDBLOCK) @@ -501,7 +565,7 @@ static int xmrecv_start_receive(int sio) /* * Receive a packet */ -static int xmrecv_receive_packet(int sio, struct xpacket_128b *packet, int fd) +static int xmrecv_receive_packet(int sio, struct xpacket_128b_crc *packet, int fd, bool use_crc) { char rxSeq1, rxSeq2 = 0; char resp = 0; @@ -566,43 +630,67 @@ static int xmrecv_receive_packet(int sio, struct xpacket_128b *packet, int fd) return ERR_FATAL; } packet->data[ix] = (uint8_t) resp; - calcCrc = update_crc16(calcCrc, resp); + if (use_crc) + calcCrc = update_crc16(calcCrc, resp); + else + calcCrc = (calcCrc + (uint8_t)resp) & 0xff; + if (key_hit) return ERR_USER_CAN; } - /* Read CRC */ - rc = read_poll(sio, &resp, 1, 3000); - if (rc == 0) + if (use_crc) { - tio_error_print("Timeout waiting for first CRC byte"); - return ERR_TMO; - } - else if (rc < 0) - { - tio_error_print("Error reading first CRC byte"); - return ERR_FATAL; - } + /* Read CRC */ + rc = read_poll(sio, &resp, 1, 3000); + if (rc == 0) + { + tio_error_print("Timeout waiting for first CRC byte"); + return ERR_TMO; + } + else if (rc < 0) + { + tio_error_print("Error reading first CRC byte"); + return ERR_FATAL; + } - uint8_t uresp = resp; - uint16_t uresp16 = uresp; - rxCrc = uresp16 << 8; + uint8_t uresp = resp; + uint16_t uresp16 = uresp; + rxCrc = uresp16 << 8; - rc = read_poll(sio, &resp, 1, 3000); - if (rc == 0) - { - tio_error_print("Timeout waiting for second CRC byte"); - return ERR_TMO; - } - else if (rc < 0) - { - tio_error_print("Error reading second CRC byte"); - return ERR_FATAL; - } + rc = read_poll(sio, &resp, 1, 3000); + if (rc == 0) + { + tio_error_print("Timeout waiting for second CRC byte"); + return ERR_TMO; + } + else if (rc < 0) + { + tio_error_print("Error reading second CRC byte"); + return ERR_FATAL; + } - uresp = resp; - uresp16 = uresp; - rxCrc |= uresp16; + uresp = resp; + uresp16 = uresp; + rxCrc |= uresp16; + } + else + { + /* Read checksum */ + rc = read_poll(sio, &resp, 1, 3000); + if (rc == 0) + { + tio_error_print("Timeout waiting for checksum byte"); + return ERR_TMO; + } + else if (rc < 0) + { + tio_error_print("Error reading checksum byte"); + return ERR_FATAL; + } + + rxCrc = (uint8_t)resp; + } if (key_hit) return ERR_USER_CAN; @@ -689,9 +777,9 @@ static int xmrecv_receive_packet(int sio, struct xpacket_128b *packet, int fd) return OK; } -int xmodem_receive(int sio, int fd) +int xmodem_receive(int sio, int fd, bool use_crc) { - struct xpacket_128b packet; + struct xpacket_128b_crc packet; char resp = 0; int rc, err; bool complete = false; @@ -709,7 +797,7 @@ int xmodem_receive(int sio, int fd) packet.hdr.type = SOH; /* Start Receive*/ - err = xmrecv_start_receive(sio); + err = xmrecv_start_receive(sio, use_crc); if (err != OK) { if (err == ERR_TMO) @@ -744,7 +832,7 @@ int xmodem_receive(int sio, int fd) { case SOH: /* Start of a packet */ - err = xmrecv_receive_packet(sio, &packet, fd); + err = xmrecv_receive_packet(sio, &packet, fd, use_crc); if (err == OK) { packet.hdr.seq++; @@ -844,7 +932,11 @@ int xymodem_send(int sio, const char *filename, modem_mode_t mode) } else if (mode == XMODEM_CRC) { - err = xmodem_send_128b(sio, buf, len); + err = xmodem_send_128b(sio, buf, len, /* use_crc= */ true); + } + else if (mode == XMODEM_SUM) + { + err = xmodem_send_128b(sio, buf, len, /* use_crc= */ false); } else /* if (mode == YMODEM) */ { @@ -880,7 +972,11 @@ int xymodem_receive(int sio, const char *filename, modem_mode_t mode) } else if (mode == XMODEM_CRC) { - err = xmodem_receive(sio, fd); + err = xmodem_receive(sio, fd, /* use_crc= */ true); + } + else if (mode == XMODEM_SUM) + { + err = xmodem_receive(sio, fd, /* use_crc= */ false); } else { diff --git a/src/xymodem.h b/src/xymodem.h index b5d2b8d..ed239be 100644 --- a/src/xymodem.h +++ b/src/xymodem.h @@ -25,6 +25,7 @@ typedef enum { XMODEM_1K, XMODEM_CRC, + XMODEM_SUM, YMODEM, } modem_mode_t;