📄 ian_xmodem.c
字号:
/* * 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 1.6 2001/07/16 15:19:55 npat 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. */intwaitchar(int tmo){ int timeout; int rval; timeout = tmo * LoopsPerSecond; while(!gotachar() && timeout) timeout--; if (timeout) rval = getchar(); else rval = -1; return(rval);}voidwaitclear (void){ ulong timeout; while (1) { timeout = 1 * LoopsPerSecond; while(!gotachar() && timeout) timeout--; if (!timeout) break; getchar(); }}intwaitbytes (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 1.6 2001/07/16 15:19:55 npat 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,};/***************************************************************************/intXmodem(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)) ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -