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