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