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   : any
    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 #ifndef XMODEM_BUFFER_SIZE
    00025 #define XMODEM_BUFFER_SIZE      1024
    00026 //#define XMODEM_BUFFER_SIZE        128
    00027 #endif
    00028
    00029 // pointers to stream I/O functions
    00030 static void (*xmodemOut)(unsigned char c);
    00031 static int (*xmodemIn)(void);
    00032
    00033 void xmodemInit(void (*sendbyte_func)(unsigned char c), int (*getbyte_func)(void))
    00034 {
    00035     // assign function pointers
    00036     xmodemOut = sendbyte_func;
    00037     xmodemIn = getbyte_func;
    00038 }
    00039
    00040 long xmodemReceive( int (*write)(unsigned char* buffer, int size) )
    00041 {
    00042     // create xmodem buffer
    00043     // 1024b for Xmodem 1K
    00044     // 128 bytes for Xmodem std.
    00045     // + 5b header/crc + NULL
    00046     unsigned char xmbuf[XMODEM_BUFFER_SIZE+6];
    00047     unsigned char seqnum=1;     // xmodem sequence number starts at 1
    00048     unsigned short pktsize=128; // default packet size is 128 bytes
    00049     unsigned char response='C'; // solicit a connection with CRC enabled
    00050     char retry=XMODEM_RETRY_LIMIT;
    00051     unsigned char crcflag=0;
    00052     unsigned long totalbytes=0;
    00053     int i,c;
    00054
    00055     while(retry > 0)
    00056     {
    00057         // solicit a connection/packet
    00058         xmodemOut(response);
    00059         // wait for start of packet
    00060         if( (c = xmodemInTime(XMODEM_TIMEOUT_DELAY)) >= 0)
    00061         {
    00062             switch(c)
    00063             {
    00064             case SOH:
    00065                 pktsize = 128;
    00066                 break;
    00067             #if(XMODEM_BUFFER_SIZE>=1024)
    00068             case STX:
    00069                 pktsize = 1024;
    00070                 break;
    00071             #endif
    00072             case EOT:
    00073                 xmodemInFlush();
    00074                 xmodemOut(ACK);
    00075                 // completed transmission normally
    00076                 return totalbytes;
    00077             case CAN:
    00078                 if((c = xmodemInTime(XMODEM_TIMEOUT_DELAY)) == CAN)
    00079                 {
    00080                     xmodemInFlush();
    00081                     xmodemOut(ACK);
    00082                     // transaction cancelled by remote node
    00083                     return XMODEM_ERROR_REMOTECANCEL;
    00084                 }
    00085             default:
    00086                 break;
    00087             }
    00088         }
    00089         else
    00090         {
    00091             // timed out, try again
    00092             // no need to flush because receive buffer is already empty
    00093             retry--;
    00094             //response = NAK;
    00095             continue;
    00096         }
    00097
    00098         // check if CRC mode was accepted
    00099         if(response == 'C') crcflag = 1;
    00100         // got SOH/STX, add it to processing buffer
    00101         xmbuf[0] = c;
    00102         // try to get rest of packet
    00103         for(i=0; i<(pktsize+crcflag+4-1); i++)
    00104         {
    00105             if((c = xmodemInTime(XMODEM_TIMEOUT_DELAY)) >= 0)
    00106             {
    00107                 xmbuf[1+i] = c;
    00108             }
    00109             else
    00110             {
    00111                 // timed out, try again
    00112                 retry--;
    00113                 xmodemInFlush();
    00114                 response = NAK;
    00115                 break;
    00116             }
    00117         }
    00118         // packet was too small, retry
    00119         if(i<(pktsize+crcflag+4-1))
    00120             continue;
    00121
    00122         // got whole packet
    00123         // check validity of packet
    00124         if( (xmbuf[1] == (unsigned char)(~xmbuf[2])) &&     // sequence number was transmitted w/o error
    00125             xmodemCrcCheck(crcflag, &xmbuf[3], pktsize) )   // packet is not corrupt
    00126         {
    00127             // is this the packet we were waiting for?
    00128             if(xmbuf[1] == seqnum)
    00129             {
    00130                 // write/deliver data
    00131                 write(&xmbuf[3], pktsize);
    00132                 totalbytes += pktsize;
    00133                 // next sequence number
    00134                 seqnum++;
    00135                 // reset retries
    00136                 retry = XMODEM_RETRY_LIMIT;
    00137                 // reply with ACK
    00138                 response = ACK;
    00139                 continue;
    00140             }
    00141             else if(xmbuf[1] == (unsigned char)(seqnum-1))
    00142             {
    00143                 // this is a retransmission of the last packet
    00144                 // ACK and move on
    00145                 response = ACK;
    00146                 continue;
    00147             }
    00148             else
    00149             {
    00150                 // we are completely out of sync
    00151                 // cancel transmission
    00152                 xmodemInFlush();
    00153                 xmodemOut(CAN);
    00154                 xmodemOut(CAN);
    00155                 xmodemOut(CAN);
    00156                 return XMODEM_ERROR_OUTOFSYNC;
    00157             }
    00158         }
    00159         else
    00160         {
    00161             // packet was corrupt
    00162             // NAK it and try again
    00163             retry--;
    00164             xmodemInFlush();
    00165             response = NAK;
    00166             continue;
    00167         }
    00168     }
    00169
    00170     // exceeded retry count
    00171     xmodemInFlush();
    00172     xmodemOut(CAN);
    00173     xmodemOut(CAN);
    00174     xmodemOut(CAN);
    00175     return XMODEM_ERROR_RETRYEXCEED;
    00176 }
    00177
    00178
    00179 long xmodemTransmit( int (*read)(unsigned char* buffer, int size) )
    00180 {
    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 }