📄 xmodem.c
字号:
/* 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. * * 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 */#include "config.h"#include "genlib.h"#include "stddefs.h"#include "flash.h"#include "tfs.h"#include "tfsprivate.h"#include "cli.h"#if INCLUDE_XMODEM/* 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 1024static 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)",#if INCLUDE_FLASH " -B boot sector reload",#endif " -c use crc (default = checksum)", " -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)", " -t{##} address for xmodem trace buffer", " -u upload", " -v verify only",#if INCLUDE_TFS " -y use Ymodem extensions",#endif "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,};intXmodem(int argc,char *argv[]){#if INCLUDE_TFS TFILE *tfp;#endif char *info, *flags; struct xinfo xi; int opt, xop, newboot; xop = XNULL; newboot = 0; info = (char *)0; flags = (char *)0; MtraceInit(0,0); xi.fname[0] = 0; xi.size = 0; xi.flags = 0; xi.filcnt = 0; xi.pktlen = PKTLEN_128; xi.base = xi.dataddr = getAppRamStart(); 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;#if INCLUDE_TFS case 'F': strncpy(xi.fname,optarg,TFSNAMESIZE); break; case 'f': flags = optarg; break; case 'i': info = optarg; break;#endif case 'k': xi.pktlen = PKTLEN_1K; break; case 's': xi.size = (ulong)strtoul(optarg,(char **)0,0); break; case 't': MtraceInit((char *)strtoul(optarg,(char **)0,0),99999999); break; case 'u': xop = XUP; break; case 'v': xi.flags |= VERIFY; break;#if INCLUDE_TFS case 'y': xi.flags |= (YMODEM | USECRC); xi.pktlen = PKTLEN_1K; break;#endif default: return(CMD_PARAM_ERROR); } } /* There should be no arguments after the option list. */ if (argc != optind) return(CMD_PARAM_ERROR); 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. */#if INCLUDE_TFS tfp = tfsstat(xi.fname); if (!tfp) { printf("%s: file not found\n",xi.fname); return(CMD_FAILURE); } xi.base = xi.dataddr = (ulong)TFS_BASE(tfp); xi.size = TFS_SIZE(tfp);#endif } rawon(); Xup(&xi); rawoff(); } } else if (xop == XDOWN) { long tmpsize; if ((xi.flags & YMODEM) && (xi.fname[0])) printf("Ymodem download gets name from protocol, '%s' ignored\n", xi.fname); rawon(); tmpsize = (long)Xdown(&xi); rawoff(); if ((!xi.size) || (tmpsize < 0)) xi.size = tmpsize;#if INCLUDE_FLASH#if INCLUDE_TFS 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) { printf("%s: %s\n",xi.fname,(char *)tfsctrl(TFS_ERRMSG,err,0)); return(CMD_FAILURE); } } else#endif if ((newboot) && (xi.size > 0)) { extern int FlashProtectWindow; char *bb; ulong bootbase; bb = getenv("BOOTROMBASE"); if (bb) bootbase = strtoul(bb,0,0); else bootbase = BOOTROM_BASE; FlashProtectWindow = 1; printf("Reprogramming 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"); return(CMD_FAILURE); } } }#endif } else return(CMD_PARAM_ERROR); return(CMD_SUCCESS);}/* putPacket(): * Used by Xup to send packets. */static intputPacket(uchar *tmppkt, struct xinfo *xip){ int c, i; uchar *cp; ushort chksm; cp = (uchar *)&chksm; chksm = 0; if (xip->pktlen == PKTLEN_128) rputchar(SOH); else rputchar(STX); rputchar(xip->sno); rputchar((uchar)~(xip->sno)); if (xip->flags & USECRC) { for(i=0;i<xip->pktlen;i++) { rputchar(*tmppkt); chksm = (chksm<<8)^xcrc16tab[(chksm>>8)^*tmppkt++]; } /* An "endian independent way to extract the CRC bytes. */ rputchar((char)(chksm >> 8)); rputchar((char)chksm); } else { for(i=0;i<xip->pktlen;i++) { rputchar(*tmppkt); chksm = ((chksm+*tmppkt++)&0xff); } rputchar((uchar)(chksm&0x00ff)); } c = getchar(); /* Wait for ack */ /* If pktcnt == -1, then this is the first packet sent by * YMODEM (filename) and we must wait for one additional * character in the response. */ if (xip->pktcnt == -1) c = getchar(); return(c);}/* getPacket(): * Used by Xdown to retrieve packets. */static intgetPacket(uchar *tmppkt, struct xinfo *xip)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -