S.F.T. XMODEM Library
1.0
|
00001 00002 // // 00003 // _ // 00004 // __ __ _ __ ___ ___ __| | ___ _ __ ___ ___ // 00005 // \ \/ /| '_ ` _ \ / _ \ / _` | / _ \| '_ ` _ \ / __| // 00006 // > < | | | | | || (_) || (_| || __/| | | | | | _| (__ // 00007 // /_/\_\|_| |_| |_| \___/ \__,_| \___||_| |_| |_|(_)\___| // 00008 // // 00009 // // 00011 // // 00012 // Copyright (c) 2012 by S.F.T. Inc. - All rights reserved // 00013 // Use, copying, and distribution of this software are licensed according // 00014 // to the GPLv2, LGPLv2, or BSD license, as appropriate (see COPYING) // 00015 // // 00017 00018 00019 // XMODEM adapted for arduino and POSIX systems. Windows code incomplete 00020 00021 #include "xmodem.h" 00022 00023 // internal structure definitions 00024 00025 // Windows requires a different way of specifying structure packing 00026 #ifdef WIN32 00027 #define PACKED 00028 #pragma pack(push,1) 00029 #else // POSIX, ARDUINO 00030 #define PACKED __attribute__((__packed__)) 00031 #endif // WIN32 vs THE REST OF THE WORLD 00032 00033 #define _SOH_ 1 /* start of packet - note XMODEM-1K uses '2' */ 00034 #define _EOT_ 4 00035 #define _ENQ_ 5 00036 #define _ACK_ 6 00037 #define _NAK_ 21 /* NAK character */ 00038 #define _CAN_ 24 /* CAN character CTRL+X */ 00039 00061 typedef struct _XMODEM_BUF_ 00062 { 00063 char cSOH; 00064 unsigned char aSEQ, aNotSEQ; 00065 char aDataBuf[128]; 00066 unsigned char bCheckSum; 00067 } PACKED XMODEM_BUF; 00068 00084 typedef struct _XMODEMC_BUF_ 00085 { 00086 char cSOH; 00087 unsigned char aSEQ, aNotSEQ; 00088 char aDataBuf[128]; 00089 unsigned short wCRC; 00090 } PACKED XMODEMC_BUF; 00091 00092 #ifdef WIN32 00093 // restore default packing 00094 #pragma pack(pop) 00095 #endif // WIN32 00096 00119 typedef struct _XMODEM_ 00120 { 00121 SERIAL_TYPE ser; 00122 FILE_TYPE file; 00123 00124 union 00125 { 00126 XMODEM_BUF xbuf; 00127 XMODEMC_BUF xcbuf; 00128 } buf; 00129 00130 unsigned char bCRC; 00131 00132 } XMODEM; 00133 00134 00135 #ifdef DEBUG_CODE 00136 static char szERR[32]; // place for error messages, up to 16 characters 00137 00138 const char *XMGetError(void) 00139 { 00140 return szERR; 00141 } 00142 #endif // DEBUG_CODE 00143 00144 #if defined(STAND_ALONE) && defined(DEBUG_CODE) 00145 void debug_dump_buffer(int iDir, const void *pBuf, int cbBuf) 00146 { 00147 int i1, i2; 00148 const unsigned char *p1, *p2; 00149 00150 if(cbBuf <= 0) 00151 { 00152 return; 00153 } 00154 00155 p1 = p2 = (const unsigned char *)pBuf; 00156 00157 for(i1=0, i2=0; i1 <= cbBuf; i1++, p1++) 00158 { 00159 if(!i1 || i2 >= 16 || i1 == cbBuf) 00160 { 00161 if(i1) 00162 { 00163 while(i2 < 16) 00164 { 00165 fputs(" ", stderr); // fill up spaces where data would be 00166 i2++; 00167 } 00168 00169 fputs(" : ", stderr); 00170 00171 while(p2 < p1) 00172 { 00173 if(*p2 >= 32 && *p2 <= 127) 00174 { 00175 fputc(*p2, stderr); 00176 } 00177 else 00178 { 00179 fputc('.', stderr); 00180 } 00181 00182 p2++; 00183 } 00184 00185 fputc('\n', stderr); 00186 } 00187 00188 if(!i1 && iDir > 0) 00189 { 00190 fputs("--> ", stderr); 00191 } 00192 else if(!i1 && iDir < 0) 00193 { 00194 fputs("<-- ", stderr); 00195 } 00196 else 00197 { 00198 fputs(" ", stderr); 00199 } 00200 00201 i2 = 0; 00202 p2 = p1; // make sure 00203 } 00204 00205 if(i1 < cbBuf) 00206 { 00207 if(!i2) 00208 { 00209 fprintf(stderr, "%02x: %02x", i1, *p1); 00210 } 00211 else 00212 { 00213 fprintf(stderr, ", %02x", *p1); 00214 } 00215 00216 i2++; 00217 } 00218 } 00219 00220 fputc('\n', stderr); 00221 fflush(stderr); 00222 } 00223 #endif // STAND_ALONE, DEBUG_CODE 00224 00225 00226 //char iBinaryTransfer = 0, iDisableRXOVER = 0; 00227 00236 unsigned char CalcCheckSum(const char *lpBuf, short cbBuf) 00237 { 00238 short iC, i1; 00239 00240 iC = 0; 00241 00242 for(i1 = 0; i1 < cbBuf; i1++) 00243 { 00244 iC += lpBuf[i1]; 00245 } 00246 00247 return (unsigned char)(iC & 0xff); 00248 } 00249 00259 static unsigned short my_htons(unsigned short sVal) 00260 { 00261 union 00262 { 00263 unsigned char aVal[2]; 00264 unsigned short sVal; 00265 } a, b; 00266 00267 // tweeked for size and speed. enjoy. 00268 00269 b.sVal = sVal; 00270 00271 #ifdef ARDUINO 00272 00273 a.aVal[0] = b.aVal[1]; // no math involved, pre-optimized code 00274 a.aVal[1] = b.aVal[0]; 00275 00276 #else 00277 00278 a.aVal[0] = (unsigned char)(sVal >> 8); // less optimized but universal code 00279 a.aVal[1] = (unsigned char)(sVal & 0xff); 00280 00281 #endif // ARDUINO 00282 00283 return a.sVal; 00284 } 00285 00296 unsigned short CalcCRC(const char *lpBuf, short cbBuf) 00297 { 00298 unsigned short wCRC; 00299 short i1, i2, iAX; 00300 char cAL; 00301 00302 // ** this function returns 2-byte string containing 00303 // ** the CRC calculation result, as high endian 00304 00305 wCRC = 0; 00306 00307 for(i1=0; i1 < cbBuf; i1++) 00308 { 00309 cAL = lpBuf[i1]; 00310 00311 iAX = (unsigned short)cAL << 8; 00312 00313 wCRC = iAX ^ wCRC; 00314 00315 for(i2=0; i2 < 8; i2++) 00316 { 00317 iAX = wCRC; 00318 00319 if(iAX & 0x8000) 00320 { 00321 wCRC <<= 1; 00322 wCRC ^= 0x1021; 00323 } 00324 else 00325 { 00326 wCRC <<= 1; 00327 } 00328 } 00329 } 00330 00331 return my_htons(wCRC); 00332 } 00333 00334 //void WaitASecond() 00335 //{ 00336 //#ifdef ARDUINO 00337 // delay(1000); 00338 //#elif defined(WIN32) 00339 // Sleep(1000); 00340 //#else // 00341 // usleep(1000000); 00342 //#endif // ARDUINO 00343 //} 00344 00345 #ifndef ARDUINO 00346 #ifdef WIN32 00347 #define MyMillis GetTickCount 00348 #else // WIN32 00349 00363 unsigned long MyMillis(void) 00364 { 00365 struct timeval tv; 00366 00367 gettimeofday(&tv, NULL); // 2nd parameter is obsolete anyway 00368 00369 // NOTE: this won't roll over the way 'GetTickCount' does in WIN32 so I'll truncate it 00370 // down to a 32-bit value to make it happen. Everything that uses 'MyGetTickCount' 00371 // must handle this rollover properly using 'int' and not 'long' (or cast afterwards) 00372 return((unsigned int)((unsigned long)tv.tv_sec * 1000L + (unsigned long)tv.tv_usec / 1000L)); 00373 } 00374 #endif // WIN32 00375 #endif // ARDUINO 00376 00377 //Function GenerateSEQ (wSeq%) As String 00378 // 00379 // GenerateSEQ = Chr$(wSeq%) + Chr$(Not (wSeq%) And &HFF) 00380 // 00381 //End Function 00382 00394 void GenerateSEQ(XMODEM_BUF *pBuf, unsigned char bSeq) 00395 { 00396 pBuf->aSEQ = bSeq; 00397 pBuf->aNotSEQ = ~bSeq; 00398 } 00399 00411 void GenerateSEQC(XMODEMC_BUF *pBuf, unsigned char bSeq) 00412 { 00413 pBuf->aSEQ = bSeq; 00414 pBuf->aNotSEQ = (255 - bSeq);//~bSeq; these should be the same but for now I do this... 00415 } 00416 00435 short GetXmodemBlock(SERIAL_TYPE ser, char *pBuf, short cbSize) 00436 { 00437 unsigned long ulCur; 00438 short cb1; 00439 char *p1; 00440 00441 // ** This function obtains a buffer of 'wSize%' bytes, ** 00442 // ** waiting a maximum of 5 seconds (of silence) to get it. ** 00443 // ** It returns this block as a string of 'wSize%' bytes, ** 00444 // ** or a zero length string on error. ** 00445 00446 // iDisableRXOVER% = 1; // bug workaround 00447 00448 #ifdef ARDUINO 00449 short i1; 00450 00451 p1 = pBuf; 00452 cb1 = 0; 00453 00454 ulCur = millis(); 00455 ser->setTimeout(SILENCE_TIMEOUT); // 5 seconds [of silence] 00456 00457 for(i1=0; i1 < cbSize; i1++) 00458 { 00459 if(ser->readBytes(p1, 1) != 1) // 5 seconds of "silence" is what fails this 00460 { 00461 break; 00462 } 00463 00464 cb1++; 00465 p1++; 00466 00467 if((millis() - ulCur) > (unsigned long)(10L * SILENCE_TIMEOUT)) // 10 times SILENCE TIMEOUT for TOTAL TIMEOUT 00468 { 00469 break; // took too long, I'm going now 00470 } 00471 } 00472 00473 #elif defined(WIN32) 00474 00475 #error no win32 code yet 00476 00477 #else // POSIX 00478 int i1, i2; 00479 unsigned long ulStart; 00480 00481 00482 if(fcntl(ser, F_SETFL, O_NONBLOCK) == -1) 00483 { 00484 static int iFailFlag = 0; 00485 00486 if(!iFailFlag) 00487 { 00488 fprintf(stderr, "Warning: 'fcntl(O_NONBLOCK)' failed, errno = %d\n", errno); 00489 fflush(stderr); 00490 iFailFlag = 1; 00491 } 00492 } 00493 00494 p1 = pBuf; 00495 cb1 = 0; 00496 00497 ulStart = ulCur = MyMillis(); 00498 00499 for(i1=0; i1 < cbSize; i1++) 00500 { 00501 while((i2 = read(ser, p1, 1)) != 1) 00502 { 00503 if(i2 < 0 && errno != EAGAIN) 00504 { 00505 // read error - exit now 00506 // return cb1; // how many bytes I actually read 00507 goto the_end; 00508 } 00509 else 00510 { 00511 usleep(1000); // 1 msec 00512 00513 if((MyMillis() - ulCur) > SILENCE_TIMEOUT || // too much silence? 00514 (MyMillis() - ulStart) > 10 * SILENCE_TIMEOUT) // too long for transfer 00515 { 00516 // return cb1; // finished (return how many bytes I actually read) 00517 goto the_end; 00518 } 00519 } 00520 } 00521 00522 // here it succeeds 00523 00524 cb1++; 00525 p1++; 00526 00527 if((MyMillis() - ulStart) > 10 * SILENCE_TIMEOUT) // 10 times SILENCE TIMEOUT for TOTAL TIMEOUT 00528 { 00529 break; // took too long, I'm going now 00530 } 00531 } 00532 00533 the_end: 00534 00535 #ifdef STAND_ALONE 00536 fprintf(stderr, "GetXmodemBlock - request %d, read %d errno=%d\n", cbSize, cb1, errno); 00537 fflush(stderr); 00538 #ifdef DEBUG_CODE 00539 debug_dump_buffer(-1, pBuf, cb1); 00540 #endif // DEBUG_CODE 00541 #endif // STAND_ALONE 00542 00543 #endif // ARDUINO 00544 00545 return cb1; // what I actually read 00546 } 00547 00558 int WriteXmodemChar(SERIAL_TYPE ser, unsigned char bVal) 00559 { 00560 int iRval; 00561 #ifdef ARDUINO 00562 00563 iRval = ser->write(bVal); 00564 // ser->flush(); // force sending it 00565 00566 #elif defined(WIN32) 00567 00568 #error no win32 code yet 00569 00570 #else // POSIX 00571 char buf[2]; // use size of '2' to avoid warnings about array size of '1' 00572 00573 if(fcntl(ser, F_SETFL, 0) == -1) // set blocking mode 00574 { 00575 static int iFailFlag = 0; 00576 00577 if(!iFailFlag) 00578 { 00579 fprintf(stderr, "Warning: 'fcntl(O_NONBLOCK)' failed, errno = %d\n", errno); 00580 iFailFlag = 1; 00581 } 00582 } 00583 00584 buf[0] = bVal; // in case args are passed by register 00585 00586 iRval = write(ser, buf, 1); 00587 00588 #if defined(STAND_ALONE) && defined(DEBUG_CODE) 00589 fprintf(stderr, "WriteXmodemChar - returns %d\n", iRval); 00590 if(iRval > 0) 00591 { 00592 debug_dump_buffer(1, buf, 1); 00593 } 00594 #endif // STAND_ALONE, DEBUG_CODE 00595 #endif // ARDUINO 00596 00597 return iRval; 00598 } 00599 00611 int WriteXmodemBlock(SERIAL_TYPE ser, const void *pBuf, int cbSize) 00612 { 00613 int iRval; 00614 #ifdef ARDUINO 00615 00616 iRval = ser->write((const uint8_t *)pBuf, cbSize); 00617 // ser->flush(); // force sending it before returning 00618 00619 #elif defined(WIN32) 00620 00621 #error no win32 code yet 00622 00623 #else // POSIX 00624 00625 00626 if(fcntl(ser, F_SETFL, 0) == -1) // set blocking mode 00627 { 00628 static int iFailFlag = 0; 00629 00630 if(!iFailFlag) 00631 { 00632 fprintf(stderr, "Warning: 'fcntl(O_NONBLOCK)' failed, errno = %d\n", errno); 00633 fflush(stderr); 00634 iFailFlag = 1; 00635 } 00636 } 00637 00638 iRval = write(ser, pBuf, cbSize); 00639 00640 #if defined(STAND_ALONE) && defined(DEBUG_CODE) 00641 fprintf(stderr, "\r\nWriteXmodemBlock - returns %d\n", iRval); 00642 fflush(stderr); 00643 00644 if(iRval > 0) 00645 { 00646 debug_dump_buffer(1, pBuf, cbSize); 00647 } 00648 #endif // STAND_ALONE, DEBUG_CODE 00649 #endif 00650 00651 return iRval; 00652 } 00653 00666 void XModemFlushInput(SERIAL_TYPE ser) 00667 { 00668 unsigned long ulStart; 00669 #ifdef ARDUINO 00670 00671 ulStart = millis(); 00672 00673 do 00674 { 00675 if(ser->available()) 00676 { 00677 ser->read(); // don't care about the data 00678 ulStart = millis(); // reset time 00679 } 00680 else 00681 { 00682 delay(1); 00683 } 00684 00685 } while((millis() - ulStart) < 1000); 00686 00687 #elif defined(WIN32) 00688 00689 #error no win32 code yet 00690 00691 #else // POSIX 00692 int i1; 00693 #ifdef DEBUG_CODE 00694 unsigned char buf[16]; 00695 int cbBuf; 00696 #else // DEBUG_CODE 00697 unsigned char buf[2]; 00698 #endif // DEBUG_CODE 00699 00700 if(fcntl(ser, F_SETFL, O_NONBLOCK) == -1) 00701 { 00702 static int iFailFlag = 0; 00703 00704 if(!iFailFlag) 00705 { 00706 fprintf(stderr, "Warning: 'fcntl(O_NONBLOCK)' failed, errno = %d\n", errno); 00707 iFailFlag = 1; 00708 } 00709 } 00710 00711 ulStart = MyMillis(); 00712 #ifdef DEBUG_CODE 00713 cbBuf = 0; 00714 #endif // DEBUG_CODE 00715 while((MyMillis() - ulStart) < 1000) 00716 { 00717 #ifdef DEBUG_CODE 00718 i1 = read(ser, &(buf[cbBuf]), 1); 00719 #else // DEBUG_CODE 00720 i1 = read(ser, buf, 1); 00721 #endif // DEBUG_CODE 00722 if(i1 == 1) 00723 { 00724 #if defined(STAND_ALONE) && defined(DEBUG_CODE) 00725 cbBuf++; 00726 if(cbBuf >= sizeof(buf)) 00727 { 00728 debug_dump_buffer(-1, buf, cbBuf); 00729 cbBuf = 0; 00730 } 00731 #endif // STAND_ALONE, DEBUG_CODE 00732 ulStart = MyMillis(); 00733 } 00734 else 00735 { 00736 usleep(1000); 00737 } 00738 } 00739 00740 #if defined(STAND_ALONE) && defined(DEBUG_CODE) 00741 if(cbBuf > 0) 00742 { 00743 debug_dump_buffer(-1, buf, cbBuf); 00744 } 00745 #endif // STAND_ALONE, DEBUG_CODE 00746 00747 #endif // ARDUINO 00748 } 00749 00758 void XmodemTerminate(XMODEM *pX) 00759 { 00760 XModemFlushInput(pX->ser); 00761 00762 // TODO: close files? 00763 } 00764 00765 00775 short ValidateSEQ(XMODEM_BUF *pX, unsigned char bSeq) 00776 { 00777 return pX->aSEQ != 255 - pX->aNotSEQ || // ~(pX->aNotSEQ) || 00778 pX->aSEQ != bSeq; // returns TRUE if not valid 00779 } 00780 00790 short ValidateSEQC(XMODEMC_BUF *pX, unsigned char bSeq) 00791 { 00792 return pX->aSEQ != 255 - pX->aNotSEQ || // ~(pX->aNotSEQ) || 00793 pX->aSEQ != bSeq; // returns TRUE if not valid 00794 } 00795 00811 int ReceiveXmodem(XMODEM *pX) 00812 { 00813 int ecount, ec2; 00814 long etotal, filesize, block; 00815 unsigned char cY; // the char to send in response to a packet 00816 // NOTE: to allow debugging the CAUSE of an xmodem block's failure, i1, i2, and i3 00817 // are assigned to function return values and reported in error messages. 00818 #ifdef DEBUG_CODE 00819 short i1, i2, i3; 00820 #define DEBUG_I1 i1 = 00821 #define DEBUG_I2 i2 = 00822 #define DEBUG_I3 i3 = 00823 #else // DEBUG_CODE 00824 #define DEBUG_I1 /*normally does nothing*/ 00825 #define DEBUG_I2 /*normally does nothing*/ 00826 #define DEBUG_I3 /*normally does nothing*/ 00827 #endif // DEBUG_CODE 00828 00829 ecount = 0; 00830 etotal = 0; 00831 filesize = 0; 00832 block = 1; 00833 00834 // ** already got the first 'SOH' character on entry to this function ** 00835 00836 // Form2.Show 0 '** modeless show of form2 (CANSEND) ** 00837 // Form2!Label1.FloodType = 0 00838 // Form2.Caption = "* XMODEM(Checksum) BINARY RECEIVE *" 00839 // Form2!Label1.Caption = "Errors: 0 Bytes: 0" 00840 00841 pX->buf.xbuf.cSOH = (char)1; // assumed already got this, put into buffer 00842 00843 do 00844 { 00845 if(!pX->bCRC && 00846 ((DEBUG_I1 GetXmodemBlock(pX->ser, ((char *)&(pX->buf.xbuf)) + 1, sizeof(pX->buf.xbuf) - 1)) 00847 != sizeof(pX->buf.xbuf) - 1 || 00848 (DEBUG_I2 ValidateSEQ(&(pX->buf.xbuf), block & 255)) || 00849 (DEBUG_I3 CalcCheckSum(pX->buf.xbuf.aDataBuf, sizeof(pX->buf.xbuf.aDataBuf)) != pX->buf.xbuf.bCheckSum))) 00850 { 00851 // did not receive properly 00852 // TODO: deal with repeated packet, sequence number for previous packet 00853 00854 #ifdef DEBUG_CODE 00855 sprintf(szERR,"A%ld,%d,%d,%d,%d,%d",block,i1,i2,i3,pX->buf.xbuf.aSEQ, pX->buf.xbuf.aNotSEQ); 00856 //#ifdef STAND_ALONE 00857 // fprintf(stderr, "TEMPORARY (csum): seq=%x, ~seq=%x i1=%d, i2=%d, i3=%d\n", pX->buf.xbuf.aSEQ, pX->buf.xbuf.aNotSEQ, i1, i2, i3); 00858 //#endif // STAND_ALONE 00859 #endif // DEBUG_CODE 00860 00861 XModemFlushInput(pX->ser); // necessary to avoid problems 00862 00863 cY = _NAK_; // send NAK (to get the checksum version) 00864 ecount ++; // for this packet 00865 etotal ++; 00866 } 00867 else if(pX->bCRC && 00868 ((DEBUG_I1 GetXmodemBlock(pX->ser, ((char *)&(pX->buf.xcbuf)) + 1, sizeof(pX->buf.xcbuf) - 1)) 00869 != sizeof(pX->buf.xcbuf) - 1 || 00870 (DEBUG_I2 ValidateSEQC(&(pX->buf.xcbuf), block & 255)) || 00871 (DEBUG_I3 CalcCRC(pX->buf.xcbuf.aDataBuf, sizeof(pX->buf.xbuf.aDataBuf)) != pX->buf.xcbuf.wCRC))) 00872 { 00873 // did not receive properly 00874 // TODO: deal with repeated packet, sequence number for previous packet 00875 00876 #ifdef DEBUG_CODE 00877 sprintf(szERR,"B%ld,%d,%d,%d,%d,%d",block,i1,i2,i3,pX->buf.xcbuf.aSEQ, pX->buf.xcbuf.aNotSEQ); 00878 //#ifdef STAND_ALONE 00879 // fprintf(stderr, "TEMPORARY (CRC): seq=%x, ~seq=%x i1=%d, i2=%d, i3=%d\n", pX->buf.xcbuf.aSEQ, pX->buf.xcbuf.aNotSEQ, i1, i2, i3); 00880 //#endif // STAND_ALONE 00881 #endif // DEBUG_CODE 00882 00883 XModemFlushInput(pX->ser); // necessary to avoid problems 00884 00885 if(block > 1) 00886 { 00887 cY = _NAK_; // TODO do I need this? 00888 } 00889 else 00890 { 00891 cY = 'C'; // send 'CRC' NAK (the character 'C') (to get the CRC version) 00892 } 00893 ecount ++; // for this packet 00894 etotal ++; 00895 } 00896 else 00897 { 00898 #ifdef ARDUINO 00899 if(pX->file.write((const uint8_t *)&(pX->buf.xbuf.aDataBuf), sizeof(pX->buf.xbuf.aDataBuf)) != sizeof(pX->buf.xbuf.aDataBuf)) 00900 { 00901 return -2; // write error on output file 00902 } 00903 #else // ARDUINO 00904 if(write(pX->file, &(pX->buf.xbuf.aDataBuf), sizeof(pX->buf.xbuf.aDataBuf)) != sizeof(pX->buf.xbuf.aDataBuf)) 00905 { 00906 XmodemTerminate(pX); 00907 return -2; // write error on output file 00908 } 00909 #endif // ARDUINO 00910 cY = _ACK_; // send ACK 00911 block ++; 00912 filesize += sizeof(pX->buf.xbuf.aDataBuf); // TODO: need method to avoid extra crap at end of file 00913 ecount = 0; // zero out error count for next packet 00914 } 00915 00916 #ifdef STAND_ALONE 00917 fprintf(stderr, "block %ld %ld bytes %d errors\r\n", block, filesize, ecount); 00918 #endif // STAND_ALONE 00919 00920 ec2 = 0; // ** error count #2 ** 00921 00922 while(ecount < TOTAL_ERROR_COUNT && ec2 < ACK_ERROR_COUNT) // ** loop to get SOH or EOT character ** 00923 { 00924 WriteXmodemChar(pX->ser, cY); // ** output appropriate command char ** 00925 00926 if(GetXmodemBlock(pX->ser, &(pX->buf.xbuf.cSOH), 1) == 1) 00927 { 00928 if(pX->buf.xbuf.cSOH == _CAN_) // ** CTRL-X 'CAN' - terminate 00929 { 00930 XmodemTerminate(pX); 00931 return 1; // terminated 00932 } 00933 else if(pX->buf.xbuf.cSOH == _EOT_) // ** EOT - end 00934 { 00935 WriteXmodemChar(pX->ser, _ACK_); // ** send an ACK (most XMODEM protocols expect THIS) 00936 // WriteXmodemChar(pX->ser, _ENQ_); // ** send an ENQ 00937 00938 return 0; // I am done 00939 } 00940 else if(pX->buf.xbuf.cSOH == _SOH_) // ** SOH - sending next packet 00941 { 00942 break; // leave this loop 00943 } 00944 else 00945 { 00946 // TODO: deal with repeated packet, i.e. previous sequence number 00947 00948 XModemFlushInput(pX->ser); // necessary to avoid problems (since the character was unexpected) 00949 // if I was asking for the next block, and got an unexpected character, do a NAK; otherwise, 00950 // just repeat what I did last time 00951 00952 if(cY == _ACK_) // ACK 00953 { 00954 cY = _NAK_; // NACK 00955 } 00956 00957 ec2++; 00958 } 00959 } 00960 else 00961 { 00962 ecount++; // increase total error count, and try writing the 'ACK' or 'NACK' again 00963 } 00964 } 00965 00966 if(ec2 >= ACK_ERROR_COUNT) // wasn't able to get a packet 00967 { 00968 break; 00969 } 00970 00971 } while(ecount < TOTAL_ERROR_COUNT); 00972 00973 XmodemTerminate(pX); 00974 return 1; // terminated 00975 } 00976 00977 00994 int SendXmodem(XMODEM *pX) 00995 { 00996 int ecount, ec2; 00997 short i1; 00998 long etotal, filesize, filepos, block; 00999 01000 01001 ecount = 0; 01002 etotal = 0; 01003 filesize = 0; 01004 filepos = 0; 01005 block = 1; 01006 01007 pX->bCRC = 0; // MUST ASSIGN TO ZERO FIRST or XMODEM-CHECKSUM may not work properly 01008 01009 // ** already got first 'NAK' character on entry as pX->buf.xbuf.cSOH ** 01010 01011 #ifdef ARDUINO 01012 01013 filesize = pX->file.size(); 01014 01015 #else // ARDUINO 01016 01017 filesize = (long)lseek(pX->file, 0, SEEK_END); 01018 if(filesize < 0) // not allowed 01019 { 01020 #ifdef STAND_ALONE 01021 fputs("SendXmodem fail (file size)\n", stderr); 01022 #endif // STAND_ALONE 01023 return -1; 01024 } 01025 01026 lseek(pX->file, 0, SEEK_SET); // position at beginning 01027 01028 #endif // ARDUINO 01029 01030 do 01031 { 01032 // ** depending on type of transfer, place the packet 01033 // ** into pX->buf with all fields appropriately filled. 01034 01035 if(filepos >= filesize) // end of transfer 01036 { 01037 for(i1=0; i1 < 8; i1++) 01038 { 01039 WriteXmodemChar(pX->ser, _EOT_); // ** send an EOT marking end of transfer 01040 01041 if(GetXmodemBlock(pX->ser, &(pX->buf.xbuf.cSOH), 1) != 1) // this takes up to 5 seconds 01042 { 01043 // nothing returned - try again? 01044 // break; // for now I loop, uncomment to bail out 01045 } 01046 else if(pX->buf.xbuf.cSOH == _ENQ_ // an 'ENQ' (apparently some expect this) 01047 || pX->buf.xbuf.cSOH == _ACK_ // an 'ACK' (most XMODEM implementations expect this) 01048 || pX->buf.xbuf.cSOH == _CAN_) // CTRL-X = TERMINATE 01049 { 01050 // both normal and 'abnormal' termination. 01051 break; 01052 } 01053 } 01054 01055 XmodemTerminate(pX); 01056 01057 #ifdef STAND_ALONE 01058 fprintf(stderr, "SendXmodem return %d\n", i1 >= 8 ? 1 : 0); 01059 #endif // STAND_ALONE 01060 return i1 >= 8 ? 1 : 0; // return 1 if receiver choked on the 'EOT' marker, else 0 for 'success' 01061 } 01062 01063 // TODO: progress indicator [can be LCD for arduino, blinky lights, ??? and of course stderr for everyone else] 01064 // If filesize& <> 0 Then Form2!Label1.FloodPercent = 100 * filepos& / filesize& 01065 01066 #ifdef STAND_ALONE 01067 fprintf(stderr, "block %ld %ld of %ld bytes %d errors\r\n", block, filepos, filesize, ecount); 01068 #endif // STAND_ALONE 01069 01070 if(pX->buf.xbuf.cSOH != 'C' // XMODEM CRC 01071 && pX->buf.xbuf.cSOH != (char)_NAK_) // NAK 01072 { 01073 // increase error count, bail if it's too much 01074 01075 ec2++; 01076 } 01077 01078 01079 #ifdef ARDUINO 01080 pX->file.seek(filepos); // in case I'm doing a 'retry' and I have to re-read part of the file 01081 #else // ARDUINO 01082 lseek(pX->file, filepos, SEEK_SET); // same reason as above 01083 #endif // ARDUINO 01084 01085 // fortunately, xbuf and xcbuf are the same through the end of 'aDataBuf' so 01086 // I can read the file NOW using 'xbuf' for both CRC and CHECKSUM versions 01087 01088 if((filesize - filepos) >= sizeof(pX->buf.xbuf.aDataBuf)) 01089 { 01090 #ifdef ARDUINO 01091 i1 = pX->file.read(pX->buf.xbuf.aDataBuf, sizeof(pX->buf.xcbuf.aDataBuf)); 01092 #else // ARDUINO 01093 i1 = read(pX->file, pX->buf.xbuf.aDataBuf, sizeof(pX->buf.xcbuf.aDataBuf)); 01094 #endif // ARDUINO 01095 01096 if(i1 != sizeof(pX->buf.xcbuf.aDataBuf)) 01097 { 01098 // TODO: read error - send a ctrl+x ? 01099 } 01100 } 01101 else 01102 { 01103 memset(pX->buf.xcbuf.aDataBuf, '\x1a', sizeof(pX->buf.xcbuf.aDataBuf)); // fill with ctrl+z which is what the spec says 01104 #ifdef ARDUINO 01105 i1 = pX->file.read(pX->buf.xbuf.aDataBuf, filesize - filepos); 01106 #else // ARDUINO 01107 i1 = read(pX->file, pX->buf.xbuf.aDataBuf, filesize - filepos); 01108 #endif // ARDUINO 01109 01110 if(i1 != (filesize - filepos)) 01111 { 01112 // TODO: read error - send a ctrl+x ? 01113 } 01114 } 01115 01116 if(pX->buf.xbuf.cSOH == 'C' || // XMODEM CRC 'NAK' (first time only, typically) 01117 ((pX->buf.xbuf.cSOH == _ACK_ || pX->buf.xbuf.cSOH == _NAK_) && pX->bCRC)) // identifies ACK/NACK with XMODEM CRC 01118 { 01119 pX->bCRC = 1; // make sure (only matters the first time, really) 01120 01121 // calculate the CRC, assign to the packet, and then send it 01122 01123 pX->buf.xcbuf.cSOH = 1; // must send SOH as 1st char 01124 pX->buf.xcbuf.wCRC = CalcCRC(pX->buf.xcbuf.aDataBuf, sizeof(pX->buf.xcbuf.aDataBuf)); 01125 01126 GenerateSEQC(&(pX->buf.xcbuf), block); 01127 01128 // send it 01129 01130 i1 = WriteXmodemBlock(pX->ser, &(pX->buf.xcbuf), sizeof(pX->buf.xcbuf)); 01131 if(i1 != sizeof(pX->buf.xcbuf)) // write error 01132 { 01133 // TODO: handle write error (send ctrl+X ?) 01134 } 01135 } 01136 else if(pX->buf.xbuf.cSOH == _NAK_ || // 'NAK' (checksum method, may also be with CRC method) 01137 (pX->buf.xbuf.cSOH == _ACK_ && !pX->bCRC)) // identifies ACK with XMODEM CHECKSUM 01138 { 01139 pX->bCRC = 0; // make sure (this ALSO allows me to switch modes on error) 01140 01141 // calculate the CHECKSUM, assign to the packet, and then send it 01142 01143 pX->buf.xbuf.cSOH = 1; // must send SOH as 1st char 01144 pX->buf.xbuf.bCheckSum = CalcCheckSum(pX->buf.xbuf.aDataBuf, sizeof(pX->buf.xbuf.aDataBuf)); 01145 01146 GenerateSEQ(&(pX->buf.xbuf), block); 01147 01148 // send it 01149 01150 i1 = WriteXmodemBlock(pX->ser, &(pX->buf.xbuf), sizeof(pX->buf.xbuf)); 01151 if(i1 != sizeof(pX->buf.xbuf)) // write error 01152 { 01153 // TODO: handle write error (send ctrl+X ?) 01154 } 01155 } 01156 01157 ec2 = 0; 01158 01159 while(ecount < TOTAL_ERROR_COUNT && ec2 < ACK_ERROR_COUNT) // loop to get ACK or NACK 01160 { 01161 if(GetXmodemBlock(pX->ser, &(pX->buf.xbuf.cSOH), 1) == 1) 01162 { 01163 if(pX->buf.xbuf.cSOH == _CAN_) // ** CTRL-X - terminate 01164 { 01165 XmodemTerminate(pX); 01166 01167 return 1; // terminated 01168 } 01169 else if(pX->buf.xbuf.cSOH == _NAK_ || // ** NACK 01170 pX->buf.xbuf.cSOH == 'C') // ** CRC NACK 01171 { 01172 break; // exit inner loop and re-send packet 01173 } 01174 else if(pX->buf.xbuf.cSOH == _ACK_) // ** ACK - sending next packet 01175 { 01176 filepos += sizeof(pX->buf.xbuf.aDataBuf); 01177 block++; // increment file position and block count 01178 01179 break; // leave inner loop, send NEXT packet 01180 } 01181 else 01182 { 01183 XModemFlushInput(pX->ser); // for now, do this here too 01184 ec2++; 01185 } 01186 } 01187 else 01188 { 01189 ecount++; // increase total error count, then loop back and re-send packet 01190 break; 01191 } 01192 } 01193 01194 if(ec2 >= ACK_ERROR_COUNT) 01195 { 01196 break; // that's it, I'm done with this 01197 } 01198 01199 } while(ecount < TOTAL_ERROR_COUNT * 2); // twice error count allowed for sending 01200 01201 // TODO: progress indicator 01202 // If filesize& <> 0 And filepos& <= filesize& Then 01203 // Form2!Label1.FloodPercent = 100 * filepos& / filesize& 01204 // Else 01205 // Form2!Label1.FloodPercent = 100 01206 // End If 01207 01208 01209 // ** at this point it is important to indicate the errors 01210 // ** and flush all buffers, and terminate process! 01211 01212 XmodemTerminate(pX); 01213 #ifdef STAND_ALONE 01214 fputs("SendXmodem fail (total error count)\n", stderr); 01215 #endif // STAND_ALONE 01216 return -2; // exit on error 01217 } 01218 01219 01232 int XReceiveSub(XMODEM *pX) 01233 { 01234 int i1; 01235 01236 // start with CRC mode [try 8 times to get CRC] 01237 01238 pX->bCRC = 1; 01239 01240 for(i1=0; i1 < 8; i1++) 01241 { 01242 WriteXmodemChar(pX->ser, 'C'); // start with NAK for XMODEM CRC 01243 01244 if(GetXmodemBlock(pX->ser, &(pX->buf.xbuf.cSOH), 1) == 1) 01245 { 01246 if(pX->buf.xbuf.cSOH == _SOH_) // SOH - packet is on its way 01247 { 01248 return ReceiveXmodem(pX); 01249 } 01250 else if(pX->buf.xbuf.cSOH == _EOT_) // an EOT [blank file? allow this?] 01251 { 01252 return 0; // for now, do this 01253 } 01254 else if(pX->buf.xbuf.cSOH == _CAN_) // cancel 01255 { 01256 return 1; // canceled 01257 } 01258 } 01259 } 01260 01261 pX->bCRC = 0; 01262 01263 // try again, this time using XMODEM CHECKSUM 01264 for(i1=0; i1 < 8; i1++) 01265 { 01266 WriteXmodemChar(pX->ser, _NAK_); // switch to NAK for XMODEM Checksum 01267 01268 if(GetXmodemBlock(pX->ser, &(pX->buf.xbuf.cSOH), 1) == 1) 01269 { 01270 if(pX->buf.xbuf.cSOH == _SOH_) // SOH - packet is on its way 01271 { 01272 return ReceiveXmodem(pX); 01273 } 01274 else if(pX->buf.xbuf.cSOH == _EOT_) // an EOT [blank file? allow this?] 01275 { 01276 return 0; // for now, do this 01277 } 01278 else if(pX->buf.xbuf.cSOH == _CAN_) // cancel 01279 { 01280 return 1; // canceled 01281 } 01282 } 01283 } 01284 01285 01286 XmodemTerminate(pX); 01287 01288 return -3; // fail 01289 } 01290 01291 01304 int XSendSub(XMODEM *pX) 01305 { 01306 unsigned long ulStart; 01307 01308 // waiting up to 30 seconds for transfer to start. this is part of the spec? 01309 01310 01311 #ifdef ARDUINO 01312 ulStart = millis(); 01313 #else // ARDUINO 01314 ulStart = MyMillis(); 01315 #endif // ARDUINO 01316 01317 do 01318 { 01319 if(GetXmodemBlock(pX->ser, &(pX->buf.xbuf.cSOH), 1) == 1) 01320 { 01321 if(pX->buf.xbuf.cSOH == 'C' || // XMODEM CRC 01322 pX->buf.xbuf.cSOH == _NAK_) // NAK - XMODEM CHECKSUM 01323 { 01324 #ifdef STAND_ALONE 01325 fprintf(stderr, "Got %d, continuing\n", pX->buf.xbuf.cSOH); 01326 #endif // STAND_ALONE 01327 return SendXmodem(pX); 01328 } 01329 else if(pX->buf.xbuf.cSOH == _CAN_) // cancel 01330 { 01331 #ifdef STAND_ALONE 01332 fputs("XSendSub fail (cancel)\n", stderr); 01333 #endif // STAND_ALONE 01334 return 1; // canceled 01335 } 01336 } 01337 } 01338 #ifdef ARDUINO 01339 while((short)(millis() - ulStart) < 30000); // 30 seconds 01340 #else // ARDUINO 01341 while((int)(MyMillis() - ulStart) < 30000); 01342 #endif // ARDUINO 01343 01344 XmodemTerminate(pX); 01345 01346 #ifdef STAND_ALONE 01347 fputs("XSendSub fail (timeout)\n", stderr); 01348 #endif // STAND_ALONE 01349 return -3; // fail 01350 } 01351 01352 //typedef struct _XMODEM_ 01353 //{ 01354 // SERIAL_TYPE ser; 01355 // FILE_TYPE file; 01356 // 01357 // union 01358 // { 01359 // XMODEM_BUF xbuf; 01360 // XMODEMC_BUF xcbuf; 01361 // } buf; // 133 bytes 01362 // 01363 // unsigned char bCRC; // non-zero for CRC, zero for checksum 01364 // 01365 //} __attribute__((__packed__)) XMODEM; 01366 01367 #ifdef ARDUINO 01368 01369 short XReceive(SDClass *pSD, HardwareSerial *pSer, const char *szFilename) 01370 { 01371 short iRval; 01372 XMODEM xx; 01373 01374 memset(&xx, 0, sizeof(xx)); 01375 01376 xx.ser = pSer; 01377 01378 if(pSD->exists((char *)szFilename)) 01379 { 01380 pSD->remove((char *)szFilename); 01381 } 01382 01383 xx.file = pSD->open((char *)szFilename, FILE_WRITE); 01384 if(!xx.file) 01385 { 01386 return -9; // can't create file 01387 } 01388 01389 iRval = XReceiveSub(&xx); 01390 01391 xx.file.close(); 01392 01393 if(iRval) 01394 { 01395 WriteXmodemChar(pSer, _CAN_); // cancel (make sure) 01396 01397 pSD->remove((char *)szFilename); // delete file on error 01398 } 01399 01400 return iRval; 01401 } 01402 01403 int XSend(SDClass *pSD, HardwareSerial *pSer, const char *szFilename) 01404 { 01405 short iRval; 01406 XMODEM xx; 01407 01408 memset(&xx, 0, sizeof(xx)); 01409 01410 xx.ser = pSer; 01411 01412 xx.file = pSD->open(szFilename, FILE_READ); 01413 if(!xx.file) 01414 { 01415 return -9; // can't open file 01416 } 01417 01418 iRval = XSendSub(&xx); 01419 01420 xx.file.close(); 01421 01422 return iRval; 01423 } 01424 01425 #else // ARDUINO 01426 01427 int XReceive(SERIAL_TYPE hSer, const char *szFilename, int nMode) 01428 { 01429 int iRval; 01430 XMODEM xx; 01431 #ifndef ARDUINO 01432 int iFlags; 01433 #endif // !ARDUINO 01434 01435 #ifdef DEBUG_CODE 01436 szERR[0]=0; 01437 #endif // DEBUG_CODE 01438 memset(&xx, 0, sizeof(xx)); 01439 01440 xx.ser = hSer; 01441 01442 unlink(szFilename); // make sure it does not exist, first 01443 xx.file = open(szFilename, O_CREAT | O_TRUNC | O_WRONLY, nMode); 01444 01445 if(!xx.file) 01446 { 01447 #ifdef STAND_ALONE 01448 fprintf(stderr, "XReceive fail \"%s\" errno=%d\n", szFilename, errno); 01449 #endif // STAND_ALONE 01450 return -9; // can't create file 01451 } 01452 01453 #ifndef ARDUINO 01454 iFlags = fcntl(hSer, F_GETFL); 01455 #endif // !ARDUINO 01456 01457 iRval = XReceiveSub(&xx); 01458 01459 #ifndef ARDUINO 01460 if(iFlags == -1 || fcntl(hSer, F_SETFL, iFlags) == -1) 01461 { 01462 fprintf(stderr, "Warning: 'fcntl' call to restore flags failed, errno=%d\n", errno); 01463 } 01464 #endif // !ARDUINO 01465 01466 close(xx.file); 01467 01468 if(iRval) 01469 { 01470 unlink(szFilename); // delete file on error 01471 } 01472 01473 #ifdef STAND_ALONE 01474 fprintf(stderr, "XReceive returns %d\n", iRval); 01475 #endif // STAND_ALONE 01476 return iRval; 01477 } 01478 01479 int XSend(SERIAL_TYPE hSer, const char *szFilename) 01480 { 01481 int iRval; 01482 XMODEM xx; 01483 #ifndef ARDUINO 01484 int iFlags; 01485 #endif // !ARDUINO 01486 01487 #ifdef DEBUG_CODE 01488 szERR[0]=0; 01489 #endif // DEBUG_CODE 01490 memset(&xx, 0, sizeof(xx)); 01491 01492 xx.ser = hSer; 01493 01494 xx.file = open(szFilename, O_RDONLY, 0); 01495 01496 if(!xx.file) 01497 { 01498 #ifdef STAND_ALONE 01499 fprintf(stderr, "XSend fail \"%s\" errno=%d\n", szFilename, errno); 01500 #endif // STAND_ALONE 01501 return -9; // can't open file 01502 } 01503 01504 #ifndef ARDUINO 01505 iFlags = fcntl(hSer, F_GETFL); 01506 #endif // !ARDUINO 01507 01508 iRval = XSendSub(&xx); 01509 01510 if(iFlags == -1 || fcntl(hSer, F_SETFL, iFlags) == -1) 01511 { 01512 fprintf(stderr, "Warning: 'fcntl' call to restore flags failed, errno=%d\n", errno); 01513 } 01514 01515 close(xx.file); 01516 01517 #ifdef STAND_ALONE 01518 fprintf(stderr, "XSend returning %d\n", iRval); 01519 #endif // STAND_ALONE 01520 return iRval; 01521 } 01522 01523 #endif // ARDUINO 01524 01525 01526 01527 #ifdef STAND_ALONE 01528 01529 static const char szSER[]="/dev/ttyU0"; 01530 01531 #include <termios.h> 01532 01547 void ttyconfig(int iFile, int iBaud, int iParity, int iBits, int iStop) 01548 { 01549 int i1; 01550 struct termios sIOS; 01551 01552 i1 = fcntl(iFile, F_GETFL); 01553 01554 i1 |= O_NONBLOCK; // i1 &= ~O_NONBLOCK); // turn OFF non-blocking? 01555 01556 fcntl(iFile, F_SETFL, i1); 01557 01558 if(!tcgetattr(iFile, &sIOS)) 01559 { 01560 cfsetspeed(&sIOS, iBaud); 01561 sIOS.c_cflag &= ~(CSIZE|PARENB|CS5|CS6|CS7|CS8); 01562 sIOS.c_cflag |= iBits == 5 ? CS5 : iBits == 6 ? CS6 : iBits == 7 ? CS7 : CS8; // 8 is default 01563 if(iStop == 2) 01564 { 01565 sIOS.c_cflag |= CSTOPB; 01566 } 01567 else 01568 { 01569 sIOS.c_cflag &= ~CSTOPB; 01570 } 01571 01572 sIOS.c_cflag &= ~CRTSCTS; // hardware flow control _DISABLED_ (so I can do the reset) 01573 sIOS.c_cflag |= CLOCAL; // ignore any modem status lines 01574 01575 if(!iParity) 01576 { 01577 sIOS.c_cflag &= ~(PARENB | PARODD); 01578 } 01579 else if(iParity > 0) // odd 01580 { 01581 sIOS.c_cflag |= (PARENB | PARODD); 01582 } 01583 else // even (negative) 01584 { 01585 sIOS.c_cflag &= PARODD; 01586 sIOS.c_cflag |= PARENB; 01587 } 01588 01589 // sIOS.c_iflag |= IGNCR; // ignore CR 01590 01591 // do not translate characters or xon/xoff and ignore break 01592 sIOS.c_iflag &= ~(IGNBRK | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY | IMAXBEL | ISTRIP); // turn these off 01593 01594 #if defined(__FreeBSD__) 01595 sIOS.c_oflag &= ~(OPOST | ONLCR | OCRNL | TABDLY | ONOEOT | ONOCR | ONLRET); // FreeBSD version 01596 #else // Linux? YMMV 01597 sIOS.c_oflag &= ~(OPOST | ONLCR | OCRNL | TABDLY | ONOCR | ONLRET); // turn these off too (see man termios) 01598 #endif // FBSD vs Linux 01599 01600 // make sure echoing is disabled and control chars aren't translated or omitted 01601 #if defined(__FreeBSD__) 01602 sIOS.c_lflag &= ~(ECHO | ECHOKE | ECHOE | ECHONL | ECHOPRT | ECHOCTL | ICANON | IEXTEN | ISIG | ALTWERASE); 01603 #else // Linux? YMMV 01604 sIOS.c_lflag &= ~(ECHO | ECHOKE | ECHOE | ECHONL | ECHOPRT | ECHOCTL | ICANON | IEXTEN | ISIG); 01605 #endif // FBSD vs Linux 01606 sIOS.c_cc[VMIN] = 0; // ensures no 'grouping' of input 01607 sIOS.c_cc[VTIME] = 0; // immediate return 01608 01609 if(tcsetattr(iFile, TCSANOW, &sIOS)) 01610 { 01611 fprintf(stderr, "error %d setting attributes\n", errno); 01612 } 01613 } 01614 else 01615 { 01616 fprintf(stderr, "error %d getting attributes\n", errno); 01617 } 01618 } 01619 01630 void reset_arduino(int iFile) 01631 { 01632 unsigned int sFlags; 01633 unsigned long ulStart; 01634 int i1; 01635 01636 // toggle the RTS and DTR high, low, then high - so much easier via POSIX-compatible OS! 01637 01638 ioctl(iFile, TIOCMGET, &sFlags); 01639 01640 sFlags &= ~(TIOCM_DTR | TIOCM_RTS); // the high to low transition discharges the capacitor (signal is inverted on board) 01641 if(ioctl(iFile, TIOCMSET, &sFlags) < 0) 01642 { 01643 fprintf(stderr, "WARNING: ioctl() returns < 0, errno=%d (%xH)\n", errno, errno); 01644 } 01645 01646 usleep(250000); // avrdude does this for 50 msecs, my change has it at 50msecs 01647 01648 sFlags |= TIOCM_DTR | TIOCM_RTS; // leave it in THIS state when I'm done 01649 if(ioctl(iFile, TIOCMSET, &sFlags) < 0) 01650 { 01651 fprintf(stderr, "WARNING: ioctl() returns < 0, errno=%d (%xH)\n", errno, errno); 01652 } 01653 01654 usleep(50000); // avrdude does this for 50 msecs (no change) 01655 01656 ulStart = MyMillis(); 01657 01658 // flush whatever is there, (5 seconds) 01659 01660 while((MyMillis() - ulStart) < 5000) 01661 { 01662 i1 = read(iFile, &i1, 1); 01663 if(i1 == 1) 01664 { 01665 ulStart = MyMillis(); 01666 } 01667 else 01668 { 01669 usleep(1000); 01670 } 01671 } 01672 01673 } 01674 01675 int main(int argc, char *argv[]) 01676 { 01677 int hSer; 01678 char tbuf[256]; 01679 int i1, iSR = 0; 01680 01681 01682 if(argc < 3) 01683 { 01684 fputs("Usage: [prog] [S|R] filename\n", stderr); 01685 return 1; 01686 } 01687 01688 if(argv[1][0] == 'R' || argv[1][1]=='r') 01689 { 01690 iSR = -1; 01691 } 01692 else if(argv[1][0] == 'S' || argv[1][1]=='s') 01693 { 01694 iSR = 1; 01695 } 01696 else if(argv[1][0] == 'X' || argv[1][1]=='x') 01697 { 01698 iSR = 0; // test function 01699 } 01700 else 01701 { 01702 fputs("Usage: [prog] [S|R] filename (b)\n", stderr); 01703 return 1; 01704 } 01705 01706 hSer = open(szSER, (O_RDWR | O_NONBLOCK), 0); 01707 if(hSer == -1) 01708 { 01709 fprintf(stderr, "Unable to open \"%s\" errno=%d\n", szSER, errno); 01710 return 3; 01711 } 01712 01713 fputs("TTYCONFIG\n", stderr); 01714 ttyconfig(hSer, 9600, 0, 8, 1); 01715 01716 reset_arduino(hSer); 01717 01718 fprintf(stderr, "Sleeping for 10 seconds to allow reset\n"); 01719 01720 // usleep(10000000); 01721 for(i1=0; i1 < 10; i1++) 01722 { 01723 XModemFlushInput(hSer); 01724 } 01725 01726 for(i1=0; i1 < 3; i1++) 01727 { 01728 sprintf(tbuf, "X%c%s", argv[1][0], argv[2]); 01729 01730 fprintf(stderr, "writing: \"%s\"\n", tbuf); 01731 strcat(tbuf, "\r"); 01732 WriteXmodemBlock(hSer, tbuf, strlen(tbuf)); 01733 01734 fputs("flush input\n", stderr); 01735 XModemFlushInput(hSer); 01736 01737 // wait for an LF response 01738 01739 if(iSR > 0) 01740 { 01741 fputs("XSEND\n", stderr); 01742 if(XSend(hSer, argv[2])) 01743 { 01744 fputs("ERROR\n", stderr); 01745 } 01746 else 01747 { 01748 fputs("SUCCESS!\n", stderr); 01749 i1 = 0; 01750 break; 01751 } 01752 } 01753 else if(iSR < 0) 01754 { 01755 fputs("XRECEIVE\n", stderr); 01756 if(XReceive(hSer, argv[2], 0664)) 01757 { 01758 fputs("ERROR\n", stderr); 01759 } 01760 else 01761 { 01762 fputs("SUCCESS!\n", stderr); 01763 i1 = 0; 01764 break; 01765 } 01766 } 01767 else 01768 { 01769 // test function 01770 XModemFlushInput(hSer); // continue doing this 01771 break; // done (once only) 01772 } 01773 } 01774 01775 fputs("EXIT\n", stderr); 01776 close(hSer); 01777 01778 return i1 ? 1 : -1; 01779 } 01780 #endif // STAND_ALONE 01781