?? digi.cpp
字號:
//
// DIGI.CPP
//
// Source code from:
//
// Serial Communications: A C++ Developer's Guide, 2nd Edition
// by Mark Nelson, IDG Books, 1999
//
// Please see the book for information on usage.
//
// This file contains all of the code used by the DigiBoard class.
// All access of the DigiBoard is done via the INT 14H interface
// described in the DOC file available from DigiBoard.
//
#include <stdio.h>
#include <ctype.h>
#include "pc8250.h"
#include "rs232.h"
#include "digi.h"
// The DigiBoard constructor is nice and simple. It has to read
// in the old settings to save them, then set the new ones according
// to the parameters passed in the constructor. The only private
// member exclusive to the derived class is the line-status flag,
// which is initialized to 0. The call to function 0x20 is used
// to disable BIOS timing emulation.
DigiBoard::DigiBoard( 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 )
{
union REGS r;
port_name = port;
error_status = RS232_SUCCESS;
first_debug_output_line = RS232::FormatDebugOutput();
debug_line_count = FormatDebugOutput();
if ( !valid_port() ) {
error_status = (RS232Error) DIGIBOARD_DRIVER_NOT_FOUND;
return;
}
read_settings();
saved_settings = settings;
settings.Adjust( baud_rate,
parity,
word_length,
stop_bits,
dtr,
rts,
xon_xoff,
rts_cts,
dtr_dsr );
write_settings();
r.h.ah = 0x20;
r.h.al = 0;
r.x.dx = port_name;
int86( 0x14, &r, &r );
line_status = 0;
}
// The destructor just restores the old state, nothing more.
DigiBoard::~DigiBoard( void )
{
settings = saved_settings;
write_settings();
}
//
// A call to function 0x0c and 0x05 are needed to read all the
// parameters found in the Settings class. All that is
// needed after that is a bunch of switch statements to convert
// the enumerated results that come back from the driver to
// settings usable by programmers.
//
void DigiBoard::read_settings( void )
{
union REGS r;
settings.BaudRate = -1L;
settings.Parity = '?';
settings.WordLength = -1;
settings.StopBits = -1;
settings.Dtr = -1;
settings.Rts = -1;
settings.XonXoff = -1;
settings.RtsCts = -1;
settings.DtrDsr = -1;
r.h.ah = 0xc;
r.x.dx = port_name;
int86( 0x14, &r, &r );
if ( r.h.ah == 0xff )
return;
switch ( r.h.cl ) {
case 0x00 : settings.BaudRate = 110L; break;
case 0x01 : settings.BaudRate = 150L; break;
case 0x02 : settings.BaudRate = 300L; break;
case 0x03 : settings.BaudRate = 600L; break;
case 0x04 : settings.BaudRate = 1200L; break;
case 0x05 : settings.BaudRate = 2400L; break;
case 0x06 : settings.BaudRate = 4800L; break;
case 0x07 : settings.BaudRate = 9600L; break;
case 0x08 : settings.BaudRate = 19200L; break;
case 0x09 : settings.BaudRate = 38400L; break;
case 0x0a : settings.BaudRate = 57600L; break;
case 0x0b : settings.BaudRate = 75600L; break;
case 0x0c : settings.BaudRate = 115200L; break;
case 0x0d : settings.BaudRate = 50L; break;
case 0x0e : settings.BaudRate = 75L; break;
case 0x0f : settings.BaudRate = 134L; break;
case 0x10 : settings.BaudRate = 200L; break;
case 0x11 : settings.BaudRate = 1800L; break;
}
switch ( r.h.bh ) {
case 0 : settings.Parity = 'N'; break;
case 1 : settings.Parity = 'O'; break;
case 2 : settings.Parity = 'E'; break;
}
switch ( r.h.ch ) {
case 0 : settings.WordLength = 5; break;
case 1 : settings.WordLength = 6; break;
case 2 : settings.WordLength = 7; break;
case 3 : settings.WordLength = 8; break;
}
switch ( r.h.bl ) {
case 0 : settings.StopBits = 1; break;
case 1 : settings.StopBits = 2; break;
}
settings.XonXoff = ( r.h.ah & 3 ) ? 1: 0;
settings.DtrDsr = ( r.h.al & 0x21 ) ? 1 : 0;
settings.RtsCts = ( r.h.al & 0x12 ) ? 1 : 0;
r.x.dx = port_name;
r.h.ah = 5;
r.h.al = 0;
int86( 0x14, &r, &r );
settings.Dtr = ( r.h.bl & MCR_DTR ) ? 1 : 0;
settings.Rts = ( r.h.bl & MCR_RTS ) ? 1 : 0;
}
// Setting the digiboard up with all the parameters found in the
// Settings class requires three INT 14H calls. Function 4
// sets the standard communications parameters, Function 5 sets
// the modem control lines, and function 0x1e sets up handshaking.
//
RS232Error DigiBoard::write_settings( void )
{
union REGS r;
RS232Error status = RS232_SUCCESS;
r.x.dx = port_name;
r.h.ah = 4;
r.h.al = 0;
switch ( toupper( settings.Parity ) ) {
case 'E' : r.h.bh = 1; break;
case 'O' : r.h.bh = 2; break;
default : settings.Parity = 'N';
status = RS232_ILLEGAL_PARITY_SETTING;
case 'N' : r.h.bh = 0; break;
}
switch ( settings.StopBits ) {
default : settings.StopBits = 1;
status = RS232_ILLEGAL_STOP_BITS;
case 1 : r.h.bl = 0; break;
case 2 : r.h.bl = 1; break;
}
switch ( settings.WordLength ) {
case 5 : r.h.ch = 0; break;
case 6 : r.h.ch = 1; break;
case 7 : r.h.ch = 2; break;
default : settings.WordLength = 8;
status = RS232_ILLEGAL_WORD_LENGTH;
case 8 : r.h.ch = 3; break;
}
switch ( settings.BaudRate ) {
case 110L : r.h.cl = 0x00; break;
case 150L : r.h.cl = 0x01; break;
case 300L : r.h.cl = 0x02; break;
case 600L : r.h.cl = 0x03; break;
case 1200L : r.h.cl = 0x04; break;
case 2400L : r.h.cl = 0x05; break;
case 4800L : r.h.cl = 0x06; break;
default : settings.BaudRate = 9600L;
status = RS232_ILLEGAL_BAUD_RATE;
case 9600L : r.h.cl = 0x07; break;
case 19200L : r.h.cl = 0x08; break;
case 38400L : r.h.cl = 0x09; break;
case 57600L : r.h.cl = 0x0a; break;
case 76800L : r.h.cl = 0x0b; break;
case 115200L : r.h.cl = 0x0c; break;
case 50L : r.h.cl = 0x0d; break;
case 75L : r.h.cl = 0x0e; break;
case 134L : r.h.cl = 0x0f; break;
case 200L : r.h.cl = 0x10; break;
case 1800L : r.h.cl = 0x11; break;
}
int86( 0x14, &r, &r );
r.x.dx = port_name;
r.h.ah = 0x1e;
r.h.bh = (unsigned char) ( ( settings.XonXoff ) ? 3: 0 );
r.h.bl = (unsigned char) ( ( settings.RtsCts ) ? 0x12 : 0 );
r.h.bl |= ( settings.DtrDsr ) ? 0x21 : 0;
int86( 0x14, &r, &r );
r.x.dx = port_name;
r.h.ah = 5;
r.h.al = 1;
r.h.bl = (unsigned char) ( ( settings.Dtr ) ? 1 : 0 );
r.h.bl |= ( settings.Rts ) ? 2 : 0;
int86( 0x14, &r, &r );
return status;
}
// Function 6 is called to return the name of the port, but
// it also functions effectively as a check to see if the
// DigiBoard considers the port to be a valid one.
int DigiBoard::valid_port( void )
{
union REGS r;
r.x.dx = port_name;
r.h.ah = 6;
r.h.al = 0;
int86( 0x14, &r, &r );
return ( r.h.ah != 0xff );
}
// Reading a byte uses the two BIOS emulation functions, one to
// read in the modem status, and the other to read the character.
// This function, like many of the other ones, updates the
// line status flags with the result read back from the board.
int DigiBoard::read_byte( void )
{
union REGS r;
if ( error_status < 0 )
return error_status;
r.h.ah = 3;
r.x.dx = port_name;
int86( 0x14, &r, &r );
line_status |= r.h.ah;
if ( r.h.ah & LSR_DATA_READY ) {
r.h.ah = 2;
r.x.dx = port_name;
int86( 0x14, &r, &r );
line_status |= r.h.ah;
return( r.h.al );
}
return( RS232_TIMEOUT );
}
// This function also uses a standard BIOS function call.
int DigiBoard::write_byte( int c )
{
union REGS r;
if ( error_status < 0 )
return error_status;
r.x.dx = port_name;
r.h.ah = 0x01;
r.h.al = (char) c;
int86( 0x14, &r, &r );
line_status |= r.h.ah;
if ( r.h.ah & 0x80 )
return RS232_TIMEOUT;
return RS232_SUCCESS;
}
// DigiBoard has two private functions, 14 and 15, which are
// used to read or write blocks of data. They both transfer
// as much data as possible, then return a count.
int DigiBoard::read_buffer( char *buffer, unsigned int count )
{
union REGS r;
struct SREGS s;
if ( error_status < 0 )
return error_status;
r.x.dx = port_name;
r.x.cx = count;
r.h.ah = 0x0f;
s.es = (unsigned int) ( (long) (void __far *) buffer >> 16 );
r.x.bx = (unsigned int) (long) (void __far *) buffer;
int86x( 0x14, &r, &r, &s );
ByteCount = r.x.ax;
buffer[ ByteCount ] = '\0';
if ( ByteCount != count )
return RS232_TIMEOUT;
return( RS232_SUCCESS );
}
int DigiBoard::write_buffer( char *buffer, unsigned int count )
{
union REGS r;
struct SREGS s;
if ( error_status < RS232_SUCCESS )
return error_status;
r.x.dx = port_name;
r.x.cx = count;
r.h.ah = 0x0e;
s.es = (unsigned int) ( (long) (void __far *) buffer >> 16 );
r.x.bx = (unsigned int) (long) (void __far *) buffer;
int86x( 0x14, &r, &r, &s );
ByteCount = r.x.ax;
if ( ByteCount != count )
return RS232_TIMEOUT;
return RS232_SUCCESS;
}
// This function does no work on its own. Instead, it uses
// the adjust function to change the settings member, then
// calls the write_settings() function to do the job.
RS232Error DigiBoard::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();
}
// DigiBoard function 7 sets a break of a variable time in 10
// millisecond ticks.
int DigiBoard::Break( long milliseconds )
{
union REGS r;
if ( error_status < RS232_SUCCESS )
return error_status;
r.x.dx = port_name;
r.h.ah = 7;
r.h.al = 1;
r.x.bx = (int) ( milliseconds / 10 );
int86( 0x14, &r, &r );
return RS232_SUCCESS;
}
// All four of the modem status functions just use BIOS function
// 3 to read in the MSR of the UART. They then just mask off
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -