This commit was generated by cvs2svn to track changes on a CVS vendor
[platform/upstream/binutils.git] / gdb / xmodem.c
1 /* XMODEM support for GDB, the GNU debugger.
2    Copyright 1995 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 "defs.h"
22 #include "serial.h"
23 #include "target.h"
24 #include "xmodem.h"
25
26 /* These definitions are for xmodem protocol. */
27
28 #define SOH     0x01
29 #define STX     0x02
30 #define ACK     0x06
31 #define NAK     0x15
32 #define EOT     0x04
33 #define CANCEL  0x18
34
35 static int blknum;              /* XMODEM block number */
36 static int crcflag;             /* Sez we are using CRC's instead of cksums */
37
38 static int
39 readchar (desc, timeout)
40      serial_t desc;
41      int timeout;
42 {
43   int c;
44
45   c = SERIAL_READCHAR (desc, timeout);
46
47   if (remote_debug > 0)
48     fputc_unfiltered (c, gdb_stdlog);
49
50   if (c >= 0)
51     return c;
52
53   if (c == SERIAL_TIMEOUT)
54     error ("Timeout reading from remote system.");
55
56   perror_with_name ("xmodem.c:readchar()");
57 }
58
59 #define CRC16 0x1021            /* Generator polynomial (X^16 + X^12 + X^5 + 1) */
60
61 static unsigned short *crctab;
62
63 /* Call this to init the fast CRC-16 calculation table.  */
64
65 static void
66 crcinit ()
67 {
68   static int crctab_inited = 0;
69   int val;
70
71   if (crctab_inited == 1)
72     return;
73
74   crctab = xmalloc (256 * sizeof (short));
75
76   for (val = 0; val <= 255; val++)
77     {
78       int i;
79       unsigned int crc;
80
81       crc = val << 8;
82
83       for (i = 0; i < 8; ++i)
84         {
85           crc <<= 1;
86
87           if (crc & 0x10000)
88             crc ^= CRC16;
89         }
90
91       crctab[val] = crc;
92     }
93
94   crctab_inited = 1;
95 }
96
97 /* Calculate a CRC-16 for the LEN byte message pointed at by P.  */
98
99 static unsigned short
100 docrc (p, len)
101      unsigned char *p;
102      int len;
103 {
104   unsigned short crc = 0;
105
106   while (len-- > 0)
107     crc = (crc << 8) ^ crctab[(crc >> 8) ^ *p++];
108
109   return crc;
110 }
111
112 /* Start up the transmit process.  Reset state variables.  Wait for receiver to
113    send NAK or CRC request.  */
114
115 int
116 xmodem_init_xfer (desc)
117      serial_t desc;
118 {
119   int c;
120   int i;
121
122   blknum = 1;
123   crcflag = 0;
124   crcinit ();
125
126   for (i = 1; i <= 10; i++)
127     {
128       c = readchar (desc, 6);
129
130       switch (c)
131         {
132         case 'C':
133           crcflag = 1;
134         case NAK:
135           return 0;
136         default:
137           fprintf_unfiltered (gdb_stderr, "xmodem_init_xfer: Got unexpected character %c (0%o)\n", c, c);
138           continue;
139         case CANCEL:            /* target aborted load */
140           fprintf_unfiltered (gdb_stderr, "Got a CANCEL from the target.\n");
141           continue;
142         }
143     }
144   error ("xmodem_init_xfer:  Too many unexpected characters.");
145 }
146
147 /* Take 128 bytes of data and make a packet out of it.
148
149  *      Each packet looks like this:
150  *      +-----+-------+-------+------+-----+
151  *      | SOH | Seq1. | Seq2. | data | SUM |
152  *      +-----+-------+-------+------+-----+
153  *      SOH  = 0x01
154  *      Seq1 = The sequence number.
155  *      Seq2 = The complement of the sequence number.
156  *      Data = A 128 bytes of data.
157  *      SUM  = Add the contents of the 128 bytes and use the low-order
158  *             8 bits of the result.
159  *
160  * send_xmodem_packet fills in the XMODEM fields of PACKET and sends it to the
161  * remote system.  PACKET must be XMODEM_PACKETSIZE bytes long.  The data must
162  * start 3 bytes after the beginning of the packet to leave room for the
163  * XMODEM header.  LEN is the length of the data portion of the packet (and
164  * must be <= 128 bytes).  If it is < 128 bytes, ^Z padding will be added.
165  */
166
167 void
168 xmodem_send_packet (desc, packet, len, hashmark)
169      serial_t desc;
170      unsigned char *packet;
171      int len;
172      int hashmark;
173 {
174   int i;
175   int retries;
176   int pktlen;
177   int datasize;
178
179   /* build the packet header */
180
181   packet[1] = blknum;
182   packet[2] = ~blknum;
183
184   blknum++;
185
186   if (len <= XMODEM_DATASIZE)
187     {
188       packet[0] = SOH;
189       datasize = XMODEM_DATASIZE;
190     }
191   else if (len <= XMODEM_1KDATASIZE)
192     {
193       packet[0] = STX;
194       datasize = XMODEM_1KDATASIZE;
195     }
196   else
197     abort ();                   /* Packet way too large */
198
199   /* Add ^Z padding if packet < 128 (or 1024) bytes */
200
201   memset (packet + 3 + len, '\026', datasize - len);
202
203   if (crcflag)
204     {
205       int crc;
206
207       crc = docrc (packet + 3, datasize);
208
209       packet[3 + datasize] = crc >> 8;
210       packet[3 + datasize + 1] = crc;
211       pktlen = datasize + 5;
212     }
213   else
214     {
215       int sum;
216
217       sum = 0;
218       for (i = 3; i < datasize + 3; i++)
219         sum += packet[i];
220
221       packet[3 + datasize] = sum;       /* add the checksum */
222       pktlen = datasize + 4;
223     }
224
225   for (retries = 3; retries >= 0; retries--)
226     {
227       int c;
228
229       SERIAL_WRITE (desc, packet, pktlen);
230
231       c = readchar (desc, 3);
232       switch (c)
233         {
234         case ACK:
235           return;
236         case NAK:
237           if (!hashmark)
238             continue;
239           putchar_unfiltered ('-');
240           gdb_flush (gdb_stdout);
241           continue;
242         case CANCEL:
243           error ("xmodem_send_packet: Transfer aborted by receiver.");
244         default:
245           fprintf_unfiltered (gdb_stderr, "xmodem_send_packet: Got unexpected character %c (0%o)\n", c, c);
246           continue;
247         }
248     }
249
250   SERIAL_WRITE (desc, "\004", 1);       /* Send an EOT */
251
252   error ("xmodem_send_packet:  Excessive retries.");
253 }
254
255 /* Finish off the transfer.  Send out the EOT, and wait for an ACK.  */
256
257 void
258 xmodem_finish_xfer (desc)
259      serial_t desc;
260 {
261   int retries;
262
263   for (retries = 10; retries >= 0; retries--)
264     {
265       int c;
266
267       SERIAL_WRITE (desc, "\004", 1);   /* Send an EOT */
268
269       c = readchar (desc, 3);
270       switch (c)
271         {
272         case ACK:
273           return;
274         case NAK:
275           continue;
276         case CANCEL:
277           error ("xmodem_finish_xfer: Transfer aborted by receiver.");
278         default:
279           fprintf_unfiltered (gdb_stderr, "xmodem_send_packet: Got unexpected character %c (0%o)\n", c, c);
280           continue;
281         }
282     }
283
284   error ("xmodem_finish_xfer:  Excessive retries.");
285 }