📄 win16.cpp
字号:
// ******************** 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 + -