Checking for Available Ports and Modems

with Async Professional

 

One common request we receive at TurboPower Software is how properly to determine the presence and availability of Serial Ports and Modems at run-time.

When a TApdComPort component attempts to open a port that is not available (either it doesn’t exist, is disabled, or perhaps has an input only device attached, such as a mouse), it throws a custom APRO exception “EBadID”; this is easy enough to trap for to detect that a good port was found.

If a good port is found it is then possible to send the common modem attention command “AT” over the port, and if the common modem response “OK” is received back then there is clearly a modem attached and active.

Here’s a simple project showing how one might set all this up:

Delphi:

unit detportu1;

interface

uses

  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

  StdCtrls, OoMisc, AdPort, AdModem, AdExcept, TypInfo;

 

const

  MIN_PORT_NUM = 1;

  MAX_PORT_NUM = 8;

 

type

  TForm1 = class(TForm)

    ApdComPort1: TApdComPort;

    Button1: TButton;

    Memo1: TMemo;

    procedure Button1Click(Sender: TObject);

  private

    { Private declarations }

  public

    { Public declarations }

  end;

 

var

  Form1: TForm1;

  OKTrig: Word;

  ModemFound: Boolean;

 

implementation

 

{$R *.DFM}

 

function CheckForPort(Port: TApdCustomComPort; PortNo: Integer): boolean;

begin

  Result := True;

  try

    Port.Open := False;

    DelayTicks(9,True);

    Port.ComNumber := PortNo;

    Port.Open := True;

    DelayTicks(9,True);

  except

    on E: EBadId do

      Result := False;

  end;

end;

 

procedure ModemTriggerHandler(Msg, wParam : Cardinal; lParam : Longint);

begin

  if (Msg = APW_TRIGGERDATA) and (wParam = OKTrig) then begin

    ModemFound := True;

    OKTrig := 0;

  end;

end;

 

function CheckForModem(Port: TApdCustomComPort; PortNo: Integer): boolean;

begin

  ModemFound := False;

  try

    Port.Open := False;

    DelayTicks(9,True);

    Port.ComNumber := PortNo;

    Port.Open := True;

    DelayTicks(9,True);

    Port.Dispatcher.RegisterProcTriggerHandler(ModemTriggerHandler);

    OKTrig := Port.AddDataTrigger('OK', True);

    Port.Output := 'AT'#13#10;

    DelayTicks(36,True);

  finally

    Result := ModemFound;

    if OKTrig = 0 then

      Port.RemoveTrigger(OKTrig);

    Port.Dispatcher.DeregisterProcTriggerHandler(ModemTriggerHandler);

  end;

end;

 

procedure TForm1.Button1Click(Sender: TObject);

var

  i: Integer;

begin

  i := MIN_PORT_NUM;

  while i <= MAX_PORT_NUM do

  begin

    if CheckForPort(ApdComPort1, i) then begin

      Memo1.Lines.Add('Opening COM' + IntToStr(i) + ':' + ' Successful!');

 

      if CheckForModem(ApdComPort1, i) then

        Memo1.Lines.Add('Modem Found on COM' + IntToStr(i) + ':' );

    end

    else

      Memo1.Lines.Add('Opening COM' + IntToStr(i) + ':' + ' Port Unavailable.');

 

    Inc(i);

  end;

  Memo1.Lines.Add('** Done Scanning **');

end;

 

end.


 

C++Builder:

 

Header:

 

//---------------------------------------------------------------------------

#include <vcl\Classes.hpp>

#include <vcl\Controls.hpp>

#include <vcl\StdCtrls.hpp>

#include <vcl\Forms.hpp>

#include "AdPort.hpp"

#include "OoMisc.hpp"

//---------------------------------------------------------------------------

#define MIN_PORT_NUM 1

#define MAX_PORT_NUM 8

//---------------------------------------------------------------------------

class TForm1 : public TForm

{

__published:  // IDE-managed Components

  TButton *Button1;

  TMemo *Memo1;

  TApdComPort *ApdComPort1;

  void __fastcall Button1Click(TObject *Sender);

private:      // User declarations

public:              // User declarations

