// Modem.cpp: implementation of the CModem class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Modem.h"

#include "regkey.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CModem::CModem()
{

}

CModem::~CModem()
{

}

BOOL CModem::GetNames(CStringList & strNameList, CStringList & strRateList)
{
	CString sKey, str;
	CRegKey regKey;

	int i = 0, count = 0;
	BOOL bRet;
	DWORD dwVersion = GetVersion();

	if (dwVersion < 0x80000000)		// Windows NT/2000
	{
		HKEY hParentKey, hSubKey, hDevKey;
		TCHAR szSubName[100], szValue[50];
		ULONG iSize;
		DWORD dwType;
		RegOpenKeyEx(HKEY_LOCAL_MACHINE,
			"System\\CurrentControlSet\\Control\\Class",
			0,
			KEY_READ,
			&hParentKey);
		while (TRUE)
		{
			if (ERROR_SUCCESS != RegEnumKey(hParentKey, i, szSubName, 100))
				break;
			i ++;
			str.Format("System\\CurrentControlSet\\Control\\Class\\%s", szSubName);
			if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
											  str,
											  0,
											  KEY_QUERY_VALUE,
											  &hSubKey))
				continue;
			iSize = 50;
			if (ERROR_SUCCESS != RegQueryValueEx(hSubKey, "Class", NULL, &dwType, (unsigned char*)szValue, &iSize))
				continue;
			if (lstrcmpi(szValue, _T("Modem")) != 0)	
				continue;
			str.Format("System\\CurrentControlSet\\Control\\Class\\%s\\0000", szSubName);
			RegOpenKeyEx(HKEY_LOCAL_MACHINE,
				str,
				0,
				KEY_QUERY_VALUE,
				&hDevKey);
			iSize = 50;
			if (ERROR_SUCCESS == RegQueryValueEx(hDevKey, "DriverDesc", NULL, &dwType, (unsigned char*)szValue, &iSize))
			{
				strNameList.AddTail(szValue);
				m_strKeyList[count++] = str;
			}
		}
	}
	else
	{		// Windows9x
		// The following code is only applicable on Win9x, there is no
		// corresponding registry key in Win2k & Winxp
		do
		{
			sKey.Format("System\\CurrentControlSet\\Services\\Class\\Modem\\%04d", i);
			if (regKey.Open(HKEY_LOCAL_MACHINE, sKey))
			{
				bRet = regKey.Read("Model", str);
				if (bRet)
				{
					strNameList.AddTail(str);
					m_strKeyList[i] = sKey;
				}
				regKey.Close();
			}
			else
				bRet = FALSE;
			i ++;
		} while (bRet);
	}

	strRateList.AddTail("14400");
	strRateList.AddTail("19200");
	strRateList.AddTail("38400");
	strRateList.AddTail("57600");
	strRateList.AddTail("115200");

	return TRUE;
}

BOOL CModem::OpenDevice(HWND hMsgWnd, int iDeviceId, int iRateId)
{
	int iRate[] = {CBR_14400, CBR_19200, CBR_38400, CBR_57600, CBR_115200};
	CString strPortName = _T("COM4");
	CRegKey regKey;

	m_strModemKey = m_strKeyList[iDeviceId];
	if (regKey.Open(HKEY_LOCAL_MACHINE, m_strModemKey))
	{	
		if (!regKey.Read("AttachedTo", strPortName))
			strPortName = _T("COM4");
		regKey.Close();
	}
	
	if (!Open(hMsgWnd, iRate[iRateId], strPortName))	return FALSE;

	if (!SetState(NULL, NULL))
	{
		Close();
		return FALSE;
	}

//	WriteAT("ATZ\r");
	WriteATSet("Init");

//	WriteAT("ATS7=60M1\\N3%C3&K3X4\r");
//	WriteAT("at%c0\r");
//	WriteAT("ats0=0\r");

	return TRUE;
}

void CModem::CloseDevice()
{
	Close();
}

void CModem::WriteAT(CString strCommand)
{
	Write((char *)(LPCTSTR(strCommand)), strCommand.GetLength());
}

void CModem::WriteATSet(CString strSection)
{
	CString sKey, sIndex, str;
	CRegKey regKey;
	int i = 1;
	BOOL bRet;

	sKey.Format("%s\\%s", m_strModemKey, strSection);
	if (regKey.Open(HKEY_LOCAL_MACHINE, sKey))
	{
		do
		{
			sIndex.Format("%d", i);
			bRet = regKey.Read(sIndex, str);
			if (bRet)
				WriteAT(str.Left(str.GetLength() - 4) + "\r");
//			else
//				OutputDebugString("regkey read fail\n");
			i ++;
		} while (bRet);
		regKey.Close();
	}
}


BOOL CModem::SetState(DCB *lpNewCommState, COMMTIMEOUTS *lpTimeOut)
{
	BOOL bReturn;
	DCB commState;
	COMMTIMEOUTS cto;
	COMMPROP cp;

	if (m_hCommFile==NULL)
		return FALSE;

	if (NULL==lpTimeOut)
	{
		cto.ReadIntervalTimeout = 0;
	    cto.ReadTotalTimeoutMultiplier = 1; 
		cto.ReadTotalTimeoutConstant = 100; 
	    cto.WriteTotalTimeoutMultiplier = 1; 
		cto.WriteTotalTimeoutConstant = 100; 
	}
	else
		memcpy(&cto, lpTimeOut, sizeof(cto));

	bReturn = PurgeComm(m_hCommFile, PURGE_TXABORT | 
				PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
	if (bReturn == FALSE)
		OutputDebugString("Purge Comm fail\n");
	bReturn = GetCommProperties(m_hCommFile, &cp);
	if (bReturn == FALSE)
		OutputDebugString("Get Comm Properties fail\n");
	bReturn = SetupComm(m_hCommFile, 1200, 1200);
	if (bReturn == FALSE)
		OutputDebugString("Setup Comm fail\n");
	bReturn = SetCommTimeouts(m_hCommFile, &cto);
	if (bReturn == FALSE)
		OutputDebugString("Set Comm Timeout fail\n");

	if (lpNewCommState!=NULL)
		bReturn = SetCommState(m_hCommFile, lpNewCommState);
	else 
	{
		bReturn = GetCommState(m_hCommFile, &commState);
		if (bReturn == FALSE)
			OutputDebugString("Get Comm State fail\n");
		if (bReturn) 
		{
			commState.BaudRate = m_iBaudRate;
			commState.ByteSize = 8;
			commState.Parity = NOPARITY;
			commState.StopBits = ONESTOPBIT;
//			commState.StopBits = ONE5STOPBITS;
//			commState.StopBits = TWOSTOPBITS;
//			commState.StopBits = ONESTOPBIT;

			bReturn = SetCommState(m_hCommFile, &commState);
			if (!bReturn) 
			{
//				OutputDebugLastError(GetLastError(), "Set Comm State:");
				OutputDebugString("Set Comm State error");
			}
		}
	}
	return bReturn;
}


