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"); tio_printf("%s", ret < 0 ? "Aborted" : "Done");
break; 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: case YMODEM:
tio_printf("Sending file '%s' using YMODEM", file); tio_printf("Sending file '%s' using YMODEM", file);
ret = xymodem_send(device_fd, file, YMODEM); 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, "toggle", 2);
script_set_global(L, "high", 1); script_set_global(L, "high", 1);
script_set_global(L, "low", 0); 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_CRC", XMODEM_CRC);
script_set_global(L, "XMODEM_1K", XMODEM_1K); script_set_global(L, "XMODEM_1K", XMODEM_1K);
script_set_global(L, "YMODEM", YMODEM); 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; 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: default:
tio_error_print("Invalid protocol option"); tio_error_print("Invalid protocol option");
break; 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(" (0) XMODEM-1K send");
tio_printf(" (1) XMODEM-CRC send"); tio_printf(" (1) XMODEM-CRC send");
tio_printf(" (2) XMODEM-CRC receive"); 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 // Process next input character as sub command
sub_command = SUBCOMMAND_XMODEM; sub_command = SUBCOMMAND_XMODEM;
break; break;

View file

@ -54,6 +54,11 @@ struct xpkt_ftr_crc
uint8_t crc_lo; uint8_t crc_lo;
} __attribute__((packed)); } __attribute__((packed));
struct xpkt_ftr_sum
{
uint8_t cksum;
} __attribute__((packed));
struct xpacket_1k struct xpacket_1k
{ {
struct xpkt_hdr hdr; struct xpkt_hdr hdr;
@ -61,13 +66,20 @@ struct xpacket_1k
struct xpkt_ftr_crc ftr; struct xpkt_ftr_crc ftr;
} __attribute__((packed)); } __attribute__((packed));
struct xpacket_128b struct xpacket_128b_crc
{ {
struct xpkt_hdr hdr; struct xpkt_hdr hdr;
uint8_t data[128]; uint8_t data[128];
struct xpkt_ftr_crc ftr; struct xpkt_ftr_crc ftr;
} __attribute__((packed)); } __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 */ /* See https://en.wikipedia.org/wiki/Computation_of_cyclic_redundancy_checks */
static uint16_t calculate_crc16(const uint8_t *data, uint16_t size) 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; 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 * Drain pending characters from serial line. Insist on the
* last drained character being initial character 'C':CRC,1K * 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; 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; const uint8_t *buf = data;
char resp = 0, tmo_resp; char resp = 0, tmo_resp;
int rc, crc, err; int rc, crc, err;
/* Drain pending characters from serial line. /* Drain pending characters from serial line.
Insist on the last drained character being 'C' */ Insist on the last drained character being 'C' */
if (use_crc)
{
err = xmsend_initial_handshake(sio, 'C'); err = xmsend_initial_handshake(sio, 'C');
}
else
{
err = xmsend_initial_handshake(sio, NAK);
}
if (err != OK) if (err != OK)
return err; return err;
/* Always work with 128b packets */ /* Always work with 128b packets */
packet.hdr.seq = 1; if (use_crc)
packet.hdr.type = SOH; {
packet.c.hdr.seq = 1;
packet.c.hdr.type = SOH;
}
else
{
packet.s.hdr.seq = 1;
packet.s.hdr.type = SOH;
}
while (len) while (len)
{ {
size_t sz, z = 0; size_t sz, z = 0;
char *from, status; char *from, status;
if (use_crc)
{
/* Build next packet, pad with 0 to full seq */ /* Build next packet, pad with 0 to full seq */
z = min(len, sizeof(packet.data)); z = min(len, sizeof(packet.c.data));
memcpy(packet.data, buf, z); memcpy(packet.c.data, buf, z);
memset(packet.data + z, 0, sizeof(packet.data) - z); memset(packet.c.data + z, 0, sizeof(packet.c.data) - z);
crc = calculate_crc16(packet.data, sizeof(packet.data)); crc = calculate_crc16(packet.c.data, sizeof(packet.c.data));
packet.ftr.crc_hi = crc >> 8; packet.c.ftr.crc_hi = crc >> 8;
packet.ftr.crc_lo = crc; packet.c.ftr.crc_lo = crc;
packet.hdr.nseq = 0xff - packet.hdr.seq; 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 */ /* Send packet */
from = (char *) &packet;
sz = sizeof(packet);
while (sz) while (sz)
{ {
if (key_hit) 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 */ /* Move to next block after ACK */
if (resp == ACK) if (resp == ACK)
{ {
packet.hdr.seq++; if (use_crc)
packet.c.hdr.seq++;
else
packet.s.hdr.seq++;
len -= z; len -= z;
buf += z; buf += z;
} }
@ -450,7 +510,7 @@ static int xmrecv_drain_pending_chars(int sio)
/* /*
* Start Receive * Start Receive
*/ */
static int xmrecv_start_receive(int sio) static int xmrecv_start_receive(int sio, bool use_crc)
{ {
int rc; int rc;
struct pollfd fds; 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 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 seconds. If nothing is received in that time then return false to indicate
that the transfer did not start. */ that the transfer did not start. */
if (use_crc)
rc = write(sio, "C", 1); rc = write(sio, "C", 1);
else
rc = write(sio, NAK_STR, 1);
if (rc < 0) if (rc < 0)
{ {
if (errno == EWOULDBLOCK) if (errno == EWOULDBLOCK)
@ -501,7 +565,7 @@ static int xmrecv_start_receive(int sio)
/* /*
* Receive a packet * 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 rxSeq1, rxSeq2 = 0;
char resp = 0; char resp = 0;
@ -566,11 +630,17 @@ static int xmrecv_receive_packet(int sio, struct xpacket_128b *packet, int fd)
return ERR_FATAL; return ERR_FATAL;
} }
packet->data[ix] = (uint8_t) resp; packet->data[ix] = (uint8_t) resp;
if (use_crc)
calcCrc = update_crc16(calcCrc, resp); calcCrc = update_crc16(calcCrc, resp);
else
calcCrc = (calcCrc + (uint8_t)resp) & 0xff;
if (key_hit) if (key_hit)
return ERR_USER_CAN; return ERR_USER_CAN;
} }
if (use_crc)
{
/* Read CRC */ /* Read CRC */
rc = read_poll(sio, &resp, 1, 3000); rc = read_poll(sio, &resp, 1, 3000);
if (rc == 0) if (rc == 0)
@ -603,6 +673,24 @@ static int xmrecv_receive_packet(int sio, struct xpacket_128b *packet, int fd)
uresp = resp; uresp = resp;
uresp16 = uresp; uresp16 = uresp;
rxCrc |= uresp16; 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) if (key_hit)
return ERR_USER_CAN; return ERR_USER_CAN;
@ -689,9 +777,9 @@ static int xmrecv_receive_packet(int sio, struct xpacket_128b *packet, int fd)
return OK; 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; char resp = 0;
int rc, err; int rc, err;
bool complete = false; bool complete = false;
@ -709,7 +797,7 @@ int xmodem_receive(int sio, int fd)
packet.hdr.type = SOH; packet.hdr.type = SOH;
/* Start Receive*/ /* Start Receive*/
err = xmrecv_start_receive(sio); err = xmrecv_start_receive(sio, use_crc);
if (err != OK) if (err != OK)
{ {
if (err == ERR_TMO) if (err == ERR_TMO)
@ -744,7 +832,7 @@ int xmodem_receive(int sio, int fd)
{ {
case SOH: case SOH:
/* Start of a packet */ /* Start of a packet */
err = xmrecv_receive_packet(sio, &packet, fd); err = xmrecv_receive_packet(sio, &packet, fd, use_crc);
if (err == OK) if (err == OK)
{ {
packet.hdr.seq++; packet.hdr.seq++;
@ -844,7 +932,11 @@ int xymodem_send(int sio, const char *filename, modem_mode_t mode)
} }
else if (mode == XMODEM_CRC) 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) */ 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) 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 else
{ {

View file

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