📄 dial.c
字号:
dwDCCLen = strlen(pchDCC);
if( ModemResponse[ModemResponseIndex] == pchDCC[ModemResponseIndex] )
{
ModemResponseIndex++;
// characters match so far, see if we have a complete response.
if( ModemResponseIndex >= dwDCCLen )
{
// OK, we got a full response. Zero terminate it and exit
ModemResponse[ModemResponseIndex] = 0;
// No need to call response handler, we already did all the work.
ModemResp = DCCResp;
DEBUGMSG (ZONE_CALLS, (TEXT("UNIMODEM:MdmGetResponse Null Response detected\r\n")));
break;
}
}
else // character mismatch - restart scan sequence.
{
// If character is 'C', it might be first character of the actual
// response. Any other case means that all data up to here is useless
// so we should toss it. This is only true because 'C' appears only as
// the first character of a response, and never after that.
ModemResponseIndex = 0;
if (pchDCC[0] == InBuf[i])
{
ModemResponse[ModemResponseIndex] = InBuf[i];
ModemResponseIndex++;
}
}
}
else
{
if( (CR == InBuf[i]) ||
(LF == InBuf[i]) ||
((DWORD)i == dwLen-1) ||
((pLineDev->dwMaxCmd - 1) <= ModemResponseIndex) )
{
// have a complete response (or max length). Now we parse it.
ModemResponse[ModemResponseIndex] = 0; // Lets Zero Terminate the string
ModemResp = ModemResponseHandler( pLineDev, ModemResponse, pszCommand );
switch (ModemResp) {
case MODEM_CARRIER:
ParseConnectSpeed(pLineDev, ModemResponse);
// fall through!!!
case MODEM_PROTOCOL:
case MODEM_PROGRESS:
NewCallState(pLineDev, LINECALLSTATE_PROCEEDING, 0L);
if (i < (int)(dwLen - 1)) {
ModemResponseIndex = 0; // Start a new response
ModemResp = MODEM_IGNORE;
}
break;
case MODEM_UNKNOWN:
case MODEM_IGNORE:
ModemResponseIndex = 0; // Start a new response
ModemResp = MODEM_IGNORE;
break;
case MODEM_CONNECT:
ParseConnectSpeed(pLineDev, ModemResponse);
// fall through
default:
goto mgr_exit;
}
ModemResponseIndex = 0; // Start a new response
}
else
{
ModemResponseIndex++; //Add another character to the string
}
}
}
}
}
else
{
// A zero ModemStat is an error, and indicates that the
// waitcommevent was stopped by our watchdog or linedrop.
ModemResp = MODEM_FAILURE;
DEBUGMSG (ZONE_CALLS, (TEXT("UNIMODEM:MdmGetResponse - Timeout\r\n")));
goto mgr_exit;
}
DEBUGMSG(ZONE_FUNC|ZONE_CALLS, (TEXT("UNIMODEM:MdmGetResponse %s\n"), ResponseName(ModemResp)));
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Must have been a bad handle. Give up
ModemResp = MODEM_FAILURE;
DEBUGMSG (ZONE_FUNC|ZONE_CALLS,
(TEXT("UNIMODEM:MdmGetResponse - Exception. Handle \r\n"),
pLineDev->hDevice ));
}
}
mgr_exit:
if (bInCS) {
LeaveCriticalSection(&pLineDev->OpenCS);
}
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-MdmGetResponse %s\r\n"), ResponseName(ModemResp)));
return ModemResp;
}
//
// There were cases where the ModemWatchdog thread would not make it to the WaitForSingleObject
// before the next SetWatchdog happened. This would leave two or more watchdogs runnning at the
// same time which leads to all kinds of problems. Now SetWatchdog passes a UNIMODEM_WATCHDOG_INFO
// structure to the thread and the watchdog checks that it is the current one before aborting
// any pending operations.
//
typedef struct _UNIMODEM_WATCHDOG_INFO {
PTLINEDEV pLineDev;
DWORD dwTimeout;
DWORD dwThisWatchdog;
} UNIMODEM_WATCHDOG_INFO, * PUNIMODEM_WATCHDOG_INFO;
// **********************************************************************
//
// This is the dialer/answer watchdog thread. It is created by the dialer thread.
// Its purpose is to wait for a specified interval, or until signalled by
// the dialer. If the wait times out, then the watchdog calls into the
// COM port driver, causing the waitcommevent in the dialer thread to
// return.
//
// **********************************************************************
void
ModemWatchdog(
PUNIMODEM_WATCHDOG_INFO pWDInfo
)
{
DWORD RetCode;
BOOL bAbort;
PTLINEDEV pLineDev;
DWORD dwTimeout;
DWORD dwThisWatchdog;
pLineDev = pWDInfo->pLineDev;
dwTimeout = pWDInfo->dwTimeout;
dwThisWatchdog = pWDInfo->dwThisWatchdog;
TSPIFree(pWDInfo);
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:+ModemWatchdog(%d) - timeout set to %d seconds\r\n"),
dwThisWatchdog, dwTimeout/1000));
// Wait for the specified interval.
RetCode = WaitForSingleObject( pLineDev->hTimeoutEvent, dwTimeout );
if ((dwThisWatchdog == pLineDev->dwCurWatchdog) && ( WAIT_TIMEOUT == RetCode )) {
pLineDev->bWatchdogTimedOut = TRUE;
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemWatchdog(%d) *** %s TIMEOUT!\n"),
dwThisWatchdog, GetPendingName(pLineDev->dwPendingType)));
// We need to stop the waitcommevent. Note that we set the
// mask to 0, which will cause any subsequent waitcommevent
// calls to also return immediately.
ToggleCommMask(pLineDev);
switch (pLineDev->dwPendingType) {
case PENDING_LINEMAKECALL:
//
// Allow an in progress DCC lineMakeCall to retry
//
bAbort = !(IS_NULL_MODEM(pLineDev));
break;
case PENDING_LINEANSWER:
NewCallState(pLineDev, LINECALLSTATE_DISCONNECTED, LINEDISCONNECTMODE_UNKNOWN);
NewCallState(pLineDev, LINECALLSTATE_IDLE, 0L);
bAbort = TRUE;
break;
case PENDING_LINEDIAL:
case PENDING_LINEDROP:
bAbort = TRUE;
break;
default:
bAbort = FALSE;
break;
}
// We set an event when we are done so that DevLineDrop can
// continue with his cleanup.
if (bAbort) {
SetEvent(pLineDev->hCallComplete);
SetAsyncStatus(pLineDev, LINEERR_OPERATIONFAILED);
}
}
#ifdef DEBUG
else {
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemWatchdog(%d) cancelled\r\n"), dwThisWatchdog));
}
#endif
// This is a one shot timeout. The thread should go away as
// soon as the timer expires or is signalled/cancelled.
}
// **********************************************************************
// Wrapper function to start the watchdog.
// Note that a timeout of 0 cancels the current watchdog.
// **********************************************************************
DWORD
SetWatchdog(
PTLINEDEV pLineDev,
DWORD dwTimeout
)
{
HANDLE hThread;
PUNIMODEM_WATCHDOG_INFO pWDInfo;
pLineDev->dwCurWatchdog++;
pLineDev->bWatchdogTimedOut = FALSE;
// First, lets cancel any current outstanding watchdogs for this line
PulseEvent(pLineDev->hTimeoutEvent); // Stop the watchdog
// And now, start a new watchdog if they want us to
if( dwTimeout ) {
pWDInfo = TSPIAlloc(sizeof(UNIMODEM_WATCHDOG_INFO));
if (NULL == pWDInfo) {
NKDbgPrintfW( TEXT("UNIMODEM:SetWatchDog Unable to alloc Watchdog info\n") );
return (DWORD)-1;
}
pWDInfo->pLineDev = pLineDev;
pWDInfo->dwTimeout = dwTimeout;
pWDInfo->dwThisWatchdog = pLineDev->dwCurWatchdog;
hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)ModemWatchdog,
pWDInfo, 0, NULL );
if ( ! hThread ) {
TSPIFree(pWDInfo);
NKDbgPrintfW( TEXT("UNIMODEM:SetWatchDog Unable to Create Watchdog Thread\n") );
return (DWORD)-1;
}
CeSetThreadPriority(hThread, g_dwUnimodemThreadPriority);
CloseHandle( hThread );
}
return STATUS_SUCCESS;
}
BOOL
ModemInit(
PTLINEDEV pLineDev
)
{
MODEMRESPCODES MdmResp = MODEM_FAILURE;
DWORD dwSize, dwCmdLen;
int RetryCount = 0;
PWCHAR pszTemp = NULL;
PWCHAR pszExpand = NULL;
PCHAR pchCmd = NULL;
MODEMMACRO ModemMacro;
DWORD dwCallSetupFailTimer;
DEVSTATES OrigDevState;
static const WCHAR szReset[] = TEXT("Reset");
static const WCHAR szFlowHard[] = TEXT("FlowHard");
static const WCHAR szFlowSoft[] = TEXT("FlowSoft");
static const WCHAR szFlowNone[] = TEXT("FlowOff");
static const WCHAR *szFlowType; // Hard, Soft, None
static const WCHAR szCallFail[] = TEXT("CallSetupFailTimeout");
static const UCHAR szEscapeCmd[] = "+++";
OrigDevState = pLineDev->DevState;
try
{
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+ModemInit\r\n")));
// Allocate temp buffers for registry results
pszTemp = (PWCHAR)TSPIAlloc( (pLineDev->dwMaxCmd + 1) * SZWCHAR );
pszExpand = (PWCHAR)TSPIAlloc( (pLineDev->dwMaxCmd + 1) * SZWCHAR );
pchCmd = (PCHAR)TSPIAlloc( pLineDev->dwMaxCmd + 1 );
// First, read the reset command from the registry
dwSize = pLineDev->dwMaxCmd * SZWCHAR;
if (ERROR_SUCCESS !=
MdmRegGetValue( pLineDev,
szSettings,
szReset,
REG_SZ,
(PUCHAR)pszTemp,
&dwSize) )
{
goto init_error;
}
MdmConvertCommand(pszTemp, pchCmd, &dwCmdLen);
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemInit Reset string is \"%s\" (%d)\r\n"),
pszTemp, dwCmdLen));
// ***** reset modem by clearing DTR
if(LineNotDropped(pLineDev, OrigDevState))
{
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemInit SetCommState - DTR off\r\n")));
EscapeCommFunction ( pLineDev->hDevice, CLRDTR);
Sleep( 400 );
}
if(LineNotDropped(pLineDev, OrigDevState))
{
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemInit SetCommState - DTR on\r\n")));
EscapeCommFunction ( pLineDev->hDevice, SETDTR);
Sleep( 200 );
}
// No matter what the state was, we are now initializing
pLineDev->MdmState = MDMST_INITIALIZING;
while( (LineNotDropped(pLineDev, OrigDevState)) &&
(RetryCount < MAX_COMMAND_TRIES) )
{
// Set short timeout for init strings
if( SetWatchdog( pLineDev, 8000 ) )
{
pLineDev->MdmState = MDMST_UNKNOWN;
goto init_error;
}
if( LineNotDropped(pLineDev, OrigDevState) )
{
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemInit Send Init\r\n")));
MdmResp = MODEM_FAILURE;
if (MdmSendCommand( pLineDev, pchCmd )) {
MdmResp = MdmGetResponse( pLineDev, pchCmd, NOCS );
}
}
// See if we managed to get initialized
if( MODEM_SUCCESS == MdmResp )
{
pLineDev->MdmState = MDMST_DISCONNECTED; // It worked
break;
}
else
{
if( LineNotDropped(pLineDev, OrigDevState) )
{
// the modem didn't reset
pLineDev->MdmState = MDMST_UNKNOWN;
// If szReset didn't work, we likely need a +++
MdmSendCommand( pLineDev, szEscapeCmd );
Sleep( 200 );
}
}
RetryCount++;
}
if( (MDMST_DISCONNECTED == pLineDev->MdmState) &&
(LineNotDropped(pLineDev, OrigDevState)) )
{
DWORD mdmRegRslt = ERROR_SUCCESS;
WORD wInitKey;
// read a sequence of additional init strings from the
// registry and send them down now. Can't enumerate the
// keys since that wouldn't allow us to have modem specific
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -