xmodem.cpp

来自「WinCE 3.0 BSP, 包含Inter SA1110, Intel_815」· C++ 代码 · 共 464 行

CPP
464
字号
/*++
Copyright (c) 1997  Microsoft Corporation

Module Name:

    xmodem.cxx

Abstract:

    This module implements xmodem transfer protocal class functions

Author:

    Jun Liu 2-Aug-1996

Revision History:

    John Cooper (johncoop) 97-Oct-24: Ported to LC2 platform

--*/

#include <windows.h>
#include "alt_def.h"
#include "bootldr.h"
#include "xmodem.hpp"
#include "uart.h"
#include "romdef.h"

#define ASC_ESC     0x1b            /* Escape */
extern "C" VOID
startcount(
    );

extern "C" ULONG
checkcount(
    );

PVUCHAR pUart = (PVUCHAR) (UART2_BASE | KSEG1_BASE);

/////////////////////////////////////////////////////////////////////
///+
BOOL CXModem::RxData( UCHAR &inData )
///
/// Check for incoming data
///
/// Return: TRUE  - Incoming data received
///         FALSE - No incoming data
///
{
    ULONG Status;

	Status = pUart[LINE_STATUS];
	if ( ((PSP_LINE_STATUS)(&Status))->DataReady ) {
		inData = (UCHAR) pUart[RECEIVE_BUFFER];
		return TRUE;
	}

    return FALSE;
}


/////////////////////////////////////////////////////////////////////
///+
void CXModem::TxData( UCHAR outData )
///
/// Send a byte of data
///
{

    ULONG Status;

	Status = pUart[LINE_STATUS];
	while ( !((PSP_LINE_STATUS)(&Status))->TransmitHoldingEmpty ) {
		Status = pUart[LINE_STATUS];
	}
	pUart[TRANSMIT_BUFFER] = outData;

}


/////////////////////////////////////////////////////////////////////
///+
void CXModem::AddCRC( UCHAR data )
///
/// Add data into CRC
///
{
    INT i;

    crc_computed = crc_computed ^ (INT)data << 8;
    for (i=0; i<8; ++i) {
        if ( crc_computed & 0x8000 ) {
            crc_computed = crc_computed << 1 ^ 0x1021;
        } else {
            crc_computed = crc_computed << 1;
        }
    }
}


/////////////////////////////////////////////////////////////////////
///+
BOOL CXModem::WaitStart()
///
/// Wait for XMODEM receiving to start
///
/// Return: TRUE  - XMODEM downloading started
///         FALSE - XMODEM downloading aborted
///
/// Note: User can press ESC to abort the downloading.
///
{
    UCHAR data;

    startcount();
    ResetXModem();
    while (1) {

        //
        // Wait for hand shake ack
        //

        if ( RxData(data) ) {

            if ( data == MODEM_SOH ) {
                blockSize = 128;
                lastBlockSize = blockSize;
                return TRUE;
            }
            if ( data == MODEM_STX ) {
                blockSize = 1024;
                lastBlockSize = blockSize;
                return TRUE;
            }
            if ( data == ASC_ESC ) {
                AssertXMError( User_Abort );
                return FALSE;
            }
        }

        //
        // Send out hand shake signal once a while
        //

        if ( checkcount() > C_TIMEOUT ) {
            TxData(MODEM_C);
            startcount();
        }
    }
}



/////////////////////////////////////////////////////////////////////
///+
BOOL CXModem::WaitBlockNumber()
///
/// Wait for XMODEM receiving the block number complement
///
/// Return: TRUE  - XMODEM received block number complement
///                 (May not be correct)
///         FALSE - Timeout, should restart the XModem
///
{

    UCHAR data;
    UCHAR receivedblockCount;

    //
    // Wait for block number
    //

    startcount();

    while (1) {

        // Check if block number is received
        if ( RxData(receivedblockCount) ) break;

        // Check for timeout
        if ( checkcount() > DATA_TIMEOUT ) {
            AssertXMError( Block_Number_Timeout );
            return FALSE;
        }
    }


    //
    // Wait for block number complement
    //

    startcount();

    while (1) {

        // Check block number
        if ( RxData(data) ) {

            // Check if complement matches
            if ( (data+receivedblockCount) != 0xff ) {
               AssertXMError( Block_Number_Unmatch );
            }

            // Check if it is re-doing the last block
            // or reciving the very first block
            if ( receivedblockCount == blockCount) {
                ClrCRC();
                return TRUE;
            }

            // Check if it is a new block
            if ( (receivedblockCount == blockCount+1) ||
                 ((receivedblockCount==0) && (blockCount==0xff)) ) {
                blockCount = receivedblockCount;
                blockPtr += lastBlockSize;
                lastBlockSize = blockSize;
                ClrCRC();
                return TRUE;
            }
         
            // Error: the block number doesn't make sense
            AssertXMError( Non_Sequential_Block_Number );
            return TRUE;
        }

        // Check for timeout
        if ( checkcount() > DATA_TIMEOUT ) {
            AssertXMError( Complement_Block_Number_Timeout );
            return FALSE;
        }
    }
}


