mirror of
https://github.com/tio/tio.git
synced 2026-05-01 14:57:59 +02:00
Add Xmodem-SUM support.
This commit is contained in:
parent
6cc0a58ed8
commit
e458b02771
4 changed files with 189 additions and 55 deletions
|
|
@ -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);
|
||||||
|
|
|
||||||
30
src/tty.c
30
src/tty.c
|
|
@ -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;
|
||||||
|
|
|
||||||
142
src/xymodem.c
142
src/xymodem.c
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ typedef enum
|
||||||
{
|
{
|
||||||
XMODEM_1K,
|
XMODEM_1K,
|
||||||
XMODEM_CRC,
|
XMODEM_CRC,
|
||||||
|
XMODEM_SUM,
|
||||||
YMODEM,
|
YMODEM,
|
||||||
} modem_mode_t;
|
} modem_mode_t;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue