00001
00028
00029
00030 #include "xmodem.h"
00031 #include "roboot.h"
00032 #include "roboot_if_comm.h"
00033
00034
00035 #define SOH 0x01
00036 #define STX 0x02
00037 #define EOT 0x04
00038 #define ACK 0x06
00039 #define NAK 0x15
00040 #define CAN 0x18
00041 #define CTRLZ 0x1A
00042
00043
00044 static void (*xmodemOut)(uint8_t c);
00045 static int16_t (*xmodemIn)(void);
00046
00047 static uint8_t *packet_buf;
00048
00049
00050 static uint8_t xmodemCrcCheck(const uint8_t *buffer, uint16_t size, const uint8_t *crc_buf);
00051
00052
00053
00054 static int16_t xmodemInTime(uint8_t timeout);
00055
00056
00057 static void xmodemInFlush(void);
00058
00059
00060 static uint8_t xmodemGetBytes(uint8_t* dst, uint16_t len);
00061
00062
00063
00064
00065 void xmodemInit(uint8_t *buf, void (*sendbyte_func)(uint8_t c), int16_t (*getbyte_func)(void))
00066 {
00067
00068 xmodemOut = sendbyte_func;
00069 xmodemIn = getbyte_func;
00070 packet_buf = buf;
00071 }
00072
00073
00074
00075
00076 int8_t xmodemReceive(int8_t (*process_packet)(uint32_t size, uint8_t **new_buf))
00077 {
00078 uint16_t pktsize;
00079 int16_t c;
00080 uint8_t header[2];
00081 uint8_t crc[2];
00082 uint8_t response;
00083 uint8_t seqnum;
00084 uint8_t retry;
00085
00086 pktsize = 0;
00087 response = 'C';
00088 seqnum = 1;
00089 retry = XMODEM_RETRY_LIMIT;
00090
00091 xmodemInFlush();
00092
00093
00094 while (retry)
00095 {
00096
00097 xmodemOut(response);
00098
00099
00100 if ((c = xmodemInTime(XMODEM_TIMEOUT_DELAY)) >= 0)
00101 {
00102 switch(c)
00103 {
00104 case SOH:
00105 pktsize = 128;
00106 break;
00107 case STX:
00108 pktsize = 1024;
00109 break;
00110 case EOT:
00111 xmodemOut(ACK);
00112 xmodemInFlush();
00113 xmodemOut(ACK);
00114
00115 return XMODEM_TRANSMISSION_OK;
00116 case CAN:
00117 if ((c = xmodemInTime(XMODEM_TIMEOUT_DELAY)) == CAN)
00118 {
00119 xmodemInFlush();
00120 xmodemOut(ACK);
00121
00122 return XMODEM_ERROR_REMOTECANCEL;
00123 }
00124 default:
00125 break;
00126 }
00127 }
00128 else
00129 {
00130
00131
00132 retry--;
00133 continue;
00134 }
00135
00136 if (0 == pktsize)
00137 {
00138 xmodemInFlush();
00139 if (response != 'C')
00140 {
00141 response = NAK;
00142 }
00143 retry--;
00144 continue;
00145 }
00146
00147
00148
00149 if ((response = xmodemGetBytes(header, sizeof(header))))
00150 {
00151 retry--;
00152 continue;
00153 }
00154
00155
00156 if ((response = xmodemGetBytes(packet_buf, pktsize)))
00157 {
00158 retry--;
00159 continue;
00160 }
00161
00162
00163 if ((response = xmodemGetBytes(crc, sizeof(crc))))
00164 {
00165 retry--;
00166 continue;
00167 }
00168
00169
00170
00171
00172
00173 if (((uint8_t) (header[0] ^ header[1]) == (uint8_t) 0xFFU) &&
00174 xmodemCrcCheck(packet_buf, pktsize, crc))
00175 {
00176
00177 if (header[0] == seqnum)
00178 {
00179
00180 if (process_packet(pktsize, &packet_buf) < 0)
00181 {
00182
00183
00184 xmodemInFlush();
00185 xmodemOut(CAN);
00186 xmodemOut(CAN);
00187 xmodemOut(CAN);
00188 return XMODEM_ERROR_DATAPROCESSING;
00189 }
00190
00191
00192 seqnum++;
00193
00194 retry = XMODEM_RETRY_LIMIT;
00195 pktsize = 0;
00196
00197 response = ACK;
00198 continue;
00199 }
00200 else if (header[0] == (uint8_t)(seqnum-1))
00201 {
00202
00203
00204 response = ACK;
00205 retry = XMODEM_RETRY_LIMIT;
00206 pktsize = 0;
00207 continue;
00208 }
00209 else
00210 {
00211
00212
00213 xmodemInFlush();
00214 xmodemOut(CAN);
00215 xmodemOut(CAN);
00216 xmodemOut(CAN);
00217 return XMODEM_ERROR_OUTOFSYNC;
00218 }
00219 }
00220 else
00221 {
00222
00223
00224 retry--;
00225 xmodemInFlush();
00226 response = NAK;
00227 }
00228 }
00229
00230
00231 xmodemInFlush();
00232 xmodemOut(CAN);
00233 xmodemOut(CAN);
00234 xmodemOut(CAN);
00235 return XMODEM_ERROR_RETRYEXCEED;
00236 }
00237
00238
00239
00240
00241 static inline uint16_t crc_xmodem_update(uint16_t crc, uint8_t data)
00242 {
00243 uint8_t i;
00244
00245 crc ^= (uint16_t)data << 8;
00246
00247 for (i=0; i < 8; i++)
00248 {
00249 if (crc & 0x8000)
00250 {
00251 crc = (crc << 1) ^ 0x1021;
00252 }
00253 else
00254 {
00255 crc <<= 1;
00256 }
00257 }
00258
00259 return crc;
00260 }
00261
00262
00263
00264
00265 static uint8_t xmodemCrcCheck(const uint8_t *buffer, uint16_t size, const uint8_t *crc_buf)
00266 {
00267 uint16_t crc = 0;
00268 uint16_t pktcrc = ((uint16_t)crc_buf[0] << 8) + (uint16_t)crc_buf[1];
00269
00270 while (size--)
00271 {
00272 crc = crc_xmodem_update(crc, *buffer++);
00273 }
00274
00275
00276 if (crc == pktcrc)
00277 {
00278 return 1;
00279 }
00280
00281 return 0;
00282 }
00283
00284
00285
00286
00287 static int16_t xmodemInTime(uint8_t timeout)
00288 {
00289 while (timeout--)
00290 {
00291 uint16_t rerties;
00292 rerties = (uint16_t) (100000UL / (2500000UL / XMODEM_BAUD_RATE));
00293
00294
00295 while (rerties--)
00296 {
00297 int16_t c;
00298
00299 if ((c = xmodemIn()) >= 0)
00300 {
00301 return c;
00302 }
00303
00304
00305 uint8_t i = (uint8_t) (250000UL / XMODEM_BAUD_RATE);
00306 while (i--)
00307 {
00308 MCUBusyDelay();
00309 }
00310 }
00311 }
00312
00313 return -1;
00314 }
00315
00316
00317
00318
00319 static void xmodemInFlush(void)
00320 {
00321 while (xmodemInTime(XMODEM_FLUSH_TIMEOUT) >= 0)
00322 {
00323 ;
00324 }
00325 }
00326
00327
00328
00329 static uint8_t xmodemGetBytes(uint8_t* dst, uint16_t len)
00330 {
00331 int16_t c;
00332
00333 while (len--)
00334 {
00335 if ((c = xmodemInTime(XMODEM_TIMEOUT_DELAY)) >= 0)
00336 {
00337 *dst++ = c;
00338 }
00339 else
00340 {
00341
00342 return NAK;
00343 }
00344 }
00345
00346 return 0;
00347 }
00348