⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 zmodem.cpp

📁 DOS下采用中断接收数据的串口通讯的例子,很难找到的好东西!
💻 CPP
📖 第 1 页 / 共 3 页
字号:
                    error( "TIMEOUT" );
                    return c;
                default:
                    error( "Garbled data subpacket" );
                    return c;
            }
        }
        *buffer++ = (char) c;
        crc.update( c );
    }
    error( "Data subpacket too long" );
    return ERROR;
}

int Zmodem::ReadDataFrameCRC16( char *buffer, int length )
{
    int c;
    Crc16 crc( 0 );
    char *end;
    int d;

    Rxcount = 0;
    end = buffer + length;
    while ( buffer <= end ) {
        if ( ( c = ReadEncodedByte() ) & ~0xff ) {
crcfoo:
            switch ( c ) {
                case GOTCRCE:
                case GOTCRCG:
                case GOTCRCQ:
                case GOTCRCW:
                    crc.update( (d = c) & 0xff );
                    if ( ( c = ReadEncodedByte()) & ~0xff )
                        goto crcfoo;
                    crc.update( c );
                    if ( ( c = ReadEncodedByte() ) & ~0xff )
                        goto crcfoo;
                    crc.update( c );
                    if ( crc.value() & 0xFFFF ) {
                        error( "Bad CRC");
                        return ERROR;
                    }
                    Rxcount = (int) ( length - ( end - buffer ) );
                    error( "ReadDataFrame: %d  %s",
                           Rxcount, 
                           Zendnames[ d - GOTCRCE & 3 ] );
                    return d;
                case GOTCAN:
                    error( "Sender Canceled" );
                    return ZCAN;
                case TIMEOUT:
                    error( "TIMEOUT" );
                    return c;
                default:
                    error( "Garbled data subpacket" );
                    return c;
            }
        }
        *buffer++ = (char) c;
        crc.update( c );
    }
    error( "Data subpacket too long" );
    return ERROR;
}

// The attention string processor has to process a couple of 
// special characters used to sleep and send breaks.

void Zmodem::SendAttentionString()
{
    int i = 0;
    int c;
    long timer;

    while ( port->TXSpaceUsed() > 0 )
        port->IdleFunction();
    while ( ( c = attention_string[ i++ ] ) != 0 ) {
        switch ( c ) {
            case 0xde :
                timer = ReadTime() + 1000L;
                while ( ReadTime() < timer )
                    port->IdleFunction();
                break;
            case 0xdd :
                port->Break();
                break;
            default:
                SendChar( c );
        }
    }
}

// This function is called by the receiver before exiting.

void Zmodem::AckZFIN( void )
{
    int n;

    status( "AckZFIN" );
    PackLongIntoHeader( 0L );
    for ( n = 0 ; n < 4 ; n++ ) {
        port->FlushRXBuffer();
        SendHexHeader( 4, ZFIN, transmitted_header );
        switch ( ReadChar( 10000L ) ) {
            case 'O':
                ReadChar( 120 );    /* Discard 2nd 'O' */
                status( "AckZFIN complete" );
                return;
            case TIMEOUT:
            default:
                break;
        }
    }
}

// This utility routine has to scan the incoming data subpacket 
// for the file name and length.

int Zmodem::OpenInputFile( char *data )
{
    strcpy( file_name, data );
    if (sscanf(data+strlen(data)+1, "%ld", &file_length ) < 1 )
        file_length = -1L;
    file = fopen( file_name, "wb" );
    if ( !file)
        return ERROR;
    return OK;
}

// File position values are longs packed into a four byt header.
// The following two routines are resposible for packing and
// unpacking the data.

void Zmodem::PackLongIntoHeader( long header_data )
{
    transmitted_header[ ZP0 ] = (char) header_data;
    transmitted_header[ ZP1 ] = (char) ( header_data >> 8 );
    transmitted_header[ ZP2 ] = (char) ( header_data >> 16 );
    transmitted_header[ ZP3 ] = (char) ( header_data >> 24 );
}

