#include "StdAfx.h"
#include <GobiAPI.h>
#include "GobiApiDms.h"
#include "FuncList.h"
#include "StatusCtrl.h"
#include "GobiConnectionMgmtAPI.h"
#include "SwiWwanCmApi.h"

#define FUNC_GetDeviceCapabilities	L"GetDeviceCapabilities"
#define FUNC_GetFirmwareRevision	L"GetFirmwareRevision"
#define FUNC_GetFirmwareRevisions	L"GetFirmwareRevisions"
#define FUNC_GetManufacturer		L"GetManufacturer"
#define FUNC_GetModelID				L"GetModelID"
#define FUNC_GetPower				L"GetPower"
#define FUNC_GetSerialNumbers		L"GetSerialNumbers"
#define FUNC_GetImsi				L"GetIMSI"
#define FUNC_GetVoiceNumber			L"GetVoiceNumber"
#define FUNC_SetPower				L"SetPower"
#define FUNC_GetHardwareRevision    L"GetHardwareRevision"
#define FUNC_GetPRLVersion			L"GetPRLVersion"
#define FUNC_GetERIFile     		L"GetERIFile"
#define FUNC_GetOfflineReason		L"GetOfflineReason"
#define FUNC_GetNetworkTime			L"GetNetworkTime"
#define FUNC_ActivateAutomatic  	L"ActivateAutomatic"
#define FUNC_ActivateManual			L"ActivateManual"
#define FUNC_GetActivationState  	L"GetActivationState"
#define FUNC_DMSUimSetPinProtection 	L"DMSUIMSetPINProtection"
#define FUNC_DMSUimVerifyPin		    L"DMSUIMVerifyPIN"
#define FUNC_DMSUimUnblockPin 		    L"DMSUIMUnblockPIN"
#define FUNC_DMSUimChangePin 		    L"DMSUIMChangePIN"
#define FUNC_DMSUimGetPinStatus		L"DMSUIMGetPINStatus"
#define FUNC_DMSUimGetIccId			L"DMSUIMGetICCID"
#define FUNC_DMSUimGetControlKeyStatus	L"DMSUIMGetControlKeyStatus"
#define FUNC_DMSUimSetControlKeyProtection	L"DMSUIMSetControlKeyProtection"
#define FUNC_DMSUimUnblockControlKey	L"DMSUIMUnblockControlKey"
#define FUNC_ResetToFactoryDefaults	L"ResetToFactoryDefaults"
#define FUNC_ValidateSPC			L"ValidateSPC"
#define FUNC_SetActivationStatusCallback	L"SetActivationStatusCallback"
#define FUNC_SetPowerCallback		L"SetPowerCallback"
#define FUNC_SwitchModemToBootMode  L"SwitchModemToBootMode"

#define PARAM_PowerMode				L"PowerMode"
#define PARAM_PinId	                L"PIN ID"
#define PARAM_SetPINProtectionEnable L"Enable"
#define PARAM_PIN               	L"PIN"
#define PARAM_UnblockPuk       	    L"PUK"
#define PARAM_NewPin       	        L"New PIN"
#define PARAM_OldPin      	        L"Old PIN"
#define PARAM_SPC      				L"SPC"
#define PARAM_ControlKey_id 		L"Control Key ID"
#define PARAM_ControlKey_State		L"Control Key State"
#define PARAM_ControlKey_String		L"Control Key De-personalization String"
#define PARAM_Enable				L"Enable"
#define PARAM_Sid					L"SID"
#define PARAM_Mdn					L"MDN"
#define PARAM_Min					L"MIN"
#define PARAM_PrlSize				L"PRL size"
#define PARAM_Mnha					L"MNHA"
#define PARAM_Mnaaa					L"Mnaaa"
#define PARAM_PrlFile				L"PRL File"

CParamList CGobiApiDms::m_sSetPowerParams;
CParamList CGobiApiDms::m_sSetPinProtection;
CParamList CGobiApiDms::m_sVerifyPin;
CParamList CGobiApiDms::m_sUnblockPin;
CParamList CGobiApiDms::m_sChangePin;
CParamList CGobiApiDms::m_sGetPinStatus;
CParamList CGobiApiDms::m_sResetDefaults;
CParamList CGobiApiDms::m_sValidateSPC;
CParamList CGobiApiDms::m_sActivateAutomatic;
CParamList CGobiApiDms::m_sActivateManual;
CParamList CGobiApiDms::m_sGetControlKeyStatus;
CParamList CGobiApiDms::m_sSetControlKeyProtection;
CParamList CGobiApiDms::m_sUnblockControlKey;
CParamList CGobiApiDms::m_sSetActivationStatusCallback;
CParamList CGobiApiDms::m_sSetPowerCallback;

const TableFuncEntry CGobiApiDms::m_TableFunc[] = 
{
	{FUNC_GetDeviceCapabilities, FuncGetDeviceCapabilities},
	{FUNC_GetModelID, FuncGetModelID},
	{FUNC_GetPower, FuncGetPower},
	{FUNC_GetSerialNumbers, FuncGetSerialNumbers},
	{FUNC_GetFirmwareRevision, FuncGetFirmwareRevision},
	{FUNC_GetFirmwareRevisions, FuncGetFirmwareRevisions},
	{FUNC_GetManufacturer, FuncGetManufacturer},
	{FUNC_GetImsi, FuncGetImsi},
	{FUNC_GetVoiceNumber, FuncGetVoiceNumber},
	{FUNC_SetPower, FuncSetPower, &m_sSetPowerParams},
	{FUNC_GetHardwareRevision, FuncGetHardwareRevision},
	{FUNC_GetPRLVersion, FuncGetPRLVersion},
	{FUNC_GetERIFile, FuncGetERIFile},
	{FUNC_GetOfflineReason, FuncGetOfflineReason},
	{FUNC_GetNetworkTime, FuncGetNetworkTime},
	{FUNC_ActivateAutomatic, FuncActivateAutomatic, &m_sActivateAutomatic},
	{FUNC_ActivateManual, FuncActivateManual, &m_sActivateManual},
	{FUNC_GetActivationState, FuncGetActivationState},
	{FUNC_DMSUimSetPinProtection, FuncDMSUimSetPinProtection, &m_sSetPinProtection},
	{FUNC_DMSUimVerifyPin, FuncDMSUimVerifyPin, &m_sVerifyPin},
	{FUNC_DMSUimUnblockPin, FuncDMSUimUnblockPin, &m_sUnblockPin},
	{FUNC_DMSUimChangePin, FuncDMSUimChangePin, &m_sChangePin},
	{FUNC_DMSUimGetPinStatus, FuncDMSUimGetPinStatus, &m_sGetPinStatus},
	{FUNC_DMSUimGetIccId, FuncDMSUimGetIccId},	
	{FUNC_DMSUimGetControlKeyStatus, FuncDMSUimGetControlKeyStatus, &m_sGetControlKeyStatus},
	{FUNC_DMSUimSetControlKeyProtection, FuncDMSUimSetControlKeyProtection, &m_sSetControlKeyProtection},
	{FUNC_DMSUimUnblockControlKey, FuncDMSUimUnblockControlKey, &m_sUnblockControlKey},
	{FUNC_ResetToFactoryDefaults, FuncResetToFactoryDefaults, &m_sResetDefaults},
	{FUNC_ValidateSPC, FuncValidateSPC, &m_sValidateSPC},
	{FUNC_SetActivationStatusCallback, FuncSetActivationStatusCallback, &m_sSetActivationStatusCallback},
	{FUNC_SetPowerCallback, FuncSetPowerCallback, &m_sSetPowerCallback},
    {FUNC_SwitchModemToBootMode, FuncSwitchModemToBootMode},
	{FUNC_EndOfList}
};

CGobiApiDms::CGobiApiDms(HMODULE hQCDll)
{
	// Initialize the Qualcomm Dll pointer
	m_hQCDll = hQCDll;

	// Define SetPower configurable parameters
	m_sSetPowerParams.Add(PARAM_PowerMode, L"0");

	// Define SetPinProtection configurable parameters
	m_sSetPinProtection.Add(PARAM_PinId,     L"1");
	m_sSetPinProtection.Add(PARAM_SetPINProtectionEnable, L"0");
	m_sSetPinProtection.Add(PARAM_PIN,    L"1234");
	
	// Define VerifyPin configurable parameters
	m_sVerifyPin.Add(PARAM_PinId, L"1");
	m_sVerifyPin.Add(PARAM_PIN,   L"1234");

	// Define UnblockPin configurable parameters
	m_sUnblockPin.Add(PARAM_PinId,  L"1");
	m_sUnblockPin.Add(PARAM_UnblockPuk,    L"1111");
	m_sUnblockPin.Add(PARAM_NewPin, L"1234");

	// Define ChangePin configurable parameters
	m_sChangePin.Add(PARAM_PinId,  L"1");
	m_sChangePin.Add(PARAM_OldPin, L"1111");
	m_sChangePin.Add(PARAM_NewPin, L"1234");

	// Define GetPinStatus configurable parameters
	m_sGetPinStatus.Add(PARAM_PinId, L"1");

	// Define ResetToFactoryDefaults configurable parameters
	m_sResetDefaults.Add(PARAM_SPC, L"000000");

	// Define ValidateSPC configurable parameters
	m_sValidateSPC.Add(PARAM_SPC, L"000000");

	// Define ActivateAutomatic configurable parameters
	m_sActivateAutomatic.Add(PARAM_SPC, L"000000");

	// Define ActivateManual configurable parameters
	m_sActivateManual.Add(PARAM_SPC, L"000000");
	m_sActivateManual.Add(PARAM_Sid, L"123456");
	m_sActivateManual.Add(PARAM_Mdn, L"1234567890");
	m_sActivateManual.Add(PARAM_Min, L"1234567890");
	m_sActivateManual.Add(PARAM_PrlFile, L"VZW56006.prl");
	
	// Define Control Key configurable parameters
	m_sGetControlKeyStatus.Add(PARAM_ControlKey_id, L"0");

	m_sSetControlKeyProtection.Add(PARAM_ControlKey_id, L"0");
	m_sSetControlKeyProtection.Add(PARAM_ControlKey_State, L"0");
	m_sSetControlKeyProtection.Add(PARAM_ControlKey_String, L"12345678");

	m_sUnblockControlKey.Add(PARAM_ControlKey_id, L"0");
	m_sUnblockControlKey.Add(PARAM_ControlKey_String, L"12345678");

	// Define configurable parameters for callbacks
	m_sSetActivationStatusCallback.Add(PARAM_Enable, L"1");
	m_sSetPowerCallback.Add(PARAM_Enable, L"1");
}

CGobiApiDms::~CGobiApiDms(void)
{
}

BOOL CGobiApiDms::GetAvailFuncList(CFuncList* pFuncList)
{
	TBD_FUNCTION(CGobiApiDms::GetAvailFuncList);

	int iIndex = 0;

	while (m_TableFunc[iIndex].szFuncName.Compare(FUNC_EndOfList))
	{
		pFuncList->Add(L"Device Management", m_TableFunc[iIndex].szFuncName, m_TableFunc[iIndex].pParamList);
		TBD_OUTPUT(TBDCT_INFO, TBDOL_INFORMATION, m_TableFunc[iIndex].szFuncName);
		iIndex++;
	}

	return TRUE;
}

UINT CGobiApiDms::ExecuteFunctions(CFuncList* pFuncList, UINT &nTotalExec)
{
	TBD_FUNCTION(CGobiApiDms::Execute);

	int iIndex = 0;
	m_nNumErrors = 0;
	nTotalExec = 0;

	while (m_TableFunc[iIndex].szFuncName.Compare(FUNC_EndOfList))
	{
		if (pFuncList->Find(m_TableFunc[iIndex].szFuncName))
		{
			// Get list of parameters
			CParamList sParams;
			pFuncList->GetFuncParams(m_TableFunc[iIndex].szFuncName, sParams);

			// execute function
			if (!m_TableFunc[iIndex].pFunc(&sParams))
				// increment error counter
				m_nNumErrors++;

			// increment total functions executed
			nTotalExec++;
		}

		iIndex++;
	}

	return m_nNumErrors;
}

BOOL CGobiApiDms::FuncGetDeviceCapabilities(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetDeviceCapabilities", STATUSMSG_Send);

	BOOL bRet = FALSE;
	const BYTE MAX_RInt = 0x10;

	typedef struct 
	{
		ULONG nMaxTXChannelRate;
		ULONG nMaxRXChannelRate;
		ULONG nDataServiceCapability;
		ULONG nSimCapability;
		ULONG nRadioIfacesSize;
		BYTE  RadioIfaces[MAX_RInt];
	} STRUCT_DeviceCaps;

	STRUCT_DeviceCaps sDeviceCaps;
	memset(&sDeviceCaps, 0, sizeof(STRUCT_DeviceCaps));
	sDeviceCaps.nRadioIfacesSize = MAX_RInt;

	ULONG nRet = GetDeviceCapabilities(&sDeviceCaps.nMaxTXChannelRate, 
									   &sDeviceCaps.nMaxRXChannelRate,
									   &sDeviceCaps.nDataServiceCapability,
									   &sDeviceCaps.nSimCapability,
									   &sDeviceCaps.nRadioIfacesSize,
									   sDeviceCaps.RadioIfaces);

	CString strTemp;
	strTemp.Format(L"Return: %04d", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	if (!nRet)
	{
		strTemp.Format(L"MaxTx: %04d MaxRx: %04d",
					   sDeviceCaps.nMaxTXChannelRate,
					   sDeviceCaps.nMaxRXChannelRate);
		ADDSTATUS(strTemp, STATUSMSG_Receive);
		strTemp.Format(L"DataSrvCaps: %04d SimCaps: %04d",
					   sDeviceCaps.nDataServiceCapability,
					   sDeviceCaps.nSimCapability);
		ADDSTATUS(strTemp, STATUSMSG_Receive);

		ULONG RadioIface;
		strTemp.Format(L"Number of Radio Interfaces: %d",
					   sDeviceCaps.nRadioIfacesSize);
		ADDSTATUS(strTemp, STATUSMSG_Receive);
		for(ULONG i=0; i<sDeviceCaps.nRadioIfacesSize; i++)
		{
			RadioIface = sDeviceCaps.RadioIfaces[i];
			strTemp.Format(L"RadioIface %d is %04d", i+1, RadioIface );
			ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
		}

		bRet = TRUE;
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_GETDEVICECAPABILITIES) (ULONG*, ULONG*, ULONG*, ULONG*, ULONG*, BYTE*);

		// get pointer to function
		LPFN_GETDEVICECAPABILITIES pFn = (LPFN_GETDEVICECAPABILITIES)GetProcAddress_W(m_hQCDll, FUNC_GetDeviceCapabilities);

		// execute function
		if (pFn)
		{
			STRUCT_DeviceCaps sQcDeviceCaps;
			memset(&sQcDeviceCaps, 0, sizeof(STRUCT_DeviceCaps));
			sQcDeviceCaps.nRadioIfacesSize = MAX_RInt;

			ULONG nQcRet = pFn(&sQcDeviceCaps.nMaxTXChannelRate, 
							  &sQcDeviceCaps.nMaxRXChannelRate,
							  &sQcDeviceCaps.nDataServiceCapability,
							  &sQcDeviceCaps.nSimCapability,
							  &sQcDeviceCaps.nRadioIfacesSize,
							  sQcDeviceCaps.RadioIfaces);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (0 != memcmp(&sQcDeviceCaps, &sDeviceCaps, sizeof(STRUCT_DeviceCaps)))
			{
				ADDSTATUS(L"Response differs from Qualcomm DLL", STATUSMSG_Error);
				bRet = FALSE;
			}
			else
			{
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
				bRet = TRUE;
			}
		}

	}

	return bRet;
}

BOOL CGobiApiDms::FuncGetModelID(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetModelID", STATUSMSG_Send);

	BOOL bRet = FALSE;
	const BYTE MAX_StringLength = 0xFF;
	CHAR szModelId[MAX_StringLength] = "";

	ULONG nRet = GetModelID(MAX_StringLength, szModelId);

	CString strTemp;
	strTemp.Format(L"Return: %04d", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	if (!nRet)
	{
		TCHAR szStringU[MAX_StringLength] = L"";

		if (MultiByteToWideChar(CP_ACP, 0, szModelId, MAX_StringLength, szStringU, MAX_StringLength) == MAX_StringLength)
		{
			strTemp.Format(L"ModelID: %s", szStringU);
			ADDSTATUS(strTemp, STATUSMSG_Receive);
		}
		bRet = TRUE;
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_GETMODELID) (BYTE, CHAR*);

		// get pointer to function
		LPFN_GETMODELID pFn = (LPFN_GETMODELID)GetProcAddress_W(m_hQCDll, FUNC_GetModelID);

		// execute function
		if (pFn)
		{
			CHAR szQcModelId[MAX_StringLength] = "";

			ULONG nQcRet = pFn(MAX_StringLength, szQcModelId);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (0 != strcmp(szQcModelId, szModelId))
			{
				ADDSTATUS(L"Response differs from Qualcomm DLL", STATUSMSG_Error);
				bRet = FALSE;
			}
			else
			{
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
				bRet = TRUE;
			}
		}

	}

	return bRet;
}

