00001
00046 #include "xmodem.h"
00047
00048 #include <appconfig.h>
00049 #include <string.h>
00050 #include <drv/ser.h>
00051 #include <algo/crc.h>
00052 #include <cfg/debug.h>
00053
00054
00055
00056
00061 #define XM_SOH 0x01
00062 #define XM_STX 0x02
00063 #define XM_EOT 0x04
00064 #define XM_ACK 0x06
00065 #define XM_NAK 0x15
00066 #define XM_C 0x43
00067 #define XM_CAN 0x18
00068
00069
00070 #define XM_MAXRETRIES 15
00071 #define XM_MAXCRCRETRIES 7
00073 #if CONFIG_XMODEM_1KCRC == 1
00074 #define XM_BUFSIZE 1024
00075 #else
00076 #define XM_BUFSIZE 128
00077 #endif
00078
00079
00080 #if CONFIG_XMODEM_RECV
00081
00089 bool xmodem_recv(struct KFileSerial *port, KFile *fd)
00090 {
00091 char block_buffer[XM_BUFSIZE];
00092 int c, i, blocksize;
00093 int blocknr = 0, last_block_done = 0, retries = 0;
00094 char *buf;
00095 uint8_t checksum;
00096 uint16_t crc;
00097 bool purge = false;
00098 bool usecrc = true;
00099
00100
00101 XMODEM_PROGRESS("Starting Transfer...\n");
00102 purge = true;
00103 ser_clearerr(port);
00104
00105
00106 for(;;)
00107 {
00108 if (XMODEM_CHECK_ABORT)
00109 {
00110 kfile_putc(XM_CAN, &port->fd);
00111 kfile_putc(XM_CAN, &port->fd);
00112 XMODEM_PROGRESS("Transfer aborted\n");
00113 return false;
00114 }
00115
00116
00117
00118
00119
00120 if (purge)
00121 {
00122 purge = false;
00123
00124 if (kfile_error(&port->fd))
00125 XMODEM_PROGRESS("Retries %d\n", retries);
00126
00127 ser_resync(port, 200);
00128 retries++;
00129
00130 if (retries >= XM_MAXRETRIES)
00131 {
00132 kfile_putc(XM_CAN, &port->fd);
00133 kfile_putc(XM_CAN, &port->fd);
00134 XMODEM_PROGRESS("Transfer aborted\n");
00135 return false;
00136 }
00137
00138
00139 if (blocknr == 0)
00140 {
00141 if (retries < XM_MAXCRCRETRIES)
00142 {
00143 XMODEM_PROGRESS("Request Tx (CRC)\n");
00144 kfile_putc(XM_C, &port->fd);
00145 }
00146 else
00147 {
00148
00149 usecrc = false;
00150 XMODEM_PROGRESS("Request Tx (BCC)\n");
00151 kfile_putc(XM_NAK, &port->fd);
00152 }
00153 }
00154 else
00155 kfile_putc(XM_NAK, &port->fd);
00156 }
00157
00158 switch (kfile_getc(&port->fd))
00159 {
00160 #if XM_BUFSIZE >= 1024
00161 case XM_STX:
00162 blocksize = 1024;
00163 goto getblock;
00164 #endif
00165
00166 case XM_SOH:
00167 blocksize = 128;
00168
00169
00170 getblock:
00171
00172 c = kfile_getc(&port->fd);
00173
00174
00175 if ((~c & 0xff) != kfile_getc(&port->fd))
00176 {
00177 XMODEM_PROGRESS("Bad blk (%d)\n", c);
00178 purge = true;
00179 break;
00180 }
00181
00182
00183 if (c == (blocknr & 0xff))
00184
00185 XMODEM_PROGRESS("Repeat blk %d\n", blocknr);
00186 else if (c == ((blocknr + 1) & 0xff))
00187
00188 XMODEM_PROGRESS("Recv blk %d\n", ++blocknr);
00189 else
00190 {
00191
00192 XMODEM_PROGRESS("Sync lost (%d/%d)\n", c, blocknr);
00193 purge = true;
00194 break;
00195 }
00196
00197 buf = block_buffer;
00198 checksum = 0;
00199 crc = 0;
00200 for (i = 0; i < blocksize; i++)
00201 {
00202 if ((c = kfile_getc(&port->fd)) == EOF)
00203 {
00204 purge = true;
00205 break;
00206 }
00207
00208
00209 *buf++ = (char)c;
00210
00211
00212 if (usecrc)
00213 crc = UPDCRC16(c, crc);
00214 else
00215 checksum += (char)c;
00216 }
00217
00218 if (purge)
00219 break;
00220
00221
00222 if ((c = kfile_getc(&port->fd)) == EOF)
00223 {
00224 purge = true;
00225 break;
00226 }
00227
00228 if (usecrc)
00229 {
00230 crc = UPDCRC16(c, crc);
00231
00232
00233 if ((c = kfile_getc(&port->fd)) == EOF)
00234 {
00235 purge = true;
00236 break;
00237 }
00238
00239 crc = UPDCRC16(c, crc);
00240
00241 if (crc)
00242 {
00243 XMODEM_PROGRESS("Bad CRC: %04x\n", crc);
00244 purge = true;
00245 break;
00246 }
00247 }
00248
00249 else if (c != checksum)
00250 {
00251 XMODEM_PROGRESS("Bad sum: %04x/%04x\n", checksum, c);
00252 purge = true;
00253 break;
00254 }
00255
00256
00257
00258
00259
00260
00261 if (last_block_done < blocknr)
00262 {
00263
00264 if (kfile_write(fd, block_buffer, blocksize))
00265 {
00266
00267 kfile_putc(XM_ACK, &port->fd);
00268 retries = 0;
00269 last_block_done = blocknr;
00270 }
00271 else
00272 {
00273
00274 retries = XM_MAXRETRIES;
00275 purge = true;
00276 }
00277 }
00278 break;
00279
00280 case XM_EOT:
00281 kfile_putchar(XM_ACK, &port->fd);
00282 XMODEM_PROGRESS("Transfer completed\n");
00283 return true;
00284
00285 case EOF:
00286 purge = true;
00287 break;
00288
00289 default:
00290 XMODEM_PROGRESS("Skipping garbage\n");
00291 purge = true;
00292 break;
00293 }
00294 }
00295 }
00296 #endif
00297
00298
00299 #if CONFIG_XMODEM_SEND
00300
00309 bool xmodem_send(struct KFileSerial *port, KFile *fd)
00310 {
00311 char block_buffer[XM_BUFSIZE];
00312 size_t size = -1;
00313 int blocknr = 1, retries = 0, c, i;
00314 bool proceed, usecrc = false;
00315 uint16_t crc;
00316 uint8_t sum;
00317
00318
00319
00320
00321
00322
00323
00324
00325 size = kfile_read(fd, block_buffer, XM_BUFSIZE);
00326
00327 kfile_clearerr(&port->fd);
00328 ser_purge(port);
00329 XMODEM_PROGRESS("Wait remote host\n");
00330
00331 for(;;)
00332 {
00333 proceed = false;
00334 do
00335 {
00336 if (XMODEM_CHECK_ABORT)
00337 return false;
00338
00339 switch (c = kfile_getc(&port->fd))
00340 {
00341 case XM_NAK:
00342 XMODEM_PROGRESS("Resend blk %d\n", blocknr);
00343 proceed = true;
00344 break;
00345
00346 case XM_C:
00347 if (c == XM_C)
00348 {
00349 XMODEM_PROGRESS("Tx start (CRC)\n");
00350 usecrc = true;
00351 }
00352 else
00353 XMODEM_PROGRESS("Tx start (BCC)\n");
00354
00355 proceed = true;
00356 break;
00357
00358 case XM_ACK:
00359
00360 if (!size)
00361 return true;
00362
00363
00364 size = kfile_read(fd, block_buffer, XM_BUFSIZE);
00365 XMODEM_PROGRESS("Send blk %d\n", blocknr);
00366 blocknr++;
00367 retries = 0;
00368 proceed = true;
00369 break;
00370
00371 case EOF:
00372 kfile_clearerr(&port->fd);
00373 retries++;
00374 XMODEM_PROGRESS("Retries %d\n", retries);
00375 if (retries <= XM_MAXRETRIES)
00376 break;
00377
00378
00379 case XM_CAN:
00380 XMODEM_PROGRESS("Transfer aborted\n");
00381 return false;
00382
00383 default:
00384 XMODEM_PROGRESS("Skipping garbage\n");
00385 break;
00386 }
00387 }
00388 while (!proceed);
00389
00390 if (!size)
00391 {
00392 kfile_putc(XM_EOT, &port->fd);
00393 continue;
00394 }
00395
00396
00397 memset(block_buffer + size, 0xFF, XM_BUFSIZE - size);
00398
00399
00400 #if XM_BUFSIZE == 128
00401 kfile_putc(XM_SOH, &port->fd);
00402 #else
00403 kfile_putc(XM_STX, &port->fd);
00404 #endif
00405 kfile_putc(blocknr & 0xFF, &port->fd);
00406 kfile_putc(~blocknr & 0xFF, &port->fd);
00407
00408
00409 sum = 0;
00410 crc = 0;
00411 for (i = 0; i < XM_BUFSIZE; i++)
00412 {
00413 kfile_putc(block_buffer[i], &port->fd);
00414 crc = UPDCRC16(block_buffer[i], crc);
00415 sum += block_buffer[i];
00416 }
00417
00418
00419 if (usecrc)
00420 {
00421 crc = UPDCRC16(0, crc);
00422 crc = UPDCRC16(0, crc);
00423 ser_putchar(crc >> 8, port);
00424 ser_putchar(crc & 0xFF, port);
00425 }
00426 else
00427 kfile_putc(sum, &port->fd);
00428 }
00429 }
00430 #endif