⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xmodem.c

📁 一款交换机BSP开发代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* xmodem.c:
 * Command to upload or download via XMODEM protocol.  Xmodem is quite
 * limited, but adequate for simple file up/down load.
 * This also supports XMODEM-1K and YMODEM.  YMODEM is an extension to XMODEM
 * that uses a 1K packet size, CRC and the first packet (seqno=0) contains
 * information about the file being downloaded (in partiuclar, the name).
 * YMODEM also supports BATCH downloads (multiple files downloaded in one
 * transaction).  This code supports incoming BATCH downloads (not tested
 * because I can't find any terminal emulators that do it), but not for 
 * uploads.
 *
 * General notice:
 * This code is part of a boot-monitor package developed as a generic base
 * platform for embedded system designs.  As such, it is likely to be
 * distributed to various projects beyond the control of the original
 * author.  Please notify the author of any enhancements made or bugs found
 * so that all may benefit from the changes.  In addition, notification back
 * to the author will allow the new user to pick up changes that may have
 * been made by other users after this version of the code was distributed.
 *
 * Author:	Ed Sutter
 * email:	esutter@lucent.com		(home: lesutter@worldnet.att.net)
 * phone:	908-582-2351			(home: 908-889-5161)
 */
#include "flash.h"
#include "tfs.h"

/* struct xinfo:
 * Used to contain information pertaining to the current transaction.
 * The structure is built by the command Xmodem, then passed to the other
 * support functions (Xup, Xdown, etc..) for reference and update.
 */
struct xinfo {
	UCHAR	sno;			/* Sequence number. */
	UCHAR	pad;			/* Unused, padding. */
	int		xfertot;		/* Running total of transfer. */
	int		pktlen;			/* Length of packet (128 or 1024). */
	int		pktcnt;			/* Running tally of number of packets processed. */
	int		filcnt;			/* Number of files transferred by ymodem. */
	long	size;			/* Size of upload. */
	ULONG	flags;			/* Storage for various runtime flags. */
	ULONG	base;			/* Starting address for data transfer. */
	ULONG	dataddr;		/* Running address for data transfer. */
	int		errcnt;			/* Keep track of errors (used in verify mode). */
	char	*firsterrat;	/* Pointer to location of error detected when */
							/* transfer is in verify mode. */
	char	fname[TFSNAMESIZE];
};

/* Runtime flags: */
#define	USECRC	(1<<0)
#define VERIFY	(1<<1)
#define YMODEM	(1<<2)

/* Current xmodem operation: */
#define XNULL	0
#define XUP		1
#define XDOWN	2

/* X/Ymodem protocol: */
#define SOH		0x01
#define STX		0x02
#define EOT		0x04
#define ACK		0x06
#define NAK		0x15
#define CAN		0x18
#define ESC		0x1b

#define PKTLEN_128	128
#define PKTLEN_1K	1024

extern USHORT xcrc16tab[];

static int Xup(struct xinfo *);
static int Xdown(struct xinfo *);
static int getPacket(UCHAR *,struct xinfo *);
static int putPacket(UCHAR *,struct xinfo *);

char *XmodemHelp[] = {
	"Xmodem file transfer",
	"-[a:BdF:f:i:s:t:uvy]",
	"Options:",
	" -a{##}     address (overrides default of APPRAMBASE)",
	" -B         boot sector reload",
	" -c         use crc (default = checksum)",
	" -d         download",
	" -F{name}   filename",
	" -f{flags}  file flags (see tfs)",
	" -i{info}   file info (see tfs)",
	" -s{##}     size (overrides computed size)",
	" -t{##}     address for xmodem trace buffer",
	" -u         upload",
	" -v         verify only",
	" -y         use Ymodem extensions",
	"Notes:",
	" * Either -d or -u must be specified (-B implies -d).",
	" * XMODEM forces a 128-byte modulo on file size.  The -s option",
	"   can be used to override this when transferring a file to TFS.",
	" * File upload requires no address or size (size will be mod 128).",
	" * When using -B, it should be the ONLY command line option,",
	"   it's purpose is to reprogram the boot sector, so be careful!",
	(char *)0,
};

extern unsigned char msgbuf[];
extern char *optarg;
extern int optind;

#ifdef _XMODEM_DEBUG
char tracebuf[10240];
char *Mtracebuf;
#endif

struct	xinfo xi;
int xmodemstart;

int
Xmodem(int argc,char *argv[])
{
	TFILE	*tfp;
	char	*info, *flags;
	int	opt, xop, newboot;

	xop = XNULL;
	newboot = 0;
	info = (char *)0;
	flags = (char *)0;

#ifdef _XMODEM_DEBUG
	Mtracebuf = tracebuf;
#endif

	xmodemstart = 1;
	xi.fname[0] = 0;
	xi.size = 0;
	xi.base = 0;
	xi.flags = 0;
	xi.filcnt = 0;
	xi.dataddr = 0;
	xi.pktlen = PKTLEN_128;
	optind = 1;
	while ((opt=getopt(argc,argv,"a:Bci:f:dF:ks:t:uvy")) != -1) {
		switch(opt) {
		case 'a':
			xi.dataddr = xi.base = strtoul(optarg,(char **)0,0);
			break;
		case 'B':
			xop = XDOWN;
			newboot = 1;
			break;
		case 'c':
			xi.flags |= USECRC;
			break;
		case 'd':
			xop = XDOWN;
			break;
		case 'F':
			strncpy(xi.fname,optarg,TFSNAMESIZE);
			break;
		case 'f':
			flags = optarg;
			break;
		case 'i':
			info = optarg;
			break;
		case 'k':
			xi.pktlen = PKTLEN_1K;
			break;
		case 's':
			xi.size = (ULONG)strtoul(optarg,(char **)0,0);
			break;
		case 't':
//			Mtracebuf = (char *)strtoul(optarg,(char **)0,0);
			break;
		case 'u':
			xop = XUP;
			break;
		case 'v':
			xi.flags |= VERIFY;
			break;
		case 'y':
			xi.flags |= (YMODEM | USECRC);
			xi.pktlen = PKTLEN_1K;
			break;
		default:
			return(-1);
		}
	}

	/* There should be no arguments after the option list. */
	if (argc != optind)
		return(-1);

	if (xop == XUP) {
		if ((xi.flags & YMODEM) && !(xi.fname[0]))
//			printf("Ymodem upload needs filename\n");
			;
		else {
			if (xi.fname[0]) {	/* Causes -a and -s options to be ignored. */
				tfp = tfsstat(xi.fname);
				if (!tfp) {
//					printf("%s: file not found\n",xi.fname);
					return(0);
				}
				xi.dataddr = (ULONG)TFS_BASE(tfp);
				xi.size = TFS_SIZE(tfp);
			}
//			rawon();
			Xup(&xi);
//			rawoff();
		}
	}
	else if (xop == XDOWN) {
		extern	ULONG APPLICATION_RAMSTART;
		long	tmpsize;

//		if ((xi.flags & YMODEM) && (xi.fname[0]))
//			printf("Ymodem download gets name from protocol, '%s' ignored\n",
//				xi.fname);

		if (!xi.base)
			xi.base = xi.dataddr = APPLICATION_RAMSTART;
//		rawon();
		tmpsize = (long)Xdown(&xi);
//		rawoff();
		if ((!xi.size) || (tmpsize < 0))
			xi.size = tmpsize;

		if ((xi.fname[0]) && (xi.size > 0)) {
			int	err;

//			printf("Writing to file '%s'...\n",xi.fname);
			err = tfsadd(xi.fname,info,flags,(UCHAR *)xi.base,xi.size);
			if (err != TFS_OKAY)
			{
				return -1;
			}
//				printf("%s: %s\n",xi.fname,(char *)tfsctrl(TFS_ERRMSG,err,0));

		}
		else
		if ((newboot) && (xi.size > 0)) {
			extern	int FlashProtectWindow;
			extern	ULONG BOOTROM_BASE;
			char	*bb;
			ULONG	bootbase;

//			bb = getenv("BOOTROMBASE");
//			if (bb)
//				bootbase = strtoul(bb,0,0);
//			else
//				bootbase = BOOTROM_BASE;
//
//			FlashProtectWindow = 1;
//			printf("Reloading boot @ 0x%lx from 0x%lx, %ld bytes.\n",
//				bootbase,xi.base,xi.size);
//			if (askuser("OK?")) {
//				if (flashewrite(&FlashBank[0],(char *)bootbase,
//				  (char *)xi.base,xi.size) == -1)
//					printf("failed\n");
//			}
		}
	}
	else
		return(-1);
	return(0);
}

/* sendSohSno():
 * Common function used to send the initial startup messages for X/Ymodem
 */
void
sendSohSno(struct xinfo *xip)
{

	if ((xip->pktlen == PKTLEN_128) || (xmodemstart && (xip->sno == 0)))
		UART_Put_Char(SOH);
	else
		UART_Put_Char(STX);

	UART_Put_Char(xip->sno);
	UART_Put_Char((UCHAR)~(xip->sno));
}

/* putPacket():
 * Used by Xup to send packets.
 */
int
putPacket(UCHAR *tmppkt, struct xinfo *xip)
{
	int		i;
	UCHAR	*cp,c;
	USHORT	chksm;

	cp = (UCHAR *)&chksm;
	chksm = 0;
	sendSohSno(xip);
	if (xip->flags & USECRC) {
		for(i=0;i<xip->pktlen;i++) {
			UART_Put_Char(*tmppkt);
			chksm = (chksm<<8)^xcrc16tab[(chksm>>8)^*tmppkt++];
		}
		UART_Put_Char(cp[0]);
		UART_Put_Char(cp[1]);
	}
	else {
		for(i=0;i<xip->pktlen;i++) {
			UART_Put_Char(*tmppkt);
			chksm = ((chksm+*tmppkt++)&0xff);
		}
		UART_Put_Char((UCHAR)(chksm&0x00ff));
	}
	/* Wait for ack */
	if (!UART_Get_Char1(&c)) return -1;
	if (xmodemstart) {
		if (xip->sno == 0)
			if (!UART_Get_Char1(&c))
				return -1;
		xmodemstart = 0;
	}
	return(c);
}

/* getPacket():
 * Used by Xdown to retrieve packets.
 */
static int
getPacket(UCHAR *tmppkt, struct xinfo *xip)
{
	int		i;
	char	*pkt;
	UCHAR	seq[2];

	UART_Get_Bytes(seq,2,1);

#ifdef _XMODEM_DEBUG
	Mtrace("*");
#endif

	if (xip->flags & VERIFY) {
		UART_Get_Bytes(tmppkt,xip->pktlen,1);
		for(i=0;i<xip->pktlen;i++) {
			if (tmppkt[i] != ((char *)xip->dataddr)[i]) {
				if (xip->errcnt++ == 0)
					xip->firsterrat = (char *)(xip->dataddr+i);
			}
		}
		pkt = (char *)tmppkt;
	}
	else {
		UART_Get_Bytes((char *)xip->dataddr,xip->pktlen,1);
		pkt = (char *)xip->dataddr;
	}

#ifdef _XMODEM_DEBUG
	Mtrace("*");
#endif

	if (xip->flags & USECRC) {
		USHORT	crc, xcrc;
		UCHAR	*cp;
		
		cp = (UCHAR *)&crc;
		UART_Get_Char1(cp);
		UART_Get_Char1(cp+1);
		xcrc = xcrc16((UCHAR *)pkt,(ULONG)(xip->pktlen));
		if (crc != xcrc) {
			UART_Put_Char(CAN);

#ifdef _XMODEM_DEBUG
			Mtrace("1 %04x != %04x",crc,xcrc);
#endif
			return(-1);
		}
	}
	else {
		UCHAR	csum, xcsum;

		if (!UART_Get_Char1(&xcsum))
			return -1;

#ifdef _XMODEM_DEBUG
		Mtrace("*");
#endif

		csum = 0;
		for(i=0;i<xip->pktlen;i++)
			csum += *pkt++;
		if (csum != xcsum) {
			UART_Put_Char(CAN);

#ifdef _XMODEM_DEBUG
			Mtrace("2");
			Mtrace("2 %02x != %02x",csum,xcsum);
#endif

			return(-1);
		}
	}
	if ((UCHAR)seq[0] !=  xip->sno) {
		if ((xip->sno == 0x02) && (seq[0] == 0x01)) {	/* TeraTerm has a */
			xip->sno = 0x01;							/* "peculiarity". */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -