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

📄 modem.cpp

📁 DOS下采用中断接收数据的串口通讯的例子,很难找到的好东西!
💻 CPP
字号:
// ********************** START OF MODEM.CPP **********************
//
//
// This file contains all of the code for the Modem class.  It should
// be compile and linked with any program wanting to use the class.

#include <iostream.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include "rs232.h"
#include "modem.h"

// The modem capability database is used to define all of the
// attributes used by a particular brand of modem.  These are
// stored in the application, which is practical when just a few
// are defined.  A bigger database might have to be moved into a
// conventional file.

ModemCapabilities ModemDataBase[] = {
{ "Hayes Compatible",
  "AT &F &C1 &D2",
  "NO CARRIER\0ERROR\0NO DIALTONE\0BUSY\0NO ANSWER\0\0",
  "",
  "",
  2400L,
  0,
  0
},
{ "Practical Peripherals V.34",
  "AT &F0 &C1 &D2 S95=44",
  "NO CARRIER\0ERROR\0NO DIALTONE\0BUSY\0NO ANSWER\0\0",
  "CLASS 5\0V.42BIS\0\0",
  "LAP-M\0ALT\0\0",
  57600L,
  1,
  1
},
{ "Intel SatisFAXtion 400e",
  "AT &F",
  "NO CARRIER\0ERROR\0NO DIALTONE\0BUSY\0NO ANSWER\0\0",
  "COMP\0\0",
  "LAPM\0MNP\0REL\0\0",
  57600L,
  1,
  1
},
{ ""
} };

// The modem constructur sets up the capability database for the
// modem of the particular name, but doesn't do much else.  If the
// brand name mode is not found via an exact match, the generic Hayes
// compatible definition is used.

Modem::Modem( RS232 &rs232_port, char *modem_name )
{
    int i;

    port = &rs232_port;
    modem_data = &ModemDataBase[ 0 ];
    for ( i = 0 ; *ModemDataBase[ i ].name != '\0' ; i++ ) {
        if ( strcmp( modem_name, ModemDataBase[ i ].name ) == 0 ) {
            modem_data = &ModemDataBase[ i ];
            break;
        }
    }
    tone_dial = 1;
    carrier_timeout = 60000L;
}

// The usual translation routine is used to print out the error
// names in more descriptive form.

char *Modem::ErrorName( ModemError status )
{
    switch ( status ) {
        case MODEM_SUCCESS           : return "Success";
        case MODEM_NO_RESPONSE       : return "No Response";
        case MODEM_NO_CONNECTION     : return "No Connection";
        case MODEM_DISCONNECT_FAILED : return "Disconnect failed";
        case MODEM_USER_ABORT        : return "User abort";
        default                      : return "Unknown Error";
    }
}

// The initialization routine just has to send out the initialization
// string, then wait for a response.  It inserts an extra one second
// delay in this routine, because some modems need a little extra time
// to handle initialization.

ModemError Modem::Initialize( void )
{
    long delay_time;

    port->Set( modem_data->initial_baud_rate );
    port->RtsCtsHandshaking( modem_data->handshaking );
    port->Write( '\r' );
    delay_time = ReadTime() + 1000;
    while ( ReadTime() < delay_time )
        port->IdleFunction();
    port->Write( modem_data->initialization_string );
    port->Write( '\r' );
    return wait_for_response();
}

// This protected routine is used to read lines of data back from the
// modem, generally after a response to a command.  It reads the
// characters in, echos them using the echo routine, and tries to
// assemble a complete line.  A '\n' character is used to terminate the
// line, or a timeout.

void Modem::read_line( char *buffer, int buf_size )
{
    int c;

    for ( ; ; ) {
        c = port->Read( 500 );
        if ( c < 0 )
            break;
        echo( (char) c );
        *buffer++ = (char) c;
        if ( --buf_size <= 1 )
           break;
        if ( c == '\n' )
            break;
    }
    *buffer = '\0';
}

// This protected routine is used to wait for an OK message
// after a modem command is sent.  If it doesn't get it within
// 2 seconds, and error is returned.  Most commands going to the
// modem can expect an OK response.  The two notable exceptions
// are the dialing and answer commands.

ModemError Modem::wait_for_response( void )
{
    long timeout;
    char buffer[ 81 ];
    ModemError status;

    timeout = ReadTime() + 2000;

    while ( ReadTime() < timeout ) {
        read_line( buffer, 81 );
        if ( strncmp( buffer, "OK", 2 ) == 0 )
            return MODEM_SUCCESS;
        if ( ( status = UserAbort() ) != MODEM_SUCCESS )
            return status;
    }
    return MODEM_NO_RESPONSE;
}

// During dialing, the Dial routine has to scan the input stream for
// lots of different strings that can indicate various things about
// protocols, data compression, and connections.  This command is used
// to scan for a list of strings stored in the format used by the
// modem capability database.

char *scan_strings( char *buffer, char *strings )
{
    char *p;

    while ( *strings ) {
        if ( ( p = strstr( buffer, strings ) ) != 0 )
            return p;
        strings += strlen( strings ) + 1;
    }
    return p;
}

// This routine is called by both the Answer and Dial routines.
// It has to scan the incoming lines of data not just for the
// "CONNECT" message, but also the protocol and compression strings
// as well.  Additionally, if the baud rate is not locked, it has
// to detect the new baud rate on connection.