BOOL CGobiApiDms::FuncGetPower(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetPower", STATUSMSG_Send);

	BOOL bRet = FALSE;
	CString strTemp;
	ULONG nPower = 0;

	ULONG nRet = GetPower(&nPower);

	strTemp.Format(L"Return: %04d ", nPower, nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	if (!nRet)
	{
		switch (nPower)
		{
		case 0:
			strTemp.Format(L"%d: Online", nPower);
			break;
		case 1:
			strTemp.Format(L"%d: Low Power (Airplane) mode", nPower);
			break;
		case 2:
			strTemp.Format(L"%d: Factory Test mode", nPower);
			break;
		case 3:
			strTemp.Format(L"%d: Offline", nPower);
			break;
		case 4:
			strTemp.Format(L"%d: Reset", nPower);
			break;
		case 5:
			strTemp.Format(L"%d: Powered Off", nPower);
			break;
		case 6:
			strTemp.Format(L"%d: Persistent Low Power (Airplane) mode", nPower);
			break;
		default:
			strTemp.Format(L"Power state: %d", nPower);
			break;
		}
	}

	ADDSTATUS(strTemp, STATUSMSG_Receive);
	bRet = (nRet == 0)?TRUE:FALSE;

	// Compare with QC DLL
	if (m_hQCDll)
	{
		ULONG qcPower = 0;

		// function prototype
		typedef ULONG (SWICMAPI*LPFN_GETPOWER) (ULONG*);
		
		// get pointer to function
		LPFN_GETPOWER pFn = (LPFN_GETPOWER)GetProcAddress_W(m_hQCDll, FUNC_GetPower);

		// execute function
		if (pFn)
		{
			ULONG nQcRet = pFn(&qcPower);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (qcPower != nPower)
			{
				ADDSTATUS(L"Response differs from Qualcomm DLL", STATUSMSG_Error);
				bRet = FALSE;
			}
			else
			{
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
				bRet = TRUE;
			}
		}
	}

	return bRet;
}

BOOL CGobiApiDms::FuncGetSerialNumbers(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetSerialNumbers", STATUSMSG_Send);

	BOOL bRet = FALSE;
	const BYTE MAX_StringLength = 0xFF;
	CHAR szEsnId[MAX_StringLength] = "";
	CHAR szImei[MAX_StringLength] = "";
	CHAR szMeid[MAX_StringLength] = "";

	ULONG nRet = GetSerialNumbers(MAX_StringLength, szEsnId, MAX_StringLength, szImei, MAX_StringLength, szMeid);

	CString strTemp;
	strTemp.Format(L"Return: %04d", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	if (!nRet)
	{
		TCHAR szStringU[MAX_StringLength] = L"";

		if (MultiByteToWideChar(CP_ACP, 0, szImei, MAX_StringLength, szStringU, MAX_StringLength) == MAX_StringLength)
		{
			strTemp.Format(L"IMEI: %s", szStringU);
			ADDSTATUS(strTemp, STATUSMSG_Receive);
		}

		if (MultiByteToWideChar(CP_ACP, 0, szEsnId, MAX_StringLength, szStringU, MAX_StringLength) == MAX_StringLength)
		{
			strTemp.Format(L"ESN: %s", szStringU);
			ADDSTATUS(strTemp, STATUSMSG_Receive);
		}

		if (MultiByteToWideChar(CP_ACP, 0, szMeid, MAX_StringLength, szStringU, MAX_StringLength) == MAX_StringLength)
		{
			strTemp.Format(L"MEID: %s", szStringU);
			ADDSTATUS(strTemp, STATUSMSG_Receive);
		}

		bRet = TRUE;
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_GETSERIALNUMBERS) (BYTE, CHAR*, BYTE, CHAR*, BYTE, CHAR*);

		// get pointer to function
		LPFN_GETSERIALNUMBERS pFn = (LPFN_GETSERIALNUMBERS)GetProcAddress_W(m_hQCDll, FUNC_GetSerialNumbers);

		// execute function
		if (pFn)
		{
			CHAR szQcEsnId[MAX_StringLength] = "";
			CHAR szQcImei[MAX_StringLength] = "";
			CHAR szQcMeid[MAX_StringLength] = "";

			ULONG nQcRet = pFn(MAX_StringLength, szQcEsnId, MAX_StringLength, szQcImei, MAX_StringLength, szQcMeid);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (0 != strcmp(szQcEsnId, szEsnId) && 0 != strcmp(szQcImei, szImei) && 0 != strcmp(szQcMeid, szMeid))
			{
				ADDSTATUS(L"Response differs from Qualcomm DLL", STATUSMSG_Error);
				bRet = FALSE;
			}
			else
			{
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
				bRet = TRUE;
			}
		}

	}

	return bRet;
}

BOOL CGobiApiDms::FuncGetFirmwareRevision(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetFirmwareRevision", STATUSMSG_Send);

	BOOL bRet = FALSE;
	const BYTE MAX_StringLength = 0xFF;
	CHAR szFwRev[MAX_StringLength] = "";

	ULONG nRet = GetFirmwareRevision(MAX_StringLength, szFwRev);

	CString strTemp;
	strTemp.Format(L"Return: %04d", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	if (!nRet)
	{
		TCHAR szStringU[MAX_StringLength] = L"";

		if (MultiByteToWideChar(CP_ACP, 0, szFwRev, MAX_StringLength, szStringU, MAX_StringLength) == MAX_StringLength)
		{
			strTemp.Format(L"%s", szStringU);
			ADDSTATUS(strTemp, STATUSMSG_Receive);
		}

		bRet = TRUE;
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_GETFIRMWAREREVISION) (BYTE, CHAR*);

		// get pointer to function
		LPFN_GETFIRMWAREREVISION pFn = (LPFN_GETFIRMWAREREVISION)GetProcAddress_W(m_hQCDll, FUNC_GetFirmwareRevision);

		// execute function
		if (pFn)
		{
			CHAR szQcFwRev[MAX_StringLength] = "";
			
			ULONG nQcRet = pFn(MAX_StringLength, szQcFwRev);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (0 != strcmp(szQcFwRev, szFwRev))
			{
				ADDSTATUS(L"Response differs from Qualcomm DLL", STATUSMSG_Error);
				bRet = TRUE;
			}
			else
			{
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
				bRet = TRUE;
			}
		}

	}

	return bRet;
}

BOOL CGobiApiDms::FuncGetFirmwareRevisions(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetFirmwareRevisions", STATUSMSG_Send);

	BOOL bRet = FALSE;
	const BYTE MAX_StringLength = 0xFF;
	CHAR szAmssRev[MAX_StringLength] = "";
	CHAR szBootRev[MAX_StringLength] = "";
	CHAR szPriRev[MAX_StringLength] = "";

	ULONG nRet = GetFirmwareRevisions(MAX_StringLength, szAmssRev, MAX_StringLength, szBootRev, MAX_StringLength, szPriRev);

	CString strTemp;
	strTemp.Format(L"Return: %04d", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	if (!nRet)
	{
		TCHAR szStringU[MAX_StringLength] = L"";

		if (MultiByteToWideChar(CP_ACP, 0, szAmssRev, MAX_StringLength, szStringU, MAX_StringLength) == MAX_StringLength)
		{
			strTemp.Format(L"Amss: %s", szStringU);
			ADDSTATUS(strTemp, STATUSMSG_Receive);
		}

		if (MultiByteToWideChar(CP_ACP, 0, szBootRev, MAX_StringLength, szStringU, MAX_StringLength) == MAX_StringLength)
		{
			strTemp.Format(L"Boot: %s", szStringU);
			ADDSTATUS(strTemp, STATUSMSG_Receive);
		}

		if (MultiByteToWideChar(CP_ACP, 0, szPriRev, MAX_StringLength, szStringU, MAX_StringLength) == MAX_StringLength)
		{
			strTemp.Format(L"Pri: %s", szStringU);
			ADDSTATUS(strTemp, STATUSMSG_Receive);
		}

		bRet = TRUE;
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_GETFIRMWAREREVISIONS) (BYTE, CHAR*, BYTE, CHAR*, BYTE, CHAR*);

		// get pointer to function
		LPFN_GETFIRMWAREREVISIONS pFn = (LPFN_GETFIRMWAREREVISIONS)GetProcAddress_W(m_hQCDll, FUNC_GetFirmwareRevisions);

		// execute function
		if (pFn)
		{
			CHAR szQcAmssRev[MAX_StringLength] = "";
			CHAR szQcBootRev[MAX_StringLength] = "";
			CHAR szQcPriRev[MAX_StringLength]  = "";

			ULONG nQcRet = pFn(MAX_StringLength, szQcAmssRev, MAX_StringLength, szQcBootRev, MAX_StringLength, szQcPriRev);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (0 != strcmp(szQcAmssRev, szAmssRev) && 
					 0 != strcmp(szQcBootRev, szBootRev) && 
					 0 != strcmp(szQcPriRev, szPriRev))
			{
				ADDSTATUS(L"Response differs from Qualcomm DLL", STATUSMSG_Error);
				bRet = FALSE;
			}
			else
			{
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
				bRet = TRUE;
			}
		}
	}

	return bRet;
}

BOOL CGobiApiDms::FuncGetManufacturer(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetManufacturer", STATUSMSG_Send);

	BOOL bRet = FALSE;
	const BYTE MAX_StringLength = 0xFF;
	CHAR szManufacturer[MAX_StringLength] = "";

	ULONG nRet = GetManufacturer(MAX_StringLength, szManufacturer);

	CString strTemp;
	strTemp.Format(L"Return: %04d", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	if (!nRet)
	{
		TCHAR szStringU[MAX_StringLength] = L"";

		if (MultiByteToWideChar(CP_ACP, 0, szManufacturer, MAX_StringLength, szStringU, MAX_StringLength) == MAX_StringLength)
		{
			strTemp.Format(L"%s", szStringU);
			ADDSTATUS(strTemp, STATUSMSG_Receive);
		}

		bRet = TRUE;
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_GETMANUFACTURER) (BYTE, CHAR*);

		// get pointer to function
		LPFN_GETMANUFACTURER pFn = (LPFN_GETMANUFACTURER)GetProcAddress_W(m_hQCDll, FUNC_GetManufacturer);

		// execute function
		if (pFn)
		{
			CHAR szQcManufacturer[MAX_StringLength] = "";

			ULONG nQcRet = pFn(MAX_StringLength, szQcManufacturer);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (0 != strcmp(szQcManufacturer, szManufacturer))
			{
				ADDSTATUS(L"Response differs from Qualcomm DLL", STATUSMSG_Error);
				bRet = FALSE;
			}
			else
			{
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
				bRet = TRUE;
			}
		}

	}

	return bRet;
}

BOOL CGobiApiDms::FuncGetImsi(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetImsi", STATUSMSG_Send);

	BOOL bRet = FALSE;
	const BYTE MAX_StringLength = 0xFF;
	CHAR szImsi[MAX_StringLength] = "";

	ULONG nRet = GetIMSI(MAX_StringLength, szImsi);

	CString strTemp;
	strTemp.Format(L"Return: %04d", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	if (!nRet)
	{
		TCHAR szStringU[MAX_StringLength] = L"";

		if (MultiByteToWideChar(CP_ACP, 0, szImsi, MAX_StringLength, szStringU, MAX_StringLength) == MAX_StringLength)
		{
			strTemp.Format(L"%s", szStringU);
			ADDSTATUS(strTemp, STATUSMSG_Receive);
		}

		bRet = TRUE;
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_GETIMSI) (BYTE, CHAR*);

		// get pointer to function
		LPFN_GETIMSI pFn = (LPFN_GETIMSI)GetProcAddress_W(m_hQCDll, FUNC_GetImsi);

		// execute function
		if (pFn)
		{
			CHAR szQcImsi[MAX_StringLength] = "";

			ULONG nQcRet = pFn(MAX_StringLength, szQcImsi);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (0 != strcmp(szQcImsi, szImsi))
			{
				ADDSTATUS(L"Response differs from Qualcomm DLL", STATUSMSG_Error);
				bRet = FALSE;
			}
			else
			{
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
				bRet = TRUE;
			}
		}

	}

	return bRet;
}

BOOL CGobiApiDms::FuncGetVoiceNumber(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetVoiceNumber", STATUSMSG_Send);

	BOOL bRet = FALSE;
	const BYTE MAX_StringLength = 0xFF;
	CHAR szVoiceNumber[MAX_StringLength] = "";
	CHAR szMin[MAX_StringLength] = "";

	ULONG nRet = GetVoiceNumber(MAX_StringLength, szVoiceNumber, MAX_StringLength, szMin);

	CString strTemp;
	strTemp.Format(L"Return: %04d", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	if (!nRet)
	{
		TCHAR szStringU[MAX_StringLength] = L"";

		if (MultiByteToWideChar(CP_ACP, 0, szVoiceNumber, MAX_StringLength, szStringU, MAX_StringLength) == MAX_StringLength)
		{
			strTemp.Format(L"%s", szStringU);
			ADDSTATUS(strTemp, STATUSMSG_Receive);
		}

		if (MultiByteToWideChar(CP_ACP, 0, szMin, MAX_StringLength, szStringU, MAX_StringLength) == MAX_StringLength)
		{
			strTemp.Format(L"MIN: %s", szStringU);
			ADDSTATUS(strTemp, STATUSMSG_Receive);
		}

		bRet = TRUE;
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_GETVOICENUMBER) (BYTE, CHAR*, BYTE, CHAR*);

		// get pointer to function
		LPFN_GETVOICENUMBER pFn = (LPFN_GETVOICENUMBER)GetProcAddress_W(m_hQCDll, FUNC_GetVoiceNumber);

		// execute function
		if (pFn)
		{
			CHAR szQcVoiceNumber[MAX_StringLength] = "";
			CHAR szQcMin[MAX_StringLength] = "";

			ULONG nQcRet = pFn(MAX_StringLength, szQcVoiceNumber, MAX_StringLength, szQcMin);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (0 != strcmp(szQcVoiceNumber, szVoiceNumber) || 0 != strcmp(szQcMin, szMin))
			{
				ADDSTATUS(L"Response differs from Qualcomm DLL", STATUSMSG_Error);
				bRet = FALSE;
			}
			else
			{
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
				bRet = TRUE;
			}
		}

	}

	return TRUE;
}

BOOL CGobiApiDms::FuncActivateAutomatic(CParamList* pParams /*= NULL*/)
{
	ADDSTATUS(L"FuncActivateAutomatic", STATUSMSG_Send);

	ULONG nRet = ActivateAutomatic(CW2A(pParams->GetValue(PARAM_SPC)));

	BOOL bRet = FALSE;
	CString strTemp;
	strTemp.Format(L"Return: %04d ", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);
	bRet = (nRet == 0)?TRUE:FALSE;

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_ACTIVATEAUTOMATIC) (CHAR*);
		
		// get pointer to function
		LPFN_ACTIVATEAUTOMATIC pFn = (LPFN_ACTIVATEAUTOMATIC)GetProcAddress_W(m_hQCDll, FUNC_ActivateAutomatic);

		// execute function
		if (pFn)
		{
			ULONG nQcRet = pFn(CW2A(pParams->GetValue(PARAM_SPC)));

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else
			{
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
				bRet = TRUE;
			}
		}
	}

	return bRet;
}

BOOL CGobiApiDms::FuncActivateManual(CParamList* pParams /*= NULL*/)
{
	ADDSTATUS(L"FuncActivateManual", STATUSMSG_Send);

	BOOL bRet = FALSE;
	ULONG nRet = 0;
	BYTE* pPrlBuffer = NULL;
	CString strTemp;

	CFile PrlFile;
	ULONG nPrlSize = 0;
	
	if (PrlFile.Open(pParams->GetValue(PARAM_PrlFile), CFile::modeRead))
		nPrlSize = (ULONG)PrlFile.GetLength();

	if (nPrlSize)
	{
		pPrlBuffer = (BYTE*)malloc(nPrlSize);

		if (!pPrlBuffer)
		{
			ADDSTATUS(L"Insufficient memory", STATUSMSG_Error);
			bRet = FALSE;
		}
		else if (PrlFile.Read(pPrlBuffer, nPrlSize) != nPrlSize)
		{
			ADDSTATUS(L"Failed to read file", STATUSMSG_Error);
			bRet = FALSE;
		}
	}

	nRet = ActivateManual(
				CW2A(pParams->GetValue(PARAM_SPC)),
				(WORD)_ttoi(pParams->GetValue(PARAM_Sid)),
				CW2A(pParams->GetValue(PARAM_Mdn)),
				CW2A(pParams->GetValue(PARAM_Min)),
				nPrlSize, 
				pPrlBuffer,
				NULL,
				NULL);

	free(pPrlBuffer);
	strTemp.Format(L"Return: %04d ", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);
	bRet = (nRet == 0)?TRUE:FALSE;

	return bRet;
}

