Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

# xmodem.c

Go to the documentation of this file.

    00001 /*! \file xmodem.c \brief XModem Transmit/Receive Implementation with CRC and 1K support. */
    00002 //*****************************************************************************
    00003 //
    00004 // File Name    : 'xmodem.c'
    00005 // Title        : XModem Transmit/Receive Implementation with CRC and 1K support
    00006 // Author       : Pascal Stang - Copyright (C) 2006
    00007 // Created      : 4/22/2006
    00008 // Revised      : 7/22/2006
    00009 // Version      : 0.1
    00010 // Target MCU   : AVR processors
    00011 // Editor Tabs  : 4
    00012 //
    00013 // This code is distributed under the GNU Public License
    00014 //      which can be found at http://www.gnu.org/licenses/gpl.txt
    00015 //
    00016 //*****************************************************************************
    00017
    00018 #include <string.h>
    00019 #include "rprintf.h"
    00020 #include "timer.h"
    00021
    00022 #include "xmodem.h"
    00023
    00024 //#define XMODEM_BUFFER_SIZE        128
    00025 #define XMODEM_BUFFER_SIZE      1024
    00026
    00027 // pointers to stream I/O functions
    00028 static void (*xmodemOut)(unsigned char c);
    00029 static int (*xmodemIn)(void);
    00030
    00031 void xmodemInit(void (*sendbyte_func)(unsigned char c), int (*getbyte_func)(void))
    00032 {
    00033     // assign function pointers
    00034     xmodemOut = sendbyte_func;
    00035     xmodemIn = getbyte_func;
    00036 }
    00037
    00038 long xmodemReceive( int (*write)(unsigned char* buffer, int size) )
    00039 {
    00040     // create xmodem buffer
    00041     // 1024b for Xmodem 1K
    00042     // 128 bytes for Xmodem std.
    00043     // + 5b header/crc + NULL
    00044     unsigned char xmbuf[XMODEM_BUFFER_SIZE+6];
    00045     unsigned char seqnum=1;     // xmodem sequence number starts at 1
    00046     unsigned short pktsize=128; // default packet size is 128 bytes
    00047     unsigned char response='C'; // solicit a connection with CRC enabled
    00048     char retry=XMODEM_RETRY_LIMIT;
    00049     unsigned char crcflag=0;
    00050     unsigned long totalbytes=0;
    00051     int i,c;
    00052
    00053     while(retry > 0)
    00054     {
    00055         // solicit a connection/packet
    00056         xmodemOut(response);
    00057         // wait for start of packet
    00058         if( (c = xmodemInTime(XMODEM_TIMEOUT_DELAY)) >= 0)
    00059         {
    00060             switch(c)
    00061             {
    00062             case SOH:
    00063                 pktsize = 128;
    00064                 break;
    00065             #if(XMODEM_BUFFER_SIZE>=1024)
    00066             case STX:
    00067                 pktsize = 1024;
    00068                 break;
    00069             #endif
    00070             case EOT:
    00071                 xmodemInFlush();
    00072                 xmodemOut(ACK);
    00073                 // completed transmission normally
    00074                 return totalbytes;
    00075             case CAN:
    00076                 if((c = xmodemInTime(XMODEM_TIMEOUT_DELAY)) == CAN)
    00077                 {
    00078                     xmodemInFlush();
    00079                     xmodemOut(ACK);
    00080                     // transaction cancelled by remote node
    00081                     return XMODEM_ERROR_REMOTECANCEL;
    00082                 }
    00083             default:
    00084                 break;
    00085             }
    00086         }
    00087         else
    00088         {
    00089             // timed out, try again
    00090             // no need to flush because receive buffer is already empty
    00091             retry--;
    00092             //response = NAK;
    00093             continue;
    00094         }
    00095
    00096         // check if CRC mode was accepted
    00097         if(response == 'C') crcflag = 1;
    00098         // got SOH/STX, add it to processing buffer
    00099         xmbuf[0] = c;
    00100         // try to get rest of packet
    00101         for(i=0; i<(pktsize+crcflag+4-1); i++)
    00102         {
    00103             if((c = xmodemInTime(XMODEM_TIMEOUT_DELAY)) >= 0)
    00104             {
    00105                 xmbuf[1+i] = c;
    00106             }
    00107             else
    00108             {
    00109                 // timed out, try again
    00110                 retry--;
    00111                 xmodemInFlush();
    00112                 response = NAK;
    00113                 break;
    00114             }
    00115         }
    00116         // packet was too small, retry
    00117         if(i<(pktsize+crcflag+4-1))
    00118             continue;
    00119
    00120         // got whole packet
    00121         // check validity of packet
    00122         if( (xmbuf[1] == (unsigned char)(~xmbuf[2])) &&     // sequence number was transmitted w/o error
    00123             xmodemCrcCheck(crcflag, &xmbuf[3], pktsize) )   // packet is not corrupt
    00124         {
    00125             // is this the packet we were waiting for?
    00126             if(xmbuf[1] == seqnum)
    00127             {
    00128                 // write/deliver data
    00129                 write(&xmbuf[3], pktsize);
    00130                 //spiflashWrite(flashaddr, pktsize, &xmbuf[3]);
    00131                 totalbytes += pktsize;
    00132                 // next sequence number
    00133                 seqnum++;
    00134                 // reset retries
    00135                 retry = XMODEM_RETRY_LIMIT;
    00136                 // reply with ACK
    00137                 response = ACK;
    00138                 continue;
    00139             }
    00140             else if(xmbuf[1] == (unsigned char)(seqnum-1))
    00141             {
    00142                 // this is a retransmission of the last packet
    00143                 // ACK and move on
    00144                 response = ACK;
    00145                 continue;
    00146             }
    00147             else
    00148             {
    00149                 // we are completely out of sync
    00150                 // cancel transmission
    00151                 xmodemInFlush();
    00152                 xmodemOut(CAN);
    00153                 xmodemOut(CAN);
    00154                 xmodemOut(CAN);
    00155                 return XMODEM_ERROR_OUTOFSYNC;
    00156             }
    00157         }
    00158         else
    00159         {
    00160             // packet was corrupt
    00161             // NAK it and try again
    00162             retry--;
    00163             xmodemInFlush();
    00164             response = NAK;
    00165             continue;
    00166         }
    00167     }
    00168
    00169     // exceeded retry count
    00170     xmodemInFlush();
    00171     xmodemOut(CAN);
    00172     xmodemOut(CAN);
    00173     xmodemOut(CAN);
    00174     return XMODEM_ERROR_RETRYEXCEED;
    00175 }
    00176
    00177
    00178 long xmodemTransmit( int (*read)(unsigned char* buffer, int size) )
    00179 {
    00180     // still to be written
    00181     return 0;
    00182 }
    00183
    00184 uint16_t crc_xmodem_update(uint16_t crc, uint8_t data)
    00185 {
    00186     int i;
    00187
    00188     crc = crc ^ ((uint16_t)data << 8);
    00189     for (i=0; i<8; i++)
    00190     {
    00191         if(crc & 0x8000)
    00192             crc = (crc << 1) ^ 0x1021;
    00193         else
    00194             crc <<= 1;
    00195     }
    00196
    00197     return crc;
    00198 }
    00199
    00200 int xmodemCrcCheck(int crcflag, const unsigned char *buffer, int size)
    00201 {
    00202     // crcflag=0 - do regular checksum
    00203     // crcflag=1 - do CRC checksum
    00204
    00205     if(crcflag)
    00206     {
    00207         unsigned short crc=0;
    00208         unsigned short pktcrc = (buffer[size]<<8)+buffer[size+1];
    00209         // do CRC checksum
    00210         while(size--)
    00211             crc = crc_xmodem_update(crc, *buffer++);
    00212         // check checksum against packet
    00213         if(crc == pktcrc)
    00214             return 1;
    00215     }
    00216     else
    00217     {
    00218         int i;
    00219         unsigned char cksum = 0;
    00220         // do regular checksum
    00221         for(i=0; i<size; ++i)
    00222         {
    00223             cksum += buffer[i];
    00224         }
    00225         // check checksum against packet
    00226         if(cksum == buffer[size])
    00227             return 1;
    00228     }
    00229
    00230     return 0;
    00231 }
    00232
    00233
    00234 int xmodemInTime(unsigned short timeout)
    00235 {
    00236     int c=-1;
    00237
    00238     while( (timeout--) && ((c=xmodemIn()) < 0) )
    00239         timerPause(1);
    00240
    00241     return c;
    00242 }
    00243
    00244 void xmodemInFlush(void)
    00245 {
    00246     while(xmodemInTime(XMODEM_TIMEOUT_DELAY) >= 0);
    00247 }