?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{FILE START}

library

?curdirlinks? - Rev 6

?prevdifflink? - Blame - ?getfile?

/*! \file xmodem.c \brief XModem Transmit/Receive Implementation with CRC and 1K support. */
//*****************************************************************************
//
// File Name    : 'xmodem.c'
// Title                : XModem Transmit/Receive Implementation with CRC and 1K support
// Author               : Pascal Stang - Copyright (C) 2006
// Created              : 4/22/2006
// Revised              : 7/22/2006
// Version              : 0.1
// Target MCU   : AVR processors
// Editor Tabs  : 4
//
// This code is distributed under the GNU Public License
//              which can be found at http://www.gnu.org/licenses/gpl.txt
//
//*****************************************************************************

#include <string.h>
#include "rprintf.h"
#include "timer.h"

#include "xmodem.h"

//#define XMODEM_BUFFER_SIZE            128
#define XMODEM_BUFFER_SIZE              1024

// pointers to stream I/O functions
static void (*xmodemOut)(unsigned char c);
static int (*xmodemIn)(void);

void xmodemInit(void (*sendbyte_func)(unsigned char c), int (*getbyte_func)(void))
{
        // assign function pointers
        xmodemOut = sendbyte_func;
        xmodemIn = getbyte_func;
}

long xmodemReceive( int (*write)(unsigned char* buffer, int size) )
{
        // create xmodem buffer
        // 1024b for Xmodem 1K
        // 128 bytes for Xmodem std.
        // + 5b header/crc + NULL
        unsigned char xmbuf[XMODEM_BUFFER_SIZE+6];
        unsigned char seqnum=1;         // xmodem sequence number starts at 1
        unsigned short pktsize=128;     // default packet size is 128 bytes
        unsigned char response='C';     // solicit a connection with CRC enabled
        char retry=XMODEM_RETRY_LIMIT;
        unsigned char crcflag=0;
        unsigned long totalbytes=0;
        int i,c;

        while(retry > 0)
        {
                // solicit a connection/packet
                xmodemOut(response);
                // wait for start of packet
                if( (c = xmodemInTime(XMODEM_TIMEOUT_DELAY)) >= 0)
                {
                        switch(c)
                        {
                        case SOH:
                                pktsize = 128;
                                break;
                        #if(XMODEM_BUFFER_SIZE>=1024)
                        case STX:
                                pktsize = 1024;
                                break;
                        #endif
                        case EOT:
                                xmodemInFlush();
                                xmodemOut(ACK);
                                // completed transmission normally
                                return totalbytes;
                        case CAN:
                                if((c = xmodemInTime(XMODEM_TIMEOUT_DELAY)) == CAN)
                                {
                                        xmodemInFlush();
                                        xmodemOut(ACK);
                                        // transaction cancelled by remote node
                                        return XMODEM_ERROR_REMOTECANCEL;
                                }
                        default:
                                break;
                        }
                }
                else
                {
                        // timed out, try again
                        // no need to flush because receive buffer is already empty
                        retry--;
                        //response = NAK;
                        continue;
                }

                // check if CRC mode was accepted
                if(response == 'C') crcflag = 1;
                // got SOH/STX, add it to processing buffer
                xmbuf[0] = c;
                // try to get rest of packet
                for(i=0; i<(pktsize+crcflag+4-1); i++)
                {
                        if((c = xmodemInTime(XMODEM_TIMEOUT_DELAY)) >= 0)
                        {
                                xmbuf[1+i] = c;
                        }
                        else
                        {
                                // timed out, try again
                                retry--;
                                xmodemInFlush();
                                response = NAK;
                                break;
                        }
                }
                // packet was too small, retry
                if(i<(pktsize+crcflag+4-1))
                        continue;

                // got whole packet
                // check validity of packet
                if(     (xmbuf[1] == (unsigned char)(~xmbuf[2])) &&             // sequence number was transmitted w/o error
                        xmodemCrcCheck(crcflag, &xmbuf[3], pktsize) )   // packet is not corrupt
                {
                        // is this the packet we were waiting for?
                        if(xmbuf[1] == seqnum)
                        {
                                // write/deliver data
                                write(&xmbuf[3], pktsize);
                                //spiflashWrite(flashaddr, pktsize, &xmbuf[3]);
                                totalbytes += pktsize;
                                // next sequence number
                                seqnum++;
                                // reset retries
                                retry = XMODEM_RETRY_LIMIT;
                                // reply with ACK
                                response = ACK;
                                continue;
                        }
                        else if(xmbuf[1] == (unsigned char)(seqnum-1))
                        {
                                // this is a retransmission of the last packet
                                // ACK and move on
                                response = ACK;
                                continue;
                        }
                        else
                        {
                                // we are completely out of sync
                                // cancel transmission
                                xmodemInFlush();
                                xmodemOut(CAN);
                                xmodemOut(CAN);
                                xmodemOut(CAN);
                                return XMODEM_ERROR_OUTOFSYNC;
                        }
                }
                else
                {
                        // packet was corrupt
                        // NAK it and try again
                        retry--;
                        xmodemInFlush();
                        response = NAK;
                        continue;
                }
        }

        // exceeded retry count
        xmodemInFlush();
        xmodemOut(CAN);
        xmodemOut(CAN);
        xmodemOut(CAN);
        return XMODEM_ERROR_RETRYEXCEED;
}


long xmodemTransmit( int (*read)(unsigned char* buffer, int size) )
{
        // still to be written
        return 0;
}

uint16_t crc_xmodem_update(uint16_t crc, uint8_t data)
{
        int i;

        crc = crc ^ ((uint16_t)data << 8);
        for (i=0; i<8; i++)
        {
                if(crc & 0x8000)
                        crc = (crc << 1) ^ 0x1021;
                else
                        crc <<= 1;
        }

        return crc;
}

int xmodemCrcCheck(int crcflag, const unsigned char *buffer, int size)
{
        // crcflag=0 - do regular checksum
        // crcflag=1 - do CRC checksum

        if(crcflag)
        {
                unsigned short crc=0;
                unsigned short pktcrc = (buffer[size]<<8)+buffer[size+1];
                // do CRC checksum
                while(size--)
                        crc = crc_xmodem_update(crc, *buffer++);
                // check checksum against packet
                if(crc == pktcrc)
                        return 1;
        }
        else
        {
                int i;
                unsigned char cksum = 0;
                // do regular checksum
                for(i=0; i<size; ++i)
                {
                        cksum += buffer[i];
                }
                // check checksum against packet
                if(cksum == buffer[size])
                        return 1;
        }

        return 0;
}


int xmodemInTime(unsigned short timeout)
{
        int c=-1;

        while( (timeout--) && ((c=xmodemIn()) < 0) )
                timerPause(1);

        return c;
}

void xmodemInFlush(void)
{
        while(xmodemInTime(XMODEM_TIMEOUT_DELAY) >= 0);
}
{FILE END}
{FOOTER START}

Powered by WebSVN v2.8.3