BOOL CGobiApiDms::FuncGetActivationState(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetActivationState", STATUSMSG_Send);

	BOOL bRet = FALSE;
	CString strTemp;
	ULONG nActivationState = 0xFF;

	ULONG nRet = GetActivationState(&nActivationState);

	strTemp.Format(L"Activation State: %i Return: %04d ", nActivationState, nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);
	bRet = (nRet == 0)?TRUE:FALSE;

	// Compare with QC DLL
	if (m_hQCDll)
	{
		ULONG QcnActivationState = 0;

		// function prototype
		typedef ULONG (SWICMAPI*LPFN_GETACTIVATIONSTATE) (ULONG*);
		
		// get pointer to function
		LPFN_GETACTIVATIONSTATE pFn = (LPFN_GETACTIVATIONSTATE)GetProcAddress_W(m_hQCDll, FUNC_GetActivationState);

		// execute function
		if (pFn)
		{
			ULONG nQcRet = pFn(&QcnActivationState);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (QcnActivationState != nActivationState)
			{
				ADDSTATUS(L"Response differs from Qualcomm DLL", STATUSMSG_Error);
				bRet = FALSE;
			}
			else
			{
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
				bRet = TRUE;
			}
		}
	}

	return bRet;
}

BOOL CGobiApiDms::FuncSetPower(CParamList* pParams /*= NULL*/)
{
	ADDSTATUS(L"FuncSetPower", STATUSMSG_Send);

	BOOL bRet = FALSE;
	//ULONG nPowerResp = -1;
	ULONG nRet = 0;
	CString strTemp;

	// Power Modes:
	// 0 - Online (default)
	// 1 - Low power
	// 2 - Factory Test mode
	// 3 - Offline
	// 4 - Reset
	// 5 - Shutdown
	// 6 - Persistent low power
	ULONG nPowerMode = 0;

	// Get user selected parameters
	if (pParams)
	{
		nPowerMode = _ttoi(pParams->GetValue(PARAM_PowerMode));
	}

	// set to low power mode
	nRet = SetPower(nPowerMode);

	strTemp.Format(L"SetPower - %i - Return: %04d", nPowerMode, nRet);
	ADDSTATUS(strTemp, STATUSMSG_Send);

	if (!nRet)
	{
		// Do not call GetPower call after calling SetPower because the modem may 
		// take some time to change power states and a modem reset may occur when 
		// transiting power states
		bRet = TRUE;
	}
	
	return bRet;
}

BOOL CGobiApiDms::FuncGetHardwareRevision(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetHardwareRevision", STATUSMSG_Send);

	BOOL bRet = FALSE;
	const BYTE MAX_StringLength = 0xFF;
	CHAR szHwRev[MAX_StringLength] = "";

	ULONG nRet = GetHardwareRevision(MAX_StringLength, szHwRev);

	CString strTemp;
	strTemp.Format(L"Return: %04d", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	if (!nRet)
	{
		TCHAR szStringU[MAX_StringLength] = L"";

		if (MultiByteToWideChar(CP_ACP, 0, szHwRev, MAX_StringLength, szStringU, MAX_StringLength) == MAX_StringLength)
		{
			strTemp.Format(L"Hardware Revision: %s", szStringU);
			ADDSTATUS(strTemp, STATUSMSG_Receive);
		}

		bRet = TRUE;
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_GETHARDWAREREVISION) (BYTE, CHAR*);

		// get pointer to function
		LPFN_GETHARDWAREREVISION pFn = (LPFN_GETHARDWAREREVISION)GetProcAddress_W(m_hQCDll, FUNC_GetHardwareRevision);

		// execute function
		if (pFn)
		{
			CHAR szQcHwRev[MAX_StringLength] = "";

			ULONG nQcRet = pFn(MAX_StringLength, szQcHwRev);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (0 != strcmp(szQcHwRev, szHwRev))
			{
				ADDSTATUS(L"Response differs from Qualcomm DLL", STATUSMSG_Error);
				bRet = FALSE;
			}
			else
			{
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
				bRet = TRUE;
			}
		}

	}

	return bRet;
}

BOOL CGobiApiDms::FuncGetPRLVersion(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetPRLVersion", STATUSMSG_Send);

	BOOL bRet = FALSE;
	CString strTemp;
	WORD nPRLVersion = 0;

	ULONG nRet = GetPRLVersion(&nPRLVersion);

	strTemp.Format(L"PRL Version: %i Return: %04d ", nPRLVersion, nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);
	bRet = (nRet == 0)?TRUE:FALSE;

	// Compare with QC DLL
	if (m_hQCDll)
	{
		WORD qcnPRLVersion = 0;

		// function prototype
		typedef ULONG (SWICMAPI*LPFN_GETPRLVERSION) (WORD*);
		
		// get pointer to function
		LPFN_GETPRLVERSION pFn = (LPFN_GETPRLVERSION)GetProcAddress_W(m_hQCDll, FUNC_GetPRLVersion);

		// execute function
		if (pFn)
		{
			ULONG nQcRet = pFn(&qcnPRLVersion);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (qcnPRLVersion != nPRLVersion)
			{
				ADDSTATUS(L"Response differs from Qualcomm DLL", STATUSMSG_Error);
				bRet = FALSE;
			}
			else
			{
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
				bRet = TRUE;
			}
		}
	}

	return bRet;
}

BOOL CGobiApiDms::FuncGetERIFile(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetERIFile", STATUSMSG_Send);

	BOOL bRet = FALSE;
	const ULONG MAX_FileSize = 1024;
	ULONG MAX_FileSize_local = MAX_FileSize;
	CHAR szFile[MAX_FileSize] = "";

	ULONG nRet = GetERIFile(&MAX_FileSize_local, (BYTE *)szFile);

	CString strTemp;
	strTemp.Format(L"Return: %04d", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	if (!nRet)
	{
		bRet = TRUE;
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_GETERIFILE) (ULONG*, BYTE*);

		// get pointer to function
		LPFN_GETERIFILE pFn = (LPFN_GETERIFILE)GetProcAddress_W(m_hQCDll, FUNC_GetERIFile);

		// execute function
		if (pFn)
		{
			BYTE szQcFile[MAX_FileSize] = "";

			ULONG nQcRet = pFn(&MAX_FileSize_local, szQcFile);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (0 != memcmp(szQcFile, szFile, MAX_FileSize))
			{
				ADDSTATUS(L"Response differs from Qualcomm DLL", STATUSMSG_Error);
				bRet = FALSE;
			}
			else
			{
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
				bRet = TRUE;
			}
		}
	}

	return bRet;
}

BOOL CGobiApiDms::FuncGetOfflineReason(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetOfflineReason", STATUSMSG_Send);

	BOOL bRet = FALSE;
	ULONG     ReasonMask;
	ULONG     bPlatform;

	ULONG nRet = GetOfflineReason(&ReasonMask, &bPlatform);

	CString strTemp;
	strTemp.Format(L"Return: %04d", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	if (!nRet)
	{
		strTemp.Format(L"Offline Reason: %ld, Platform: %d", ReasonMask, bPlatform);
		ADDSTATUS(strTemp, STATUSMSG_Receive);
		bRet = TRUE;
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_GETOFFLINEREASON) (ULONG*, ULONG*);

		// get pointer to function
		LPFN_GETOFFLINEREASON pFn = (LPFN_GETOFFLINEREASON)GetProcAddress_W(m_hQCDll, FUNC_GetOfflineReason);

		// execute function
		if (pFn)
		{
			ULONG QcReasonMask;
			ULONG QcbPlatform;

			ULONG nQcRet = pFn(&QcReasonMask, &QcbPlatform);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (QcReasonMask != ReasonMask)
			{
				ADDSTATUS(L"Response differs from Qualcomm DLL", STATUSMSG_Error);
				bRet = FALSE;
			}
			else
			{
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
				bRet = TRUE;
			}
		}

	}

	return bRet;
}

BOOL CGobiApiDms::FuncGetNetworkTime(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetNetworkTime", STATUSMSG_Send);

	BOOL bRet = FALSE;
	ULONGLONG TimeStamp;
	ULONG     TimeSource;
	ULONGLONG PrintTime;

	ULONG nRet = GetNetworkTime(&TimeStamp, &TimeSource);

	CString strTemp;
	strTemp.Format(L"Return: %04d", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	if (!nRet)
	{
		PrintTime = TimeStamp & 0x0000FFFFFFFFFFFF;   // Need this to print correctly in ARM 
		strTemp.Format(L"TimeStamp: %I64u (0x%I64x), Source: %ld", PrintTime, PrintTime, TimeSource);
		ADDSTATUS(strTemp, STATUSMSG_Receive);
		bRet = TRUE;
	}

	// Compare with QC DLL - this will never be the same since the clock keeps on ticking
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_GETNETWORKTIME) (ULONGLONG*, ULONG*);

		// get pointer to function
		LPFN_GETNETWORKTIME pFn = (LPFN_GETNETWORKTIME)GetProcAddress_W(m_hQCDll, FUNC_GetNetworkTime);

		// execute function
		if (pFn)
		{
			ULONGLONG QcTimeStamp;
			ULONG QcTimeSource;

			ULONG nQcRet = pFn(&QcTimeStamp, &QcTimeSource);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (TimeStamp != QcTimeStamp)
			{
				ADDSTATUS(L"Response differs from Qualcomm DLL, this is normal for this test", STATUSMSG_Error);
				// QC test program displays only the low LONG !
		        PrintTime = TimeStamp & 0x0000FFFFFFFFFFFF;   // Need this to print correctly in ARM 
				strTemp.Format(L"TimeStamp: %I64u (0x%I64x), Source: %ld", PrintTime, PrintTime, TimeSource);
				ADDSTATUS(strTemp, STATUSMSG_Receive);
				// The time is supposed to be different
				bRet = TRUE;
			}
			else
			{
				// This should never happen for this test. If it did, the clock has stopped.
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
				bRet = TRUE;
			}
		}

	}

	return bRet;
}

BOOL CGobiApiDms::FuncDMSUimSetPinProtection(CParamList* pParams /*= NULL*/)
{
	ADDSTATUS(L"FuncDMSUimSetPinProtection", STATUSMSG_Send);

	const BYTE MAX_StringLength = 0xFF;

	// Pin values = 1 or 2
	ULONG Pin = 1;

	ULONG Enable = 1;
	CHAR szValue[MAX_StringLength] = "1111";

	ULONG VerifyRetriesLeft  = 0xFF;
	ULONG UnblockRetriesLeft = 0xFF;

	// Get user specified parameters
	if (pParams)
	{
		Pin = _ttoi(pParams->GetValue(PARAM_PinId));
		Enable = _ttoi(pParams->GetValue(PARAM_SetPINProtectionEnable));
		WideCharToMultiByte(CP_ACP, 0, pParams->GetValue(PARAM_PIN), -1, szValue, MAX_StringLength, 0, 0);
	}

	ULONG nRet = DMSUIMSetPINProtection(Pin, Enable, szValue, &VerifyRetriesLeft, &UnblockRetriesLeft);

	CString strTemp;
	strTemp.Format(L"Return: %04d", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	if (nRet)
	{
		strTemp.Format(L"Verify Retries Left:  %d", VerifyRetriesLeft);
	    ADDSTATUS(strTemp, STATUSMSG_Receive);
		strTemp.Format(L"Unblock Retries Left: %d", UnblockRetriesLeft);
	    ADDSTATUS(strTemp, STATUSMSG_Receive);
	}

#if 0
	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_DMSUIMSETPINPROTECTION) (ULONG, ULONG, CHAR*, ULONG*, ULONG*);

		// get pointer to function
		LPFN_DMSUIMSETPINPROTECTION pFn = (LPFN_DMSUIMSETPINPROTECTION)GetProcAddress_W(m_hQCDll, FUNC_DMSUimSetPinProtection);

		// execute function
		if (pFn)
		{
			ULONG QcVerifyRetriesLeft  = 0xFF;
			ULONG QcUnblockRetriesLeft = 0xFF;

			ULONG nQcRet = pFn(Pin, Enable, szValue, &QcVerifyRetriesLeft, &QcUnblockRetriesLeft);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
			}
			else
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
		}
	}
#endif

	return (nRet == 0)?TRUE:FALSE;
}

BOOL CGobiApiDms::FuncDMSUimVerifyPin(CParamList* pParams /*= NULL*/)
{
	ADDSTATUS(L"FuncDMSUimVerifyPin", STATUSMSG_Send);

	const BYTE MAX_StringLength = 0xFF;

	ULONG Pin = 1;

	CHAR szValue[MAX_StringLength] = "1111";

	ULONG VerifyRetriesLeft  = 0xFF;
	ULONG UnblockRetriesLeft = 0xFF;

	// Get user selected parameters
	if (pParams)
	{
		Pin = _ttoi(pParams->GetValue(PARAM_PinId));
		WideCharToMultiByte(CP_ACP, 0, pParams->GetValue(PARAM_PIN), -1, szValue, MAX_StringLength, 0, 0);
	}

	ULONG nRet = DMSUIMVerifyPIN(Pin, szValue, &VerifyRetriesLeft, &UnblockRetriesLeft);

	//Indicates the current status of the PIN; valid values are:
	// 0 ?PIN not initialized
	// 1 ?PIN enabled, not verified
	// 2 ?PIN enabled, verified
	// 3 ?PIN disabled
	// 4 ?PIN blocked
	// 5 ?PIN permanently blocked	
	CString strTemp;
	strTemp.Format(L"Return: %04d", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	if (nRet)
	{
		strTemp.Format(L"Verify Retries Left:  %d", VerifyRetriesLeft);
	    ADDSTATUS(strTemp, STATUSMSG_Receive);
		strTemp.Format(L"Unblock Retries Left: %d", UnblockRetriesLeft);
	    ADDSTATUS(strTemp, STATUSMSG_Receive);
	}

#if 0
	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_DMSUIMVERIFYPIN) (ULONG, CHAR*, ULONG*, ULONG*);

		// get pointer to function
		LPFN_DMSUIMVERIFYPIN pFn = (LPFN_DMSUIMVERIFYPIN)GetProcAddress_W(m_hQCDll, FUNC_DMSUimVerifyPin);

		// execute function
		if (pFn)
		{
			ULONG QcVerifyRetriesLeft  = 0xFF;
			ULONG QcUnblockRetriesLeft = 0xFF;

			ULONG nQcRet = pFn(Pin, szValue, &QcVerifyRetriesLeft, &QcUnblockRetriesLeft);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
			}
			else
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
		}

	}
#endif

	return (nRet == 0)?TRUE:FALSE;
}

BOOL CGobiApiDms::FuncDMSUimUnblockPin(CParamList* pParams /*= NULL*/)
{
	ADDSTATUS(L"FuncDMSUimUnblockPin", STATUSMSG_Send);

	const BYTE MAX_StringLength = 0xFF;

	ULONG Pin = 1;
	
	CHAR szPukValue[MAX_StringLength] = "1234";
	CHAR szNewValue[MAX_StringLength] = "1111";

	ULONG VerifyRetriesLeft  = 0xFF;
	ULONG UnblockRetriesLeft = 0xFF;

	// Get user selected parameters
	if (pParams)
	{
		Pin = _ttoi(pParams->GetValue(PARAM_PinId));
		WideCharToMultiByte(CP_ACP, 0, pParams->GetValue(PARAM_UnblockPuk), -1, szPukValue, MAX_StringLength, 0, 0);
		WideCharToMultiByte(CP_ACP, 0, pParams->GetValue(PARAM_NewPin), -1, szNewValue, MAX_StringLength, 0, 0);
	}

	ULONG nRet = DMSUIMUnblockPIN(Pin, szPukValue, szNewValue, &VerifyRetriesLeft, &UnblockRetriesLeft);

	CString strTemp;
	strTemp.Format(L"Return: %04d", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	if (nRet)
	{
		strTemp.Format(L"Verify Retries Left:  %d", VerifyRetriesLeft);
	    ADDSTATUS(strTemp, STATUSMSG_Receive);
		strTemp.Format(L"Unblock Retries Left: %d", UnblockRetriesLeft);
	    ADDSTATUS(strTemp, STATUSMSG_Receive);
	}

#if 0
	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_DMSUIMUNBLOCKPIN) (ULONG, CHAR*, CHAR*, ULONG*, ULONG*);

		// get pointer to function
		LPFN_DMSUIMUNBLOCKPIN pFn = (LPFN_DMSUIMUNBLOCKPIN)GetProcAddress_W(m_hQCDll, FUNC_DMSUimUnblockPin);

		// execute function
		if (pFn)
		{
			ULONG QcVerifyRetriesLeft  = 0xFF;
			ULONG QcUnblockRetriesLeft = 0xFF;

			ULONG nQcRet = pFn(Pin, szPukValue, szNewValue, &QcVerifyRetriesLeft, &QcUnblockRetriesLeft);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
			}
			else
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
		}

	}
#endif

	return (nRet == 0)?TRUE:FALSE;
}

