?? 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 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 + -