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 }

Generated on Mon Nov 6 23:36:59 2006 for Procyon ARMlib by  doxygen 1.4.2