OpenCores
URL https://opencores.org/ocsvn/amber/amber/trunk

Subversion Repositories amber

[/] [amber/] [trunk/] [sw/] [boot-loader-serial/] [xmodem.c] - Rev 72

Go to most recent revision | Compare with Previous | Blame | View Log

/*	
 * Copyright 2001-2010 Georges Menie (www.menie.org)
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the University of California, Berkeley nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
/* this code needs standard functions memcpy() and memset()
   and input/output functions _inbyte() and _outbyte().
 
   the prototypes of the input/output functions are:
     int _inbyte(unsigned short timeout); // msec timeout
     void _outbyte(int c);
 
 */
 
#include "crc16.h"
#include "boot-loader.h"
 
/*
#define DEBUG_XMODEM
*/
 
#define SOH  0x01
#define STX  0x02
#define EOT  0x04
#define ACK  0x06
#define NAK  0x15
#define CAN  0x18
#define CTRLZ 0x1A
 
 
#define MAXRETRANS 25
 
#ifdef DEBUG_XMODEM        
char* dbuf;
#endif
 
 
static int check(int crc, const unsigned char *buf, int sz)
{
	if (crc) {
		unsigned short crc = crc16_ccitt(buf, sz);
		unsigned short tcrc = (buf[sz]<<8)+buf[sz+1];
		if (crc == tcrc) {
                        #ifdef DEBUG_XMODEM        
                        dbuf += sprintf(dbuf, "cok1\n");
                        #endif
			return 1;
                        }
	}
	else {
		int i;
		unsigned char cks = 0;
		for (i = 0; i < sz; ++i) {
			cks += buf[i];
		}
		if (cks == buf[sz]) {
                    #ifdef DEBUG_XMODEM        
                    dbuf += sprintf(dbuf, "cok2\n");
                    #endif
		    return 1;
                    }
	}
 
        #ifdef DEBUG_XMODEM        
        dbuf += sprintf(dbuf, "cer\n");
        #endif
	return 0;
}
 
 
static void flushinput(void)
{
	while (_inbyte(DLY_300MS) >= 0) ;
}
 
 
int xmodemReceive(unsigned char *dest, int destsz)
{
	unsigned char xbuff[1030]; /* 1024 for XModem 1k + 3 head chars + 2 crc + nul */
	unsigned char *p;
	int bufsz, crc = 0;
	unsigned char trychar = 'C';
	unsigned char packetno = 1;
	int i, c, len = 0;
	int retry, retrans = MAXRETRANS;
        unsigned int wait;
 
        #ifdef DEBUG_XMODEM        
        dbuf = (char *) DEBUG_BUF;
        dbuf += sprintf(dbuf, "XR\n");
        #endif
 
	for(;;) {
		for( retry = 0; retry < 80; ++retry) {
			if (trychar) _outbyte(trychar);
			if ((c = _inbyte(DLY_1S)) >= 0) {		
				switch (c) {
				case SOH:
					bufsz = 128;
                                        #ifdef DEBUG_XMODEM
                                        dbuf += sprintf(dbuf, "128\n");
                                        #endif
					goto start_recv;
				case STX:
					bufsz = 1024;
                                        #ifdef DEBUG_XMODEM
                                        dbuf += sprintf(dbuf, "1k\n");
                                        #endif
					goto start_recv;
				case EOT:
					_outbyte(ACK);
					flushinput();
                                        #ifdef DEBUG_XMODEM
                                        dbuf += sprintf(dbuf, "EOT\n");
                                        #endif
					return len; /* normal end */
				case CAN:
                                        #ifdef DEBUG_XMODEM
                                        dbuf += sprintf(dbuf, "CAN\n");
                                        #endif
					if ((c = _inbyte(DLY_1S)) == CAN) {
						flushinput();
						_outbyte(ACK);
						return -1; /* canceled by remote */
					}
					break;
				default:
					break;
				}
			}
		}
		if (trychar == 'C') { trychar = NAK; continue; }
		flushinput();
		_outbyte(CAN);
		_outbyte(CAN);
		_outbyte(CAN);
		return -2; /* sync error */
 
	start_recv:
                #ifdef DEBUG_XMODEM
                dbuf += sprintf(dbuf, "sr\n");
                #endif
		if (trychar == 'C') crc = 1;
		trychar = 0;
		p = xbuff;
		*p++ = c;
		for (i = 0;  i < (bufsz+(crc?1:0)+3); ++i) {
			if ((c = _inbyte(DLY_1S)) < 0) goto reject;
			*p++ = c;
		}
 
 
		if (xbuff[1] == (unsigned char)(~xbuff[2]) && 
			(xbuff[1] == packetno || xbuff[1] == (unsigned char)packetno-1) &&
			check(crc, &xbuff[3], bufsz)) {
			if (xbuff[1] == packetno)	{
				register int count = destsz - len;
				if (count > bufsz) count = bufsz;
				if (count > 0) {
					memcpy (&dest[len], &xbuff[3], count);
					len += count;
				}
				++packetno;
				retrans = MAXRETRANS+1;
			}
			if (--retrans <= 0) {
				flushinput();
				_outbyte(CAN);
				_outbyte(CAN);
				_outbyte(CAN);
                                #ifdef DEBUG_XMODEM
                                dbuf += sprintf(dbuf, "mx e\n");                
                                #endif
				return -3; /* too many retry error */
			}
			_outbyte(ACK);
			continue;
 
 
		}
                else {
                        #ifdef DEBUG_XMODEM
                        dbuf += sprintf(dbuf, "bad\n");                
                        #endif
                        }
 
	reject:
                #ifdef DEBUG_XMODEM
                dbuf += sprintf(dbuf, "rj %d\n", c);
                #endif
 
		flushinput();
		_outbyte(NAK);
	}
}
 
 
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.