| home
| contents
| previous
| next page
| send comment
| send link
| add bookmark |
modem.cpp
/*-------------------------------------------------------------------------*
MODEM.CPP
modem input/output module
by: Stephen R. Schmitt
*-------------------------------------------------------------------------*/
#include <bios.h>
#include <ctype.h>
#include <dos.h>
#include <stdio.h>
#include <string.h>
#include "modem.h"
#define DTR 0x03 // DTR and RTS bits in mcr
// constants for the bioscom() function
// return values
#define SEND_READY 0x2000 // UART ready for next char
#define COMM_ERROR 0x9e00 // int 14h error flags
#define DATA_READY 0x0100 // int 14h data ready
#define CARRIER_DET 0x0080 // int 14h carrier detected
// cmd values
#define COMM_INIT 0x00
#define COMM_SEND 0x01
#define COMM_RECEIVE 0x02
#define COMM_STATUS 0x03
// abyte values
#define DATA_7 0x02
#define DATA_8 0x03
#define STOP_1 0x00
#define STOP_2 0x04
#define PARITY_NO 0x00
#define PARITY_ODD 0x08
#define PARITY_EVEN 0x18
#define BAUD_110 0x00
#define BAUD_150 0x20
#define BAUD_300 0x40
#define BAUD_600 0x60
#define BAUD_1200 0x80
#define BAUD_2400 0xA0
#define BAUD_4800 0xC0
#define BAUD_9600 0xE0
char *COM[] = { "COM1", "COM2", "COM3", "COM4", "" };
#define MODEM_OK 0
#define NO_PORT 1
#define BAD_PORT 2
#define NOT_READY 3
#define NO_CONNECT 4
#define XMT_TIME_OUT 5
#define RCV_TIME_OUT 6
extern char no_port[];
extern char bad_port[];
extern char not_ready[];
extern char no_connect[];
extern char time_out[];
extern char timed_out[];
/*-------------------------------------------------------------------------*
* "validate_port" validate communications port parameter
*
* returns: 1 if valid, else 0
*/
int modem::validate_port( char *com )
{
int i;
int far *port_table;
char *ch = com;
/*
* BIOS serial port table
*/
port_table = (int far *)MK_FP( 0x40, 0 );
// convert "com" to upper case
while( *ch )
{
*ch = toupper( *ch );
ch++;
}
i = 0;
while( COM[i][0] )
{
if( !strncmp( com, COM[i], 4 ) ) // match?
{
port = i;
hw_port = port_table[port];
if( !hw_port ) // port available?
{
status = NO_PORT;
return 0;
}
mcr_port = hw_port + 4; // set up mcr i/o address
status = MODEM_OK;
return 1;
}
else
i++;
}
status = BAD_PORT;
return 0;
}
/*-------------------------------------------------------------------------*
* "set_up_comm" initializes communications port and modem
*
* returns: 1 on success, else 0
*/
int modem::set_up_comm()
{
/*
* turn DTR and RTS off and wait 1/2 second
*/
outp( mcr_port, inp( mcr_port ) & ~DTR );
delay( 500 );
/*
* set up comm port for 1200 baud, no parity, 8 data bits, 1 stop bit
*/
bioscom( COMM_INIT, BAUD_1200 | PARITY_NO | DATA_8 | STOP_1, port );
/*
* capture current mcr and turn on DTR and RTS and wait 1/2 second
*/
outp( mcr_port, mcr_val = ( inp( mcr_port ) | DTR ) );
delay( 500 );
if( send_string( "ATE0V1X1\r" ) ) // modem accept init?
{
status = NOT_READY;
return 0;
}
delay( 1000 ); // wait a second
status = MODEM_OK;
return 1;
}
/*--------------------------------------------------------------------------*
* "place_call" calls out through the computer modem
*
* returns: 1 on success, else 0
*/
int modem::place_call( char *number, // number to call
char dt ) // tone or pulse dial flag
{
char dial_buf[40];
char buf[80];
char *d, *n;
if( dt == 'P' ) // copy in dial command
strcpy( dial_buf, "ATDP" ); // pulse dialing
else
strcpy( dial_buf, "ATDT" ); // tone dialing
n = number; // add telephone number
d = dial_buf + 4;
while( *n )
{
if( isdigit( *n ) || *n == ',' )
{
*d = *n;
d++;
n++;
}
else
n++;
}
*d = '\r'; // add a <cr>
d++;
*d = 0; // terminate
if( send_string( dial_buf ) ) // send dial command ok?
{
status = XMT_TIME_OUT;
return 0;
}
if( !get_line( buf, 80 ) ) // get modem response
{
status = RCV_TIME_OUT;
return 0;
}
delay( 1000 ); // ..and wait a second
if( strncmp( in_buffer, "CONNECT", 7 ) &&
!( bioscom( COMM_STATUS, 0, port ) & CARRIER_DET ) )
{
status = NO_CONNECT;
return 0;
}
status = MODEM_OK;
return 1;
}
/*-------------------------------------------------------------------------*
* "send_string" send a null terminated string out the comm port
*
* returns: status code
*/
int modem::send_string( char *s ) // string to send
{
int rc = 0; // return code
while( *s )
{
/*
* wait for UART to finish with the last character
*/
while( !( bioscom( COMM_STATUS, 0, port ) & SEND_READY ) )
/* do nothing */;
/*
* character transmitted ok?
*/
rc = bioscom( COMM_SEND, *s++, port );
if( ( rc & COMM_ERROR ) != 0 )
break;
}
return ( rc & COMM_ERROR );
}
/*-------------------------------------------------------------------------*
* "get_line" read a line from the comm port
*
* returns: 1 if ok, else 0 on time-out
*/
int modem::get_line( char *buf, // buffer for input
int len ) // max length to get
{
long start, work; // start tick count
int rv; // return code
int bn; // unprocessed buffer length
int elapsed = 819; // 45sec timeout
int far *timer; // BIOS timer tick counter
char c; // last char read
char *ip = in_buffer; // set input pointer
timer = (int far *)MK_FP(0x40, 0x6c);
start = *timer; // get current time
/*
* for each received char while not timed out
*/
for( bn = sizeof( in_buffer ); bn > 0 && elapsed > 0; )
{
if( bioscom( COMM_STATUS, 0, port ) & DATA_READY )
{
c = bioscom( COMM_RECEIVE, 0, port );
*ip++ = c;
outp( mcr_port, mcr_val ); // and make RTS on again
if( c == '\r' || c == '\n' ) // get a <cr> or <lf>?
{
if( ( ip - in_buffer ) > 1 ) // 1st char in buffer?
{
ip--; // back up pointer
break; // and stop loop here
}
else
{
ip = in_buffer; // restart buffer
bn = sizeof( in_buffer ); // and reset length
}
}
else
bn--; // decrement available
}
if( ( work = *timer ) != start ) // time pass?
{
if( work < start ) // go past midnight?
elapsed--; // count as 1 tick
else
elapsed -= (int)(work - start); // count everything
start = work; // start again w/curr time
}
}
*ip = '\0'; // null terminate string
if( elapsed <= 0 ) // time out waiting?
{
buf[0] = 0; // null string
status = RCV_TIME_OUT;
rv = 0; // signal no input
}
else
{
strncpy( buf, in_buffer, len ); // input line
status = MODEM_OK;
rv = 1; // good input
}
return rv;
}
/*-------------------------------------------------------------------------*
* "hang_up" disconnects modem from line
*
* returns: nothing
*/
void modem::hang_up()
{
outp( mcr_port, inp( mcr_port ) & ~DTR );
}
/*-------------------------------------------------------------------------*
* "status_code" accesses modem status code used in error messages.
*
* returns: modem status
*/
int modem::status_code()
{
return status;
}
| home
| contents
| previous
| next page
| send comment
| send link
| add bookmark |
Copyright © 2004, Stephen R. Schmitt