BOOL CGobiApiDms::FuncDMSUimChangePin(CParamList* pParams /*= NULL*/)
{
	ADDSTATUS(L"FuncDMSUimChangePin", STATUSMSG_Send);

	const BYTE MAX_StringLength = 0xFF;

	ULONG Pin = 1;
	
	CHAR szOldValue[MAX_StringLength] = "1234";
	CHAR szNewValue[MAX_StringLength] = "1111";

	ULONG VerifyRetriesLeft  = 0xFF;
	ULONG UnblockRetriesLeft = 0xFF;

	if (pParams)
	{
		Pin = _ttoi(pParams->GetValue(PARAM_PinId));
		WideCharToMultiByte(CP_ACP, 0, pParams->GetValue(PARAM_OldPin), -1, szOldValue, MAX_StringLength, 0, 0);
		WideCharToMultiByte(CP_ACP, 0, pParams->GetValue(PARAM_NewPin), -1, szNewValue, MAX_StringLength, 0, 0);
	}

	ULONG nRet = DMSUIMChangePIN(Pin, szOldValue, szNewValue, &VerifyRetriesLeft, &UnblockRetriesLeft);

	CString strTemp;
	strTemp.Format(L"Return: %04d", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	if (nRet)
	{
		strTemp.Format(L"Verify Retries Left:  %d", VerifyRetriesLeft);
	    ADDSTATUS(strTemp, STATUSMSG_Receive);
		strTemp.Format(L"Unblock Retries Left: %d", UnblockRetriesLeft);
	    ADDSTATUS(strTemp, STATUSMSG_Receive);
	}

#if 0
	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_DMSUIMCHANGEPIN) (ULONG, CHAR*, CHAR*, ULONG*, ULONG*);

		// get pointer to function
		LPFN_DMSUIMCHANGEPIN pFn = (LPFN_DMSUIMCHANGEPIN)GetProcAddress_W(m_hQCDll, FUNC_DMSUimChangePin);

		// execute function
		if (pFn)
		{
			ULONG QcVerifyRetriesLeft  = 0xFF;
			ULONG QcUnblockRetriesLeft = 0xFF;

			ULONG nQcRet = pFn(Pin, szOldValue, szNewValue, &QcVerifyRetriesLeft, &QcUnblockRetriesLeft);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
			}
			else
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
		}

	}
#endif

	return (nRet == 0)?TRUE:FALSE;
}

BOOL CGobiApiDms::FuncDMSUimGetPinStatus(CParamList* pParams /*= NULL*/)
{
	ADDSTATUS(L"FuncDMSUimGetPinStatus", STATUSMSG_Send);

	BOOL bRet = FALSE;
	ULONG Pin = 1;
	ULONG Status = 0xFF;;
	ULONG VerifyRetriesLeft  = 0xFF;
	ULONG UnblockRetriesLeft = 0xFF;

	// Get user selected parameters
	if (pParams)
	{
		Pin = _ttoi(pParams->GetValue(PARAM_PinId));
	}

	ULONG nRet = DMSUIMGetPINStatus(Pin, &Status, &VerifyRetriesLeft, &UnblockRetriesLeft);

	CString strTemp;
	strTemp.Format(L"Return: %04d", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	if (!nRet)
	{
		switch (Status)
		{
			case 0:
				strTemp.Format(L"%d: PIN not initialized", Status);
				break;
			case 1:
				strTemp.Format(L"%d: PIN enabled, not verified", Status);
				break;
			case 2:
				strTemp.Format(L"%d: PIN enabled, verified", Status);
				break;
			case 3:
				strTemp.Format(L"%d: PIN disabled", Status);
				break;
			case 4:
				strTemp.Format(L"%d: PIN blocked", Status);
				break;
			case 5:
				strTemp.Format(L"%d: PIN permanently blocked", Status);
				break;
			default:
				strTemp.Format(L"PIN status:	%d", Status);
				break;
		}
		
	    ADDSTATUS(strTemp, STATUSMSG_Receive);
		strTemp.Format(L"Verify Retries Left:  %d", VerifyRetriesLeft);
	    ADDSTATUS(strTemp, STATUSMSG_Receive);
		strTemp.Format(L"Unblock Retries Left: %d", UnblockRetriesLeft);
	    ADDSTATUS(strTemp, STATUSMSG_Receive);
		bRet = TRUE;
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_DMSUIMGETPINSTATUS) (ULONG, ULONG*, ULONG*, ULONG*);

		// get pointer to function
		LPFN_DMSUIMGETPINSTATUS pFn = (LPFN_DMSUIMGETPINSTATUS)GetProcAddress_W(m_hQCDll, FUNC_DMSUimGetPinStatus);

		// execute function
		if (pFn)
		{
			ULONG QcStatus = 0xFF;;
			ULONG QcVerifyRetriesLeft  = 0xFF;
			ULONG QcUnblockRetriesLeft = 0xFF;

			ULONG nQcRet = pFn(Pin, &QcStatus, &QcVerifyRetriesLeft, &QcUnblockRetriesLeft);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (!(QcStatus == Status))
			{
				ADDSTATUS(L"Response differs from Qualcomm DLL", STATUSMSG_Error);
				bRet = FALSE;
			}
			else
			{
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
				bRet = TRUE;
			}
		}

	}

	return bRet;
}

BOOL CGobiApiDms::FuncDMSUimGetIccId(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncDMSUimGetIccId", STATUSMSG_Send);

	BOOL bRet = FALSE;
	const BYTE MAX_StringLength = 0xFF;
	CHAR szIccId[MAX_StringLength] = "";

	ULONG nRet = DMSUIMGetICCID(MAX_StringLength, szIccId);

	CString strTemp;
	strTemp.Format(L"Return: %04d", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	if (!nRet)
	{
		TCHAR szStringU[MAX_StringLength] = L"";

		if (MultiByteToWideChar(CP_ACP, 0, szIccId, MAX_StringLength, szStringU, MAX_StringLength) == MAX_StringLength)
		{
			strTemp.Format(L"%s", szStringU);
			ADDSTATUS(strTemp, STATUSMSG_Receive);
		}

		bRet = TRUE;
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_DMSUIMGETICCID) (BYTE, CHAR*);

		// get pointer to function
		LPFN_DMSUIMGETICCID pFn = (LPFN_DMSUIMGETICCID)GetProcAddress_W(m_hQCDll, FUNC_DMSUimGetIccId);

		// execute function
		if (pFn)
		{
			CHAR szQcIccId[MAX_StringLength] = "";

			ULONG nQcRet = pFn(MAX_StringLength, szQcIccId);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (0 != strcmp(szQcIccId, szIccId))
			{
				ADDSTATUS(L"Response differs from Qualcomm DLL", STATUSMSG_Error);
				bRet = FALSE;
			}
			else
			{
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
				bRet = TRUE;
			}
		}
	}

	return bRet;
}

BOOL CGobiApiDms::FuncDMSUimGetControlKeyStatus(CParamList* pParams /*= NULL*/)
{
	ADDSTATUS(L"FuncDMSUimGetControlKeyStatus", STATUSMSG_Send);
	//const BYTE MAX_StringLength = 0xFF;

	ULONG id = 1;
	ULONG Status = 0xFF;;
	ULONG VerifyRetriesLeft  = 0xFF;
	ULONG UnblockRetriesLeft = 0xFF;

	// Get user selected parameters
	if (pParams)
	{
		id = _ttoi(pParams->GetValue(PARAM_ControlKey_id));
	}

	ULONG nRet = DMSUIMGetControlKeyStatus(id, &Status, &VerifyRetriesLeft, &UnblockRetriesLeft);

	CString strTemp;
	strTemp.Format(L"Return: %04d", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	if (!nRet)
	{
		strTemp.Format(L"Control Key: %d, Status: %d", id, Status);
	    ADDSTATUS(strTemp, STATUSMSG_Receive);
		strTemp.Format(L"Verify Retries Left:  %d", VerifyRetriesLeft);
	    ADDSTATUS(strTemp, STATUSMSG_Receive);
		strTemp.Format(L"Unblock Retries Left: %d", UnblockRetriesLeft);
	    ADDSTATUS(strTemp, STATUSMSG_Receive);
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_DMSUIMGETCONTROLKEYSTATUS) (ULONG, ULONG*, ULONG*, ULONG*);

		// get pointer to function
		LPFN_DMSUIMGETCONTROLKEYSTATUS pFn = (LPFN_DMSUIMGETCONTROLKEYSTATUS)GetProcAddress_W(m_hQCDll, FUNC_DMSUimGetControlKeyStatus);

		// execute function
		if (pFn)
		{
			ULONG QcStatus = 0xFF;;
			ULONG QcVerifyRetriesLeft  = 0xFF;
			ULONG QcUnblockRetriesLeft = 0xFF;

			ULONG nQcRet = pFn(id, &QcStatus, &QcVerifyRetriesLeft, &QcUnblockRetriesLeft);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
			}
			else if (!(QcStatus == Status))
				ADDSTATUS(L"Response differs from Qualcomm DLL", STATUSMSG_Error);
			else
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
		}

	}

	return (nRet == 0)?TRUE:FALSE;
}

