📄 adsmodem.pas
字号:
property NoDialToneMsg : String
read FNoDialToneMsg write FNoDialToneMsg;
property OkMsg : String
read FOkMsg write FOkMsg;
property RingMsg : String
read FRingMsg write FRingMsg;
property AnswerTimeout : Cardinal
read FAnswerTimeout write FAnswerTimeout default adsmDefAnswerTimeout;
property CmdTimeout : Cardinal
read FCmdTimeout write FCmdTimeout default adsmDefCmdTimeout;
property ConnectInfoTimeout : Cardinal
read FConnectInfoTimeout write FConnectInfoTimeout
default adsmDefConnectInfoTimeout;
property DialTimeout : Cardinal
read FDialTimeout write FDialTimeout default adsmDefDialTimeout;
property RingWaitTimeout : Cardinal
read FRingWaitTimeout write FRingWaitTimeout
default adsmDefRingWaitTimeout;
property DTRDropHoldDelay : Cardinal
read FDTRDropHoldDelay write FDTRDropHoldDelay
default adsmDefDTRDropHoldDelay;
property InterCharDelay : Cardinal
read FInterCharDelay write FInterCharDelay default adsmDefInterCharDelay;
property InterCmdDelay : Cardinal
read FInterCmdDelay write FInterCmdDelay default adsmDefInterCmdDelay;
property TildeDelay : Cardinal
read FTildeDelay write FTildeDelay default adsmDefTildeDelay;
property AutoRetryDial : Boolean
read FAutoRetryDial write FAutoRetryDial default adsmDefAutoRetryDial;
property ConnectSpeed : Cardinal
read FConnectSpeed;
property DialAttempt : Cardinal
read FDialAttempt;
property ExtendTime : Cardinal
read FExtendTime write FExtendTime;
property ForceHangup : Boolean
read FForceHangup write FForceHangup default adsmDefForceHangup;
property LockDTE : Boolean
read FLockDTE write FLockDTE;
property MaxDialAttempts : Cardinal
read FMaxDialAttempts write FMaxDialAttempts;
property PreferredPortSpeed : Cardinal
read FPreferredPortSpeed write FPreferredPortSpeed;
property RetryWaitTime : Cardinal
read FRetryWaitTime write FRetryWaitTime;
property ShowStatus : Boolean
read FShowStatus write FShowStatus default adsmDefShowStatus;
property ModemState : TApdSModemStates
read FModemState write SetModemState;
property ModemStateFlags : Cardinal
read FModemStateFlags write FModemStateFlags;
property OnConnectionStatus : TApdSModemEvent
read FConnectionStatus write FConnectionStatus;
procedure Answer;
{Answer the modem immediately -- not documented}
procedure AutoAnswer(RingCount : Byte);
{Tell modem to auto answer on Nth ring}
procedure Cancel;
{Cancel current modem operation (e.g., dialing)}
procedure Dial(AutoRetry : Boolean);
{Attempt connection}
procedure ExtendConnectTime(ExtraSeconds : Integer);
{Extend the timer for the current connect attempt}
procedure Hangup;
{Break modem connection}
procedure Initialize;
{Return modem to known state}
procedure PutStringModem(ModemString : String);
{Send the string to the modem}
procedure Redial;
{Cause an immediate redial}
end;
TApdSModem = class(TApdCustomSModem)
protected
FModemIniName : String;
FModemName : String;
public
constructor Create(AOwner : TComponent); override;
procedure ModifyInitCommand;
function SelectModem: Boolean;
procedure SetAllDefaults; override;
procedure SetModemIniName(NewIniFileName : String); virtual;
procedure SetModemName(ModemName : String); virtual;
published
property ComPort;
property ModemIniName : String
read FModemIniName write SetModemIniName;
property ModemName : String
read FModemName write SetModemName;
property PhoneNumber;
property ShowStatus;
property OnConnectionStatus;
end;
TApdSModemStatusDisplay = class(TForm)
msGroupBox1: TGroupBox;
msAction: TLabel;
msActionInfo: TLabel;
msInfo1: TLabel;
msInfo2: TLabel;
msInfo3: TLabel;
msInfo4: TLabel;
msValue1: TLabel;
msValue2: TLabel;
msValue3: TLabel;
msValue4: TLabel;
msGroupBox2: TGroupBox;
msMessages: TMemo;
msButtonExtend: TButton;
msButtonCycle: TButton;
msButtonCancel: TButton;
procedure msButtonExtendClick(Sender: TObject);
procedure msButtonCycleClick(Sender: TObject);
procedure msButtonCancelClick(Sender: TObject);
procedure msEraseAllValues;
private
{ Private declarations }
msdCurrentRow : Integer;
protected
procedure UpdateDisplay(ModemStatus : TApdSModemStatusInfo);
public
{ Public declarations }
SModem : TApdCustomSModem;
end;
procedure GetModemDatabaseEntries(ModemIniName : String;
var ModemList : TStringList; AtDesignTime : Boolean);
const
{character used to delimit responses when combined in one string}
MultiResponseSeparator : Char = '|';
MultiCmdSeparator : Char = '|';
SModemDataPtrID = 5;
implementation
{Status display form}
{$R *.DFM}
const
IgnoreCase = True;
{- TApdSModem State Machine -------------------------------}
procedure TApdCustomSModem.SimpleModemStateMachine(Msg, wParam : Cardinal;
lParam : Longint);
{- Handle data flow to and from the simple modem component}
const
msAvailTrigger = $FFFF; {simulate a handle for an avail trigger}
var
TriggerID : Cardinal absolute wParam;
Finished : Boolean;
function CollectResponse : Boolean;
{- Check for text responses}
var
c : Char;
begin
{Collect characters until CR/LF}
Finished := False;
CollectResponse := False;
while ComPort.CharReady and not Finished do begin
c := ComPort.getChar;
msModemResponse := msModemResponse + c;
if ComPort.CheckForString(msCRLFIndex, c, #13#10, True) then begin
msModemResponse := Trim(msModemResponse);
if (msModemResponse <> '') then begin
{Got a text response}
Finished := True;
CollectResponse := True;
{Add completed message to connect response buffer}
if Length(msConnectResponses) + Length(msModemResponse) < 255 then
msConnectResponses := msConnectResponses + msModemResponse;
{All error responses are aborts}
if msResponseIsError then
SetModemState(smsAbort);
end;
end;
end;
end;
begin
{Find which modem instance we are working with}
{Dispatcher := TApdBaseDispatcher(PortList[LH(lParam).H]);
with Dispatcher do begin
Dispatcher.GetDataPointer(Pointer(SModem), SModemDataPtrID);}
with {SModem, }FComPort do begin
{If it's a TriggerAvail message, then force the TriggerID to msAvailTrigger}
if (Msg = APW_TRIGGERAVAIL) then
TriggerID := msAvailTrigger;
{Exit immediately on triggers that aren't ours}
if (TriggerID <> msAvailTrigger) and
(TriggerID <> msTimeoutTrigger) and
(TriggerID <> msModemStatusTrigger) and
(TriggerID <> msUpdateStatusTrigger) then
Exit;
{Exit when in connected state unless the DCD status trigger fired}
if (FModemState = smsConnected) and
(TriggerID <> msModemStatusTrigger) then
Exit;
{Process until we encounter a wait condition}
repeat
{Show status periodically}
if (TriggerID = msUpdateStatusTrigger) or msForceUpdateStatus then begin
msForceUpdateStatus := False;
RefreshModemStatus;
SetTimerTrigger(msUpdateStatusTrigger,
Secs2Ticks(FUpdateStatusTime), True);
{If it was just our timer for a status update, we're done}
if (TriggerID = msUpdateStatusTrigger) then
Exit;
end;
{Preprocess pending modem responses while in certain states}
case FModemState of
smsAutoAnswerBackground,
smsAutoAnswerWait,
smsAnswerWait,
smsDialWait,
smsConnectWait :
begin
if (TriggerID = msAvailTrigger) and (not CollectResponse) then
{Entire message not ready, exit until more received}
Exit;
end;
end;
{Process the current modem state}
case FModemState of
smsReady,
smsUnknown :
{Nothing to do...exit}
Exit;
smsAutoAnswerBackground,
smsAutoAnswerWait :
begin
{If message received was RingMsg then we need to increment
the ring received count. If RingRecvCount = RingToAnswerOn,
then we need to clear the RingWaitTimeout timer, send AnswerCmd,
set a connect timer, prepare for a response, and change to
AnswerWait state. If not enough rings have been received, then
we need to set a timer for RingWaitTimeout and we are done.
}
if (FModemState = smsAutoAnswerBackground) then begin
{Show status when first ring is detected}
if (TriggerID = msAvailTrigger) then
SetModemState(smsAutoAnswerWait);
Exit;
end;
if (TriggerID = msAvailTrigger) then begin
if msResponseIsRing then begin
inc(msRingReceiveCount);
if (msRingReceiveCount = FAnswerOnRing) then begin
msPrepareForAnswerResponse;
PutStringModem(FAnswerCmd);
SetModemState(smsAnswerWait);
end else begin
{Not enough rings received yet; set timer for next ring}
Dispatcher.SetTimerTrigger(msTimeoutTrigger,
FRingWaitTimeout, True);
end;
end else
msPrepareForAutoAnswerResponse;
end else if (TriggerID = msTimeoutTrigger) then begin
{Didn't receive next ring within specified time, so reset count}
{Log the fact that we received rings but didn't answer}
msRingReceiveCount := 0;
{Modem state stays as AutoAnswerWait}
end;
end;
smsAnswerWait :
begin
{We're in the process of answering and waiting for ConnectMsg
to be received. Other possible messages to watch for include
NoCarrier.
}
if (TriggerID = msAvailTrigger) then begin
if msResponseIsConnect then begin
{Set a timer to watch for optional data (e.g., data comp.)}
Dispatcher.SetTimerTrigger(msTimeoutTrigger,
FConnectInfoTimeout, True);
SetModemState(smsConnectWait);
end else if msResponseIsNoCarrier then begin
{Didn't get a connect}
SetModemState(smsReady);
end else begin
{Got something else we didn't expect, ignore it}
end;
end else if (TriggerID = msTimeoutTrigger) then begin
{Didn't get a connect}
SetModemState(smsReady);
end;
end;
smsDialWait :
begin
{We're in the process of dialing a call. We could arrive here
if we receive any of the following -- NoCarrierMsg,
NoDialToneMsg, ConnectMsg, or timeout while waiting for data.
}
if (TriggerID = msAvailTrigger) then begin
if msResponseIsConnect then begin
{Set a timer to watch for optional data (e.g., data comp.)}
msPrepareForConnectInfoResponse;
SetModemState(smsConnectWait);
end else if msResponseIsNoCarrier or
msResponseIsBusy then begin
{If we're in auto-retry mode, set a timer for the retry delay}
if AutoRetryDial then begin
Dispatcher.SetTimerTrigger(msTimeoutTrigger,
Secs2Ticks(FRetryWaitTime), True);
SetModemState(smsDialCycle);
Exit;
end else begin
SetModemState(smsReady);
end;
end else if msResponseIsNoDialTone then begin
FStatusDisplay.UpdateDisplay(FStatusInfo);
Dispatcher.SetTimerTrigger(msTimeoutTrigger, 0, False);
SetModemState(smsNoDialTone);
{ one-time status, return to smsReady }
SetModemState(smsReady);
end else
{It wasn't a response we were looking for}
msPrepareForDialResponse;
end else if (TriggerID = msTimeoutTrigger) then begin
{Didn't get a connect, so send the cancel command (and cycle?)}
PutStringModem(FDialCancelCmd);
if AutoRetryDial and
(FDialAttempt < FMaxDialAttempts) then begin {!!.01}
Dispatcher.SetTimerTrigger(msTimeoutTrigger,
Secs2Ticks(FRetryWaitTime), True);
SetModemState(smsDialCycle);
Exit;
end else
SetModemState(smsReady);
end;
end;
smsDialCycle :
begin
if (TriggerID = msTimeoutTrigger) then begin
PutStringModem(FDialCmd + ' ' + FPhoneNumber + FDialTerminatorCmd);
inc(FDialAttempt);
msPrepareForDialResponse;
SetModemState(smsDialWait);
end;
Exit; {!!.01}
end;
smsConnectWait :
begin
{We received a connect message already; now we're waiting for
optional connect data (e.g., data compression messages) or
a timeout if no other connect information is sent.}
if (TriggerID = msAvailTrigger) then begin
{Got optional connect info or other end sent data very quickly}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -