Blame view

common/xyzModem.c 15.3 KB
cf48eb9ab   Wolfgang Denk   Some code cleanup
1
2
3
4
5
6
7
8
  /*
   *==========================================================================
   *
   *      xyzModem.c
   *
   *      RedBoot stream handler for xyzModem protocol
   *
   *==========================================================================
e85427fd6   Wolfgang Denk   Add eCos-2.0 SPDX...
9
   * SPDX-License-Identifier:	eCos-2.0
cf48eb9ab   Wolfgang Denk   Some code cleanup
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
   *==========================================================================
   *#####DESCRIPTIONBEGIN####
   *
   * Author(s):    gthomas
   * Contributors: gthomas, tsmith, Yoshinori Sato
   * Date:         2000-07-14
   * Purpose:
   * Description:
   *
   * This code is part of RedBoot (tm).
   *
   *####DESCRIPTIONEND####
   *
   *==========================================================================
   */
f2841d377   Markus Klotzbuecher   Add support for y...
25
26
27
28
  #include <common.h>
  #include <xyzModem.h>
  #include <stdarg.h>
  #include <crc.h>
cf48eb9ab   Wolfgang Denk   Some code cleanup
29
  /* Assumption - run xyzModem protocol over the console port */
f2841d377   Markus Klotzbuecher   Add support for y...
30

cf48eb9ab   Wolfgang Denk   Some code cleanup
31
  /* Values magic to the protocol */
f2841d377   Markus Klotzbuecher   Add support for y...
32
33
34
35
36
37
38
  #define SOH 0x01
  #define STX 0x02
  #define EOT 0x04
  #define ACK 0x06
  #define BSP 0x08
  #define NAK 0x15
  #define CAN 0x18
7d0432c9e   Wolfgang Denk   Coding Style clea...
39
  #define EOF 0x1A		/* ^Z for DOS officionados */
f2841d377   Markus Klotzbuecher   Add support for y...
40

cf48eb9ab   Wolfgang Denk   Some code cleanup
41
  /* Data & state local to the protocol */
7d0432c9e   Wolfgang Denk   Coding Style clea...
42
43
  static struct
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
44
    int *__chan;
7d0432c9e   Wolfgang Denk   Coding Style clea...
45
46
47
48
49
50
    unsigned char pkt[1024], *bufp;
    unsigned char blk, cblk, crc1, crc2;
    unsigned char next_blk;	/* Expected block */
    int len, mode, total_retries;
    int total_SOH, total_STX, total_CAN;
    bool crc_mode, at_eof, tx_ack;
7d0432c9e   Wolfgang Denk   Coding Style clea...
51
    unsigned long file_length, read_length;
f2841d377   Markus Klotzbuecher   Add support for y...
52
  } xyz;
7d0432c9e   Wolfgang Denk   Coding Style clea...
53
  #define xyzModem_CHAR_TIMEOUT            2000	/* 2 seconds */
f2841d377   Markus Klotzbuecher   Add support for y...
54
55
  #define xyzModem_MAX_RETRIES             20
  #define xyzModem_MAX_RETRIES_WITH_CRC    10
7d0432c9e   Wolfgang Denk   Coding Style clea...
56
  #define xyzModem_CAN_COUNT                3	/* Wait for 3 CAN before quitting */
f2841d377   Markus Klotzbuecher   Add support for y...
57

f2841d377   Markus Klotzbuecher   Add support for y...
58
  typedef int cyg_int32;
199adb601   Kim Phillips   common/misc: spar...
59
  static int
7d0432c9e   Wolfgang Denk   Coding Style clea...
60
61
  CYGACC_COMM_IF_GETC_TIMEOUT (char chan, char *c)
  {
2c77c0d65   tomas.melin@vaisala.com   xyz-modem: Change...
62
63
64
  
    ulong now = get_timer(0);
    while (!tstc ())
7d0432c9e   Wolfgang Denk   Coding Style clea...
65
      {
2c77c0d65   tomas.melin@vaisala.com   xyz-modem: Change...
66
67
        if (get_timer(now) > xyzModem_CHAR_TIMEOUT)
          break;
7d0432c9e   Wolfgang Denk   Coding Style clea...
68
69
70
71
72
73
74
      }
    if (tstc ())
      {
        *c = getc ();
        return 1;
      }
    return 0;
f2841d377   Markus Klotzbuecher   Add support for y...
75
  }