ModemError Modem::wait_for_connection( void )
{
    long timeout;
    char *connect;
    char buffer[ 81 ];
    ModemError status;

    compressing = 0;
    protocol = 0;
    timeout = ReadTime() + carrier_timeout;
    while ( ReadTime() < timeout ) {
        read_line( buffer, 81 );
        if ( scan_strings( buffer, modem_data->fail_strings ) )
            return MODEM_NO_CONNECTION;
        if ( scan_strings( buffer, modem_data->compression_strings ) )
            compressing = 1;
        if ( scan_strings( buffer, modem_data->protocol_strings ) )
            protocol = 1;
        if ( ( connect = strstr( buffer, "CONNECT" ) ) != 0 ) {
            if ( !modem_data->locked_baud_rate ) {
                local_baud_rate = atol( connect + 8 );
                if ( local_baud_rate !=0 )
                    port->Set( local_baud_rate );
            } else
                local_baud_rate = modem_data->initial_baud_rate;
            return MODEM_SUCCESS;
        }
        if ( ( status = UserAbort() ) != MODEM_SUCCESS )
            return status;
    }
    return MODEM_NO_CONNECTION;
}

// This routine dials and then has another routine do the hard work
// of waiting for a response.

ModemError Modem::Dial( char *dial_string )
{

    port->Write( "ATD" );
    if ( tone_dial )
        port->Write( 'T' );
    else
        port->Write( 'P' );
    port->Write( dial_string );
    port->Write( '\r' );
    return wait_for_connection();
}

// This routine sends the answer command, then lets the other routine
// wait for success or failure.

ModemError Modem::Answer( void )
{
    port->Write( "ATA\r" );
    return wait_for_connection();
}

// Although all of the modems in the database are supposed to be set
// up so that dropping DTR causes a disconnect, some may slip through
// the net.  If dropping DTR doesn't cause a disconnect, the
// escape sequence is sent, followed by a Hangup message.

ModemError Modem::Disconnect( void )
{
    long delay_time;

    port->Dtr( 0 );
    delay_time = ReadTime() + 1250;
    while ( ReadTime() < delay_time )
        port->IdleFunction();
    port->Dtr( 1 );
    port->Write( "AT\r" );
    if ( wait_for_response() == MODEM_SUCCESS ) {
        port->Set( modem_data->initial_baud_rate );
        return MODEM_SUCCESS;
    }
    port->Write( "+++" );
    delay_time = ReadTime() + 1250;
    wait_for_response();
    port->Write( "ATH0\r" );
    if ( wait_for_response() == MODEM_SUCCESS ) {
        port->Set( modem_data->initial_baud_rate );
        return MODEM_SUCCESS;
    }
    return MODEM_DISCONNECT_FAILED;
}

// This routine gives the user an opportunity to abort during long
// sequences, such as dialing.

ModemError Modem::UserAbort( void )
{
    if ( !kbhit() )
        return MODEM_SUCCESS;
    getch();
    return MODEM_USER_ABORT;

}

// ReadRegister() not only asks for the register value, it then
// scans it in and converts it from ASCII to binary so it can be
// used by the program.

int Modem::ReadRegister( int reg )
{
    char buffer[ 81 ];
    long timeout;
    int value;
    ModemError status;

    sprintf( buffer, "ATS%d?\r", reg );
    port->Write( buffer );
    timeout = ReadTime() + 3000;
    value = (int) MODEM_NO_RESPONSE;
    while ( timeout > ReadTime() ) {
        read_line( buffer, 80 );
        if ( strncmp( buffer, "OK", 2 ) == 0 )
            break;
        if ( ( status = UserAbort() ) != MODEM_SUCCESS )
            return status;
        if ( isdigit( *buffer ) )
            value = atoi( buffer );
    }
    return value;
}

// This is the generic routine to send a command of your choice.  It
// assumes the command will get an OK message in return.

ModemError Modem::SendCommand( char *command )
{
    port->Write( command );
    port->Write( '\r' );
    return wait_for_response();
}

// This routine is generally only useful during debugging.  It
// dumps the state of the Modem structure out to the screen.

void Modem::DumpState( void )
{
    char *p;

    cout << "\nModem Status:\n\n"
         << "Name:                 "
         << modem_data->name << '\n';
    cout << "Init string:          "
         << modem_data->initialization_string << '\n';
    cout << "Fail strings:         ";
    p = modem_data->fail_strings;
    while ( *p ) {
        cout << p;
        p += strlen( p ) + 1;
        if ( *p )
            cout << ", ";
    }
    cout << '\n';
    cout << "Compression strings:  ";
    p = modem_data->compression_strings;
    while ( *p ) {
        cout << p;
        p += strlen( p ) + 1;
        if ( *p )
            cout << ", ";
    }
    cout << '\n';
    cout << "Protocol strings:     ";
    p = modem_data->protocol_strings;
    while ( *p ) {
        cout << p;
        p += strlen( p ) + 1;
        if ( *p )
            cout << ", ";
    }
    cout << '\n';
    cout << "Initial baud rate:    "
         << modem_data->initial_baud_rate << '\n';
    cout << "Baud rate locked:     "
         << (( modem_data->locked_baud_rate ) ? 'Y' : 'N') << '\n';
    cout << "Hardware handshaking: "
         << (( modem_data->handshaking ) ? 'Y' : 'N') << '\n';
    cout << "Dialing method:       "
         << (( tone_dial ) ? "Tone" : "Pulse" ) << '\n';
    cout << "Carrier timeout:      " << carrier_timeout << '\n';
    cout << "Connected:            "
         << (( port->Cd() ) ? 'Y' : 'N' ) << '\n';
    if ( !port->Cd() )
        return;
    cout << "Local baud rate:      " << local_baud_rate << '\n';
    cout << "Compressing:          "
         << (( compressing ) ? 'Y' : 'N' ) << '\n';
    cout << "Protocol:             "
         << (( protocol ) ? 'Y' : 'N' ) << '\n';
}

// ********************** END OF MODEM.CPP **********************

⌨️ 快捷键说明

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