📄 linux_xmload.c
字号:
/* xmloac.c for down soft to uclinux* Copyright (C) 2007/3/27 wangwudong <w..d@163.com>, 255k libmit 1000ms timeout use: xmload [filename] */#include <errno.h>#include <stdio.h>#include <sys/ioctl.h>#include <asm/termbits.h>#define TIMEOUT 1000#define MAX_DOWNLOAD_SIZE 1024*128#define MAXERRORS 10 //10#define SOH 0x01#define STX 0x02#define EOT 0x04#define ACK 0x06#define NAK 0x15#define CAN 0x18#define BS 0x08typedef int BOOL;#define FALSE ((BOOL) 0)#define TRUE ((BOOL) 1)#define STDIN 0 /*标准输入文件描述符*/#define STDOUT 1/*错误日志,调试用*/char msg[1024] = "erro is ";/*向终端写一个字节*/static __inline void WriteByte(char cc) { //write(STDOUT, cc, 1);/*不知道为什么发不了数,有时间再看看*/ //sprintf(&msg[strlen(msg)],"\n?\n");/*调试显示用*/ /*向终端发送一个字符*/ fputc(cc, stdout); /*必需要的,否则不能立即显示*/ fflush(stdout); }/*从终端等待一个字节*/int ReadByteWithTimeout(unsigned int msecs) { /*nfds为select函数的返回值 result暂存结果*/ int nfds,result; /*读操作文件描述集*/ fd_set readset; /*时间变量,超时参数*/ struct timeval timeout; /*秒和微秒分别计算*/ timeout.tv_sec = msecs / 1000; timeout.tv_usec = (msecs % 1000) * 1000; /*下面第一种是采用循环查迅法,附带超时处理,效率不高,影响传输速度*/ /*result = 0; for(i = 0 ; i < 20 && result <= 0 ; i++) { ioctl(STDIN, FIONREAD, &result); usleep(1); } if ( result >0) { sprintf(&msg[strlen(msg)]," (%d)",result); result = fgetc(stdin) & 0xff; sprintf(&msg[strlen(msg)],"%x ",result); } else { result = -1; } */ /*select有很强大的功能,对阻塞通道可以多个同时监控并可以超时返回*/ for( ; ; ) { FD_ZERO(&readset); FD_SET(STDIN, &readset); //遇到ctrl+c继续注意:STDIN 和 stdin的区别 if (((nfds = select( STDIN +1, &readset, NULL, NULL, &timeout)) == -1) && (errno == EINTR)) { /*如果因信号中断退出,则继续,但实际上终端以不是行输入,则不会出现组合键的中断信号*/ //sprintf(&msg[strlen(msg)],"errno == EINTRr!\n"); continue; } if (nfds == -1) { result = -1; //sprintf(&msg[strlen(msg)],"\nerr!\n "); break; } /*检测是否是该通道的事件*/ if (FD_ISSET(STDIN, &readset)) { /*第一种方法读有影响,可揣摩*/ //result = read(stdin, &cc, 1) & 0xff; /*安全起见,还是与调前面的未知数*/ result = fgetc(stdin) & 0xff; //sprintf(&msg[strlen(msg)],"%x ",result); break; } else { /*超时事件或其它事件都做超时处理*/ errno = EINVAL; result = -1; //sprintf(&msg[strlen(msg)],"... "); break; } } return result ; }/*读空终端的输入字节存储区*/static void ReadFlush() { while(ReadByteWithTimeout(1000) >= 0); }int XModemReceive(char *name){ FILE *fp; int bufLen = MAX_DOWNLOAD_SIZE; unsigned int errors = 0; unsigned int wantBlockNo = 1; unsigned int length = 0; int crc = 1; //use crc by send 'C', use checksum by send NAK char nak = 'C'; int crc_val; unsigned char expectedCksum; static char *blockBuf, *bufBase; /*分配文件临时缓冲空间*/ if(!(bufBase = malloc(bufLen))) { sprintf(stderr, "no memory\n"); return(0); } blockBuf = bufBase; //("start xmodem!\n"); fflush(stdout); ReadFlush(); /* Ask for CRC; if we get errors, we will go with checksum */ WriteByte(nak); //("WriteByte(nak)\n"); for (;;) { int blockBegin; int blockNo, blockNoOnesCompl; int blockLength; int cksum = 0; int crcHi = 0; int crcLo = 0; blockBegin = ReadByteWithTimeout(TIMEOUT); if (blockBegin < 0) { sprintf(&msg[strlen(msg)],"Read blockBegin timeout!\n"); goto timeout; } nak = NAK; switch (blockBegin) { case SOH: case STX: break; case EOT: WriteByte(ACK); //("WriteByte(ACK): done\n"); goto done; default: //("blockBegin error!\n"); sprintf(&msg[strlen(msg)],"blockBegin error!!\n"); errors--; goto error; } /* block no */ blockNo = ReadByteWithTimeout(TIMEOUT); if (blockNo < 0) { sprintf(&msg[strlen(msg)],"blockNo timeout!\n"); goto timeout; } /* block no one's compliment */ blockNoOnesCompl = ReadByteWithTimeout(TIMEOUT); if (blockNoOnesCompl < 0) { sprintf(&msg[strlen(msg)],"blockNoOnesCompl timeout!\n"); goto timeout; } if (( blockNo + blockNoOnesCompl ) != 255 ) { sprintf(&msg[strlen(msg)], "bad block ones compl(blockNo is %x,blockNoOnesCompl is %x)\n", blockNo, blockNoOnesCompl); goto error; } blockLength = (blockBegin == SOH) ? 128 : 1024; { int i, j; crc_val = 0; expectedCksum = 0; for (i = 0; i < blockLength; i++) { int cc = ReadByteWithTimeout(TIMEOUT); if (cc < 0) { sprintf(&msg[strlen(msg)]," read block byte timeout!(i is %d)\n", i); goto timeout; } blockBuf[i] = cc; //crc 或 checksum 计算加在读数据后 if (crc) { crc_val = crc_val ^ cc << 8; for (j = 0; j < 8; j++) if (crc_val & 0x8000) crc_val = crc_val << 1 ^ 0x1021; else crc_val = crc_val << 1; } else { expectedCksum += cc; } } } if (crc) { crcHi = ReadByteWithTimeout(TIMEOUT); if (crcHi < 0) { sprintf(&msg[strlen(msg)]," read crcHi timeout!\n"); goto timeout; } crcLo = ReadByteWithTimeout(TIMEOUT); if (crcLo < 0) { sprintf(&msg[strlen(msg)]," read crcLo timeout!\n"); goto timeout; } if ((crcHi != ((crc_val>>8) & 0xff)) || (crcLo != (crc_val & 0xff))) { sprintf(&msg[strlen(msg)],"crc error!\n"); goto error; } } else { cksum = ReadByteWithTimeout(TIMEOUT); if (cksum < 0) { sprintf(&msg[strlen(msg)]," read chksum timeout!\n"); goto timeout; } if (cksum != expectedCksum) { sprintf(&msg[strlen(msg)],"checksum error! \n"); goto error; } } if (blockNo == ((wantBlockNo - 1) & 0xff)) { /* a repeat of the last block is ok, just ignore it. */ /* this also ignores the initial block 0 which is */ /* meta data. */ goto next; } else if (blockNo != (wantBlockNo & 0xff)) { sprintf(&msg[strlen(msg)],"unexpected block no! \n"); goto error; } wantBlockNo++; length += blockLength; if (length > bufLen) { sprintf(&msg[strlen(msg)],"out of space(length is %d)\n",length); goto error; } blockBuf += blockLength; //接收成功,指针加上收到字节数next: errors = 0; WriteByte(ACK); //("Receive one block OK!\n"); continue;error: timeout: //("Timeout.\n"); errors++; if (errors == MAXERRORS) { /* Abort */ int i; // if using crc, try again w/o crc if (nak == 'C') { nak = NAK; errors = 0; crc = 0; //use checksum goto timeout; } for (i = 0; i < 5; i ++) WriteByte(CAN); for (i = 0; i < 5; i ++) WriteByte(BS); puts(" too many errors; giving up\n"); free(bufBase); return -1; } ReadFlush(); WriteByte(nak); //("WriteByte(nak)\n"); }done: //("\nxmodem done.\n"); ReadFlush(); if( length > 0) { fp = fopen(name, "w"); fwrite(bufBase,1,length,fp); fclose(fp); chmod(name, 777); } free(bufBase); return length;}int main(int argc, char * argv[]){ /*argv[0] argv[1]*/ /*xmload mytest*/ char *name; int tmp; struct termios newterm ; int saveflag ; name = argv[1]; if(argc==2 && name[0] == '?') { printf("Default download name : xmload \n"); printf("Set new download name : xmload destination_address \n"); return 0; } if(argc<2) { name = "/tmp/tt"; } //printf("Now download file by xmodem to %s...\n", name); /*错误日志初始化*/ sprintf(msg,"\n erro is \n"); /**/ /*设置终端为非行输入,去掉终端回显*/ tcgetattr( STDIN, &newterm ); newterm.c_iflag = 0; newterm.c_oflag &= ~OPOST; newterm.c_lflag &= ~ ( ECHO | ISIG | ICANON ); newterm.c_cc[VMIN] = 1; newterm.c_cc[VTIME] = 0; tcsetattr(STDIN, TCSANOW, &newterm); //system("stty raw"); /*必需设置终端输入无缓冲,否则getc一次后数据都读进来了,影响select的事件触发*/ setbuf(stdin,NULL); /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ /*输出不必要设置,但必需每次putc后,fflush()一次*/ //setbuf(stdout,NULL); /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ tmp = XModemReceive( name ); /*恢复终端为行输入,回显*/ //system("stty cooked echo"); newterm.c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON; newterm.c_oflag |= OPOST; newterm.c_lflag |= ECHO | ISIG | ICANON; tcsetattr( STDIN, TCSANOW, &newterm); fflush(stdout); if ( tmp <0 ) { printf("%s",msg); } printf("\nfile[%s] length is %d...\n",name, tmp); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -