📄 dial.c
字号:
// values mixed with default values.
wInitKey = 0;
while( (wInitKey < MAXINITKEYS) &&
(LineNotDropped(pLineDev, OrigDevState)) &&
(ERROR_SUCCESS == mdmRegRslt) )
{
dwSize = pLineDev->dwMaxCmd * SZWCHAR;
mdmRegRslt = MdmRegGetValue( pLineDev,
szInit,
szInitNum[wInitKey],
REG_SZ,
(PUCHAR)pszTemp,
&dwSize);
if (ERROR_SUCCESS == mdmRegRslt)
{
MdmConvertCommand(pszTemp, pchCmd, &dwCmdLen);
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemInit Init string %d - %s\r\n"),
wInitKey, pszTemp));
// Set short timeout for init strings
if( SetWatchdog( pLineDev, 8000 ) )
{
pLineDev->MdmState = MDMST_UNKNOWN;
goto init_error;
}
if (LineNotDropped(pLineDev, OrigDevState)) {
// We got a value, write it out to modem
MdmResp = MODEM_FAILURE;
if (MdmSendCommand( pLineDev, pchCmd )) {
if (LineNotDropped(pLineDev, OrigDevState)) {
MdmResp = MdmGetResponse( pLineDev, pchCmd, NOCS );
}
}
}
if( MODEM_SUCCESS != MdmResp )
{
// bad init string. We can't recover from this so exit
pLineDev->MdmState = MDMST_UNKNOWN;
goto init_error;
}
}
else
{
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:ModemInit Error x%X reading Init string %d\r\n"),
mdmRegRslt, wInitKey));
}
wInitKey++;
}
// And now that we have the basic init in place, we still need to
// make sure the flow control settings match what we are doing in
// the UART.
if( MDM_FLOWCONTROL_HARD & pLineDev->DevMiniCfg.dwModemOptions )
{ // Set Modem for hardware flow control
szFlowType = szFlowHard;
}
else if( MDM_FLOWCONTROL_SOFT & pLineDev->DevMiniCfg.dwModemOptions )
{ // Set Modem for software flow control
szFlowType = szFlowSoft;
}
else
{ // Set modem for no flow control
szFlowType = szFlowNone;
}
dwSize = pLineDev->dwMaxCmd * SZWCHAR;
if( ERROR_SUCCESS == MdmRegGetValue( pLineDev,
szSettings,
szFlowType,
REG_SZ,
(PUCHAR)pszTemp,
&dwSize) )
{
// OK, we got the flow control command, send it.
MdmConvertCommand(pszTemp, pchCmd, &dwCmdLen);
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemInit Flow Control string %s\r\n"),
pszTemp));
if (LineNotDropped(pLineDev, OrigDevState))
{
// We got a value, write it out to modem
MdmResp = MODEM_FAILURE;
if (MdmSendCommand( pLineDev, pchCmd )) {
if (LineNotDropped(pLineDev, OrigDevState)) {
MdmResp = MdmGetResponse( pLineDev, pchCmd, NOCS );
}
}
}
if( MODEM_SUCCESS != MdmResp )
{
// bad flow control string. We can't recover from this.
pLineDev->MdmState = MDMST_UNKNOWN;
goto init_error;
}
}
// Now we set up the call fail timer if it exists.
dwSize = pLineDev->dwMaxCmd * SZWCHAR;
if( ERROR_SUCCESS == MdmRegGetValue( pLineDev,
szSettings,
szCallFail,
REG_SZ,
(PUCHAR)pszTemp,
&dwSize) )
{
// OK, we got the Call Fail setup command, send it.
// Most modems can't handle a value > 255 for call fail time
// And a time of 0 usually really means wait the maximum
dwCallSetupFailTimer = pLineDev->DevMiniCfg.dwCallSetupFailTimer;
if( (dwCallSetupFailTimer > 255) ||
(dwCallSetupFailTimer == 0) )
dwCallSetupFailTimer = 255;
// Expand macros, including the fail time <#>
wcscpy(ModemMacro.MacroName, INTEGER_MACRO);
wsprintf(ModemMacro.MacroValue, TEXT("%d"), dwCallSetupFailTimer );
ExpandMacros(pszTemp, pszExpand, NULL, &ModemMacro, 1);
// We need to convert the UniCode to ASCII
dwCmdLen = wcslen(pszExpand) + 1;
dwCmdLen = wcstombs( pchCmd, pszExpand, dwCmdLen );
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemInit Call fail timer string %s\r\n"),
pszTemp));
if (LineNotDropped(pLineDev, OrigDevState))
{
// We got a value, write it out to modem
MdmResp = MODEM_FAILURE;
if (MdmSendCommand( pLineDev, pchCmd )) {
if (LineNotDropped(pLineDev, OrigDevState)) {
MdmResp = MdmGetResponse( pLineDev, pchCmd, NOCS );
}
}
}
if( MODEM_SUCCESS != MdmResp )
{
// Hmm, we could probably ignore this failure, but the call might
// never time out. Lets be safe and abort now.
pLineDev->MdmState = MDMST_UNKNOWN;
goto init_error;
}
}
// And finally, see if user requested any special modifier string
if( dwCmdLen = wcslen(pLineDev->DevMiniCfg.szDialModifier) )
{
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemInit Dial Modifier string %s\r\n"),
pLineDev->DevMiniCfg.szDialModifier));
// Convert the UniCode to ASCII, and insert 'AT' in command
pchCmd[0] = 'A';
pchCmd[1] = 'T';
dwCmdLen += 1;
dwCmdLen = wcstombs( pchCmd+2, pLineDev->DevMiniCfg.szDialModifier, dwCmdLen );
// OK, now don't forget the CR at end.
strcat( pchCmd, "\r" );
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemInit Generated Modifier string %a\r\n"),
pchCmd));
if (LineNotDropped(pLineDev, OrigDevState))
{
// And write this out to modem
MdmResp = MODEM_FAILURE;
if (MdmSendCommand( pLineDev, pchCmd )) {
if (LineNotDropped(pLineDev, OrigDevState)) {
MdmResp = MdmGetResponse( pLineDev, pchCmd, NOCS );
}
}
}
if( MODEM_SUCCESS != MdmResp )
{
// bad modifier string. We can't recover from this.
pLineDev->MdmState = MDMST_UNKNOWN;
DEBUGMSG(ZONE_CALLS | ZONE_ERROR,
(TEXT("UNIMODEM:ModemInit Bad user supplied dial modifier %s\r\n"),
pLineDev->DevMiniCfg.szDialModifier));
goto init_error;
}
}
}
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Most likely a bad handle. Just give up
pLineDev->MdmState = MDMST_UNKNOWN;
}
init_error:
// Cancel watchdog if he's still around.
SetWatchdog( pLineDev, 0 );
if( pszTemp )
TSPIFree( pszTemp );
if( pchCmd )
TSPIFree( pchCmd );
if( pszExpand )
TSPIFree( pszExpand );
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM: -ModemInit %s\n"),
(pLineDev->MdmState == MDMST_UNKNOWN) ? TEXT("FAILED"): TEXT("OK")));
return (pLineDev->MdmState == MDMST_UNKNOWN) ? FALSE : TRUE;
} // ModemInit
#define NUM_BAUD_RATES 9
DWORD
NextBaudRate(
DWORD dwBaudRate
)
{
switch (dwBaudRate) {
case CBR_19200: return CBR_57600;
case CBR_57600: return CBR_115200;
case CBR_115200: return CBR_38400;
case CBR_38400: return CBR_56000;
case CBR_56000: return CBR_128000;
case CBR_128000: return CBR_256000;
case CBR_256000: return CBR_9600;
case CBR_9600: return CBR_14400;
case CBR_14400: return CBR_19200;
}
return CBR_19200;
}
//
// Called to set the baud rate for a NULL MODEM device.
//
BOOL
AutoBaudRate(
PTLINEDEV pLineDev,
DWORD dwBaudRate
)
{
DCB commDCB;
DWORD status;
DWORD Retry;
DWORD dwCurBaud;
Sleep(200);
if (!EscapeCommFunction ( pLineDev->hDevice, CLRDTR)) {
status = GetLastError();
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:AutoBaudRate EscapeCommFunction(CLRDTR) failed %d\n"), status));
return FALSE;
}
Sleep(400);
if (!GetCommState(pLineDev->hDevice, &commDCB)) {
status = GetLastError();
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:AutoBaudRate GetCommState failed %d\n"), status));
return FALSE;
}
Retry = 0;
if (dwBaudRate) {
dwCurBaud = dwBaudRate;
} else {
abr_next:
dwCurBaud = NextBaudRate(pLineDev->dwCurrentBaudRate);
}
pLineDev->dwCurrentBaudRate = commDCB.BaudRate = dwCurBaud;
if (!PurgeComm(pLineDev->hDevice, PURGE_TXCLEAR|PURGE_RXCLEAR)) {
status = GetLastError();
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:AutoBaudRate PurgeComm failed %d\r\n"), status));
}
if (!SetCommState(pLineDev->hDevice, &commDCB)) {
status = GetLastError();
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:AutoBaudRate SetCommState(baud = %d) failed %d\n"),
commDCB.BaudRate, status));
//
// If SetCommState fails with inval parm, assume the error was an unsupported baud rate
// and try the next one.
//
if (status == ERROR_INVALID_PARAMETER) {
Retry++;
if (Retry < NUM_BAUD_RATES) {
goto abr_next;
}
}
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:AutoBaudRate failed.\n")));
return FALSE;
}
if (!EscapeCommFunction ( pLineDev->hDevice, SETDTR)) {
status = GetLastError();
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:AutoBaudRate EscapeCommFunction(SETDTR) failed %d\n"), status));
return FALSE;
}
Sleep(200);
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:AutoBaudRate trying %d\n"), commDCB.BaudRate));
return TRUE;
} // AutoBaudRate
BOOL
CallNotDropped(
PTLINEDEV pLineDev
)
{
switch (pLineDev->dwCallState) {
case LINECALLSTATE_CONNECTED:
case LINECALLSTATE_DIALING:
case LINECALLSTATE_DIALTONE:
case LINECALLSTATE_PROCEEDING:
case LINECALLSTATE_UNKNOWN:
return TRUE;
}
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:CallNotDropped call state = %x\n"), pLineDev->dwCallState));
return FALSE;
}
// **********************************************************************
//
// This is the dialer thread. It is created whenever we decide to
// dial a modem, and exists until the call completes or is terminated.
//
// **********************************************************************
void
Dialer(
PTLINEDEV pLineDev
)
{
DCB commDCB;
MODEMRESPCODES MdmResp;
BOOL fOriginate;
BOOL bFirstResp;
PWCHAR pszzDialCommands = NULL; // strings of dial strings returned from CreateDialCommand
PWCHAR ptchDialCmd;
PCHAR pchDialCmd = NULL;
DWORD dwDialLen;
DWORD LineCallState;
DWORD LineCallStateParm2;
DWORD LineError; // Indicates asynchronous return code for LineMakeCall completion
DWORD dwCallFailTimer;
BOOL bKeepLooping;
DEBUGMSG(ZONE_FUNC|ZONE_CALLS,
(TEXT("UNIMODEM:Dialer - dial options x%X (x%X), modem options x%X\r\n"),
pLineDev->dwDialOptions, pLineDev->DevMiniCfg.fwOptions, pLineDev->DevMiniCfg.dwModemOptions));
dwCallFailTimer = pLineDev->DevMiniCfg.dwCallSetupFailTimer;
LineCallStateParm2 = LINEDISCONNECTMODE_NORMAL;
LineError = LINEERR_OPERATIONFAILED;
bFirstResp = TRUE;
if( (dwCallFailTimer == 0) ||
(dwCallFailTimer > 512) )
dwCallFailTimer = 512;
// Clear any old CallComplete events before starting a new call
WaitForSingleObject(pLineDev->hCallComplete, 0);
pLineDev->dwCallState = LineCallState = LINECALLSTATE_UNKNOWN;
try
{
// Disable HW flow control while we try to connect.
// Otherwise, our xmit may get stuck in a flowed-off state and
// then we cannot send.
GetCommState( pLineDev->hDevice, &commDCB );
commDCB.fRtsControl = RTS_CONTROL_ENABLE;
commDCB.fOutxCtsFlow = 0;
SetCommState( pLineDev->hDevice, &commDCB );
// Our job is to dial the modem, and then sit here waiting for
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -