📄 cpftserial.cpp
字号:
/*____________________________________________________________________________
Copyright (C) 1996-1999 Network Associates, Inc.
All rights reserved.
$Id: CPFTSerial.cpp,v 1.5 1999/03/10 02:36:19 heller Exp $
____________________________________________________________________________*/
#include "StdAfx.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "CPFTSerial.h"
#include "CPFWindow.h"
#include "CStatusPane.h"
#include "PGPFone.h"
#include <mmsystem.h>
#ifdef _DEBUG
#define MODEM_ERROR(s, e) \
{ \
char str[100]; \
sprintf(str, "%s(%d{l})", (s), (e)); \
pgp_errstring(str); \
}
#else
#define MODEM_ERROR(s, e) (void)0 // do nothing
#endif // _DEBUG
CPFTSerial::CPFTSerial(SerialOptions *serOpt, CPFWindow *cpfWindow,
short *result)
: CPFTransport(cpfWindow)
{
COMMTIMEOUTS timeouts;
mPortHandle = INVALID_HANDLE_VALUE;
mRXevent = mTXevent = INVALID_HANDLE_VALUE;
mDataEvent = INVALID_HANDLE_VALUE;
*result = 0;
mAbort = FALSE;
pgp_memcpy(mPort, serOpt->port, 5);
pgp_memcpy(&mSerOpts, serOpt, sizeof(SerialOptions));
// open the port for reading and writing
mPortHandle = CreateFile(mPort, GENERIC_READ|GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, NULL);
if(mPortHandle == INVALID_HANDLE_VALUE)
{
*result = -1;
MODEM_ERROR("error opening port", GetLastError());
goto error;
}
// setup the input and output buffers
if(! SetupComm(mPortHandle, 4096, 4096))
{
*result = -2;
MODEM_ERROR("error creating input/output buffers", GetLastError());
goto error;
}
// setup the timeouts for reading and writing
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
if(! SetCommTimeouts(mPortHandle, &timeouts))
{
*result = -3;
MODEM_ERROR("error setting port timeouts", GetLastError());
goto error;
}
// create event objects for OVERLAPPED structures in reading and writing
mRXevent = CreateEvent(NULL, TRUE, FALSE, NULL);
if(mRXevent == INVALID_HANDLE_VALUE)
{
*result = -4;
MODEM_ERROR("error creating event for reading", GetLastError());
goto error;
}
mTXevent = CreateEvent(NULL, TRUE, FALSE, NULL);
if(mTXevent == INVALID_HANDLE_VALUE)
{
*result = -5;
MODEM_ERROR("error creating event for writing", GetLastError());
goto error;
}
mDataEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if(mDataEvent == INVALID_HANDLE_VALUE)
{
*result = -6;
MODEM_ERROR("error creating mDataEvent", GetLastError());
goto error;
}
SetState(_cs_none);
mInBack = mInFront = 0;
return;
error:
PGFAlert("Could not open serial port!", 0);
}
CPFTSerial::~CPFTSerial()
{
AbortSync();
mTMutex->Wait();
if(mState == _cs_connected)
Disconnect();
if(mPortHandle != INVALID_HANDLE_VALUE)
CloseHandle(mPortHandle);
if(mRXevent != INVALID_HANDLE_VALUE)
CloseHandle(mRXevent);
if(mTXevent != INVALID_HANDLE_VALUE)
CloseHandle(mTXevent);
if(mDataEvent != INVALID_HANDLE_VALUE)
CloseHandle(mDataEvent);
}
PGErr
CPFTSerial::Connect(ContactEntry *con, short *connectResult)
{
static char s[256], t[256], number[64];
short reply = _cr_NoReply, x;
short result=0;
char *p;
mTMutex->Wait();
SetState(_cs_connecting);
*connectResult = 0;
if(con->modemInit[0])
{
for (short retries = 3; reply != _cr_OK && retries; retries--)
{
Write("%s\r", con->modemInit);
reply = GetModemResult(1000*5);
}
if(reply != _cr_OK)
{
*connectResult = reply;
result = _pge_ModemNotAvail;
goto done;
}
}
if(con->useDialInfo)
{
x=0;
strcpy(t,con->phoneNumber);
for (p = t; *p && (x < 63); p++)
if((*p != ' ') && (*p != '-') && (*p != '(') && (*p != ')'))
number[x++] = *p;
number[x] = 0;
if(number[0] != gPGFOpts.dopt.dialInfo[gPGFOpts.dopt.curDialSet].areaCode[1] ||
number[1] != gPGFOpts.dopt.dialInfo[gPGFOpts.dopt.curDialSet].areaCode[2] ||
number[2] != gPGFOpts.dopt.dialInfo[gPGFOpts.dopt.curDialSet].areaCode[3])
x = 2;
else if(con->nonLocal)
x = 1;
else
x = 0;
strcpy(s, gPGFOpts.dopt.dialInfo[gPGFOpts.dopt.curDialSet].catBefore[x]);
strcat(s, number);
strcat(s, gPGFOpts.dopt.dialInfo[gPGFOpts.dopt.curDialSet].catAfter[x]);
}
else
strcpy(s, con->phoneNumber);
CStatusPane::GetStatusPane()->AddStatus(0, "Contacting %s", s);
strcpy(t, "ATD ");
t[3] = gPGFOpts.dopt.dialInfo[gPGFOpts.dopt.curDialSet].usePulseDial ? 'P' : 'T';
strcat(t, s);
Write("%s\r", t);
reply = GetModemResult(1000*80);
if(mAbort)
Write("\r");
*connectResult = reply;
if(reply != _cr_Connect)
{
if(gPGFOpts.dopt.dialInfo[gPGFOpts.dopt.curDialSet].redialDelay)
Sleep(gPGFOpts.dopt.dialInfo[gPGFOpts.dopt.curDialSet].redialDelay);
CStatusPane::GetStatusPane()->AddStatus(0, "Connection failed.");
SetState(_cs_none);
}
else
{
CStatusPane::GetStatusPane()->AddStatus(0, "Connected %s.", mConnectString);
SetState(_cs_connected);
}
done:
mTMutex->Signal();
return result;
}
#define CheckModemResponse(strP, num) \
if(!strP ## Str || ch!=*strP ## Str) strP ## Str=NULL; \
else if(!*++strP ## Str) response=num;
short
CPFTSerial::GetModemResult(long timeout)
{
char *okStr = NULL, *noCarrierStr = NULL, *noAnswerStr = NULL, *busyStr = NULL;
char *noDialtoneStr = NULL, *connectStr = NULL, *errorStr = NULL;
uchar *p, ch, count, i;
ulong outOfTime;
short response = _cr_Timeout, state = 0, csLen;
OVERLAPPED overlapped;
short handle_error_count = 0;
HANDLE handleArray[2] = {mAbortEvent, mDataEvent};
DWORD eventMask, result, timeToWait, error;
memset(&overlapped, 0, sizeof(overlapped));
ResetEvent(handleArray[1]);
overlapped.hEvent = handleArray[1];
outOfTime = pgp_getticks() + timeout;
while ((response == _cr_Timeout || state == 1) && !mAbort &&
(!timeout || pgp_getticks() < outOfTime))
{
// try and read some data from the modem
if(Read(NIL, 0, NIL) > 0)
{
if(mInFront > mInBack)
count = mInFront - mInBack;
else
count = -mInBack;
p = mInBuffer + mInBack;
if(!state)
{
for (i = 0; i < count && response == _cr_Timeout; i++, p++)
{
ch = (*p & 0x7F);
if((ch == '\r') || (ch == '\n'))
{
okStr = "OK";
noCarrierStr = "NO CARRIER";
noAnswerStr = "NO ANSWER";
busyStr = "BUSY";
noDialtoneStr = "NO DIAL";
connectStr = "CONNECT";
errorStr = "ERROR";
}
else
{
CheckModemResponse(connect, _cr_Connect);
CheckModemResponse(ok, _cr_OK);
CheckModemResponse(noCarrier, _cr_NoCarrier);
CheckModemResponse(noDialtone, _cr_NoDialTone);
CheckModemResponse(noAnswer, _cr_NoAnswer);
CheckModemResponse(busy, _cr_Busy);
CheckModemResponse(error, _cr_Error);
}
}
if(response == _cr_Connect)
{
state++;
csLen = 0;
goto getConSuffix;
}
}
else
{
i = 0;
getConSuffix:
for(;i<count && *p != '\r';i++,p++)
if(csLen<CONNECTSTRINGLEN-1)
mConnectString[csLen++]=*p;
if((*p=='\r') || (csLen==CONNECTSTRINGLEN-1))
{
mConnectString[csLen]=0;
state++;
}
}
mInBack += i;
}
else
{
// if we don't have any data in our buffer then we should setup to
// fall asleep until some comes in
if(! WaitCommEvent(mPortHandle, &eventMask, &overlapped) &&
(error = GetLastError()) != ERROR_IO_PENDING)
{
MODEM_ERROR("error setting up comm event", error);
response = _pge_InternalAbort;
break;
}
// make sure that some data didn't come in before WaitCommEvent()
// was called
if(Read(NIL, 0, NIL) > 0)
{
// flush the pending wait and reset the event for another call
SetCommMask(mPortHandle, EV_RXCHAR);
ResetEvent(handleArray[1]);
continue;
}
// figure out how long to wait.
if(!timeout)
timeToWait = INFINITE;
else
timeToWait = outOfTime - pgp_getticks();
WAIT_AGAIN: // wait for the first event that gets triggered.
result = WaitForMultipleObjects(2, handleArray, FALSE, timeToWait);
if(result == WAIT_OBJECT_0 || result == WAIT_TIMEOUT)
break; // we have to abort or we timed out
if(result != (WAIT_OBJECT_0+1))
{
int error = GetLastError();
if(error == ERROR_INVALID_HANDLE && handle_error_count++ < 50)
goto WAIT_AGAIN;
MODEM_ERROR("unknown result waiting on event", error);
response = _pge_InternalAbort;
break;
}
ResetEvent(handleArray[1]); // must have gotten data
}
}
// flush any pending calls to WaitCommMask
SetCommMask(mPortHandle, EV_RXCHAR);
return response;
}
short
CPFTSerial::Disconnect()
{
DCB dcb;
mTMutex->Wait();
SetState(_cs_disconnecting);
GetCommState(mPortHandle, &dcb);
// drop DTR...
dcb.fDtrControl = DTR_CONTROL_DISABLE;
SetCommState(mPortHandle, &dcb);
Sleep(250);
// ...and pick it up again
dcb.fDtrControl = DTR_CONTROL_ENABLE;
SetCommState(mPortHandle, &dcb);
Sleep(250);
mPFWindow->GetStatusPane()->AddStatus(0, "Disconnected.");
SetState(_cs_none);
mTMutex->Signal();
return 0;
}
short
CPFTSerial::WaitForRing()
{
char *ringStr = NULL;
uchar *p, ch, count, i;
short response = _cr_Timeout;
OVERLAPPED overlapped;
int handle_error_count = 0;
HANDLE handleArray[3] = {mAbortEvent, mAnswerEvent, mDataEvent};
DWORD eventMask, result, timeout, error;
long now;
memset(&overlapped, 0, sizeof(overlapped));
ResetEvent(handleArray[2]);
overlapped.hEvent = handleArray[2];
while (response == _cr_Timeout && !mAbort && !mAnswer)
{
// try to read some data
if(Read(NIL, 0, NIL) > 0)
{
if(mInFront > mInBack)
count = mInFront - mInBack;
else
count = -mInBack;
p = mInBuffer + mInBack;
for (i = 0; i < count && response == _cr_Timeout; i++)
{
ch = (*p & 0x7F);
if(ch == '\r' || ch == '\n')
ringStr = "RING";
else
CheckModemResponse(ring, _cr_Ring);
p++;
}
mInBack += i;
}
else
{
// if we don't have any data in our buffer then we should setup to
// fall asleep until some comes in
if(! WaitCommEvent(mPortHandle, &eventMask, &overlapped) &&
(error = GetLastError()) != ERROR_IO_PENDING)
{
MODEM_ERROR("error setting up comm event", error);
response = _pge_InternalAbort;
break;
}
// make sure that some data didn't come in before WaitCommEvent()
// was called
if(Read(NIL, 0, NIL) > 0)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -