comparison packages/redboot/current/src/xyzModem.c @ 132:0ae0bc38e387 ecos-sw-2000-10-31

Merge from eCos master repository on 2000-10-31-00:30:36-GMT
author jlarmour
date Tue, 31 Oct 2000 20:53:09 +0000
parents
children 289bf90c6a9b
comparison
equal deleted inserted replaced
131:8461114e4f19 132:0ae0bc38e387
1 //==========================================================================
2 //
3 // xyzModem.c
4 //
5 // RedBoot stream handler for xyzModem protocol
6 //
7 //==========================================================================
8 //####COPYRIGHTBEGIN####
9 //
10 // -------------------------------------------
11 // The contents of this file are subject to the Red Hat eCos Public License
12 // Version 1.1 (the "License"); you may not use this file except in
13 // compliance with the License. You may obtain a copy of the License at
14 // http://www.redhat.com/
15 //
16 // Software distributed under the License is distributed on an "AS IS"
17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
18 // License for the specific language governing rights and limitations under
19 // the License.
20 //
21 // The Original Code is eCos - Embedded Configurable Operating System,
22 // released September 30, 1998.
23 //
24 // The Initial Developer of the Original Code is Red Hat.
25 // Portions created by Red Hat are
26 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
27 // All Rights Reserved.
28 // -------------------------------------------
29 //
30 //####COPYRIGHTEND####
31 //==========================================================================
32 //#####DESCRIPTIONBEGIN####
33 //
34 // Author(s): gthomas
35 // Contributors: gthomas
36 // Date: 2000-07-14
37 // Purpose:
38 // Description:
39 //
40 // This code is part of RedBoot (tm).
41 //
42 //####DESCRIPTIONEND####
43 //
44 //==========================================================================
45
46 #include <redboot.h>
47 #include <xyzModem.h>
48
49 // Assumption - run xyzModem protocol over the console port
50
51 // Values magic to the protocol
52 #define SOH 0x01
53 #define STX 0x02
54 #define EOT 0x04
55 #define ACK 0x06
56 #define NAK 0x15
57 #define CAN 0x18
58
59 // Data & state local to the protocol
60 static struct {
61 hal_virtual_comm_table_t* __chan;
62 unsigned char pkt[1024], *bufp;
63 unsigned char blk,cblk,crc1,crc2;
64 unsigned char next_blk; // Expected block
65 int len;
66 bool crc_mode, at_eof;
67 } xyz;
68
69 #define xyzModem_CHAR_TIMEOUT 1000 // 1 second
70 #define xyzModem_MAX_RETRIES 20
71
72 // Table of CRC constants - implements x^16+x^12+x^5+1
73 static unsigned short crc16[] = {
74 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
75 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
76 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
77 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
78 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
79 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
80 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
81 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
82 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
83 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
84 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
85 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
86 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
87 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
88 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
89 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
90 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
91 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
92 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
93 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
94 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
95 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
96 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
97 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
98 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
99 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
100 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
101 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
102 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
103 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
104 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
105 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0,
106 };
107
108 void
109 zm_dprintf(char *fmt, ...)
110 {
111 int cur_console;
112 va_list args;
113
114 va_start(args, fmt);
115 cur_console = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
116 CYGACC_CALL_IF_SET_CONSOLE_COMM(1);
117 vprintf(fmt, args);
118 CYGACC_CALL_IF_SET_CONSOLE_COMM(cur_console);
119 }
120
121 void
122 zm_dump_buf(void *buf, int len)
123 {
124 int cur_console;
125
126 cur_console = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
127 CYGACC_CALL_IF_SET_CONSOLE_COMM(1);
128 dump_buf(buf, len);
129 CYGACC_CALL_IF_SET_CONSOLE_COMM(cur_console);
130 }
131
132 // Wait for the line to go idle
133 static void
134 xyzModem_flush(void)
135 {
136 int res;
137 char c;
138 while (true) {
139 res = CYGACC_COMM_IF_GETC_TIMEOUT(*xyz.__chan, &c);
140 if (!res) return;
141 }
142 }
143
144 static int
145 xyzModem_get_hdr(void)
146 {
147 char c;
148 int res;
149 bool hdr_found = false;
150 int i;
151 unsigned short cksum;
152
153 // Find the start of a header
154 while (!hdr_found) {
155 res = CYGACC_COMM_IF_GETC_TIMEOUT(*xyz.__chan, &c);
156 if (res) {
157 switch (c) {
158 case SOH:
159 case STX:
160 hdr_found = true;
161 break;
162 case CAN:
163 return xyzModem_cancel;
164 case EOT:
165 return xyzModem_eof;
166 default:
167 // Ignore, waiting for start of header
168 }
169 } else {
170 // Data stream timed out
171 return xyzModem_timeout;
172 }
173 }
174
175 // Header found, now read the data
176 res = CYGACC_COMM_IF_GETC_TIMEOUT(*xyz.__chan, &xyz.blk);
177 if (!res) {
178 return xyzModem_timeout;
179 }
180 res = CYGACC_COMM_IF_GETC_TIMEOUT(*xyz.__chan, &xyz.cblk);
181 if (!res) {
182 return xyzModem_timeout;
183 }
184 xyz.len = (c == SOH) ? 128 : 1024;
185 xyz.bufp = xyz.pkt;
186 for (i = 0; i < xyz.len; i++) {
187 res = CYGACC_COMM_IF_GETC_TIMEOUT(*xyz.__chan, &c);
188 if (res) {
189 xyz.pkt[i] = c;
190 } else {
191 return xyzModem_timeout;
192 }
193 }
194 res = CYGACC_COMM_IF_GETC_TIMEOUT(*xyz.__chan, &xyz.crc1);
195 if (!res) {
196 return xyzModem_timeout;
197 }
198 if (xyz.crc_mode) {
199 res = CYGACC_COMM_IF_GETC_TIMEOUT(*xyz.__chan, &xyz.crc2);
200 if (!res) {
201 return xyzModem_timeout;
202 }
203 }
204 // Validate the message
205 if ((xyz.blk ^ xyz.cblk) != (unsigned char)0xFF) {
206 zm_dprintf("Framing error - blk: %x/%x/%x\n", xyz.blk, xyz.cblk, (xyz.blk ^ xyz.cblk));
207 zm_dump_buf(xyz.pkt, xyz.len);
208 xyzModem_flush();
209 return xyzModem_frame;
210 }
211 // Verify checksum/CRC
212 if (xyz.crc_mode) {
213 cksum = 0;
214 for (i = 0; i < xyz.len; i++) {
215 cksum = crc16[((cksum>>8) ^ xyz.pkt[i]) & 0xFF] ^ (cksum << 8);
216 }
217 if (cksum != ((xyz.crc1 << 8) | xyz.crc2)) {
218 zm_dprintf("CRC error - recvd: %02x%02x, computed: %x\n",
219 xyz.crc1, xyz.crc2, cksum & 0xFFFF);
220 return xyzModem_cksum;
221 }
222 } else {
223 cksum = 0;
224 for (i = 0; i < xyz.len; i++) {
225 cksum += xyz.pkt[i];
226 }
227 if (xyz.crc1 != (cksum & 0xFF)) {
228 zm_dprintf("Checksum error - recvd: %x, computed: %x\n", xyz.crc1, cksum & 0xFF);
229 return xyzModem_cksum;
230 }
231 }
232 // If we get here, the message passes [structural] muster
233 return 0;
234 }
235
236 int
237 xyzModem_stream_open(char *filename, int mode, int *err)
238 {
239 int console_chan, stat;
240 int retries = xyzModem_MAX_RETRIES;
241
242 if (mode == xyzModem_zmodem) {
243 *err = xyzModem_noZmodem;
244 return -1;
245 }
246
247 // Set up the I/O channel. Note: this allows for using a different port in the future
248 console_chan = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
249 CYGACC_CALL_IF_SET_CONSOLE_COMM(console_chan);
250 xyz.__chan = CYGACC_CALL_IF_CONSOLE_PROCS();
251 CYGACC_CALL_IF_SET_CONSOLE_COMM(console_chan);
252 CYGACC_COMM_IF_CONTROL(*xyz.__chan, __COMMCTL_SET_TIMEOUT, xyzModem_CHAR_TIMEOUT);
253 xyz.len = 0;
254 xyz.crc_mode = true;
255 xyz.at_eof = false;
256
257 while (retries-- > 0) {
258 stat = xyzModem_get_hdr();
259 if (stat == 0) {
260 CYGACC_COMM_IF_PUTC(*xyz.__chan, ACK);
261 // Note: yModem file name data blocks quietly discarded
262 xyz.next_blk = 1;
263 xyz.len = 0;
264 return 0;
265 } else
266 if (stat == xyzModem_timeout) {
267 CYGACC_CALL_IF_DELAY_US(5*100000); // Extra delay for startup
268 CYGACC_COMM_IF_PUTC(*xyz.__chan, 'C');
269 }
270 }
271 *err = stat;
272 return -1;
273 }
274
275 int
276 xyzModem_stream_read(char *buf, int size, int *err)
277 {
278 int stat, total, len;
279 int retries;
280
281 total = 0;
282 // Try and get 'size' bytes into the buffer
283 while (!xyz.at_eof && (size > 0)) {
284 if (xyz.len == 0) {
285 retries = xyzModem_MAX_RETRIES;
286 while (retries-- > 0) {
287 stat = xyzModem_get_hdr();
288 if (stat == 0) {
289 if (xyz.blk == xyz.next_blk) {
290 CYGACC_COMM_IF_PUTC(*xyz.__chan, ACK);
291 xyz.next_blk = (xyz.next_blk + 1) & 0xFF;
292 break;
293 } else if (xyz.blk == ((xyz.next_blk - 1) & 0xFF)) {
294 // Just re-ACK this so sender will get on with it
295 CYGACC_COMM_IF_PUTC(*xyz.__chan, ACK);
296 continue; // Need new header
297 } else {
298 stat = xyzModem_sequence;
299 }
300 }
301 if (stat == xyzModem_eof) {
302 CYGACC_COMM_IF_PUTC(*xyz.__chan, ACK);
303 xyz.at_eof = true;
304 break;
305 }
306 CYGACC_COMM_IF_PUTC(*xyz.__chan, 'C');
307 }
308 if (stat < 0) {
309 *err = stat;
310 xyz.len = -1;
311 return total;
312 }
313 }
314 len = xyz.len;
315 if (size < len) len = size;
316 memcpy(buf, xyz.bufp, len);
317 size -= len;
318 buf += len;
319 total += len;
320 xyz.len -= len;
321 xyz.bufp += len;
322 }
323 return total;
324 }
325
326 char *
327 xyzModem_error(int err)
328 {
329 switch (err) {
330 case xyzModem_access:
331 return "Can't access file";
332 break;
333 case xyzModem_noZmodem:
334 return "Sorry, zModem not available yet";
335 break;
336 case xyzModem_timeout:
337 return "Timed out";
338 break;
339 case xyzModem_eof:
340 return "End of file";
341 break;
342 case xyzModem_cancel:
343 return "Cancelled";
344 break;
345 case xyzModem_frame:
346 return "Invalid framing";
347 break;
348 case xyzModem_cksum:
349 return "CRC/checksum error";
350 break;
351 case xyzModem_sequence:
352 return "Block sequence error";
353 break;
354 default:
355 return "Unknown error";
356 break;
357 }
358 }