  __fastcall TForm1(TComponent* Owner);

 

  Boolean  __fastcall CheckForPort(TApdCustomComPort* Port, int PortNo);

  Boolean  __fastcall CheckForModem(TApdCustomComPort* Port, int PortNo);

 

};

//---------------------------------------------------------------------------

extern TForm1 *Form1;

 

Word OKTrig;

Boolean ModemFound;

 

//---------------------------------------------------------------------------

#endif

 

Unit:

 

//---------------------------------------------------------------------------

#include <vcl\vcl.h>

#pragma hdrstop

 

#include "detprtub1.h"

//---------------------------------------------------------------------------

#pragma link "AdPort"

#pragma link "OoMisc"

#pragma resource "*.dfm"

TForm1 *Form1;

//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)

  : TForm(Owner)

{

}

//---------------------------------------------------------------------------

 

Boolean  __fastcall TForm1::CheckForPort(TApdCustomComPort* Port, int PortNo)

{

  try {

    Port->Open = FALSE;

    DelayTicks(9,True);

    Port->ComNumber = (Word)PortNo;

    Port->Open = True;

    DelayTicks(9,True);

  }

  catch (EBadId*) {

    return  False;

  }

  return True;

}

//---------------------------------------------------------------------------

void __fastcall ModemTriggerHandler(Cardinal Msg, Cardinal wParam, int lParam)

{

  if ((Msg == apw_TriggerData) && ((Word)wParam == OKTrig)) {

    ModemFound = True;

    OKTrig = 0;

  }

}

//---------------------------------------------------------------------------

Boolean  __fastcall TForm1::CheckForModem(TApdCustomComPort* Port, int PortNo)

{

  ModemFound = False;

  try {

    Port->Open = False;

    DelayTicks(9,True);

    Port->ComNumber = (Word)PortNo;

    Port->Open = True;

    DelayTicks(9,True);

    Port->Dispatcher->RegisterProcTriggerHandler(*ModemTriggerHandler);

    OKTrig = Port->AddDataTrigger("OK", True);

    Port->Output = "AT\x0D";

    DelayTicks(45,True);

  }

  catch (...) { // finally

 

    if OKTrig = 0 {

      Port->RemoveTrigger(OKTrig);

    }

    Port->Dispatcher->RegisterProcTriggerHandler(ModemTriggerHandler);

    return  ModemFound;

  }

  if OKTrig = 0 {

    Port->RemoveTrigger(OKTrig);

  }

  Port->Dispatcher->RegisterProcTriggerHandler(ModemTriggerHandler);

  return  ModemFound;

}

//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)

{

  for (int i = MIN_PORT_NUM; i < MAX_PORT_NUM; i++) {

    if (CheckForPort(ApdComPort1, i)) {

      Memo1->Lines->Add("Opening COM" + IntToStr(i) + ":" + " Successful!");

 

      if (CheckForModem(ApdComPort1, i))

        Memo1->Lines->Add("Modem Found on COM" + IntToStr(i) + ":" );

    }

    else

      Memo1->Lines->Add("Opening COM" + IntToStr(i) + ":" + " Unavailable.");

  }

  Memo1->Lines->Add("** Done Scanning **");

}

 

So, what’s going on here?  Basically all the project does is iterate through a set of Com Port numbers (set by the MIN_PORT_NUM and MAX_PORT_NUM constants), and display the results from the CheckForPort and CheckForModem routines.

Really all the CheckForPort routine does is attempt to open the specified port and returns whether or not it could, trapping for exceptions as described above in the introduction.

CheckForModem is a bit more complex; it makes use of the Trigger registration facilities of TApdComPort so that it gets itself notified when the modem responds with the traditional “OK” prompt, and simply opens the requested port, attempts sending “AT” plus a Carriage Return/Line Feed combination, and waits a bit for the Modem to respond.

This site is not affiliated, endorsed, or otherwise associated with the entity formerly known as TurboPower Software. The owners and maintainers of Aprozilla.com were merely meager employees of the aforementioned organization, providing this site out of the pure goodness of their collective hearts. SourceForge.net Logo

Last updated: July 22, 2003.