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

📄 win16.cpp

📁 DOS下采用中断接收数据的串口通讯的例子,很难找到的好东西!
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// ******************** START OF WIN16.CPP ********************
//
//
// This file contains the source code that implements the
// Win16Port class. This class uses the Windows 3.1 comm
// driver.

#include <windows.h>
#include <ctype.h>
#include "win16.h"

#define INPUT_BUFFER_SIZE 1024
#define OUTPUT_BUFFER_SIZE 1024

// The Win16Port constructor opens the port using the MS-Windows
// function call OpenComm().  It then does the standard reading of
// the existing settings, saving them, and then writing the new
// settings.  Note that we acquire a pointer to the internal driver
// byte that has the Modem Status Lines.

Win16Port::Win16Port( RS232PortName port,
                      long baud_rate,
                      char parity,
                      int word_length,
                      int stop_bits,
                      int dtr,
                      int rts,
                      int xon_xoff,
                      int rts_cts,
                      int dtr_dsr )
{
    char name[ 15 ];

    port_name = port;
    error_status = RS232_SUCCESS;
    line_status = 0;

    first_debug_output_line = RS232::FormatDebugOutput();
    debug_line_count = FormatDebugOutput();

    wsprintf( name, "COM%d", port_name + 1 );
    handle = OpenComm( name, INPUT_BUFFER_SIZE, OUTPUT_BUFFER_SIZE );
    if ( handle < 0 ) {
        error_status = translate_windows_error( handle );
        return;
    }
    modem_status_register = (char FAR *) SetCommEventMask( handle, 0 );
    modem_status_register += 35;
    read_settings();
    saved_settings = settings;
    saved_dcb = dcb;
    settings.Adjust( baud_rate,
                     parity,
                     word_length,
                     stop_bits,
                     dtr,
                     rts,
                     xon_xoff,
                     rts_cts,
                     dtr_dsr );
    write_settings();
}

// The destructor restores the previous settings, then closes the
// port using the Windows call,

Win16Port::~Win16Port( void )
{
    if ( error_status == RS232_SUCCESS ) {
        settings = saved_settings;
        dcb = saved_dcb;
        write_settings();
        CloseComm( handle );
    }
}

// The set function looks much like the Set function for all the other
// RS232 derivatives seen in the book.  It just adjusts the current
// port settings, then calls write_settings() to do the dirty work.

RS232Error Win16Port::Set( long baud_rate,
                           int parity,
                           int word_length,
                           int stop_bits )
{
    settings.Adjust( baud_rate,
                     parity,
                     word_length,
                     stop_bits,
                     UNCHANGED,
                     UNCHANGED,
                     UNCHANGED,
                     UNCHANGED,
                     UNCHANGED );
    return write_settings();
}

// read_settings() does most of its work on the DCB associated with
// the current port.  All of the settings that it can figure out
// are found in the DCB.  The current settings of RTS and DTR can't
// be found, so they are set to -1, indicating that they are unknown.

void Win16Port::read_settings( void )
{
    int status;
    RS232Error error;

    status = GetCommState( handle, &dcb );
    if ( status < 0 ) {
        error = translate_windows_error( status );
        if ( error >= RS232_ERROR ) 
            error_status = error;
        return;
    }
    if ( ( dcb.BaudRate & 0xff00 ) == 0xff00 )
        switch( dcb.BaudRate ) {
            case CBR_110    : settings.BaudRate = 110;     break;
            case CBR_300    : settings.BaudRate = 300;     break;
            case CBR_600    : settings.BaudRate = 600;     break;
            case CBR_1200   : settings.BaudRate = 1200;    break;
            case CBR_2400   : settings.BaudRate = 2400;    break;
            case CBR_4800   : settings.BaudRate = 4800;    break;
            case CBR_9600   : settings.BaudRate = 9600;    break;
            case CBR_14400  : settings.BaudRate = 14400;   break;
            case CBR_19200  : settings.BaudRate = 19200;   break;
            case CBR_38400  : settings.BaudRate = 38400L;  break;
            case CBR_56000  : settings.BaudRate = 56000L;  break;
            case CBR_128000 : settings.BaudRate = 128000L; break;
            case CBR_256000 : settings.BaudRate = 256000L; break;
            default         : settings.BaudRate = -1;      break;
    } else
        settings.BaudRate = dcb.BaudRate;
    switch ( dcb.Parity ) {
        case NOPARITY    : settings.Parity = 'N'; break;
        case ODDPARITY   : settings.Parity = 'O'; break;
        case EVENPARITY  : settings.Parity = 'E'; break;
        case MARKPARITY  : settings.Parity = 'M'; break;
        case SPACEPARITY : settings.Parity = 'S'; break;
        default          : settings.Parity = '?'; break;
    }
    settings.WordLength = dcb.ByteSize;
    switch ( dcb.StopBits ) {
        case ONESTOPBIT   : settings.StopBits = 1; break;
        case ONE5STOPBITS : 
        case TWOSTOPBITS  : settings.StopBits = 2; break;
        default           : settings.StopBits = -1; break;
    }
    settings.Rts = -1;
    settings.Dtr = -1;
    settings.XonXoff = dcb.fOutX;
    settings.RtsCts = dcb.fRtsflow;
    settings.DtrDsr = dcb.fDtrflow;
}