199adb601   Kim Phillips   common/misc: spar...
76
  static void
7d0432c9e   Wolfgang Denk   Coding Style clea...
77
78
79
  CYGACC_COMM_IF_PUTC (char x, char y)
  {
    putc (y);
f2841d377   Markus Klotzbuecher   Add support for y...
80
  }
cf48eb9ab   Wolfgang Denk   Some code cleanup
81
  /* Validate a hex character */
f2841d377   Markus Klotzbuecher   Add support for y...
82
  __inline__ static bool
7d0432c9e   Wolfgang Denk   Coding Style clea...
83
  _is_hex (char c)
f2841d377   Markus Klotzbuecher   Add support for y...
84
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
85
86
    return (((c >= '0') && (c <= '9')) ||
  	  ((c >= 'A') && (c <= 'F')) || ((c >= 'a') && (c <= 'f')));
f2841d377   Markus Klotzbuecher   Add support for y...
87
  }
cf48eb9ab   Wolfgang Denk   Some code cleanup
88
  /* Convert a single hex nibble */
f2841d377   Markus Klotzbuecher   Add support for y...
89
  __inline__ static int
7d0432c9e   Wolfgang Denk   Coding Style clea...
90
  _from_hex (char c)
f2841d377   Markus Klotzbuecher   Add support for y...
91
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
92
93
94
95
96
97
98
99
100
    int ret = 0;
  
    if ((c >= '0') && (c <= '9'))
      {
        ret = (c - '0');
      }
    else if ((c >= 'a') && (c <= 'f'))
      {
        ret = (c - 'a' + 0x0a);
f2841d377   Markus Klotzbuecher   Add support for y...
101
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
102
103
104
105
106
    else if ((c >= 'A') && (c <= 'F'))
      {
        ret = (c - 'A' + 0x0A);
      }
    return ret;
f2841d377   Markus Klotzbuecher   Add support for y...
107
  }
cf48eb9ab   Wolfgang Denk   Some code cleanup
108
  /* Convert a character to lower case */
f2841d377   Markus Klotzbuecher   Add support for y...
109
  __inline__ static char
7d0432c9e   Wolfgang Denk   Coding Style clea...
110
  _tolower (char c)
f2841d377   Markus Klotzbuecher   Add support for y...
111
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
112
113
114
    if ((c >= 'A') && (c <= 'Z'))
      {
        c = (c - 'A') + 'a';
f2841d377   Markus Klotzbuecher   Add support for y...
115
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
116
    return c;
f2841d377   Markus Klotzbuecher   Add support for y...
117
  }
cf48eb9ab   Wolfgang Denk   Some code cleanup
118
  /* Parse (scan) a number */
199adb601   Kim Phillips   common/misc: spar...
119
  static bool
7d0432c9e   Wolfgang Denk   Coding Style clea...
120
  parse_num (char *s, unsigned long *val, char **es, char *delim)
f2841d377   Markus Klotzbuecher   Add support for y...
121
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
    bool first = true;
    int radix = 10;
    char c;
    unsigned long result = 0;
    int digit;
  
    while (*s == ' ')
      s++;
    while (*s)
      {
        if (first && (s[0] == '0') && (_tolower (s[1]) == 'x'))
  	{
  	  radix = 16;
  	  s += 2;
  	}
        first = false;
        c = *s++;
        if (_is_hex (c) && ((digit = _from_hex (c)) < radix))
  	{
  	  /* Valid digit */
7d0432c9e   Wolfgang Denk   Coding Style clea...
142
  	  result = (result * radix) + digit;
7d0432c9e   Wolfgang Denk   Coding Style clea...
143
144
145
146
147
148
149
150
151
152
153
154
155
156
  	}
        else
  	{
  	  if (delim != (char *) 0)
  	    {
  	      /* See if this character is one of the delimiters */
  	      char *dp = delim;
  	      while (*dp && (c != *dp))
  		dp++;
  	      if (*dp)
  		break;		/* Found a good delimiter */
  	    }
  	  return false;		/* Malformatted number */
  	}
f2841d377   Markus Klotzbuecher   Add support for y...
157
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
158
159
160
161
    *val = result;
    if (es != (char **) 0)
      {
        *es = s;
f2841d377   Markus Klotzbuecher   Add support for y...
162
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
163
    return true;
f2841d377   Markus Klotzbuecher   Add support for y...
164
  }
f2841d377   Markus Klotzbuecher   Add support for y...
165

f2841d377   Markus Klotzbuecher   Add support for y...
166
  #ifdef DEBUG
cf48eb9ab   Wolfgang Denk   Some code cleanup
167
168
169
  /*
   * Note: this debug setup works by storing the strings in a fixed buffer
   */
b09ece083   Alexandru Gagniuc   common/xyzModem.c...
170
171
172
  static char zm_debug_buf[8192];
  static char *zm_out = zm_debug_buf;
  static char *zm_out_start = zm_debug_buf;
f2841d377   Markus Klotzbuecher   Add support for y...
173

f2841d377   Markus Klotzbuecher   Add support for y...
174
  static int
7d0432c9e   Wolfgang Denk   Coding Style clea...
175
  zm_dprintf (char *fmt, ...)
f2841d377   Markus Klotzbuecher   Add support for y...
176
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
177
178
    int len;
    va_list args;
f2841d377   Markus Klotzbuecher   Add support for y...
179

7d0432c9e   Wolfgang Denk   Coding Style clea...
180
181
182
183
    va_start (args, fmt);
    len = diag_vsprintf (zm_out, fmt, args);
    zm_out += len;
    return len;
f2841d377   Markus Klotzbuecher   Add support for y...
184
185
186
  }
  
  static void
7d0432c9e   Wolfgang Denk   Coding Style clea...
187
  zm_flush (void)
f2841d377   Markus Klotzbuecher   Add support for y...
188
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
189
    zm_out = zm_out_start;
f2841d377   Markus Klotzbuecher   Add support for y...
190
  }
f2841d377   Markus Klotzbuecher   Add support for y...
191
192
  
  static void
7d0432c9e   Wolfgang Denk   Coding Style clea...
193
  zm_dump_buf (void *buf, int len)
f2841d377   Markus Klotzbuecher   Add support for y...
194
  {
f2841d377   Markus Klotzbuecher   Add support for y...
195

f2841d377   Markus Klotzbuecher   Add support for y...
196
197
198
199
200
201
  }
  
  static unsigned char zm_buf[2048];
  static unsigned char *zm_bp;
  
  static void
7d0432c9e   Wolfgang Denk   Coding Style clea...
202
  zm_new (void)
f2841d377   Markus Klotzbuecher   Add support for y...
203
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
204
    zm_bp = zm_buf;
f2841d377   Markus Klotzbuecher   Add support for y...
205
206
207
  }
  
  static void
7d0432c9e   Wolfgang Denk   Coding Style clea...
208
  zm_save (unsigned char c)
f2841d377   Markus Klotzbuecher   Add support for y...
209
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
210
    *zm_bp++ = c;
f2841d377   Markus Klotzbuecher   Add support for y...
211
212
213
  }
  
  static void
7d0432c9e   Wolfgang Denk   Coding Style clea...
214
  zm_dump (int line)
f2841d377   Markus Klotzbuecher   Add support for y...
215
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
216
217
218
    zm_dprintf ("Packet at line: %d
  ", line);
    zm_dump_buf (zm_buf, zm_bp - zm_buf);
f2841d377   Markus Klotzbuecher   Add support for y...
219
220
221
222
223
224
  }
  
  #define ZM_DEBUG(x) x
  #else
  #define ZM_DEBUG(x)
  #endif
cf48eb9ab   Wolfgang Denk   Some code cleanup
225
  /* Wait for the line to go idle */
f2841d377   Markus Klotzbuecher   Add support for y...
226
  static void
7d0432c9e   Wolfgang Denk   Coding Style clea...
227
  xyzModem_flush (void)
f2841d377   Markus Klotzbuecher   Add support for y...
228
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
229
230
231
232
233
234
235
    int res;
    char c;
    while (true)
      {
        res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, &c);
        if (!res)
  	return;
f2841d377   Markus Klotzbuecher   Add support for y...
236
237
238
239
      }
  }
  
  static int
7d0432c9e   Wolfgang Denk   Coding Style clea...
240
  xyzModem_get_hdr (void)
