| 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