Message Integrity Checking
[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 #include "crctab.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 (int timeout)
40 {
41   int c;
42
43   c = serial_readchar (timeout);
44
45   if (c >= 0)
46     return c;
47
48   if (c == SERIAL_TIMEOUT)
49           chime_for(0xff);
50     /*error ("Timeout reading from remote system.")*/;
51
52   return 0;
53 }
54
55 /* Calculate a CRC-16 for the LEN byte message pointed at by P.  */
56 /* Pads with ^Z up to 128 bytes if told to */
57
58 unsigned short
59 docrc (unsigned char *p, short len, bool pad, unsigned short crc)
60 {
61   short len2 = len;
62
63   while (len-- > 0) {
64     crc = (crc << 8) ^ (crctab[(crc >> 8) ^ *p]);
65         p++;
66   }
67   if (pad && len2 < 128) {
68     len = 128-len;
69     while (len-- > 0)
70       crc = (crc << 8) ^ crctab[(crc >> 8) ^ 0x1a];
71   }
72
73   return crc;
74 }
75
76 /* Start up the transmit process.  Reset state variables.  Wait for receiver to
77    send NAK or CRC request.  */
78
79 int
80 xmodem_init_xfer ()
81 {
82   int c;
83   int i;
84
85   blknum = 1;
86   crcflag = 0;
87
88   for (i = 1; i <= 10; i++)
89     {
90       c = readchar (6);
91
92       switch (c)
93         {
94         case 'C':
95           crcflag = 1;
96           /* fall through */
97         case NAK:
98           return 1;
99         default:
100           chime_for(0x7f);
101           /* fprintf_unfiltered (gdb_stderr, "xmodem_init_xfer: Got unexpected character %c (0%o)\n", c, c); */
102           continue;
103         case CANCEL:            /* target aborted load */
104           /* fprintf_unfiltered (gdb_stderr, "Got a CANCEL from the target.\n"); */
105           return 0;
106         }
107     }
108   chime_for(0xff);
109   /*error ("xmodem_init_xfer:  Too many unexpected characters.");*/
110   return 0;
111 }
112
113 /* Take 128 bytes of data and make a packet out of it.
114
115  *      Each packet looks like this:
116  *      +-----+-------+-------+------+-----+
117  *      | SOH | Seq1. | Seq2. | data | SUM |
118  *      +-----+-------+-------+------+-----+
119  *      SOH  = 0x01
120  *      Seq1 = The sequence number.
121  *      Seq2 = The complement of the sequence number.
122  *      Data = A 128 bytes of data.
123  *      SUM  = Add the contents of the 128 bytes and use the low-order
124  *             8 bits of the result.
125  *
126  * send_xmodem_packet fills in the XMODEM fields of PACKET and sends it to the
127  * remote system.  PACKET must be XMODEM_PACKETSIZE bytes long.  The data must
128  * start 3 bytes after the beginning of the packet to leave room for the
129  * XMODEM header.  LEN is the length of the data portion of the packet (and
130  * must be <= 128 bytes).  If it is < 128 bytes, ^Z padding will be added.
131  */
132
133 bool
134 xmodem_send_packet (const unsigned char *packet, int len)
135 {
136   int i;
137   int retries;
138   char p;
139   char s[3];
140
141   if (len > XMODEM_DATASIZE) {
142     chime_for(0xff);
143     return 0;
144   }
145
146   for (retries = 3; retries >= 0; retries--) {
147     int c;
148     /* send the packet header */
149     send_string("\x01"); /* SOH */
150     p = blknum; serial_write(&p, 1);
151     p = ~blknum; serial_write(&p, 1);
152
153     serial_write(packet, len); /* Send data bytes */
154
155     char *ptr, *end;
156     ptr = (char*)(packet+len);
157     end = (char*)(packet+128);
158     for (; ptr < end; ptr++) {
159       send_string("\x1A"); /* pad with ^Z */
160     }
161
162     /* Add ^Z padding if packet < 128 (or 1024) bytes */
163     if (crcflag) {
164       u16 crc;
165
166       crc = docrc ((unsigned char*)packet, len, 1, 0);
167
168       s[0] = crc >> 8;
169       s[1] = crc & 0xff;
170       s[2] = '\0';
171       send_string(s);
172     } else {
173       int sum;
174
175       sum = 0;
176       for (i = 0; i < len; i++)
177         sum += packet[i];
178       for (; i < 128; i++)
179         sum += 0x1a;
180
181       s[0] = sum;
182       s[1] = '\0';
183       send_string(s);
184     }
185
186     c = readchar (3);
187     switch (c)
188       {
189       case ACK:
190         goto out;
191       case NAK:
192         continue;
193       case CANCEL:
194         /* error ("xmodem_send_packet: Transfer aborted by receiver."); */
195         chime_for(0xff);
196         return 0;
197       default:
198         /*fprintf_unfiltered (gdb_stderr, "xmodem_send_packet: Got unexpected character %c (0%o)\n", c, c);*/
199         /* mtearle is evil */
200         chime_for(c);
201         continue;
202       }
203   }
204
205   //serial_write ("\004", 1);   /* Send an EOT */
206
207   /* error ("xmodem_send_packet:  Excessive retries."); */
208   chime_for(0xff);
209   return 0;
210 out:
211   blknum++;
212   return 1;
213 }
214
215 /* Finish off the transfer.  Send out the EOT, and wait for an ACK.  */
216
217 void
218 xmodem_finish_xfer ()
219 {
220   int retries;
221
222   for (retries = 10; retries >= 0; retries--)
223     {
224       int c;
225
226       serial_write ("\004", 1); /* Send an EOT */
227
228       c = readchar (3);
229       switch (c)
230         {
231         case ACK:
232           return;
233         case NAK:
234           continue;
235         case CANCEL:
236           chime_for(0xff);
237           /* error ("xmodem_finish_xfer: Transfer aborted by receiver."); */
238         default:
239           /* fprintf_unfiltered (gdb_stderr, "xmodem_send_packet: Got unexpected character %c (0%o)\n", c, c); */
240           chime_for(c);
241           continue;
242         }
243     }
244
245   chime_for(0xff);
246   /* error ("xmodem_finish_xfer:  Excessive retries."); */
247 }

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