/////////////////////////////////////////////////////////////////////
///+
BOOL CXModem::WaitData()
///
/// Wait for data
///
/// Return: TRUE  - XMODEM received data block
///         FALSE - Timeout, should restart the XModem
///
{

    UCHAR data;
    UINT   i;

    for (i = 0; i<blockSize; i++) {

        startcount();

        while (1) {

            if ( RxData(data) ) {
                *(UCHAR*)(blockPtr+i) = data; 
                AddCRC( data );
                break;
            };

            if ( checkcount() > DATA_TIMEOUT ) {
                AssertXMError( Data_Timeout);
                return FALSE;
            };

        }

    }

return TRUE;

}


/////////////////////////////////////////////////////////////////////
///+
BOOL CXModem::WaitCRC()
///
/// Wait for CRC check sum
///
/// Return: TRUE  - XMODEM received check sum
///         FALSE - Timeout, should restart the XModem
///
{

    UCHAR data;
    INT   crc_received;

    //
    // Wait CRC check sum high byte
    //

    startcount();

    while (1) {

        // Wait for CRC check sum high byte
        if ( RxData(data) ) {
            crc_received = data << 8;
            break;
        }

        // Check for timeout
        if ( checkcount() > DATA_TIMEOUT ) {
            AssertXMError( Checksum_High_Timeout );
            return FALSE;
        }
    }


    //
    // Wait CRC check sum low byte
    //

    startcount();

    while (1) {

        // Wait for CRC check sum low byte
        if ( RxData(data) ) {
            crc_received |= data ;
            break;
        }

        // Check for timeout
        if ( checkcount() > DATA_TIMEOUT ) {
            AssertXMError( Checksum_High_Timeout );
            return FALSE;
        }
    }

    if ( crc_received != GetCRC() ) {
        AssertXMError( Bad_Checksum );
    }

    return TRUE;

}



/////////////////////////////////////////////////////////////////////
///+
BOOL CXModem::WaitSOH()
///
/// Wait for SOH control character
///
/// Return: TRUE  - SOH or STX or EOT recived
///         FALSE - Timeout
///
///
{


    UCHAR data;

    startcount();

    while (1) {

        // Wait for hand shake (SOH or EOT) 
        if ( RxData(data) ) {

            if ( data == MODEM_SOH ) {
                blockSize = 128;
                return TRUE;
            }

            if ( data == MODEM_STX ) {
                blockSize = 1024;
                return TRUE;
            }

            if ( data == MODEM_EOT ) {
                TxData(MODEM_ACK);
                AssertXMError( EOT_received );
                return TRUE;
            }

            startcount();
        }

        // Send out hand shake signal once a while
        if ( checkcount() > SOH_TIMEOUT ) {
            AssertXMError( SOH_Timeout );
            return FALSE;
        }
    }
}




/////////////////////////////////////////////////////////////////////
///+
UINT CXModem::Receive( ADDRESS buf )
///
/// Start XModem receive
///
/// Return: The number of bytes received
///         If it is zero, an error condition has occurred.
///
{
    // Initialize the buffer pointer
    target_buffer = buf;

    // Clear error count
    errCount   = 0;

    // Wait X Modem start
    if ( !WaitStart() ) {
        return 0;
    }

    //
    // X Modem main loop
    //
    do {

        if ( !WaitBlockNumber() ) {
            if ( !WaitStart() ) {
                return 0;
            }
        } else if ( !WaitData() ) {
            if ( !WaitStart() ) {
                return 0;
            }
        } else if ( !WaitCRC() ) {
            if ( !WaitStart() ) {
                return 0;
            }
        } else {

            if ( modemError == No_Error ) {

                TxData(MODEM_ACK);
                if ( !WaitSOH() )
                if ( !WaitStart() ) return 0;

            } else {

                modemError = No_Error;

                if ( errCount > XMODEM_MAX_ERROR ) {
                    TxData(MODEM_CAN);
                    errCount = 0;
                    if ( !WaitStart() ) return 0;
                } else {
                    TxData(MODEM_NCK);
                    if ( !WaitSOH() )
                    if ( !WaitStart() ) return 0;
                }

            }

        }

    } while ( modemError != EOT_received );


    return (UINT)(blockPtr - target_buffer + blockSize);

}

⌨️ 快捷键说明

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