static unsigned char xmodem_buff[128+4];
static unsigned char xmodem_block_number;
static int xmodem_index = -1;
static int get_xmodem_frame(void)
{
TIMER timeout;
int index;
int c;
xmodem_index = -1;
set_timer(&timeout, ONE_SECOND*10 );
do {
c = getchar();
} while(c < 0 && ! timer_expired(&timeout));
if(c < 0) {
return -1;
}
if(c != XMODEM_SOH && c != XMODEM_EOT && c != XMODEM_CAN) {
set_timer(&timeout, ONE_SECOND);
do {
c = getchar();
if(c >= 0) {
set_timer(&timeout, ONE_SECOND);
}
} while( ! timer_expired(&timeout));
return -1;
}
index = 0;
xmodem_buff[index++] = c;
if(c == XMODEM_EOT || c == XMODEM_CAN)
{
return 0;
}
while(index < sizeof(xmodem_buff)) {
set_timer(&timeout, ONE_SECOND);
do {
c = getchar();
} while(c < 0 && ! timer_expired(&timeout));
if(c < 0) {
return -1;
}
xmodem_buff[index++] = c;
}
xmodem_index = 0;
return 0;
}
static int xmodem_verify_frame(void)
{
int i;
unsigned char checksum;
if(xmodem_buff[0] != XMODEM_SOH) {
return -1;
}
if(xmodem_buff[1] != xmodem_block_number) {
return -1;
}
if(xmodem_buff[2] != ((~xmodem_block_number) & 0xff)) {
return -1;
}
checksum = 0;
for(i = 3; i < sizeof(xmodem_buff)-1; i++) {
checksum += xmodem_buff[i];
}
if(checksum != xmodem_buff[sizeof(xmodem_buff)-1]) {
return -1;
}
return 0;
}
static int xmodem_get_more(void)
{
int err;
int err_retry_count;
xmodem_block_number++;
err_retry_count = 0;
while(err_retry_count < XMODEM_ERR_RETRY_COUNT)
{
if(xmodem_index < 0) {
putchar(XMODEM_NAK);
}
err = get_xmodem_frame();
if(err == 0) {
if(xmodem_buff[0] == XMODEM_SOH) {
if( xmodem_verify_frame() == 0) {
putchar(XMODEM_ACK);//uart_sendchar
xmodem_index = 3;
return 0;
} else if(xmodem_buff[1] == xmodem_block_number -1) {
putchar(XMODEM_ACK);//uart_sendchar
} else {
xmodem_index = -1;
}
err_retry_count++;
continue;
} else if(xmodem_buff[0] == XMODEM_EOT) {
putchar(XMODEM_ACK);
xmodem_index = -1;
return -1;
}
}
xmodem_index = -1;
err_retry_count++;
}
xmodem_index = -1;
return -2;
}
static int xmodem_eof(void)
{
int i;
if(xmodem_index < 0) {
return 1;
}
for( i = xmodem_index; i < sizeof(xmodem_buff) -1; i++) {
if(xmodem_buff[i] != XMODEM_EOF) {
return 0;
}
}
if(peekchar() != XMODEM_EOT) {
return 0;
}
return 1;
}
int xmodem_start(void)
{
xmodem_index = sizeof(xmodem_buff)-1;
xmodem_block_number = 0;
return 0;
}
int xmodem_finish(void)
{
int c;
do {
c = xmodem_getchar();
} while(c >= 0);
return 0;
}
int xmodem_abort(void)
{
int i;
for(i=0; i<8; i++) {
putchar(XMODEM_CAN);
}
xmodem_finish();
return 0;
}
/****************************************************************
* This is the user api call for xmodem transfers.
*
*
*/
int xmodem_getchar(void)
{
int err;
int c;
if(xmodem_index < 0) {
return -1;
}
if(xmodem_index >= sizeof(xmodem_buff)-1) {
err = xmodem_get_more();
if(err < 0) {
return err;
}
}
c = xmodem_buff[xmodem_index];
xmodem_index++;
if(c == XMODEM_EOF) {
if( xmodem_eof() ) {
xmodem_finish();
xmodem_index = -1;
return -1;
}
}
return c;
}