📄 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.
*
* 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 + -