// write_settings() does almost everything it needs to do by
// modifying the DCB and then calling SetCommState().  Setting
// RTS and DTR is done by sending an escape function to the
// driver.

RS232Error Win16Port::write_settings( void )
{
    int set_status;
    RS232Error status = RS232_SUCCESS;

    if ( settings.BaudRate <= 19200L )
        dcb.BaudRate = (int) settings.BaudRate;
    else if ( settings.BaudRate == 38400L )
        dcb.BaudRate = CBR_38400;
    else
       status = RS232_ILLEGAL_BAUD_RATE;
    switch ( toupper( settings.Parity ) ) {
        case 'N' : dcb.Parity = NOPARITY; break;
        case 'E' : dcb.Parity = EVENPARITY; break;
        case 'O' : dcb.Parity = ODDPARITY; break;
        case 'M' : dcb.Parity = MARKPARITY; break;
        case 'S' : dcb.Parity = SPACEPARITY; break;
        default : status = RS232_ILLEGAL_PARITY_SETTING; break;
    }
    switch ( settings.WordLength ) {
        case 8 : dcb.ByteSize = 8; break;
        case 7 : dcb.ByteSize = 7; break;
        case 6 : dcb.ByteSize = 6; break;
        case 5 : dcb.ByteSize = 5; break;
        default : status = RS232_ILLEGAL_PARITY_SETTING; break;
    }
    switch ( settings.StopBits ) {
        case ONESTOPBIT   : dcb.StopBits = 1; break;
        case ONE5STOPBITS :
        case TWOSTOPBITS  : dcb.StopBits = 2; break;
        default : status = RS232_ILLEGAL_STOP_BITS; break;
    }
    if ( settings.Rts == 0 )
        EscapeCommFunction( handle, CLRRTS );
    else if ( settings.Rts == 1 )
        EscapeCommFunction( handle, SETRTS );
    if ( settings.Dtr == 0 )
        EscapeCommFunction( handle, CLRDTR );
    else if ( settings.Dtr == 1 )
        EscapeCommFunction( handle, SETDTR );
    dcb.fOutX = dcb.fInX = ( settings.XonXoff != 0 );
    dcb.fOutxCtsFlow = dcb.fRtsflow = ( settings.RtsCts != 0 );
    dcb.fOutxDsrFlow = dcb.fDtrflow = ( settings.DtrDsr != 0 );
    set_status = SetCommState( &dcb );
    if ( set_status == 0 )
        return status;
    return translate_windows_error( set_status );
}

// The Windows port driver sends back its own error codes in
// certain stituations.  This function translates them to their
// class RS232 equivalents.

RS232Error Win16Port::translate_windows_error( int error )
{
    switch ( error ) {
        case IE_BADID     : return RS232_PORT_NOT_FOUND;
        case IE_BAUDRATE  : return RS232_ILLEGAL_BAUD_RATE;
        case IE_BYTESIZE  : return RS232_ILLEGAL_WORD_LENGTH;
        case IE_DEFAULT   : return (RS232Error) WINDOWS_PORT_DEFAULT_PARAMETERS;
        case IE_HARDWARE  : return RS232_PORT_IN_USE;
        case IE_MEMORY    : return RS232_MEMORY_ALLOCATION_ERROR;
        case IE_NOPEN     : return (RS232Error) WINDOWS_PORT_NOT_OPEN;
        case IE_OPEN      : return (RS232Error) WINDOWS_PORT_ALREADY_OPEN;
        default           : return RS232_ERROR;
    }
}

// ReadComm() does all the work necessary to implement this function.

int Win16Port::read_byte( void )
{
    int result;
    unsigned char c;
    COMSTAT comstat;

    if ( error_status < 0 )
        return error_status;
    result = ReadComm( handle, &c, 1 );
    if ( result > 0 )
        return (int) c;
    line_status |= GetCommError( handle, &comstat );
    return RS232_TIMEOUT;
}

// Before calling WriteComm(), I check to be sure there is room
// for a new character in the output queue.  Once that is
// determined, WriteComm() does the rest of the work.

int Win16Port::write_byte( int c )
{
    int result;
    COMSTAT comstat;

    if ( error_status < 0 )
        return error_status;
    line_status |= GetCommError( handle, &comstat );
    if ( comstat.cbOutQue == OUTPUT_BUFFER_SIZE )
        return RS232_TIMEOUT;
    result = WriteComm( handle, &c, 1 );
    if ( result > 0 )
        return RS232_SUCCESS;
    line_status |= GetCommError( handle, &comstat );
    return RS232_TIMEOUT;
}

// The read_buffer() routine is slightly more complicated than
// read_byte(), but it still calls ReadComm() to do most of the
// work.  It just has to take into account the possibility that
// an incomplete read may take place.

int Win16Port::read_buffer( char *buffer, unsigned int count )
{
    int result;
    COMSTAT comstat;

    ByteCount = 0;
    if ( error_status < 0 )
        return error_status;
    result = ReadComm( handle, buffer, (int) count );
    if ( result > 0 )
        ByteCount = result;
    else {
        ByteCount = -result;
        line_status |= GetCommError( handle, &comstat );
    }
    if ( ByteCount < count )
        return RS232_TIMEOUT;
    else
        return RS232_SUCCESS;
}

// Like read_buffer(), this routine is basically just an extension
// of its single byte sibling.  However, it has to take into account
// the possibility that a partial buffer write may occur.

int Win16Port::write_buffer( char *buffer, unsigned int count )
{
    int result;
    COMSTAT comstat;
    unsigned int buffer_space;

    ByteCount = 0;
    if ( error_status < 0 )
        return error_status;
    line_status |= GetCommError( handle, &comstat );
    buffer_space = OUTPUT_BUFFER_SIZE - comstat.cbOutQue;
    if ( buffer_space > count )
        result = WriteComm( handle, buffer, count );
    else
        result = WriteComm( handle, buffer, buffer_space );
    if ( result > 0 )
        ByteCount = result;
    else {
        ByteCount = -result;
        line_status |= GetCommError( handle, &comstat );
    }
    if ( ByteCount < count )
        return RS232_TIMEOUT;
    return RS232_SUCCESS;
}

// This function has a dedicated Windows API call to do its work.

int Win16Port::FlushRXBuffer( void )
{
    int status;

    if ( error_status < RS232_SUCCESS )
        return error_status;
    status = FlushComm( handle, 1 );
    if ( status != 0 )
        return translate_windows_error( status );
    return RS232_SUCCESS;
}

// The COMSTAT structure returned from GetCommError contains
// the information we need to determine how the space in both
// the TX and RX buffers is presently being used.

int Win16Port::TXSpaceFree( void )
{
    COMSTAT comstat;

    if ( error_status < RS232_SUCCESS )
        return error_status;
    line_status |= GetCommError( handle, &comstat );
    return OUTPUT_BUFFER_SIZE - comstat.cbOutQue;
}

int Win16Port::RXSpaceUsed( void )
{
    COMSTAT comstat;

    if ( error_status < RS232_SUCCESS )
        return error_status;
    line_status |= GetCommError( handle, &comstat );
    return comstat.cbInQue;
}

// The Windows API function takes care of sending the break.

int Win16Port::Break( long milliseconds )
{
    long timer;

⌨️ 快捷键说明

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