f2841d377   Markus Klotzbuecher   Add support for y...
241
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
    char c;
    int res;
    bool hdr_found = false;
    int i, can_total, hdr_chars;
    unsigned short cksum;
  
    ZM_DEBUG (zm_new ());
    /* Find the start of a header */
    can_total = 0;
    hdr_chars = 0;
  
    if (xyz.tx_ack)
      {
        CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
        xyz.tx_ack = false;
f2841d377   Markus Klotzbuecher   Add support for y...
257
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
    while (!hdr_found)
      {
        res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, &c);
        ZM_DEBUG (zm_save (c));
        if (res)
  	{
  	  hdr_chars++;
  	  switch (c)
  	    {
  	    case SOH:
  	      xyz.total_SOH++;
  	    case STX:
  	      if (c == STX)
  		xyz.total_STX++;
  	      hdr_found = true;
  	      break;
  	    case CAN:
  	      xyz.total_CAN++;
  	      ZM_DEBUG (zm_dump (__LINE__));
  	      if (++can_total == xyzModem_CAN_COUNT)
  		{
  		  return xyzModem_cancel;
  		}
  	      else
  		{
  		  /* Wait for multiple CAN to avoid early quits */
  		  break;
  		}
  	    case EOT:
  	      /* EOT only supported if no noise */
  	      if (hdr_chars == 1)
  		{
  		  CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
  		  ZM_DEBUG (zm_dprintf ("ACK on EOT #%d
  ", __LINE__));
  		  ZM_DEBUG (zm_dump (__LINE__));
  		  return xyzModem_eof;
  		}
  	    default:
  	      /* Ignore, waiting for start of header */
  	      ;
  	    }
  	}
        else
  	{
  	  /* Data stream timed out */
  	  xyzModem_flush ();	/* Toss any current input */
  	  ZM_DEBUG (zm_dump (__LINE__));
  	  CYGACC_CALL_IF_DELAY_US ((cyg_int32) 250000);
  	  return xyzModem_timeout;
  	}
f2841d377   Markus Klotzbuecher   Add support for y...
309
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
310
311
312
313
314
315
316
    /* Header found, now read the data */
    res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.blk);
    ZM_DEBUG (zm_save (xyz.blk));
    if (!res)
      {
        ZM_DEBUG (zm_dump (__LINE__));
        return xyzModem_timeout;
f2841d377   Markus Klotzbuecher   Add support for y...
317
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
318
319
320
321
322
323
    res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.cblk);
    ZM_DEBUG (zm_save (xyz.cblk));
    if (!res)
      {
        ZM_DEBUG (zm_dump (__LINE__));
        return xyzModem_timeout;
f2841d377   Markus Klotzbuecher   Add support for y...
324
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
    xyz.len = (c == SOH) ? 128 : 1024;
    xyz.bufp = xyz.pkt;
    for (i = 0; i < xyz.len; i++)
      {
        res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, &c);
        ZM_DEBUG (zm_save (c));
        if (res)
  	{
  	  xyz.pkt[i] = c;
  	}
        else
  	{
  	  ZM_DEBUG (zm_dump (__LINE__));
  	  return xyzModem_timeout;
  	}
f2841d377   Markus Klotzbuecher   Add support for y...
340
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
341
342
343
344
345
346
    res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.crc1);
    ZM_DEBUG (zm_save (xyz.crc1));
    if (!res)
      {
        ZM_DEBUG (zm_dump (__LINE__));
        return xyzModem_timeout;
f2841d377   Markus Klotzbuecher   Add support for y...
347
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
348
349
350
351
352
353
354
355
356
    if (xyz.crc_mode)
      {
        res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.crc2);
        ZM_DEBUG (zm_save (xyz.crc2));
        if (!res)
  	{
  	  ZM_DEBUG (zm_dump (__LINE__));
  	  return xyzModem_timeout;
  	}
f2841d377   Markus Klotzbuecher   Add support for y...
357
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
358
359
360
361
362
363
364
365
366
367
368
    ZM_DEBUG (zm_dump (__LINE__));
    /* Validate the message */
    if ((xyz.blk ^ xyz.cblk) != (unsigned char) 0xFF)
      {
        ZM_DEBUG (zm_dprintf
  		("Framing error - blk: %x/%x/%x
  ", xyz.blk, xyz.cblk,
  		 (xyz.blk ^ xyz.cblk)));
        ZM_DEBUG (zm_dump_buf (xyz.pkt, xyz.len));
        xyzModem_flush ();
        return xyzModem_frame;
f2841d377   Markus Klotzbuecher   Add support for y...
369
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
370
371
372
    /* Verify checksum/CRC */
    if (xyz.crc_mode)
      {
ecb57f69b   Stefan Roese   lib/crc16.c: Rena...
373
        cksum = crc16_ccitt(0, xyz.pkt, xyz.len);
7d0432c9e   Wolfgang Denk   Coding Style clea...
374
375
376
377
378
379
380
        if (cksum != ((xyz.crc1 << 8) | xyz.crc2))
  	{
  	  ZM_DEBUG (zm_dprintf ("CRC error - recvd: %02x%02x, computed: %x
  ",
  				xyz.crc1, xyz.crc2, cksum & 0xFFFF));
  	  return xyzModem_cksum;
  	}
f2841d377   Markus Klotzbuecher   Add support for y...
381
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
    else
      {
        cksum = 0;
        for (i = 0; i < xyz.len; i++)
  	{
  	  cksum += xyz.pkt[i];
  	}
        if (xyz.crc1 != (cksum & 0xFF))
  	{
  	  ZM_DEBUG (zm_dprintf
  		    ("Checksum error - recvd: %x, computed: %x
  ", xyz.crc1,
  		     cksum & 0xFF));
  	  return xyzModem_cksum;
  	}
      }
    /* If we get here, the message passes [structural] muster */
    return 0;
f2841d377   Markus Klotzbuecher   Add support for y...
400
  }
cf48eb9ab   Wolfgang Denk   Some code cleanup
401
  int
7d0432c9e   Wolfgang Denk   Coding Style clea...
402
  xyzModem_stream_open (connection_info_t * info, int *err)
f2841d377   Markus Klotzbuecher   Add support for y...
403
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
404
405
406
    int stat = 0;
    int retries = xyzModem_MAX_RETRIES;
    int crc_retries = xyzModem_MAX_RETRIES_WITH_CRC;
f2841d377   Markus Klotzbuecher   Add support for y...
407

cf48eb9ab   Wolfgang Denk   Some code cleanup
408
  /*    ZM_DEBUG(zm_out = zm_out_start); */
f2841d377   Markus Klotzbuecher   Add support for y...
409
  #ifdef xyzModem_zmodem
7d0432c9e   Wolfgang Denk   Coding Style clea...
410
411
412
413
    if (info->mode == xyzModem_zmodem)
      {
        *err = xyzModem_noZmodem;
        return -1;
f2841d377   Markus Klotzbuecher   Add support for y...
414
415
      }
  #endif
cf48eb9ab   Wolfgang Denk   Some code cleanup
416
  /* TODO: CHECK ! */
2a2ed845c   Kim Phillips   common: fix 'dumm...
417
    int dummy = 0;
7d0432c9e   Wolfgang Denk   Coding Style clea...
418
    xyz.__chan = &dummy;
7d0432c9e   Wolfgang Denk   Coding Style clea...
419
420
421
422
423
424
425
426
427
    xyz.len = 0;
    xyz.crc_mode = true;
    xyz.at_eof = false;
    xyz.tx_ack = false;
    xyz.mode = info->mode;
    xyz.total_retries = 0;
    xyz.total_SOH = 0;
    xyz.total_STX = 0;
    xyz.total_CAN = 0;
7d0432c9e   Wolfgang Denk   Coding Style clea...
428
429
    xyz.read_length = 0;
    xyz.file_length = 0;
cf48eb9ab   Wolfgang Denk   Some code cleanup
430

7d0432c9e   Wolfgang Denk   Coding Style clea...
431
    CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
f2841d377   Markus Klotzbuecher   Add support for y...
432

7d0432c9e   Wolfgang Denk   Coding Style clea...
433
434
435
436
437
    if (xyz.mode == xyzModem_xmodem)
      {
        /* X-modem doesn't have an information header - exit here */
        xyz.next_blk = 1;
        return 0;
f2841d377   Markus Klotzbuecher   Add support for y...
438
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
439
440
441
442
443
444
445
446
    while (retries-- > 0)
      {
        stat = xyzModem_get_hdr ();
        if (stat == 0)
  	{
  	  /* Y-modem file information header */
  	  if (xyz.blk == 0)
  	    {
7d0432c9e   Wolfgang Denk   Coding Style clea...
447
448
449
450
  	      /* skip filename */
  	      while (*xyz.bufp++);
  	      /* get the length */
  	      parse_num ((char *) xyz.bufp, &xyz.file_length, NULL, " ");
7d0432c9e   Wolfgang Denk   Coding Style clea...
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
  	      /* The rest of the file name data block quietly discarded */
  	      xyz.tx_ack = true;
  	    }
  	  xyz.next_blk = 1;
  	  xyz.len = 0;
  	  return 0;
  	}
        else if (stat == xyzModem_timeout)
  	{
  	  if (--crc_retries <= 0)
  	    xyz.crc_mode = false;
  	  CYGACC_CALL_IF_DELAY_US (5 * 100000);	/* Extra delay for startup */
  	  CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
  	  xyz.total_retries++;
  	  ZM_DEBUG (zm_dprintf ("NAK (%d)
  ", __LINE__));
  	}
        if (stat == xyzModem_cancel)
  	{
  	  break;
  	}
f2841d377   Markus Klotzbuecher   Add support for y...
472
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
473
474
475
    *err = stat;
    ZM_DEBUG (zm_flush ());
    return -1;
f2841d377   Markus Klotzbuecher   Add support for y...
476
  }
cf48eb9ab   Wolfgang Denk   Some code cleanup
477
  int
7d0432c9e   Wolfgang Denk   Coding Style clea...
478
  xyzModem_stream_read (char *buf, int size, int *err)
f2841d377   Markus Klotzbuecher   Add support for y...
479
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
    int stat, total, len;
    int retries;
  
    total = 0;
    stat = xyzModem_cancel;
    /* Try and get 'size' bytes into the buffer */
    while (!xyz.at_eof && (size > 0))
      {
        if (xyz.len == 0)
  	{
  	  retries = xyzModem_MAX_RETRIES;
  	  while (retries-- > 0)
  	    {
  	      stat = xyzModem_get_hdr ();
  	      if (stat == 0)
  		{
  		  if (xyz.blk == xyz.next_blk)
  		    {
  		      xyz.tx_ack = true;
  		      ZM_DEBUG (zm_dprintf
  				("ACK block %d (%d)
  ", xyz.blk, __LINE__));
  		      xyz.next_blk = (xyz.next_blk + 1) & 0xFF;
f2841d377   Markus Klotzbuecher   Add support for y...
503

7d0432c9e   Wolfgang Denk   Coding Style clea...
504
505
  		      if (xyz.mode == xyzModem_xmodem || xyz.file_length == 0)
  			{
7d0432c9e   Wolfgang Denk   Coding Style clea...
506
507
508
509
510
511
512
513
514
515
516
517
518
  			  /* Data blocks can be padded with ^Z (EOF) characters */
  			  /* This code tries to detect and remove them */
  			  if ((xyz.bufp[xyz.len - 1] == EOF) &&
  			      (xyz.bufp[xyz.len - 2] == EOF) &&
  			      (xyz.bufp[xyz.len - 3] == EOF))
  			    {
  			      while (xyz.len
  				     && (xyz.bufp[xyz.len - 1] == EOF))
  				{
  				  xyz.len--;
  				}
  			    }
  			}
f2841d377   Markus Klotzbuecher   Add support for y...
519

7d0432c9e   Wolfgang Denk   Coding Style clea...
520
521
522
523
524
525
526
527
528
529
530
531
532
533
  		      /*
  		       * See if accumulated length exceeds that of the file.
  		       * If so, reduce size (i.e., cut out pad bytes)
  		       * Only do this for Y-modem (and Z-modem should it ever
  		       * be supported since it can fall back to Y-modem mode).
  		       */
  		      if (xyz.mode != xyzModem_xmodem && 0 != xyz.file_length)
  			{
  			  xyz.read_length += xyz.len;
  			  if (xyz.read_length > xyz.file_length)
  			    {
  			      xyz.len -= (xyz.read_length - xyz.file_length);
  			    }
  			}
7d0432c9e   Wolfgang Denk   Coding Style clea...
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
  		      break;
  		    }
  		  else if (xyz.blk == ((xyz.next_blk - 1) & 0xFF))
  		    {
  		      /* Just re-ACK this so sender will get on with it */
  		      CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
  		      continue;	/* Need new header */
  		    }
  		  else
  		    {
  		      stat = xyzModem_sequence;
  		    }
  		}
  	      if (stat == xyzModem_cancel)
  		{
  		  break;
  		}
  	      if (stat == xyzModem_eof)
  		{
  		  CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
  		  ZM_DEBUG (zm_dprintf ("ACK (%d)
  ", __LINE__));
  		  if (xyz.mode == xyzModem_ymodem)
  		    {
  		      CYGACC_COMM_IF_PUTC (*xyz.__chan,
  					   (xyz.crc_mode ? 'C' : NAK));
  		      xyz.total_retries++;
  		      ZM_DEBUG (zm_dprintf ("Reading Final Header
  "));
  		      stat = xyzModem_get_hdr ();
  		      CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
  		      ZM_DEBUG (zm_dprintf ("FINAL ACK (%d)
  ", __LINE__));
  		    }
  		  xyz.at_eof = true;
  		  break;
  		}
  	      CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
  	      xyz.total_retries++;
  	      ZM_DEBUG (zm_dprintf ("NAK (%d)
  ", __LINE__));
  	    }
  	  if (stat < 0)
  	    {
  	      *err = stat;
  	      xyz.len = -1;
  	      return total;
  	    }
  	}
        /* Don't "read" data from the EOF protocol package */
        if (!xyz.at_eof)
  	{
  	  len = xyz.len;
  	  if (size < len)
  	    len = size;
  	  memcpy (buf, xyz.bufp, len);
  	  size -= len;
  	  buf += len;
  	  total += len;
  	  xyz.len -= len;
  	  xyz.bufp += len;
  	}
f2841d377   Markus Klotzbuecher   Add support for y...
596
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
597
    return total;
f2841d377   Markus Klotzbuecher   Add support for y...
598
599
600
  }
  
  void
7d0432c9e   Wolfgang Denk   Coding Style clea...
601
  xyzModem_stream_close (int *err)
f2841d377   Markus Klotzbuecher   Add support for y...
602
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
603
604
605
606
607
608
    diag_printf
      ("xyzModem - %s mode, %d(SOH)/%d(STX)/%d(CAN) packets, %d retries
  ",
       xyz.crc_mode ? "CRC" : "Cksum", xyz.total_SOH, xyz.total_STX,
       xyz.total_CAN, xyz.total_retries);
    ZM_DEBUG (zm_flush ());
f2841d377   Markus Klotzbuecher   Add support for y...
609
  }
cf48eb9ab   Wolfgang Denk   Some code cleanup
610
611
  /* Need to be able to clean out the input buffer, so have to take the */
  /* getc */
7d0432c9e   Wolfgang Denk   Coding Style clea...
612
613
  void
  xyzModem_stream_terminate (bool abort, int (*getc) (void))
f2841d377   Markus Klotzbuecher   Add support for y...
614
615
  {
    int c;
7d0432c9e   Wolfgang Denk   Coding Style clea...
616
617
618
619
620
621
    if (abort)
      {
        ZM_DEBUG (zm_dprintf ("!!!! TRANSFER ABORT !!!!
  "));
        switch (xyz.mode)
  	{
f2841d377   Markus Klotzbuecher   Add support for y...
622
623
  	case xyzModem_xmodem:
  	case xyzModem_ymodem:
cf48eb9ab   Wolfgang Denk   Some code cleanup
624
625
  	  /* The X/YMODEM Spec seems to suggest that multiple CAN followed by an equal */
  	  /* number of Backspaces is a friendly way to get the other end to abort. */
7d0432c9e   Wolfgang Denk   Coding Style clea...
626
627
628
629
630
631
632
633
  	  CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN);
  	  CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN);
  	  CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN);
  	  CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN);
  	  CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP);
  	  CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP);
  	  CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP);
  	  CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP);
cf48eb9ab   Wolfgang Denk   Some code cleanup
634
  	  /* Now consume the rest of what's waiting on the line. */
7d0432c9e   Wolfgang Denk   Coding Style clea...
635
636
637
638
639
  	  ZM_DEBUG (zm_dprintf ("Flushing serial line.
  "));
  	  xyzModem_flush ();
  	  xyz.at_eof = true;
  	  break;
f2841d377   Markus Klotzbuecher   Add support for y...
640
641
  #ifdef xyzModem_zmodem
  	case xyzModem_zmodem:
cf48eb9ab   Wolfgang Denk   Some code cleanup
642
  	  /* Might support it some day I suppose. */
f2841d377   Markus Klotzbuecher   Add support for y...
643
  #endif
7d0432c9e   Wolfgang Denk   Coding Style clea...
644
645
646
647
648
649
650
  	  break;
  	}
      }
    else
      {
        ZM_DEBUG (zm_dprintf ("Engaging cleanup mode...
  "));
cf48eb9ab   Wolfgang Denk   Some code cleanup
651
652
        /*
         * Consume any trailing crap left in the inbuffer from
162630879   Mike Williams   cleanup: Fix typo...
653
         * previous received blocks. Since very few files are an exact multiple
cf48eb9ab   Wolfgang Denk   Some code cleanup
654
655
656
         * of the transfer block size, there will almost always be some gunk here.
         * If we don't eat it now, RedBoot will think the user typed it.
         */
7d0432c9e   Wolfgang Denk   Coding Style clea...
657
658
        ZM_DEBUG (zm_dprintf ("Trailing gunk:
  "));
e153b13c8   Jeroen Hofstee   common/xyzModem.c...
659
660
        while ((c = (*getc) ()) > -1)
          ;
7d0432c9e   Wolfgang Denk   Coding Style clea...
661
662
        ZM_DEBUG (zm_dprintf ("
  "));
cf48eb9ab   Wolfgang Denk   Some code cleanup
663
664
665
666
667
        /*
         * Make a small delay to give terminal programs like minicom
         * time to get control again after their file transfer program
         * exits.
         */
7d0432c9e   Wolfgang Denk   Coding Style clea...
668
669
        CYGACC_CALL_IF_DELAY_US ((cyg_int32) 250000);
      }
f2841d377   Markus Klotzbuecher   Add support for y...
670
671
672
  }
  
  char *
7d0432c9e   Wolfgang Denk   Coding Style clea...
673
  xyzModem_error (int err)
f2841d377   Markus Klotzbuecher   Add support for y...
674
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
675
676
    switch (err)
      {
f2841d377   Markus Klotzbuecher   Add support for y...
677
      case xyzModem_access:
7d0432c9e   Wolfgang Denk   Coding Style clea...
678
679
        return "Can't access file";
        break;
f2841d377   Markus Klotzbuecher   Add support for y...
680
      case xyzModem_noZmodem:
7d0432c9e   Wolfgang Denk   Coding Style clea...
681
682
        return "Sorry, zModem not available yet";
        break;
f2841d377   Markus Klotzbuecher   Add support for y...
683
      case xyzModem_timeout:
7d0432c9e   Wolfgang Denk   Coding Style clea...
684
685
        return "Timed out";
        break;
f2841d377   Markus Klotzbuecher   Add support for y...
686
      case xyzModem_eof:
7d0432c9e   Wolfgang Denk   Coding Style clea...
687
688
        return "End of file";
        break;
f2841d377   Markus Klotzbuecher   Add support for y...
689
      case xyzModem_cancel:
7d0432c9e   Wolfgang Denk   Coding Style clea...
690
691
        return "Cancelled";
        break;
f2841d377   Markus Klotzbuecher   Add support for y...
692
      case xyzModem_frame:
7d0432c9e   Wolfgang Denk   Coding Style clea...
693
694
        return "Invalid framing";
        break;
f2841d377   Markus Klotzbuecher   Add support for y...
695
      case xyzModem_cksum:
7d0432c9e   Wolfgang Denk   Coding Style clea...
696
697
        return "CRC/checksum error";
        break;
f2841d377   Markus Klotzbuecher   Add support for y...
698
      case xyzModem_sequence:
7d0432c9e   Wolfgang Denk   Coding Style clea...
699
700
        return "Block sequence error";
        break;
f2841d377   Markus Klotzbuecher   Add support for y...
701
      default:
7d0432c9e   Wolfgang Denk   Coding Style clea...
702
703
        return "Unknown error";
        break;
f2841d377   Markus Klotzbuecher   Add support for y...
704
705
      }
  }
cf48eb9ab   Wolfgang Denk   Some code cleanup
706
707
708
  /*
   * RedBoot interface
   */