Add Xmodem-SUM support.

This commit is contained in:
yabu76 2025-08-16 10:52:31 +09:00
parent 6cc0a58ed8
commit e458b02771
4 changed files with 189 additions and 55 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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
{

View file

@ -25,6 +25,7 @@ typedef enum
{
XMODEM_1K,
XMODEM_CRC,
XMODEM_SUM,
YMODEM,
} modem_mode_t;