BOOL CGobiApiDms::FuncDMSUimSetControlKeyProtection(CParamList* pParams /*= NULL*/)
{
	ADDSTATUS(L"FuncDMSUimSetControlKeyProtection", STATUSMSG_Send);
	const BYTE MAX_StringLength = 0xFF;

	char szPassword[MAX_StringLength];

	ULONG id = 1;
	ULONG Status = 0xFF;;
	ULONG VerifyRetriesLeft  = 0xFF;

	// Get user selected parameters
	if (pParams)
	{
		id = _ttoi(pParams->GetValue(PARAM_ControlKey_id));
		Status = _ttoi(pParams->GetValue(PARAM_ControlKey_State));
		WideCharToMultiByte(CP_ACP, 0, pParams->GetValue(PARAM_ControlKey_String), -1, szPassword, MAX_StringLength, 0, 0);
	}

	ULONG nRet = DMSUIMSetControlKeyProtection(id, Status, szPassword, &VerifyRetriesLeft);

	CString strTemp;
	strTemp.Format(L"Return: %04d", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	if (!nRet)
	{
		strTemp.Format(L"Control Key Status:   %d", Status);
	    ADDSTATUS(strTemp, STATUSMSG_Receive);
	}
	strTemp.Format(L"Verify Retries Left:  %d", VerifyRetriesLeft);
	ADDSTATUS(strTemp, STATUSMSG_Receive);


	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_DMSUIMSETCONTROLKEYPROTECTION) (ULONG, ULONG, char*, ULONG*);

		// get pointer to function
		LPFN_DMSUIMSETCONTROLKEYPROTECTION pFn = (LPFN_DMSUIMSETCONTROLKEYPROTECTION)GetProcAddress_W(m_hQCDll, FUNC_DMSUimSetControlKeyProtection);

		// execute function
		if (pFn)
		{
			ULONG QcVerifyRetriesLeft  = 0xFF;

			ULONG nQcRet = pFn(id, Status, szPassword, &QcVerifyRetriesLeft);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
			}
//			else if (!(QcStatus == Status))
//				ADDSTATUS(L"Response differs from Qualcomm DLL", STATUSMSG_Error);
			else
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
		}

	}

	return (nRet == 0)?TRUE:FALSE;
}

BOOL CGobiApiDms::FuncDMSUimUnblockControlKey(CParamList* pParams /*= NULL*/)
{
	ADDSTATUS(L"FuncDMSUimUnblockControlKey", STATUSMSG_Send);
	const BYTE MAX_StringLength = 0xFF;

	char szPassword[MAX_StringLength];

	ULONG id = 1;
	ULONG UnblockRetriesLeft  = 0xFF;

	// Get user selected parameters
	if (pParams)
	{
		id = _ttoi(pParams->GetValue(PARAM_ControlKey_id));
		WideCharToMultiByte(CP_ACP, 0, pParams->GetValue(PARAM_ControlKey_String), -1, szPassword, MAX_StringLength, 0, 0);
	}

	ULONG nRet = DMSUIMUnblockControlKey(id, szPassword, &UnblockRetriesLeft);

	CString strTemp;
	strTemp.Format(L"Return: %04d", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	if (!nRet)
	{
		strTemp.Format(L"Verify Retries Left:  %d", UnblockRetriesLeft);
	    ADDSTATUS(strTemp, STATUSMSG_Receive);
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_DMSUIMUNBLOCKCONTROLKEY) (ULONG, char*, ULONG*);

		// get pointer to function
		LPFN_DMSUIMUNBLOCKCONTROLKEY pFn = (LPFN_DMSUIMUNBLOCKCONTROLKEY)GetProcAddress_W(m_hQCDll, FUNC_DMSUimUnblockControlKey);

		// execute function
		if (pFn)
		{
			ULONG QcUnblockRetriesLeft = 0xFF;

			ULONG nQcRet = pFn(id, szPassword, &QcUnblockRetriesLeft);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
			}
//			else if (!(QcStatus == Status))
//				ADDSTATUS(L"Response differs from Qualcomm DLL", STATUSMSG_Error);
			else
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
		}

	}

	return (nRet == 0)?TRUE:FALSE;
}

BOOL CGobiApiDms::FuncResetToFactoryDefaults(CParamList* pParams /*= NULL*/)
{
	ADDSTATUS(L"FuncResetToFactoryDefaults", STATUSMSG_Send);

	BOOL bRet = FALSE;
	CString strTemp;
	const ULONG MAX_SPC = 0xFF;
	CHAR szSPC[MAX_SPC] ;

	// Get user selected parameters
	if (pParams)
	{
		WideCharToMultiByte(CP_ACP, 0, pParams->GetValue(PARAM_SPC), -1, szSPC, MAX_SPC, 0, 0);
	}

	ULONG nRet = ResetToFactoryDefaults(szSPC);

	strTemp.Format(L"Return: %04d ", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);
	bRet = (nRet == 0)?TRUE:FALSE;

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_RESETTOFACTORYDEFAULTS) (CHAR*);
		
		// get pointer to function
		LPFN_RESETTOFACTORYDEFAULTS pFn = (LPFN_RESETTOFACTORYDEFAULTS)GetProcAddress_W(m_hQCDll, FUNC_ResetToFactoryDefaults);

		// execute function
		if (pFn)
		{
			ULONG nQcRet = pFn(szSPC);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else
			{
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
				bRet = TRUE;
			}
		}
	}

	return bRet;
}

BOOL CGobiApiDms::FuncValidateSPC(CParamList* pParams /*= NULL*/)
{
	ADDSTATUS(L"FuncValidateSPC", STATUSMSG_Send);

	BOOL bRet = FALSE;
	CString strTemp;
	const ULONG MAX_SPC = 0xFF;
	CHAR szSPC[MAX_SPC] ;

	// Get user selected parameters
	if (pParams)
	{
		WideCharToMultiByte(CP_ACP, 0, pParams->GetValue(PARAM_SPC), -1, szSPC, MAX_SPC, 0, 0);
	}

	ULONG nRet = ValidateSPC(szSPC);

	strTemp.Format(L"Return: %04d ", nRet);
	ADDSTATUS(strTemp, STATUSMSG_Receive);
	bRet = (nRet == 0)?TRUE:FALSE;

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (SWICMAPI*LPFN_VALIDATESPC) (CHAR*);
		
		// get pointer to function
		LPFN_VALIDATESPC pFn = (LPFN_VALIDATESPC)GetProcAddress_W(m_hQCDll, FUNC_ValidateSPC);

		// execute function
		if (pFn)
		{
			ULONG nQcRet = pFn(szSPC);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else
			{
				ADDSTATUS(L"Response matches Qualcomm DLL", STATUSMSG_Status);
				bRet = TRUE;
			}
		}
	}

	return bRet;
}

// DMS Callback tests

static void SWICALLBACK ActivationStatusCallback(ULONG activationStatus)
{
	CString strTemp;
	strTemp.Format(L"Activation Status: %d", activationStatus);
	ADDSTATUS(strTemp, STATUSMSG_Notif);  
}

BOOL CGobiApiDms::FuncSetActivationStatusCallback(CParamList* pParams /*= NULL*/)
{
	ADDSTATUS(L"FuncSetActivationStatusCallback", STATUSMSG_Send);

	ULONG ret = 0;

	if (0 != _ttoi(pParams->GetValue(PARAM_Enable)))
	{
		ret = SetActivationStatusCallback(ActivationStatusCallback);
	}
	else
	{
		ret = SetActivationStatusCallback(NULL);
	}

	CString strTemp;
	strTemp.Format(L"Result: %d", ret);
	ADDSTATUS(strTemp, (0==ret)?STATUSMSG_Receive:STATUSMSG_Error);

	return !ret;
}

static void SWICALLBACK PowerCallback(ULONG operatingMode)
{
	CString strTemp;
	strTemp.Format(L"Operating Mode: %d", operatingMode);
	ADDSTATUS(strTemp, STATUSMSG_Notif);  
}

BOOL CGobiApiDms::FuncSetPowerCallback(CParamList* pParams /*= NULL*/)
{
	ADDSTATUS(L"FuncSetPowerCallback", STATUSMSG_Send);

	ULONG ret = 0;

	if (0 != _ttoi(pParams->GetValue(PARAM_Enable)))
	{
		ret = SetPowerCallback(PowerCallback);
	}
	else
	{
		ret = SetPowerCallback(NULL);
	}

	CString strTemp;
	strTemp.Format(L"Result: %d", ret);
	ADDSTATUS(strTemp, (0==ret)?STATUSMSG_Receive:STATUSMSG_Error);

	return !ret;
}

BOOL CGobiApiDms::FuncSwitchModemToBootMode(CParamList * pParams)
{
    ADDSTATUS(L"SwitchModemToBootMode", STATUSMSG_Send);
	UNREFERENCED_PARAMETER(pParams);

    ULONG ret = SwitchModemToBootMode();

    CString strTemp;
    strTemp.Format(L"Result: %d", ret);
    ADDSTATUS(strTemp, (0==ret)?STATUSMSG_Receive:STATUSMSG_Error);

    return !ret;
}