xmodem support
[uccvend-snackrom.git] / ROM2 / xmodem.c
1 /* XMODEM support for GDB, the GNU debugger.
2    Copyright 1995, 2000, 2001 Free Software Foundation, Inc.
3
4    This file is part of GDB.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21 #include "chime.h"
22 #include "sci.h"
23 #include "xmodem.h"
24
25 /* These definitions are for xmodem protocol. */
26
27 #define SOH     0x01
28 #define STX     0x02
29 #define ACK     0x06
30 #define NAK     0x15
31 #define EOT     0x04
32 #define CANCEL  0x18
33
34 static int blknum;              /* XMODEM block number */
35 static int crcflag;             /* Sez we are using CRC's instead of cksums */
36
37 static int
38 readchar (int timeout)
39 {
40   int c;
41
42   c = serial_readchar (timeout);
43
44   if (c >= 0)
45     return c;
46
47   if (c == SERIAL_TIMEOUT)
48           chime_for(0xff);
49     /*error ("Timeout reading from remote system.")*/;
50
51   return 0;
52 }
53
54 #define CRC16 0x1021            /* Generator polynomial (X^16 + X^12 + X^5 + 1) */
55
56
57 /* Call this to init the fast CRC-16 calculation table.  */
58
59 static short crctab(u8 val) {
60       int i;
61       unsigned int crc;
62
63       crc = val << 8;
64
65       for (i = 0; i < 8; ++i)
66         {
67           crc <<= 1;
68
69           if (crc & 0x10000)
70             crc ^= CRC16;
71         }
72
73           return crc;
74 }
75
76 /* Calculate a CRC-16 for the LEN byte message pointed at by P.  */
77 /* Pads with ^Z if necessary */
78
79 static unsigned short
80 docrc (unsigned char *p, int len)
81 {
82   int len2 = len;
83   unsigned short crc = 0;
84
85   while (len-- > 0)
86     crc = (crc << 8) ^ crctab((crc >> 8) ^ *p++);
87   if (len2 < 128) {
88     len = 128-len;
89     while (len-- > 0)
90       crc = (crc << 8) ^ crctab((crc >> 8) ^ 0x1a);
91   }
92
93   return crc;
94 }
95
96 /* Start up the transmit process.  Reset state variables.  Wait for receiver to
97    send NAK or CRC request.  */
98
99 int
100 xmodem_init_xfer ()
101 {
102   int c;
103   int i;
104
105   blknum = 1;
106   crcflag = 0;
107
108   for (i = 1; i <= 10; i++)
109     {
110       c = readchar (6);
111
112       switch (c)
113         {
114         case 'C':
115           crcflag = 1;
116           /* fall through */
117         case NAK:
118           return 1;
119         default:
120           chime_for(0x7f);
121           /* fprintf_unfiltered (gdb_stderr, "xmodem_init_xfer: Got unexpected character %c (0%o)\n", c, c); */
122           continue;
123         case CANCEL:            /* target aborted load */
124           /* fprintf_unfiltered (gdb_stderr, "Got a CANCEL from the target.\n"); */
125           return 0;
126         }
127     }
128   chime_for(0xff);
129   /*error ("xmodem_init_xfer:  Too many unexpected characters.");*/
130   return 0;
131 }
132
133 /* Take 128 bytes of data and make a packet out of it.
134
135  *      Each packet looks like this:
136  *      +-----+-------+-------+------+-----+
137  *      | SOH | Seq1. | Seq2. | data | SUM |
138  *      +-----+-------+-------+------+-----+
139  *      SOH  = 0x01
140  *      Seq1 = The sequence number.
141  *      Seq2 = The complement of the sequence number.
142  *      Data = A 128 bytes of data.
143  *      SUM  = Add the contents of the 128 bytes and use the low-order
144  *             8 bits of the result.
145  *
146  * send_xmodem_packet fills in the XMODEM fields of PACKET and sends it to the
147  * remote system.  PACKET must be XMODEM_PACKETSIZE bytes long.  The data must
148  * start 3 bytes after the beginning of the packet to leave room for the
149  * XMODEM header.  LEN is the length of the data portion of the packet (and
150  * must be <= 128 bytes).  If it is < 128 bytes, ^Z padding will be added.
151  */
152
153 bool
154 xmodem_send_packet (const unsigned char *packet, int len)
155 {
156   int i;
157   int retries;
158   char p;
159   char s[3];
160
161   if (len > XMODEM_DATASIZE) {
162     chime_for(0xff);
163     return 0;
164   }
165
166   for (retries = 3; retries >= 0; retries--) {
167     int c;
168     /* send the packet header */
169     send_string("\x01"); /* SOH */
170     p = blknum; serial_write(&p, 1);
171     p = ~blknum; serial_write(&p, 1);
172
173     serial_write(packet, len); /* Send data bytes */
174
175     char *ptr, *end;
176     ptr = (char*)(packet+len);
177     end = (char*)(packet+128);
178     for (; ptr < end; ptr++) {
179       send_string("\x1A"); /* pad with ^Z */
180     }
181
182     /* Add ^Z padding if packet < 128 (or 1024) bytes */
183     if (crcflag) {
184       u16 crc;
185
186       crc = docrc ((unsigned char*)packet, len);
187
188       s[0] = crc >> 8;
189       s[1] = crc & 0xff;
190       s[2] = '\0';
191       send_string(s);
192     } else {
193       int sum;
194
195       sum = 0;
196       for (i = 0; i < len; i++)
197         sum += packet[i];
198       for (; i < 128; i++)
199         sum += 0x1a;
200
201       s[0] = sum;
202       s[1] = '\0';
203       send_string(s);
204     }
205
206     c = readchar (3);
207     switch (c)
208       {
209       case ACK:
210         goto out;
211       case NAK:
212         continue;
213       case CANCEL:
214         /* error ("xmodem_send_packet: Transfer aborted by receiver."); */
215         chime_for(0xff);
216         return 0;
217       default:
218         /*fprintf_unfiltered (gdb_stderr, "xmodem_send_packet: Got unexpected character %c (0%o)\n", c, c);*/
219         /* mtearle is evil */
220         chime_for(c);
221         continue;
222       }
223   }
224
225   //serial_write ("\004", 1);   /* Send an EOT */
226
227   /* error ("xmodem_send_packet:  Excessive retries."); */
228   chime_for(0xff);
229   return 0;
230 out:
231   blknum++;
232   return 1;
233 }
234
235 /* Finish off the transfer.  Send out the EOT, and wait for an ACK.  */
236
237 void
238 xmodem_finish_xfer ()
239 {
240   int retries;
241
242   for (retries = 10; retries >= 0; retries--)
243     {
244       int c;
245
246       serial_write ("\004", 1); /* Send an EOT */
247
248       c = readchar (3);
249       switch (c)
250         {
251         case ACK:
252           return;
253         case NAK:
254           continue;
255         case CANCEL:
256           chime_for(0xff);
257           /* error ("xmodem_finish_xfer: Transfer aborted by receiver."); */
258         default:
259           /* fprintf_unfiltered (gdb_stderr, "xmodem_send_packet: Got unexpected character %c (0%o)\n", c, c); */
260           chime_for(c);
261           continue;
262         }
263     }
264
265   chime_for(0xff);
266   /* error ("xmodem_finish_xfer:  Excessive retries."); */
267 }

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