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