2003-07-16 Andrew Cagney <cagney@redhat.com>
[deliverable/binutils-gdb.git] / gdb / xmodem.c
CommitLineData
c906108c 1/* XMODEM support for GDB, the GNU debugger.
b6ba6518 2 Copyright 1995, 2000, 2001 Free Software Foundation, Inc.
c906108c 3
c5aa993b 4 This file is part of GDB.
c906108c 5
c5aa993b
JM
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.
c906108c 10
c5aa993b
JM
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.
c906108c 15
c5aa993b
JM
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. */
c906108c
SS
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
35static int blknum; /* XMODEM block number */
36static int crcflag; /* Sez we are using CRC's instead of cksums */
37
38static int
819cc324 39readchar (struct serial *desc, int timeout)
c906108c
SS
40{
41 int c;
42
2cd58942 43 c = serial_readchar (desc, timeout);
c906108c
SS
44
45 if (remote_debug > 0)
9846de1b 46 fputc_unfiltered (c, gdb_stdlog);
c906108c
SS
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
59static unsigned short *crctab;
60
61/* Call this to init the fast CRC-16 calculation table. */
62
63static void
fba45db2 64crcinit (void)
c906108c
SS
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
c5aa993b 89 crctab[val] = crc;
c906108c
SS
90 }
91
92 crctab_inited = 1;
93}
94
95/* Calculate a CRC-16 for the LEN byte message pointed at by P. */
96
97static unsigned short
fba45db2 98docrc (unsigned char *p, int len)
c906108c
SS
99{
100 unsigned short crc = 0;
101
102 while (len-- > 0)
c5aa993b 103 crc = (crc << 8) ^ crctab[(crc >> 8) ^ *p++];
c906108c
SS
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
111int
819cc324 112xmodem_init_xfer (struct serial *desc)
c906108c
SS
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.
c5aa993b
JM
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.
c906108c
SS
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
162void
819cc324 163xmodem_send_packet (struct serial *desc, unsigned char *packet, int len, int hashmark)
c906108c
SS
164{
165 int i;
166 int retries;
167 int pktlen;
168 int datasize;
c5aa993b 169
c906108c
SS
170 /* build the packet header */
171
172 packet[1] = blknum;
173 packet[2] = ~blknum;
174
175 blknum++;
c5aa993b 176
c906108c
SS
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
e1e9e218 188 internal_error (__FILE__, __LINE__, "failed internal consistency check"); /* Packet way too large */
c906108c
SS
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
c5aa993b 212 packet[3 + datasize] = sum; /* add the checksum */
c906108c
SS
213 pktlen = datasize + 4;
214 }
215
216 for (retries = 3; retries >= 0; retries--)
217 {
218 int c;
219
2cd58942 220 serial_write (desc, packet, pktlen);
c906108c
SS
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
2cd58942 241 serial_write (desc, "\004", 1); /* Send an EOT */
c906108c
SS
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
248void
819cc324 249xmodem_finish_xfer (struct serial *desc)
c906108c
SS
250{
251 int retries;
252
253 for (retries = 10; retries >= 0; retries--)
254 {
255 int c;
256
2cd58942 257 serial_write (desc, "\004", 1); /* Send an EOT */
c906108c
SS
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}
This page took 0.546547 seconds and 4 git commands to generate.