long Zmodem::UnpackHeaderIntoLong( char *header )
{
    long l;

    l = header[ ZP3 ] & 0xff;
    l = ( l << 8 ) | ( header[ ZP2 ] & 0xff );
    l = ( l << 8 ) | ( header[ ZP1 ] & 0xff );
    l = ( l << 8 ) | ( header[ ZP0 ] & 0xff );
    return l;
}

// Hex headers need to send data in hex format.
void Zmodem::SendHexEncodedChar( int c )
{
    static char *digits = "0123456789abcdef";

    SendChar( digits[ ( c & 0xF0 ) >> 4 ] );
    SendChar( digits[ c & 0xF ] );
}

// This routine handles all the escape sequences necessary to send
// control characters.

void Zmodem::SendEncodedChar( int c )
{
    if ( c & 0x60 )
        SendChar( last_char_sent = c );
    else {
        switch ( c &= 0xff ) {
            case CR :
            case CR | 0x80 :
                if ( ( last_char_sent & 0x7f ) != '@' ) {
                    SendChar( last_char_sent = c );
                    break;
                } // else fall through
            case ZDLE :
            case DLE :
            case XON :
            case XOFF :
            case DLE | 0x80 :
            case XON | 0x80 :
            case XOFF | 0x80 :
                SendChar( ZDLE );
                c ^= 0x40;
                SendChar( last_char_sent = c );
                break;
            default:
                SendChar( last_char_sent = c );
        }
    }
}

// Read a byte, taking into account escape sequences, and checking
// for the 5*CAN abort sequence.

int Zmodem::ReadEncodedByte( void )
{
    int c;

    for ( ; ; ) {
        c = ReadChar( 10000L );
        if ( c == ZDLE )
            break;
        switch ( c ) {
            case XON :
            case XON | 0x80 :
            case XOFF :
            case XOFF | 0x80 :
                break;
            default:
                return c;
        }
    }
    for ( ; ; ) {
        if ( ( c = ReadChar( 10000L ) ) < 0 )
            return c;
        if ( c == CAN && ( c = ReadChar( 10000L ) ) < 0 )
            return c;
        if ( c == CAN && ( c = ReadChar( 10000L ) ) < 0 )
            return c;
        if ( c == CAN && ( c = ReadChar( 10000L ) ) < 0 )
            return c;
        switch ( c ) {
            case CAN:
                return GOTCAN;
            case ZCRCE:
            case ZCRCG:
            case ZCRCQ:
            case ZCRCW:
                return c | GOTFLAG;
            case ZRUB0:
                return 0x7f;
            case ZRUB1:
                 return 0xff;
            case XOFF :
            case XOFF | 0x80 :
            case XON :
            case XON | 0x80 :
                break;
            default:
                if ( ( c & 0x60 ) ==  0x40 )
                    return ( c ^ 0x40 );
                else
                    return ERROR;
        }
    }
}

// This routine reads a raw data byte, throws out the parity bit and
// ignores handshaking characters.

int Zmodem::ReadUnencodedByte( void )
{
    int c;

    for ( ; ; ) {
        if ( ( c = ReadChar( 10000L ) ) < 0 )
            return c;
        switch ( c &= 0x7f ) {
            case XON:
            case XOFF:
                continue;
            default:
                return c;
        }
    }
}

// When reading Hex headers, we need to convert hex values to a
// usable format.

int Zmodem::ReadHexByte( void )
{
    int c;
    int n;

    if ( ( c = ReadUnencodedByte() ) < 0 )
        return c;
    n = c - '0';
    if ( n > 9 )
        n -= ( 'a' - ':' );
    if ( n & ~0xF )
        return ERROR;
    if ( ( c = ReadUnencodedByte( )) < 0 )
        return c;
    c -= '0';
    if ( c > 9 )
        c -= ( 'a' - ':' );
    if ( c & ~0xF )
        return ERROR;
    c += ( n << 4 );
    return c;
}

// The sender needs to get the RINIT frame before it can start
// sending the file.  This routine takes care of that.

int Zmodem::GetRinitHeader( void )
{
  int i;

  for ( i = 0 ; i < 10 ; i++ ) {
    switch ( ReadHeader( received_header ) ) {
      case ZCHALLENGE:    // Echo receiver's challenge number 
        PackLongIntoHeader( received_file_position );
        SendHexHeader( 4, ZACK, transmitted_header );
        continue;
      case ZCOMMAND:        // They didn't see our ZRQINIT 
        PackLongIntoHeader( 0L );
        SendHexHeader( 4, ZRQINIT, transmitted_header );
        continue;
      case ZRINIT:
        receiver_wants_crc32 = received_header[ ZF0 ] & CANFC32;
        receiver_buffer_length =
                ( received_header[ ZP0 ] & 0xff ) +
                ( ( received_header[ ZP1 ] & 0xff ) << 8 );
        return OK;
      case ZCAN:
      case TIMEOUT:
        return ERROR;
      case ZRQINIT:
        if ( received_header[ ZF0 ] == ZCOMMAND )
          continue;
      default:
        SendHexHeader( 4, ZNAK, transmitted_header );
        continue;
    }
  }
  return ERROR;
}

// This routine sends a data subpacket, which is used here to send
// file names and file data.

void Zmodem::SendDataFrame( char *buffer, int length, int frameend )
{
    Crc32 crc32( 0xFFFFFFFFL );
    unsigned long crc32val;
    Crc16 crc16( 0 );
    int i;

    status( "SendDataFrame: %d %s",
            length, Zendnames[ frameend - ZCRCE & 3 ] );
    if ( receiver_wants_crc32 ) {
        for ( i = 0 ; i < length ; i++ ) {
            SendEncodedChar( buffer[ i ] );
            crc32.update( buffer[ i ] & 0xff );
        }
        SendChar( ZDLE );
        SendChar( frameend );
        crc32.update( frameend );
        crc32val = ~crc32.value();
        for ( i = 0 ; i < 4 ; i++ ) {
            SendEncodedChar( (int) crc32val );
            crc32val >>= 8;
        }
    } else {
        for ( i = 0 ; i < length ; i++ ) {
            SendEncodedChar( buffer[ i ] );
            crc16.update( buffer[ i ] & 0xff );
        }
        SendChar( ZDLE);
        SendChar( frameend);
        crc16.update( frameend );
        crc16.update( 0 );
        crc16.update( 0 );
        SendEncodedChar( crc16.value() >> 8 );
        SendEncodedChar( crc16.value() );
    }
    if ( frameend == ZCRCW )
        SendChar( XON );
}

// The sender sends a ZFIN frame just before exiting.

void Zmodem::SendZFIN( void )
{
    for ( ; ; ) {
        PackLongIntoHeader( 0L );
        SendHexHeader( 4, ZFIN, transmitted_header );
        switch ( ReadHeader( received_header ) ) {
            case ZFIN:
                SendChar( 'O');
                SendChar( 'O');
            case ZCAN:
            case TIMEOUT:
                return;
        }
    }
}

int Zmodem::SyncWithReceiver( int flag )
{
  int c;

  for ( ; ; ) {
    c = ReadHeader( received_header );
    switch ( c ) {
      case ZCAN:
      case ZABORT:
      case ZFIN:
      case TIMEOUT:
        return ERROR;
      case ZRPOS:
        if ( fseek( file, received_file_position, SEEK_SET ) )
          return ERROR;
        file_at_eof = 0;
        byte_count = last_reported_position
           = transmitted_file_position = received_file_position;
        last_sync_position = received_file_position;
        return c;
      case ZACK:
        last_reported_position = received_file_position;
        if ( flag || transmitted_file_position ==
                     received_file_position )
          return ZACK;
        continue;
      case ZRINIT:
      case ZSKIP:
        fclose( file );
        return c;
      case ERROR:
      default:
        SendBinaryHeader( 4, ZNAK, transmitted_header );
        continue;
    }
  }
}

// ********************* END OF ZMODEM.CPP **********************

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -