XMODEM.C
资源名称:ertos.rar [点击查看]
上传用户:sunrenlu
上传日期:2022-06-13
资源大小:1419k
文件大小:15k
源码类别:
操作系统开发
开发平台:
DOS
- /*
- * xmodem.exe - terminal session with XMODEM (xsum+CRC) up/download capabilities
- * - edit xmodem.ini to change desired COM port
- * - Keystrokes:
- * Esc to exit terminal
- * PgUp - upload a file (prompts for name)
- * PgDn - download a file (prompts for name)
- *
- * - download function could be shorter but more cryptic
- */
- #include <rtos.h>
- #include <sio.h>
- #include <xmodem.h>
- #include <stdio.h>
- #include <mem.h>
- #include <bios.h>
- #include <inifile.h>
- #include <kconio.h>
- #define COMBASE1 0x3f8
- #define COMBASE2 0x2f8
- #define COMIRQ1 4
- #define COMIRQ2 3
- #define NUM_RETRIES 10 /* # of consecutive failures before abort xfer */
- int combuf = 256;
- /*********************************************************************/
- void get_userfilename( char *msg, char *buffer )
- {
- cprintf("rn%s : ", msg );
- *buffer = 255;
- kgets( buffer );
- }
- /*********************************************************************/
- /* debug_getbyte - read serial byte if available
- * - break program if user hits esc
- */
- int debug_getbyte( WORD port, BYTE *data )
- {
- BYTE b;
- if ( kbhit() ) {
- b = getch();
- if ( b == 27 ) {
- sio_writebyte( port, XM_CAN );
- sio_writebyte( port, 3 ); /* ctrl c */
- rt_halt("user exit from XMODEM mode");
- } else
- sio_writebyte( port, b );
- }
- if ( sio_recv_waiting( port ) ) {
- b = sio_readbyte( port );
- *data = b;
- return( 1 );
- }
- return( 0 );
- }
- /*********************************************************************/
- /* debug_readbyte - busy wait for data from a port
- * - inherits keyboard ESC feature from debug_getbyte
- */
- BYTE debug_readbyte( int port )
- {
- BYTE b;
- while ( ! debug_getbyte( port, &b ) )
- /* nothing to do */
- rt_sleep( 0 );
- return( b );
- }
- /*********************************************************************/
- temp_outbyte( int port, BYTE b )
- {
- // while ( sio_tran_waiting( port )) rt_yield();
- sio_writebyte( port, b );
- }
- /*********************************************************************/
- BYTE calc_xsum( BYTE *p, int count )
- {
- BYTE xsum;
- int i;
- xsum = 0;
- while ( count-- )
- xsum += *p++;
- return( xsum );
- }
- /*********************************************************************/
- WORD calc_crc( BYTE *p, int count )
- {
- WORD crc;
- int i;
- crc = 0;
- while ( count-- ) {
- crc = crc ^ ((*p++) <<8);
- for ( i = 0 ; i < 8 ; ++i )
- if ( crc & 0x8000 )
- crc = crc << 1 ^ 0x1021;
- else
- crc = crc << 1;
- }
- return( crc );
- }
- /*********************************************************************/
- void upload(WORD port, char *fname)
- {
- int i, count;
- BYTE b;
- char *buffer = NULL;
- FILE *f = NULL;
- BYTE seq; /* XMODEM sequence number, */
- BYTE xsum; /* 8 bit checksum */
- WORD xcrc; /* 16 bit CRC */
- int use_crc = 0;
- DWORD bytes = 0;
- DWORD timer;
- timer = ktime; /* note start time */
- b = debug_readbyte( port );
- if ( b == XM_CRC ) {
- use_crc = 1;
- b = XM_NAK; /* start the syphon */
- }
- do { /* structured exception handler-like */
- /* need a NAK from receiver to start this going */
- if ( b != XM_NAK) {
- cprintf("ERROR: receiver is not listenningrn");
- break;
- }
- if ( ( f = fopen( fname, "rb" ))== NULL ) {
- cprintf("ERROR: cannot open file: %srn", fname );
- /* inform our peer */
- break;
- }
- if ( ( buffer = kcalloc( 1, XM_BUFSIZE)) == NULL ) {
- cprintf("ERROR: out of memoryrn" );
- break;
- }
- seq = 1;
- do {
- /* read some of the file from disk */
- count = fread( buffer, 1, XM_BUFSIZE, f );
- /* reached end of file */
- if ( count == 0 ) break;
- /* set any unread bytes to zero */
- if ( count < XM_BUFSIZE )
- memset( buffer + count, 26, XM_BUFSIZE - count ); /* Ctrl Z */
- /* look for errors while disk reading */
- while ( debug_getbyte( port, &b ));
- /* next part may have to be retried - communications are not perfect */
- do {
- cprintf("data packet # %i ", (WORD) seq );
- temp_outbyte( port, XM_SOH ); /* start */
- temp_outbyte( port, seq ); /* sequence number */
- temp_outbyte( port, seq ^ 0xff ); /* and its complement */
- /* write bytes and compute checksum */
- if ( use_crc )
- xcrc = calc_crc( buffer, XM_BUFSIZE);
- else
- xsum = calc_xsum( buffer, XM_BUFSIZE);
- for ( i = 0 ; i < XM_BUFSIZE ; ++i ) {
- b = buffer[i];
- temp_outbyte( port, b );
- }
- /* write the CRC or checksum */
- if ( use_crc ) {
- temp_outbyte( port, xcrc >> 8 );
- temp_outbyte( port, xcrc & 255 );
- } else
- temp_outbyte( port, xsum );
- /* and now we get the news */
- b = debug_readbyte( port );
- switch ( b ) {
- case XM_NAK : cprintf("NAKrn"); break;
- case XM_ACK : cprintf("ACKrn"); break;
- default : cprintf("%02xrn", b ); break;
- }
- } while ( b == XM_NAK );
- bytes += XM_BUFSIZE;
- /* now advance to the next packet */
- ++seq;
- } while ( 1 );
- } while ( 0 );
- do {
- temp_outbyte( port, XM_EOT );
- b = debug_readbyte( port );
- switch ( b ) {
- case XM_NAK : cprintf("NAKrn"); break;
- case XM_ACK : cprintf("ACKrn"); break;
- default : cprintf("%02xrn", b );
- }
- } while ( b == XM_NAK );
- timer = ktime - timer;
- if ( timer > 0 ) {
- cprintf(" %lu bytes in %lu.%lu seconds, %lu bpsn",
- bytes, timer / 1000, timer % 1000,
- bytes*8*1000/timer );
- }
- if ( buffer != NULL ) kfree( buffer );
- if ( f != NULL ) fclose( f );
- }
- /*********************************************************************/
- /* xm_waitbyte - wait a spell = 0
- * - return early with 1 if a BYTE found for read
- */
- xm_waitbyte( WORD port, BYTE *p, DWORD delay_seconds )
- {
- DWORD when;
- /* calculate when loop would timeout */
- when = ktime + delay_seconds * 1000;
- if ( when < (delay_seconds * 1000))
- /* timer wrapping - once every 57 days, we'll ignore it in simple example*/
- return( 1 );
- while ( ktime < when ) {
- if ( kbhit() )
- rt_halt("user requested exit while waiting for serial bytes");
- if ( sio_recv_waiting( port ) ) {
- *p = sio_readbyte( port );
- return( 1 );
- }
- rt_sleep( 0 ); /* give up slice */
- }
- /* timed out */
- return( 0 );
- }
- /*********************************************************************/
- void download(WORD port, char *fname)
- {
- int i, count;
- BYTE b;
- int retries;
- char buffer[ XM_BUFSIZE ];
- FILE *f = NULL;
- BYTE seq; /* XMODEM sequence number */
- BYTE localseq; /* our expected sequence number */
- BYTE xsum; /* 8 bit checksum */
- WORD xcrc; /* 16 bit CRC */
- int use_crc = 0;
- DWORD bytes = 0;
- DWORD timer;
- timer = ktime; /* note start time */
- /* write out C's waiting for input */
- retries = 10;
- use_crc = 1;
- do {
- do {
- /* write out individual C */
- sio_writebyte( port, XM_CRC ); /* C */
- if ( xm_waitbyte( port, &b, 10 ) ) break;
- if ( retries-- == 0 ) {
- cprintf("Download gave up after no responsern");
- return;
- }
- } while ( 1 );
- /* look at sent data */
- if ( b == 3 ) return; /* control break */
- } while ( b != XM_SOH );
- /* we have a SOH */
- localseq = 1;
- timer = ktime;
- /* try to create output file */
- if ( (f = fopen( fname,"wb")) == NULL ) {
- sio_writebyte( port, XM_CAN );
- rt_halt("unable to open local file for download");
- }
- retries = NUM_RETRIES;
- goto skip_soh; /* we already have the first byte handy */
- /* we expect packets full of bytes */
- do {
- if ( --retries == 0 ) {
- cprintf("too many retries, giving uprn");
- sio_writebyte( port, XM_CAN );
- break;
- }
- if ( !xm_waitbyte( port, &b, 10 ) ) {
- /* handle timeout */
- cprintf("timeout waiting for start of packetrn");
- sio_writebyte( port, XM_NAK );
- continue;
- }
- skip_soh:
- if ( b == XM_CAN ) /* sender requests a cancel */
- break;
- if ( b == XM_EOT ) {/* end of transmission !!! */
- sio_writebyte( port, XM_ACK ); // acknowledge it
- break;
- }
- if ( b != XM_SOH ) {
- cprintf("garbage received at start of packetrn");
- sio_writebyte( port, XM_NAK );
- continue;
- }
- /* looking for sequence number */
- if ( !xm_waitbyte( port, &b, 10 ) ) {
- /* handle timeout */
- cprintf("timeout waiting for sequence numberrn");
- sio_writebyte( port, XM_NAK );
- continue;
- }
- if ( b == (localseq-1 )) {
- /* we already acknowledged it */
- cprintf("received duplicate packetrn");
- sio_writebyte( port, XM_ACK );
- continue;
- }
- if ( b != localseq ) {
- /* either garbage or peer is on a different packet */
- cprintf("sequence number out of order : %u expected : %urn",
- b, localseq );
- sio_writebyte( port, XM_NAK );
- continue;
- }
- /* look for complement byte */
- if ( !xm_waitbyte( port, &b, 10 ) ) {
- /* handle timeout */
- cprintf("timeout waiting for sequence complementrn");
- sio_writebyte( port, XM_NAK );
- continue;
- }
- if ( b != (~localseq &255 )) {
- /* complement failed */
- cprintf("sequence number corrupt, complement <> seqrn");
- sio_writebyte( port, XM_NAK );
- continue;
- }
- /* get data */
- for ( count = 0 ; count < XM_BUFSIZE ; ++count ) {
- if ( !xm_waitbyte( port, &b, 10 ) ) {
- /* handle timeout */
- cprintf("timeout waiting for data item %urn", count+1);
- sio_writebyte( port, XM_NAK );
- continue;
- }
- buffer[ count ] = b;
- }
- /* get CRC or checksum */
- if ( !xm_waitbyte( port, &b, 10 ) ) {
- /* handle timeout */
- cprintf("timeout waiting for xsumrn");
- sio_writebyte( port, XM_NAK );
- continue;
- }
- if ( use_crc ) {
- xcrc = b << 8;
- if ( !xm_waitbyte( port, &b, 10 ) ) {
- /* handle timeout */
- cprintf("timeout waiting for xsumrn");
- sio_writebyte( port, XM_NAK );
- continue;
- }
- xcrc |= (b & 255);
- if ( xcrc != calc_crc( buffer, XM_BUFSIZE)) {
- cprintf("CRC failedrn");
- sio_writebyte( port, XM_NAK );
- continue;
- }
- } else {
- if ( b != calc_xsum( buffer, XM_BUFSIZE)) {
- cprintf("checksum failedrn");
- sio_writebyte( port, XM_NAK );
- continue;
- }
- }
- /* packet was successful */
- if ( fwrite( buffer, sizeof( buffer ), 1, f) != 1 ) {
- cprintf("disk file write failedrn");
- break;
- }
- cprintf("downloaded %u bytesr", bytes );
- sio_writebyte( port, XM_ACK );
- /* now advance to the next packet */
- bytes += XM_BUFSIZE;
- localseq++;
- retries = NUM_RETRIES;
- } while ( 1 );
- timer = ktime - timer;
- if ( timer > 0 ) {
- cprintf(" %lu bytes in %lu.%lu seconds, %lu bpsn",
- bytes, timer / 1000, timer % 1000,
- bytes*8*1000/timer );
- }
- if ( f != NULL ) fclose( f );
- }
- /***********************************************************************/
- /* term_thread - includes all the code to make this work as a terminal */
- /* session while user negotiates upload/download */
- /* - PgUp initiates upload */
- /* - PgDn initiates download */
- /***********************************************************************/
- void term_thread(DWORD port)
- {
- int i, count;
- BYTE b;
- WORD key;
- static char buffer[ 256 ];
- /*
- * Initialize the COM port
- */
- if ( port == 1 )
- sio_init( 1, COMBASE1, COMIRQ1, combuf, combuf, NULL, 0 );
- else
- sio_init( 2, COMBASE2, COMIRQ2, combuf, combuf, NULL, 0 );
- sio_setup (port, (DWORD)9600, 8, SIO_PARITY_NONE, 2, 0);
- kwindow( 1,2, 80,25 );
- do { /* structured exception handler-like */
- if ( kbhit() ) {
- key = bioskey( 0 );
- b = key & 255;
- if ( key == 0x4900 ) { /* PgUp */
- cprintf("uploading ...nr");
- get_userfilename( "file to upload", buffer );
- upload( port, buffer );
- cprintf("...donern");
- } else if ( key == 0x5100 ) {
- cprintf("downloading ...nr");
- get_userfilename( "file to write to", buffer );
- download( port, buffer );
- cprintf("...donern");
- } else if ( b == 27 ) break;
- else sio_writebyte( port, b );
- }
- if ( sio_recv_waiting( port ) ) {
- b = sio_readbyte( port );
- putch( b );
- }
- } while ( 1 );
- sio_close (port);
- rt_halt("user terminated");
- }
- /*********************************************************************/
- main ()
- {
- int comport;
- int msg;
- DWORD data;
- rt_init (200);
- rt_timerfreq( 100 );
- kpreemptive = 1;
- kctrlbreak = 0; /* ignore ctrl breaks */
- clrscr();
- cprintf("Esc to escape..., PgUp to invoke upload, PgDn for download");
- /* determine the desired com port */
- if ((comport = (int)GetIniDWORD("xmodem.ini","default","comport",-1))==-1){
- comport = 1;
- SetIniDWORD("xmodem.ini","default","comport", comport );
- }
- rt_newthread(term_thread, comport , 8192, 0, "term session" );
- kreadmessage( &msg, &data );
- }