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