📄 xmodem.c
字号:
/*
* vivi/deriver/serialxmodem.c:
* - an implementation of the xmodem protocol from the spec.
*
* Based on bootldr/xmodem.c (C) 2000 Compaq Computer Coporation.
*
* Copyright (C) 2001 MIZI Research, Inc.
*
*
* 1999-01-xx: Edwin Foo <efoo@crl.dec.com>
* - Initial code
*
* 2001-10-04: Janghoon Lyu <nandy@mizi.com>
* - Modified a little bit.
*
* 2002-07-04: Janghoon Lyu <nandy@mizi.com>
* - get_param_value()
2006-05: jkuang BUPT
some bugs are killed & code optimized
UART related are changed by jkuang. 2006-05
Buffer copy is canceled by jkuang, so this program can works very good with fast speed
Windows terminal. 2006-05
*/
#include "stdio.h"
#include "string.h"
#include "vxworks.h"
#include "tylib.h"
/*
#include "def.h"
#include "option.h"
#include "s3c2410.h"
#include "2410slib.h"
#include "xmodem.h"
#include "uart.h"
*/
/* XMODEM parameters */
#define BLOCK_SIZE_1 128 /* size of transmit blocks , SOH=0x01时的block大小*/
#define BLOCK_SIZE_2 1024 /* size of transmit blocks , SOH=0x02时的block大小*/
#define BLOCK_SIZE block_size
#define RETRIES 20 /* maximum number of RETRIES */
#define MAX_BUF 80000
static int block_size = BLOCK_SIZE_1;
typedef int __u32;
/* Line control codes */
#define SOH_1 0x01 /* start of header */
#define SOH_2 0x02 /* 1K xmodem start of header */
#define ACK 0x06 /* Acknowledge */
#define NAK 0x15 /* Negative acknowledge */
#define CAN 0x18 /* Cancel */
#define EOT 0x04 /* end of text */
#define GET_BYTE_TIMEOUT 250000 /* 1000000 */
/* #define GET_BYTE_TIMEOUT (1000 * 5) //秒 */
/* global error variable */
char *xmodem_errtxt = NULL;
/* prototypes of helper functions */
static int get_record(char* bufptr);
static int do_getc( unsigned long timeout, char *cp);
static int get_byte(char * cp);
enum
{
SAC_SEND_NAK = 0,
SAC_SENT_NAK = 1,
SAC_PAST_START_NAK = 2
};
static unsigned long xmodem_timeout = GET_BYTE_TIMEOUT;
static volatile int seen_a_char = SAC_SEND_NAK;
static int one_nak = 0;
#ifdef XMODEM_DEBUG
char debugbuf[DEBUGBUF_SIZE];
int db_idx = 0;
/*-------------------------------------------------------------------*/
void bufputs(char *s)
{
size_t len = strlen(s) + 1;
if (len + db_idx > sizeof(debugbuf))
len = sizeof(debugbuf) - db_idx;
if (len) {
memcpy(&debugbuf[db_idx], s, len);
db_idx += len;
}
}
/*-------------------------------------------------------------------*/
void reset_debugbuf(void)
{
memset(debugbuf, 0x0, sizeof(debugbuf));
db_idx = 0;
}
#endif
/*-------------------------------------------------------------------*/
__u32 xmodem_receive(char *dldaddr)
{
char ochr;
int r, rx_block_num, error_count;
__u32 foffset = 0; /* The offset */
serial_init(); /* Initialize the serial port I/O */
do{
taskDelay(60);
if (!sio_ischar())
Uart_SendKey(NAK);
} while(!sio_ischar()); /* Wait for the Terminal to Send file,sending NAK*/
xmodem_errtxt = NULL; /* The error log */
seen_a_char = 0;
/* one_nak = get_param_value("xmodem_one_nak", &ret);*/
one_nak = 0;
xmodem_timeout = GET_BYTE_TIMEOUT/2; /* The time out value */
rx_block_num = 1; /* The first packet number */
error_count = RETRIES; /* Retries times */
do{
if (foffset < (MAX_BUF-BLOCK_SIZE)) /* Test whether it is out of offset */
{
if ((r = get_record((char*)(dldaddr+foffset))) == (rx_block_num & 255))
/* Get a packet and set test if it is in the rang of 1 - 255 */
{
/* printf("xmodem_receive: Get a packet... Block Num %d\n",r);*/
error_count = RETRIES;
/* xmodem_errtxt = "RX PACKET";*/
rx_block_num++; /* Increase the packet num */
foffset += BLOCK_SIZE; /* Add the offset */
Uart_SendKey(ACK); /* jkuang*/
/* printf("xmodem_receive: An ACK Sent continue...\n");*/
continue; /* Go on with the packet getting */
}
}else {
r = -1; /* Offset deal: mark as TIME OUT */
}
if((r == -4)||(r == -5)) /* EOT or CAN*/
{
/* printf("xmodem_receive: EOT or CAN... Block Num %d\n",r);*/
/* xmodem_errtxt = "DONE";*/
{
/* some terminal prog send more chars after 'EOT'*/
/* printf("xmodem_receive: An ACK Sent.\n");*/
Uart_SendKey(ACK); /* Send 2 ACKs */
Uart_SendKey(ACK);
}
break; /* Jump out of the loop */
}
switch (r)
{
case -1: /* TIMEOUT */
printf("xmodem_receive: TIMEOUT \n");
xmodem_errtxt = "TIMEOUT";
ochr = NAK;
break;
case -2: /* Bad block */
printf("xmodem_receive: Bad block \n");
xmodem_errtxt = "BAD BLOCK#";
/* eat teh rest of the block */
while (get_byte(&ochr) != -1);
ochr = NAK;
break;
case -3: /* Bad checksum */
printf("xmodem_receive: Bad checksum \n");
xmodem_errtxt = "BAD CHKSUM";
ochr = NAK;
break;
default: /* Block out of sequence */
/* printf("xmodem_receive: Block out of sequence \n"); */
xmodem_errtxt = "WRONG BLK";
ochr = NAK;
}
error_count--; /* Decrease the retry time */
Uart_SendKey(ochr); /* Send info */
} while ((r > -3) && error_count);
if ((!error_count) || (r != -4)) /* If out of retries or other errors */
{
printf("x-modem error: %s\n", xmodem_errtxt); /* Display the error log */
return 0; /* indicate failure to caller */
/*printk("x-modem error: %s\n", xmodem_errtxt); */
}
return foffset;
}
/*-------------------------------------------------------------------*/
/*
* Read a record in the XMODEM protocol, return the block number
* (0-255) if successful, or one of the following return codes:
* -1 = Bad byte
* -2 = Bad block number
* -3 = Bad block checksum
* -4 = End of file
* -5 = Canceled by remote
*/
static int get_record(char* bufptr)
{
char c;
int block_num;
int i;
__u32 check_sum;
if (!get_byte(&c)) /* 1st byte */
{
printf("get_record: First byte Error.\n");
return -1;
}
switch (c) /* Switch the first byte */
{
case SOH_1: /* Receive packet */
BLOCK_SIZE = BLOCK_SIZE_1;
/* printf("get_record: Block Size 1 \n");*/
break;
case SOH_2: /* Receive packet */
BLOCK_SIZE = BLOCK_SIZE_2;
printf("get_record: Block Size 2 \n");
break;
case EOT: /* end of file encountered */
printf("get_record: End of Transmit. \n");
return -4;
case CAN: /* cancel protocol */
default:
printf("get_record: Cancelled or error. \n");
return -5;
}
if (!get_byte(&c)) /* 2nd byte */
{
printf("get_record: Second byte error.\n");
return -1;
}
block_num = c;
if (!get_byte(&c)) /* 3rd byte */
{
printf("get_record: Third block error.\n");
return -1;
}
/* from 4th -> byte before last */
/* printf("get_record: Start recieving data part.\n");*/
check_sum = 0;
for(i=0; i<BLOCK_SIZE; i++) /* Get the data bytes */
{
if (!get_byte(&c))
{
printf("get_record: Data byte recieving error.\n");
return -1;
}
/* printf("get_record: Get a data byte %c \n",c);*/
/* get_byte(&c);*/
*bufptr = c;
check_sum += c;
bufptr++;
}
get_byte(&c); /* last byte :check sum */
if ((check_sum & 0xff) == c) /* test the check sum */
{
/* printf("get_record: check is OK.Return the check_sum.\n");*/
return block_num;
}
printf("get_record: Checksum error.\n");
return -3;
}
/*-------------------------------------------------------------------*/
static int do_getc(unsigned long timeout, char * cp)
{
int rxstat;
while((rxstat = Uart_GetKey( cp )) == -1)
/* Get a byte from Uart and test if it is -1 */
{
printf("do_getc: Get -1 waiting for timeout.\n");
if (!(timeout--))
{
printf("do_getc: Getting char timeout.\n");
taskDelay(2);
break;
}
}
/* printf("do_getc: get char integer %d \n" ,rxstat);*/
return rxstat;
}
/*-------------------------------------------------------------------*/
static int get_byte(char *cp)
{
int rc;
again:
/*
* Reads and returns a character from the serial port
* - Times out after delay iterations checking for presence of character
* - Sets *error_p to UART error bits or - on timeout
* - On timeout, sets *error_p to -1 and returns 0
*/
rc = do_getc( xmodem_timeout, cp); /* get a byte */
/* printf("get_byte: get char integer %d %c \n",rc,(char)rc);*/
if (rc) /* if the byte is meanful not zero */
{
/* printf("get_byte: Return a char integer.\n"); */
seen_a_char = SAC_PAST_START_NAK;
return rc;
}
else /* zero byte handling */
{
/* printf("get_byte: get a zero char integer.\n"); */
if (seen_a_char == SAC_SEND_NAK || !one_nak)
{
/* bufputs("timeout nak");*/
Uart_SendKey(NAK); /* jkuang*/
}
if (seen_a_char < SAC_PAST_START_NAK)
{
seen_a_char = SAC_SENT_NAK;
xmodem_timeout = GET_BYTE_TIMEOUT;
goto again;
}
}
return (rc);
}
void gt(void)
{
char text[MAX_BUF]; /* Set the data buffer */
int i;
int st;
printf ("Prepare your terminal emulator to receive data now...\n");
st = xmodem_receive(text);
for (i = strlen(text)-2; i> 0; i--) /* if reach the end of the data,trunk it */
if (text[i] == 26)
text[i] = 0;
if (st <= 0) {
printf ("Xmodem transmit error: status: %d\n", st);
}
else {
printf ("Xmodem successfully transmitted %d bytes\n", st);
}
printf("The context of the file is : \n\n");
printf("%s\n",text);
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -