📄 modem.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
// ****************************************************************************
//
// Module: Unimdm
// File: modem.c
//
//
// Revision History
//
// Description: Intermediate modem SPI layer
//
// ****************************************************************************
#include "windows.h"
#include "types.h"
#include "memory.h"
#include "tspi.h"
#include "linklist.h"
#include "tspip.h"
#include "tapicomn.h"
#include "mcx.h"
#include "dial.h"
static const WCHAR szAnswer[] = TEXT("Answer"); // Registry value name under Settings
static const CHAR szDefaultAnswerCmd[] = "ATA\r\n";
static const WCHAR szAnswerTimeout[] = TEXT("AnswerTimeout");
static const WCHAR szMonitor[] = TEXT("Monitor"); // Registry value name under Settings
static const CHAR szDefaultMonitorCmd[] = "ATS0=0\r\n";
static const WCHAR szMdmLogBase[] = TEXT("mdmlog");
static const WCHAR szMdmLogExt[] = TEXT(".txt");
extern const WCHAR szSettings[];
extern DWORD SetWatchdog(PTLINEDEV pLineDev,DWORD dwTimeout);
LONG ProcessModemFailure(PTLINEDEV pLineDev);
// Unimodem thread priority
extern DWORD g_dwUnimodemThreadPriority;
extern HANDLE g_hCoreDLL;
#ifdef DEBUG
LPWSTR
GetPendingName(
DWORD dwPendingType
)
{
LPWSTR lpszType;
switch (dwPendingType) {
case PENDING_LINEACCEPT: lpszType = TEXT("LINEACCEPT"); break;
case PENDING_LINEANSWER: lpszType = TEXT("LINEANSWER"); break;
case PENDING_LINEDEVSPECIFIC: lpszType = TEXT("LINEDEVSPECIFIC"); break;
case PENDING_LINEDIAL: lpszType = TEXT("LINEDIAL"); break;
case PENDING_LINEDROP: lpszType = TEXT("LINEDROP"); break;
case PENDING_LINEMAKECALL: lpszType = TEXT("LINEMAKECALL"); break;
case PENDING_LISTEN: lpszType = TEXT("LISTEN"); break;
case PENDING_EXIT: lpszType = TEXT("EXIT"); break;
case INVALID_PENDINGOP: lpszType = TEXT("INVALIDOP"); break;
default: lpszType = TEXT("UNKNOWN!!!"); break;
}
return lpszType;
}
#endif
#define MDMLOGNAME_CHARS 32
//
// Function to open the modem command log file for the specified line device
//
void
OpenModemLog(
PTLINEDEV pLineDev
)
{
WCHAR FileName[MDMLOGNAME_CHARS];
HANDLE hFile;
if (pLineDev->bMdmLogFile == FALSE) {
return;
}
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+OpenModemLog\n")));
if (pLineDev->hMdmLog != (HANDLE)INVALID_DEVICE) {
CloseHandle(pLineDev->hMdmLog);
}
//
// Format modem log file name "mdmlog<dwDeviceID>.txt"
//
StringCchPrintfW(FileName, MDMLOGNAME_CHARS, L"%s%d.%s", szMdmLogBase, pLineDev->dwDeviceID, szMdmLogExt);
hFile = CreateFile(FileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
DEBUGMSG(ZONE_CALLS|ZONE_FUNC|ZONE_ERROR,
(TEXT("UNIMODEM:OpenModemLog CreateFile(%s) failed %d\n"), FileName, GetLastError()));
pLineDev->hMdmLog = (HANDLE)INVALID_DEVICE;
} else {
DEBUGMSG(ZONE_CALLS|ZONE_FUNC, (TEXT("UNIMODEM:OpenModemLog CreateFile(%s) succeeded\n"), FileName));
pLineDev->hMdmLog = hFile;
}
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-OpenModemLog\n")));
} // OpenModemLog
//
// Function to write modem commands to the line device's command history file.
//
void
WriteModemLog(
PTLINEDEV pLineDev,
UCHAR * szCommand,
DWORD dwOp
)
{
CHAR Buf[MAXSTRINGLENGTH];
LPSTR lpsz;
DWORD dwLen;
DWORD dwIO;
if (pLineDev->bMdmLogFile == FALSE) {
return;
}
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+WriteModemLog %a\n"), szCommand));
switch (dwOp) {
case MDMLOG_COMMAND_OK:
lpsz = "Modem Command: ";
break;
case MDMLOG_COMMAND_FAIL:
lpsz = "Failed Command: ";
break;
case MDMLOG_RESPONSE:
lpsz = "Modem Response: ";
break;
default:
lpsz = " ";
break;
}
Buf[MAXSTRINGLENGTH-2] = 0;
strcpy(Buf, lpsz);
dwLen = strlen(Buf);
strncat(Buf, szCommand, MAXSTRINGLENGTH - dwLen - 2);
dwLen += strlen(szCommand);
if (dwLen > (MAXSTRINGLENGTH - 2)) {
dwLen = MAXSTRINGLENGTH - 2;
}
Buf[dwLen] = '\n';
dwLen++;
Buf[dwLen] = '\0';
DEBUGMSG(ZONE_CALLS|ZONE_FUNC, (TEXT("UNIMODEM:WriteModemLog(%a) %d bytes\n"), Buf, dwLen));
if (!WriteFile(pLineDev->hMdmLog, (PUCHAR)Buf, dwLen, &dwIO, NULL)) {
DEBUGMSG(ZONE_CALLS|ZONE_FUNC, (TEXT("UNIMODEM:WriteModemLog WriteFile() failed %d\n"), GetLastError()));
}
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-WriteModemLog\n")));
} // WriteModemLog
void
SetDCBfromDevMiniCfg(
DCB * pDCB,
PDEVMINICFG lpDevMiniCfg
)
{
pDCB->BaudRate = lpDevMiniCfg->dwBaudRate;
pDCB->ByteSize = lpDevMiniCfg->ByteSize;
pDCB->StopBits = lpDevMiniCfg->StopBits;
pDCB->fParity = (NOPARITY == lpDevMiniCfg->Parity) ? FALSE : TRUE;
pDCB->Parity = lpDevMiniCfg->Parity;
pDCB->fDsrSensitivity = FALSE;
pDCB->fDtrControl = DTR_CONTROL_ENABLE;
if( MDM_FLOWCONTROL_HARD & lpDevMiniCfg->dwModemOptions ) {
// Enable RTS/CTS Flow Control
pDCB->fRtsControl = RTS_CONTROL_HANDSHAKE;
pDCB->fOutxCtsFlow = 1;
pDCB->fOutX = 0;
pDCB->fInX = 0;
} else if( MDM_FLOWCONTROL_SOFT & lpDevMiniCfg->dwModemOptions ) {
// Enable XON/XOFF Flow Control
pDCB->fRtsControl = RTS_CONTROL_ENABLE;
pDCB->fOutxCtsFlow = 0;
pDCB->fOutX = 1;
pDCB->fInX = 1;
} else {
pDCB->fRtsControl = RTS_CONTROL_ENABLE;
pDCB->fOutxCtsFlow = 0;
pDCB->fOutX = 0;
pDCB->fInX = 0;
}
} // SetDCBfromDevMiniCfg
void
SetDialerTimeouts(
PTLINEDEV pLineDev
)
{
COMMTIMEOUTS commTimeouts;
switch (pLineDev->DevMiniCfg.dwBaudRate) {
//
// These millisecond timeouts are the expected inter-character delay for
// the various baud rates + 50%. Previously, the fixed "read" timeouts
// were too short for low baud rates so the connection attempt would
// get aborted.
//
case 110: commTimeouts.ReadTotalTimeoutMultiplier = 73+36; break;
case 300: commTimeouts.ReadTotalTimeoutMultiplier = 27+14; break;
case 600: commTimeouts.ReadTotalTimeoutMultiplier = 14+7; break;
case 1200: commTimeouts.ReadTotalTimeoutMultiplier = 7+3; break;
case 4800: commTimeouts.ReadTotalTimeoutMultiplier = 4+2; break;
case 9600: commTimeouts.ReadTotalTimeoutMultiplier = 2+1; break;
default: commTimeouts.ReadTotalTimeoutMultiplier = 1; break;
}
commTimeouts.ReadIntervalTimeout = 50;
commTimeouts.ReadTotalTimeoutConstant = 50;
commTimeouts.WriteTotalTimeoutMultiplier = 5;
commTimeouts.WriteTotalTimeoutConstant = 500;
SetCommTimeouts(pLineDev->hDevice, &commTimeouts);
} // SetDialerTimeouts
DWORD
OpenModem (
PTLINEDEV pLineDev
)
{
HANDLE hComDev;
HANDLE hComDev0;
DEBUGMSG(ZONE_FUNC|ZONE_CALLS, (TEXT("UNIMODEM:+OpenModem('%s')\r\n"), pLineDev->szDeviceName));
// Open the device getting a full access handle and a monitor handle
//
if ((hComDev = CreateFile(pLineDev->szDeviceName, GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
goto om_fail;
}
if ((hComDev0 = CreateFile(pLineDev->szDeviceName, 0, 0,
NULL, OPEN_EXISTING, 0, 0)) != INVALID_HANDLE_VALUE) {
DCB commDCB;
DEBUGMSG(ZONE_MISC|ZONE_CALLS,
(TEXT("UNIMODEM:OpenModem - createfile OK, handle x%X\n"),
hComDev));
// ********************************************************
// Set the device configuration based on DEVMINICFG
//
GetCommState( hComDev, &commDCB );
SetDCBfromDevMiniCfg(&commDCB, &pLineDev->DevMiniCfg);
DEBUGMSG(ZONE_FUNCTION|ZONE_CALLS,
(TEXT("UNIMODEM:OpenModem Setting port configuration :\n")));
DEBUGMSG(ZONE_FUNCTION|ZONE_CALLS,
(TEXT("UNIMODEM:OpenModem Baud %d, Byte Size %d, Stop bits %d, Parity %d\n"),
commDCB.BaudRate, commDCB.ByteSize, commDCB.StopBits, commDCB.Parity));
DEBUGMSG(ZONE_FUNCTION|ZONE_CALLS,
(TEXT("UNIMODEM:OpenModem RTS Control %d, CTS Out Flow %d, XON/XOFF out/in %d/%d\n"),
commDCB.fRtsControl, commDCB.fOutxCtsFlow, commDCB.fOutX, commDCB.fInX));
SetCommState( hComDev, &commDCB );
pLineDev->hDevice = hComDev;
pLineDev->hDevice_r0 = hComDev0;
// Adjust the read/write timeouts as required by dialer thread
SetDialerTimeouts(pLineDev);
DEBUGMSG(ZONE_FUNCTION, (TEXT("UNIMODEM:-OpenModem\n")));
return ERROR_SUCCESS;
} else {
CloseHandle(hComDev);
}
om_fail:
DEBUGMSG(ZONE_FUNCTION,
(TEXT("UNIMODEM:-OpenModem : Unable to open %s, hComdev x%X\n"),
pLineDev->szDeviceName, hComDev));
return ERROR_OPEN_FAILED;
}
// ****************************************************************************
// lineOpen()
//
// Function: Emulate the TAPI lineOpen call.
//
// ****************************************************************************
LONG
DevlineOpen (
PTLINEDEV pLineDev
)
{
DWORD dwRet;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+DevlineOpen\r\n")));
EnterCriticalSection(&pLineDev->OpenCS);
// The line must be closed
if (pLineDev->hDevice != (HANDLE)INVALID_DEVICE) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:DevlineOpen - device already open\r\n")));
dwRet = LINEERR_ALLOCATED;
goto exit_Point;
}
if (0 == pLineDev->wDeviceAvail) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:DevlineOpen - device has been removed\r\n")));
dwRet = LINEERR_NODEVICE;
goto exit_Point;
}
// Open the modem port
DEBUGMSG(ZONE_MISC, (TEXT("UNIMODEM:DevlineOpen - calling openmodem\r\n")));
dwRet = OpenModem(pLineDev);
if (dwRet == SUCCESS) {
// we successfully opened the modem
pLineDev->DevState = DEVST_DISCONNECTED;
OpenModemLog(pLineDev);
} else {
dwRet = LINEERR_RESOURCEUNAVAIL;
};
exit_Point:
LeaveCriticalSection(&pLineDev->OpenCS);
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-DevlineOpen x%X\r\n"), dwRet));
return dwRet;
}
//****************************************************************************
// lineClose()
//
// Function: Emulate the TAPI lineClose call.
//
// NOTE : The fDoDrop flag is used to indicate that we should
// make sure the line gets dropped before we close it.
//
//****************************************************************************
LONG
DevlineClose (
PTLINEDEV pLineDev,
BOOL fDoDrop
)
{
DWORD dwPrevCallState;
HTAPICALL hPrevCall;
DWORD dwPrevProcPerms;
DEBUGMSG(ZONE_FUNC|ZONE_CALLS,
(TEXT("UNIMODEM:+DevlineClose, handle x%X, callstate x%X\r\n"),
pLineDev->hDevice, pLineDev->dwCallState));
// Grab a critical section to ensure the app doesn't call in and
// cause a line close while we are in the middle of doing a close
// ourselves.
EnterCriticalSection(&pLineDev->OpenCS);
dwPrevCallState = pLineDev->dwCallState;
hPrevCall = pLineDev->htCall;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -