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

📄 ian_xmodem.c

📁 umon bootloader source code, support mips cpu.
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 
 * ian_xmodem.c
 *
 * X and Y modem file download and upload protocols.
 *
 * by Nick Patavalis (npat@inaccessnetworks.com)
 *
 *	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.
 *
 *	Note1: the majority of this code was edited with 4-space tabs.
 *	Note2: as more and more contributions are accepted, the term "author"
 *		   is becoming a mis-representation of credit.
 *
 *	Original author:	Ed Sutter
 *	Email:				esutter@lucent.com
 *	Phone:				908-582-2351
 *
 * $Id: ian_xmodem.c,v 2.0 2006/09/22 05:28:45 lxw Exp $
 */

/***************************************************************************/

#include "config.h"
#include "genlib.h"
#include "stddefs.h"
#include "flash.h"
#include "tfs.h"
#include "tfsprivate.h"
#include "cli.h"
#include "ascii.h"

/***************************************************************************/

#if INCLUDE_XMODEM

/* These "wait" functions may be better placed in chario.c.  They
 * are here for now, because this version of xmodem is the only
 * module that uses them.
 */

int
waitchar(int tmo)
{
	int timeout;
	int rval;

	timeout = tmo * LoopsPerSecond;
	while(!gotachar() && timeout)
		timeout--;
	if (timeout)
		rval = getchar();
	else
		rval = -1;

	return(rval);
}

void
waitclear (void)
{
	ulong timeout;

	while (1) {
		timeout = 1 * LoopsPerSecond;

		while(!gotachar() && timeout)
			timeout--;
		if (!timeout)
			break;
		getchar();
	}
}

int
waitbytes (char *buf, int cnt, int tmo)
{
	ulong timeout;
	int	i;

	for(i=0; i<cnt; i++) {
		timeout = tmo * LoopsPerSecond;
		while(!gotachar() && timeout)
			timeout--;
	    if (!timeout)
			break;
		buf[i] = (char)getchar();
	}
	return (i < cnt) ? -1 : i;
}

char ian_xmodem_cvsid[] = "$Id: ian_xmodem.c,v 2.0 2006/09/22 05:28:45 lxw Exp $";

/***************************************************************************/

/* RCV: Frame timeout. Time to wait for next frame, before sending a NAK */
#define FRAME_TMO  5
/* RCV: Character timeout. Characters in the same frame should normally 
   not be more than CHAR_TMO seconds appart */
#define CHAR_TMO   1
/* TRN: Transmiter timeout. Usually a large value. The standard suggests 
   something in the order of 1m */
#define TRANS_TMO  20
/* TRN: Number of times to retransmit a frame before quiting */
#define RETR_MAX   10
/* TRN: Number of invalid characters (i.e. not ACK or NAK) received 
   by the transmiter before quiting. This *not* the right way to do 
   things. The right way is to wait for a valid char up to TRANS_TMO 
   secs, and then quit. Unfortunatelly without timers, this behavior is 
   a bit tricky to implement. So this crude approxomation will have to do 
   for the moment. */
#define NOISE_MAX 100

/* Maximum number of files per Y-modem transfer */
#define YFILES_MAX 10

/***************************************************************************/

/* X/Ymodem protocol: */
#define SOH ASCII_SOH
#define STX ASCII_STX
#define EOT ASCII_EOT
#define ACK ASCII_ACK
#define NAK ASCII_NAK
#define CAN ASCII_CAN
#define ESC ASCII_ESC
#define BS  ASCII_BS

#define PKTLEN_128 128
#define PKTLEN_1K  1024

/***************************************************************************/

enum _xmodem_ops {
	XNULL = 0,
	XUP,
	XDOWN
};

enum _protocol_type {
	XMODEM = 0,
	YMODEM = 1
};

#define XERR_GEN  (-1)
#define XERR_TOUT (-2)
#define XERR_SYNC (-3)
#define XERR_CAN  (-4)
#define XERR_UCAN (-5)
#define XERR_RETR (-6)
#define XERR_HEAD (-7)
#define XERR_TFS  (-8)
#define XERR_NOFILE (-9)
#define XERR_NOSIZE (-10)

static char *xerr_msgs[] = {
	"E00:No Error",
	"E01:General Error",
	"E02:Timeout",
	"E03:Synchronization error",
	"E04:Operation canceled",
	"E05:Operation canceled by user",
	"E06:Maximum retransmitions exceeded",
	"E07:Invalid header-block",
	"E08:TFS error",
	"E09:File not found",
	"E10:Cannot determine file size"
};

/***************************************************************************/

/* struct yinfo:
 * used to pass information to and from the y-modem transfer functions.
 */
struct yinfo {	
	int usecrc;      /* use 16bit CRC instead of 8bit checksum */
	int onek;        /* use 1k blocks instead of 128bytes blocks */ 
	int verify;      /* operate in verification-mode */
	ulong baseaddr;  /* start address for the first file data transfer */
	char *flags;     /* TFS file flags (same for all files) */
	char *info;      /* TFS file info (same for all files) */

	int filecnt;                         /* number of files processed */
	char fname[YFILES_MAX][TFSNAMESIZE]; /* names of files processed */
	ulong dataddr[YFILES_MAX];           /* start address of each file */
	long size[YFILES_MAX];               /* size of each file in bytes */
	long pktcnt[YFILES_MAX];             /* number of frames exchanged */
	long errcnt[YFILES_MAX];             /* number of verification errors */
	ulong firsterrat[YFILES_MAX];        /* offset of first error */
};

/* struct xinfo:
 * used to pass information to and from the x-modem transfer functions.
 */
struct xinfo {
	int     usecrc;      /* use 16bit CRC instead of 8bit checksum */
	int     onek;        /* use 1k blocks instead of 128bytes blocks */ 
	int     verify;      /* operate in verification-mode */
	ulong	dataddr;	 /* start address for data transfer */
	long	size;	     /* size of the tansfer in bytes */
	int		pktcnt;		 /* number of packets processed */
	int		errcnt;		 /* number of errors (used in verify mode) */
	ulong	firsterrat;  /* pointer to location if first error (vrf mode) */
};

/***************************************************************************/

/* local prototypes */

static int Xup(struct xinfo *, int);
static int Xdown(struct xinfo *, int);
static int Ydown(struct yinfo *);
static int Yup(struct yinfo *);
static int getPacket(uchar *, int, int);
static void putPacket (uchar *, int, int, int);
static char *xerr_msg(int);
static void doCAN(void);

/***************************************************************************/

/* Defined globaly to conserve stack-space. Ugly but effective. */
static struct yinfo yif;
static struct xinfo xif;
static uchar pktbuff[PKTLEN_1K];

/* Used to pass-back the TFS error code, in case of a TFS error */
int tfserr;

/***************************************************************************/

