xmodem support
[uccvend-snackrom.git] / ROM2 / xmodem.c
diff --git a/ROM2/xmodem.c b/ROM2/xmodem.c
new file mode 100644 (file)
index 0000000..7615d9b
--- /dev/null
@@ -0,0 +1,267 @@
+/* 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."); */
+}

UCC git Repository :: git.ucc.asn.au