--- /dev/null
+/* XMODEM support for GDB, the GNU debugger.
+ Copyright 1995, 2000, 2001 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "chime.h"
+#include "sci.h"
+#include "xmodem.h"
+
+/* These definitions are for xmodem protocol. */
+
+#define SOH 0x01
+#define STX 0x02
+#define ACK 0x06
+#define NAK 0x15
+#define EOT 0x04
+#define CANCEL 0x18
+
+static int blknum; /* XMODEM block number */
+static int crcflag; /* Sez we are using CRC's instead of cksums */
+
+static int
+readchar (int timeout)
+{
+ int c;
+
+ c = serial_readchar (timeout);
+
+ if (c >= 0)
+ return c;
+
+ if (c == SERIAL_TIMEOUT)
+ chime_for(0xff);
+ /*error ("Timeout reading from remote system.")*/;
+
+ return 0;
+}
+
+#define CRC16 0x1021 /* Generator polynomial (X^16 + X^12 + X^5 + 1) */
+
+
+/* Call this to init the fast CRC-16 calculation table. */
+
+static short crctab(u8 val) {
+ int i;
+ unsigned int crc;
+
+ crc = val << 8;
+
+ for (i = 0; i < 8; ++i)
+ {
+ crc <<= 1;
+
+ if (crc & 0x10000)
+ crc ^= CRC16;
+ }
+
+ return crc;
+}
+
+/* Calculate a CRC-16 for the LEN byte message pointed at by P. */
+/* Pads with ^Z if necessary */
+
+static unsigned short
+docrc (unsigned char *p, int len)
+{
+ int len2 = len;
+ unsigned short crc = 0;
+
+ while (len-- > 0)
+ crc = (crc << 8) ^ crctab((crc >> 8) ^ *p++);
+ if (len2 < 128) {
+ len = 128-len;
+ while (len-- > 0)
+ crc = (crc << 8) ^ crctab((crc >> 8) ^ 0x1a);
+ }
+
+ return crc;
+}
+
+/* Start up the transmit process. Reset state variables. Wait for receiver to
+ send NAK or CRC request. */
+
+int
+xmodem_init_xfer ()
+{
+ int c;
+ int i;
+
+ blknum = 1;
+ crcflag = 0;
+
+ for (i = 1; i <= 10; i++)
+ {
+ c = readchar (6);
+
+ switch (c)
+ {
+ case 'C':
+ crcflag = 1;
+ /* fall through */
+ case NAK:
+ return 1;
+ default:
+ chime_for(0x7f);
+ /* fprintf_unfiltered (gdb_stderr, "xmodem_init_xfer: Got unexpected character %c (0%o)\n", c, c); */
+ continue;
+ case CANCEL: /* target aborted load */
+ /* fprintf_unfiltered (gdb_stderr, "Got a CANCEL from the target.\n"); */
+ return 0;
+ }
+ }
+ chime_for(0xff);
+ /*error ("xmodem_init_xfer: Too many unexpected characters.");*/
+ return 0;
+}
+
+/* Take 128 bytes of data and make a packet out of it.
+
+ * Each packet looks like this:
+ * +-----+-------+-------+------+-----+
+ * | SOH | Seq1. | Seq2. | data | SUM |
+ * +-----+-------+-------+------+-----+
+ * SOH = 0x01
+ * Seq1 = The sequence number.
+ * Seq2 = The complement of the sequence number.
+ * Data = A 128 bytes of data.
+ * SUM = Add the contents of the 128 bytes and use the low-order
+ * 8 bits of the result.
+ *
+ * send_xmodem_packet fills in the XMODEM fields of PACKET and sends it to the
+ * remote system. PACKET must be XMODEM_PACKETSIZE bytes long. The data must
+ * start 3 bytes after the beginning of the packet to leave room for the
+ * XMODEM header. LEN is the length of the data portion of the packet (and
+ * must be <= 128 bytes). If it is < 128 bytes, ^Z padding will be added.
+ */
+
+bool
+xmodem_send_packet (const unsigned char *packet, int len)
+{
+ int i;
+ int retries;
+ char p;
+ char s[3];
+
+ if (len > XMODEM_DATASIZE) {
+ chime_for(0xff);
+ return 0;
+ }
+
+ for (retries = 3; retries >= 0; retries--) {
+ int c;
+ /* send the packet header */
+ send_string("\x01"); /* SOH */
+ p = blknum; serial_write(&p, 1);
+ p = ~blknum; serial_write(&p, 1);
+
+ serial_write(packet, len); /* Send data bytes */
+
+ char *ptr, *end;
+ ptr = (char*)(packet+len);
+ end = (char*)(packet+128);
+ for (; ptr < end; ptr++) {
+ send_string("\x1A"); /* pad with ^Z */
+ }
+
+ /* Add ^Z padding if packet < 128 (or 1024) bytes */
+ if (crcflag) {
+ u16 crc;
+
+ crc = docrc ((unsigned char*)packet, len);
+
+ s[0] = crc >> 8;
+ s[1] = crc & 0xff;
+ s[2] = '\0';
+ send_string(s);
+ } else {
+ int sum;
+
+ sum = 0;
+ for (i = 0; i < len; i++)
+ sum += packet[i];
+ for (; i < 128; i++)
+ sum += 0x1a;
+
+ s[0] = sum;
+ s[1] = '\0';
+ send_string(s);
+ }
+
+ c = readchar (3);
+ switch (c)
+ {
+ case ACK:
+ goto out;
+ case NAK:
+ continue;
+ case CANCEL:
+ /* error ("xmodem_send_packet: Transfer aborted by receiver."); */
+ chime_for(0xff);
+ return 0;
+ default:
+ /*fprintf_unfiltered (gdb_stderr, "xmodem_send_packet: Got unexpected character %c (0%o)\n", c, c);*/
+ /* mtearle is evil */
+ chime_for(c);
+ continue;
+ }
+ }
+
+ //serial_write ("\004", 1); /* Send an EOT */
+
+ /* error ("xmodem_send_packet: Excessive retries."); */
+ chime_for(0xff);
+ return 0;
+out:
+ blknum++;
+ return 1;
+}
+
+/* Finish off the transfer. Send out the EOT, and wait for an ACK. */
+
+void
+xmodem_finish_xfer ()
+{
+ int retries;
+
+ for (retries = 10; retries >= 0; retries--)
+ {
+ int c;
+
+ serial_write ("\004", 1); /* Send an EOT */
+
+ c = readchar (3);
+ switch (c)
+ {
+ case ACK:
+ return;
+ case NAK:
+ continue;
+ case CANCEL:
+ chime_for(0xff);
+ /* error ("xmodem_finish_xfer: Transfer aborted by receiver."); */
+ default:
+ /* fprintf_unfiltered (gdb_stderr, "xmodem_send_packet: Got unexpected character %c (0%o)\n", c, c); */
+ chime_for(c);
+ continue;
+ }
+ }
+
+ chime_for(0xff);
+ /* error ("xmodem_finish_xfer: Excessive retries."); */
+}