char *XmodemHelp[] = {
	"X/Y modem file transfer",
#if INCLUDE_TFS
#if INCLUDE_FLASH
	"-[a:BckdF:f:i:s:t:uvy]",
#else /* of INCLUDE_FLASH */
	"-[a:ckdF:f:i:s:t:uvy]",
#endif /* of INCLUDE_FLASH */
#else /* of INCLUDE_TFS */
#if INCLUDE_FLASH
	"-[a:Bckds:t:uvy]",
#else /* of INCLUDE_FLASH */
	"-[a:ckds:t:uvy]",
#endif /* of INCLUDE_FLASH */
#endif /* of INCLUDE_TFS */
	"Options:",
	" -a{##}     address (overrides default of APPRAMBASE)",
#if INCLUDE_FLASH
	" -B         Program boot-sector (i.e. uMon-binary reload)",
#endif
	" -c         have xmodem receiver request the use of CRC (def = chksum)",
	"            have ymodem receiver request the use of chksum (def = CRC)",
	" -k         send 1K frames (default = 128bytes)",
	" -d         download",
#if INCLUDE_TFS
	" -F{name}   filename",
	" -f{flags}  file flags (see tfs)",
	" -i{info}   file info (see tfs)",
#endif
	" -s{##}     size (overrides computed size)",
	" -u         upload",
	" -v         verify only",
	" -y         use YMODEM extensions",
	"Notes:",
	" * Either -d or -u must be specified (-B implies -d).",
	" * The -c argument affects only the receiver (download operations).",
    "   The -k option affects only the transmitter (upload operations).",
#if INCLUDE_TFS
    " * YMODEM downloads: The file-name and size arguments are ignored,",
    "   since they are supplied by the sender. Multiple files can be",
    "   downloaded. Each file is downloaded at the address specified by",
    "   the '-a' argument (or at APPRAMBASE), and then saved to the TFS.",
    "   A summary of the files downloaded, their sizes and the download",
	"   locations is displayed at the end of the transfer.", 
#else /* of INCLUDE_TFS */
    " * YMODEM downloads: The file-name and size arguments are ignored,",
    "   since they are supplied by the sender. Multiple files can be",
    "   downloaded. The files are stored sequencially starting at the", 
    "   address specified with '-a' (or at APPRAMBASE). A summary of the",
    "   files downloaded, their sizes and the download locations is",
    "   displayed at the end of the transfer.",
#endif /* of INCLUDE_TFS */
#if INCLUDE_FLASH
    "   If -B is given, the boot-sector is programmed with the contents",
    "   of the last file downloaded.",
#endif
#if INCLUDE_TFS
	" * XMODEM downloads: Only one file can be downloaded. A 128-byte",
    "   modulo is forced on file size. The file is downloaded at the address",
    "   specified by '-a' (or at APPRAMBASE), and then saved to a TFS file",
    "   if a file-name argument is given. The '-s' option can be used to", 
    "   override the 128-bytes modulo when transferring a file to TFS.",
#else /* of INCLUDE_TFS */
	" * XMODEM downloads: Only one file can be downloaded. A 128-byte",
    "   modulo is forced on file size. The file is downloaded at the address",
    "   specified by '-a' (or at APPRAMBASE).",
#endif /* of INCLUDE_TFS */
#if INCLUDE_FLASH
    "   If -B is given, the boot-sector is programmed with the contents",
    "   of the downloaded file.",
#endif /* of INCLUDE_FLASH */
#if INCLUDE_TFS
    " * X/YMODEM uploads: Only one file can be uploaded. The size argument",
    "   is ignored since it is taken form the TFS. Before the file is", 
	"   uploaded it is copied at the address specified by '-a' (or at", 
    "   APPRAMBASE).",
#else /* of INCLUDE_TFS */
    " * X/YMODEM uploads: Only one file can be uploaded. The size argument",
    "   is mandatory (since there is no other way to know the number of", 
    "   bytes to transfer). The data (file) to be uploaded are taken form",
    "   the address specified by '-a' (or from APPRAMBASE).",
#endif /* of INCLUDE_TFS */
	(char *)0,
};

/***************************************************************************/

int
Xmodem(int argc,char *argv[])
{
#if INCLUDE_TFS
	TFILE	*tfp;
#endif
	char fname[TFSNAMESIZE+1], *info, *flags;
	int	opt, xop, newboot, usecrc, verify, onek, ymodem;
	ulong dataddr;
	long size;
	int i, r;

	/* Initialize to defaults */
	dataddr = getAppRamStart();
	xop = XNULL;
	newboot = 0;
	usecrc = 0;
	fname[0]='\0';
	info = (char *)0;
	flags = (char *)0;
	onek = 0;
	size = 0;
	verify = 0;
	ymodem = 0;

	/* Parse command line arguments */
	while ((opt=getopt(argc,argv,"a:Bci:f:dF:ks:uvy")) != -1) {
		switch(opt) {
		case 'a':
			dataddr = strtoul(optarg,(char **)0,0);
			break;
#if INCLUDE_FLASH
		case 'B':
			xop = XDOWN;
			newboot = 1;
			break;
#endif
		case 'c':
			usecrc = 1;
			break;
		case 'd':
			xop = XDOWN;
			break;
#if INCLUDE_TFS
		case 'F':
			strncpy(fname, optarg, TFSNAMESIZE);
			break;
		case 'f':
			flags = optarg;
			break;
		case 'i':
			info = optarg;
			break;
#endif
		case 'k':
			onek = 1;
			break;
		case 's':
			size = (ulong)strtoul(optarg,(char **)0,0);
			break;
		case 'u':
			xop = XUP;
			break;
		case 'v':
			verify = 1;
			break;
		case 'y':
			ymodem = 1;
			break;
		default:
			return(CMD_PARAM_ERROR);
		}
	}

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

	if ( xop == XUP ) {

		/* UPLOAD: Host <-- Micromonitor */

		if ( ymodem ) {

			/* we 're using the Y-Modem extensions */

			yif.onek = onek;
			yif.baseaddr = dataddr;
			yif.filecnt = 1;
			if (fname && fname[0]) {
				strcpy(yif.fname[0], fname);
			} else {
				strcpy(yif.fname[0], "noname");
			}
			yif.size[0] = size;

#if ! INCLUDE_TFS
			if ( yif.size[0] <= 0 ) {
				printf("%s\n", xerr_msg(XERR_NOSIZE));
				return(CMD_FAILURE);
			}
#endif

			r = Yup(&yif);

			printf("\n");

			if ( yif.filecnt > 0 ) {
				printf("Sent %d file%s.\n",
					   yif.filecnt, (yif.filecnt > 1) ? "s" : "");
				for (i = 0; i < yif.filecnt; i++) {
					printf(" %s: %ld bytes, %ld blocks, @ 0x%08lx\n",
						   yif.fname[i] ? yif.fname[i] : "<noname>",
						   yif.size[i],
						   yif.pktcnt[i],
						   yif.dataddr[i]);
				}
			}

			if ( r < 0 ) {
				printf("%s\n", xerr_msg(r));
				return(CMD_FAILURE);
			}			

		} else {

			/* plain X-modem */

			xif.dataddr = dataddr;
			xif.size = size;
			xif.onek = onek;

			if ( fname && fname[0] ) {
#if INCLUDE_TFS
				if ( ! (tfp = tfsstat(fname)) ) {
					printf("%s\n", xerr_msg(XERR_NOFILE));
					return(CMD_FAILURE);
				}
				memcpy((char *)(xif.dataddr), TFS_BASE(tfp), tfp->filsize);
				xif.size = size = tfp->filsize;
#endif
			}

			if ( xif.size <= 0 ) {
				printf("%s\n", xerr_msg(XERR_NOSIZE));
				return(CMD_FAILURE);
			}

			r = Xup(&xif, XMODEM);

			printf("\n");

			if ( r < 0 ) {
				printf("%s\n", xerr_msg(r));
				return(CMD_FAILURE);
			}

			printf("Sent 1 file.\n");

			printf(" %s: %ld bytes, %d blocks, @ 0x%08lx\n",
				   fname[0] ? fname : "<no-name>",
				   xif.size,
				   xif.pktcnt,
				   xif.dataddr);
		}

	} else if ( xop == XDOWN ) {

		/* DOWNLOAD: Host --> Micromonitor */

		if ( ymodem ) {

			/* Use Y-Modem extensions */

			yif.baseaddr = dataddr;
			yif.usecrc = !usecrc;
			yif.verify = verify;
			yif.flags = flags;
			yif.info = info;

			r = Ydown(&yif);

			printf("\n");

			if ( yif.filecnt ) {
				printf("Rcvd %d file%s.\n",
					   yif.filecnt, (yif.filecnt > 1) ? "s" : "");
				if ( yif.verify ) {
					for (i = 0; i < yif.filecnt; i++) {
						printf(" %s: %ld bytes, %ld blocks, %ld errors, " 
							   "first err @ 0x%08lx\n",
							   yif.fname[i] ? yif.fname[i] : "<noname>",
							   yif.size[i],
							   yif.pktcnt[i],
							   yif.errcnt[i], yif.firsterrat[i]);
					}
				} else {
					for (i = 0; i < yif.filecnt; i++) {
						printf(" %s: %ld bytes, %ld blocks, @ 0x%08lx\n",
							   yif.fname[i] ? yif.fname[i] : "<noname>",
							   yif.size[i],
							   yif.pktcnt[i],
							   yif.dataddr[i]);
					}
				}
			}

			if ( r < 0 ) {
				if ( r == XERR_TFS ) {
					printf("%s: %s: %s\n",
						   xerr_msg(XERR_TFS),
						   yif.fname[yif.filecnt], 
						   (char *)tfsctrl(TFS_ERRMSG,tfserr,0));
				} else {
					printf("%s\n", xerr_msg(r));
				}
				return(CMD_FAILURE);
			}

		} else {

			/* plain X-Modem */

			xif.dataddr = dataddr;
			xif.usecrc = usecrc;
			xif.verify = verify;

			if (verify && fname && fname[0]) {
#if INCLUDE_TFS
				if (! (tfp = tfsstat(fname)) ) {
					printf("%s\n", xerr_msg(XERR_NOFILE));

⌨️ 快捷键说明

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