#include "StdAfx.h"
#include <GobiAPI.h>
#include "GobiApiNas.h"
#include "FuncList.h"
#include "StatusCtrl.h"
#include "GobiConnectionMgmtApi.h"
#include "SwiWwanCmApi.h"

#define SPCLength	7

#define FUNC_GetServingNetwork				L"GetServingNetwork"
#define FUNC_GetServingNetworkCapabilities	L"GetServingNetworkCapabilities"
#define FUNC_SwiGetServingNetwork			L"SwiGetServingNetwork"
#define FUNC_GetSignalStrengths				L"GetSignalStrengths"
#define FUNC_PerformNetworkScan             L"PerformNetworkScan"
#define FUNC_PerformNetworkRATScan          L"PerformNetworkRATScan"
#define FUNC_InitiateNetworkRegistration    L"InitiateNetworkRegistration"
#define FUNC_InitiateDomainAttach           L"InitiateDomainAttach"
#define FUNC_GetHomeNetwork					L"GetHomeNetwork"
#define FUNC_GetNetworkPreference           L"GetNetworkPreference"
#define FUNC_SetNetworkPreference           L"SetNetworkPreference"
#define FUNC_SetSignalStrengthCallback		L"SetSignalStrengthCallback"
#define FUNC_SetRoamingIndicatorCallback	L"SetRoamingIndicatorCallback"
#define FUNC_SetDataCapabilitiesCallback	L"SetDataCapabilitiesCallback"
#define FUNC_SetCDMANetworkParameters    	L"SetCDMANetworkParameters"
#define FUNC_GetCDMANetworkParameters		L"GetCDMANetworkParameters"
#define FUNC_SetACCOLC						L"SetACCOLC"
#define FUNC_GetACCOLC						L"GetACCOLC"
#define FUNC_GetANAAAAuthenticationStatus	L"GetANAAAAuthenticationStatus"
#define FUNC_GetRFInfo						L"GetRFInfo"
#define FUNC_SetRFInfoCallback				L"SetRFInfoCallback"
#define FUNC_SetLURejectCallback			L"SetLURejectCallback"
#define FUNC_SetPLMNModeCallback            L"SetPLMNModeCallback"
#define FUNC_GetPLMNMode                    L"GetPLMNMode"
#define FUNC_GetPLMNName                    L"GetPLMNName"
#define FUNC_SwiSetEcioCallback				L"SwiSetEcioCallback"
#define FUNC_SwiSetSnirCallback				L"SwiSetSnirCallback"
#define FUNC_SwiSetErrorRateCallback		L"SwiSetErrorRateCallback"
#define FUNC_SwiSetRsrqCallback				L"SwiSetRsrqCallback"
#define FUNC_SwiGetSignalStrengthInfo		L"SwiGetSignalStrengthInfo"
#define FUNC_SwiSetSignalStrengthInfoCallback		L"SwiSetSignalStrengthInfoCallaback"

#define PARAM_TechPref						L"TechnologyPref"
#define PARAM_Duration						L"Duration"
#define PARAM_SPC							L"SPC"
#define PARAM_ForceRev0						L"ForceRev0"
#define PARAM_CustomSCP						L"CustomSCP"
#define PARAM_Protocol						L"Protocol"
#define PARAM_Broadcast						L"Broadcast"
#define PARAM_Application					L"Application"
#define PARAM_Roaming						L"Roaming"
#define PARAM_ACCOLC						L"ACCOLC"
#define PARAM_RegType						L"RegType"
#define PARAM_Mcc							L"MCC"
#define PARAM_Mnc							L"MNC"
#define PARAM_Rat							L"RAT"
#define PARAM_Action						L"Action"
#define PARAM_Enable						L"Enable"
#define PARAM_Threshold						L"Threshold"

CParamList CGobiApiNas::m_sSetNetworkPrefParams;
CParamList CGobiApiNas::m_sSetCDMANetworkParameters;
CParamList CGobiApiNas::m_sSetACCOLC;
CParamList CGobiApiNas::m_sInitiateNetworkRegistration;
CParamList CGobiApiNas::m_sInitiateDomainAttach;
CParamList CGobiApiNas::m_sGetPLMNName;
CParamList CGobiApiNas::m_sSetSignalStrengthCallback;
CParamList CGobiApiNas::m_sSetRoamingIndicatorCallback;
CParamList CGobiApiNas::m_sSetDataCapabilitiesCallback;
CParamList CGobiApiNas::m_sSetRFInfoCallback;
CParamList CGobiApiNas::m_sSetLURejectCallback;
CParamList CGobiApiNas::m_sSetPLMNModeCallback;
CParamList CGobiApiNas::m_sSwiSetEcioCallback;
CParamList CGobiApiNas::m_sSwiSetSnirCallback;
CParamList CGobiApiNas::m_sSwiSetErrorRateCallback;
CParamList CGobiApiNas::m_sSwiSetRsrqCallback;
CParamList CGobiApiNas::m_sSwiSetSignalStrengthInfoCallback;

// List of supported functions
const TableFuncEntry CGobiApiNas::m_TableFunc[] = 
{
	{FUNC_GetServingNetwork, FuncGetServingNetwork},
	{FUNC_GetServingNetworkCapabilities, FuncGetServingNetworkCapabilities},
	{FUNC_SwiGetServingNetwork, FuncSwiGetServingNetwork},
	{FUNC_GetSignalStrengths, FuncGetSignalStrengths},
	{FUNC_PerformNetworkScan, FuncPerformNetworkScan},
	{FUNC_PerformNetworkRATScan, FuncPerformNetworkRATScan},
	{FUNC_InitiateNetworkRegistration, FuncInitiateNetworkRegistration, &m_sInitiateNetworkRegistration},
	{FUNC_InitiateDomainAttach, FuncInitiateDomainAttach, &m_sInitiateDomainAttach},
	{FUNC_GetHomeNetwork, FuncGetHomeNetwork},
	{FUNC_GetNetworkPreference, FuncGetNetworkPreference},
	{FUNC_SetNetworkPreference, FuncSetNetworkPreference, &m_sSetNetworkPrefParams},
	{FUNC_SetCDMANetworkParameters, FuncSetCDMANetworkParameters, &m_sSetCDMANetworkParameters},
	{FUNC_GetCDMANetworkParameters, FuncGetCDMANetworkParameters},
	{FUNC_SetACCOLC, FuncSetACCOLC, &m_sSetACCOLC},
	{FUNC_GetACCOLC, FuncGetACCOLC},
	{FUNC_GetANAAAAuthenticationStatus, FuncGetANAAAAuthenticationStatus},
	{FUNC_GetRFInfo, FuncGetRFInfo},
	{FUNC_GetPLMNMode, FuncGetPLMNMode},
	{FUNC_GetPLMNName, FuncGetPLMNName, &m_sGetPLMNName},
	{FUNC_SwiGetSignalStrengthInfo, FuncSwiGetSignalStrengthInfo},
	{FUNC_SetSignalStrengthCallback, FuncSetSignalStrengthCallback, &m_sSetSignalStrengthCallback},
	{FUNC_SetRoamingIndicatorCallback, FuncSetRoamingIndicatorCallback, &m_sSetRoamingIndicatorCallback},
	{FUNC_SetDataCapabilitiesCallback, FuncSetDataCapabilitiesCallback, &m_sSetDataCapabilitiesCallback},
	{FUNC_SetRFInfoCallback, FuncSetRFInfoCallback, &m_sSetRFInfoCallback},
	{FUNC_SetLURejectCallback, FuncSetLURejectCallback, &m_sSetLURejectCallback},
	{FUNC_SetPLMNModeCallback, FuncSetPLMNModeCallback, &m_sSetPLMNModeCallback},
	{FUNC_SwiSetEcioCallback, FuncSwiSetEcioCallback, &m_sSwiSetEcioCallback},
	{FUNC_SwiSetSnirCallback, FuncSwiSetSnirCallback, &m_sSwiSetSnirCallback},
	{FUNC_SwiSetErrorRateCallback, FuncSwiSetErrorRateCallback, &m_sSwiSetErrorRateCallback},
	{FUNC_SwiSetRsrqCallback, FuncSwiSetRsrqCallback, &m_sSwiSetRsrqCallback},
	{FUNC_SwiSetSignalStrengthInfoCallback, FuncSwiSetSignalStrengthInfoCallback, &m_sSwiSetSignalStrengthInfoCallback},
	{FUNC_EndOfList}
};

CGobiApiNas::CGobiApiNas(HMODULE hQCDll)
{
	m_hQCDll = hQCDll;

	// Define configurable parameters for SetNetworkPrefParams
	m_sSetNetworkPrefParams.Add(PARAM_TechPref, L"0");
	m_sSetNetworkPrefParams.Add(PARAM_Duration, L"1");

	// Define configurable parameters for SetCDMANetworkParameters 
	m_sSetCDMANetworkParameters.Add(PARAM_SPC, L"123456");
	m_sSetCDMANetworkParameters.Add(PARAM_ForceRev0, L"0");
	m_sSetCDMANetworkParameters.Add(PARAM_CustomSCP, L"0");
	m_sSetCDMANetworkParameters.Add(PARAM_Protocol, L"0");
	m_sSetCDMANetworkParameters.Add(PARAM_Broadcast, L"0");
	m_sSetCDMANetworkParameters.Add(PARAM_Application, L"0");
	m_sSetCDMANetworkParameters.Add(PARAM_Roaming, L"0");

	// Define configurable parameters for SetACCOLC
	m_sSetACCOLC.Add(PARAM_SPC, L"123456");
	m_sSetACCOLC.Add(PARAM_ACCOLC, L"0");

	// Define configurable parameters for InitiateNetworkRegistration
	m_sInitiateNetworkRegistration.Add(PARAM_RegType, L"2"); // Manual Registration
	m_sInitiateNetworkRegistration.Add(PARAM_Mcc, L"302");
	m_sInitiateNetworkRegistration.Add(PARAM_Mnc, L"720");	// Default to Rogers
	m_sInitiateNetworkRegistration.Add(PARAM_Rat, L"4");	// 0x04 = GSM, 0x05 = UMTS   

	// Define configurable parameters for InitiateDomainAttach
	m_sInitiateDomainAttach.Add(PARAM_Action, L"2");		// 1 = attach, 2 = detach

	// Define configurable parameters for GetPLMNName
    m_sGetPLMNName.Add(PARAM_Mcc, L"302");
    m_sGetPLMNName.Add(PARAM_Mnc, L"720");	// Default to Rogers
    
	// Define configurable parameters for callbacks
	m_sSetSignalStrengthCallback.Add(PARAM_Enable, L"1");
	m_sSetDataCapabilitiesCallback.Add(PARAM_Enable, L"1");
	m_sSetRoamingIndicatorCallback.Add(PARAM_Enable, L"1");
	m_sSetRFInfoCallback.Add(PARAM_Enable, L"1");
	m_sSetLURejectCallback.Add(PARAM_Enable, L"1");
    m_sSetPLMNModeCallback.Add(PARAM_Enable, L"1");
	m_sSwiSetEcioCallback.Add(PARAM_Enable, L"1");
	m_sSwiSetEcioCallback.Add(PARAM_Threshold, L"2");
	m_sSwiSetSnirCallback.Add(PARAM_Enable, L"1");
	m_sSwiSetSnirCallback.Add(PARAM_Threshold, L"2");
	m_sSwiSetErrorRateCallback.Add(PARAM_Enable, L"1");
	m_sSwiSetRsrqCallback.Add(PARAM_Enable, L"1");
	m_sSwiSetRsrqCallback.Add(PARAM_Threshold, L"2");
	m_sSwiSetSignalStrengthInfoCallback.Add(PARAM_Enable, L"1");
}

CGobiApiNas::~CGobiApiNas(void)
{
}

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

	int iIndex = 0;

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

	return TRUE;
}

UINT CGobiApiNas::ExecuteFunctions(CFuncList* pFuncList, UINT &nTotalExec)
{
	TBD_FUNCTION(CGobiApiNas::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 CGobiApiNas::FuncGetServingNetwork(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetServingNetwork", STATUSMSG_Send);

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

	// create structure for easy comparison later
	typedef struct 
	{
		ULONG   RegistrationState; 
		ULONG   CSDomain ; 
		ULONG   PSDomain; 
		ULONG   RAN; 
		BYTE    RadioIfacesSize;
		BYTE    RadioIfaces[MAX_RInt]; 
		ULONG   Roaming; 
		WORD    MCC; 
		WORD    MNC;
		BYTE	NameSize;
		CHAR    Name[MAX_Name];
	} STRUCT_GetServingNetwork;

	STRUCT_GetServingNetwork sParam;

	// clear structure
	memset(&sParam, 0, sizeof(STRUCT_GetServingNetwork));
	// initialize structure
	sParam.RadioIfacesSize = MAX_RInt;
	sParam.NameSize = MAX_Name;

	// call Sierra interface
	ULONG nRet = GetServingNetwork(&sParam.RegistrationState, 
								   &sParam.CSDomain, 
								   &sParam.PSDomain, 
								   &sParam.RAN, 
								   &sParam.RadioIfacesSize, 
								   sParam.RadioIfaces, 
								   &sParam.Roaming, 
								   &sParam.MCC, 
								   &sParam.MNC, 
								   sParam.NameSize, 
								   sParam.Name);

	// display output in GUI
	CString strTemp;
	strTemp.Format(L"Result: %04d", nRet);
	ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

	if (!nRet)
	{
		strTemp.Format(L"RegState: %04d CSDomain: %04d PSDomain: %04d", sParam.RegistrationState, sParam.CSDomain, sParam.PSDomain);
		ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
		strTemp.Format(L"Roaming: %04d MCC: %04d MNC: %04d", sParam.Roaming, sParam.MCC, sParam.MNC);
		ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
		strTemp.Format(L"RAN: %d", sParam.RAN);
		ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

		strTemp.Format(L"Number of Radio Interfaces received: %d", sParam.RadioIfacesSize);
		ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

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

		TCHAR szStringU[MAX_Name] = L"";

		if (MultiByteToWideChar(CP_ACP, 0, sParam.Name, sParam.NameSize, szStringU, MAX_Name) == sParam.NameSize)
		{
			strTemp.Format(L"Network: %s", szStringU);
			ADDSTATUS(strTemp, STATUSMSG_Receive);
		}
				
		bRet = TRUE;
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (GOBICMAPI*LPFN_GETSERVINGNETWORK) (ULONG*, ULONG*, ULONG*, ULONG*, BYTE*, BYTE*, ULONG*, WORD*, WORD*, BYTE, CHAR*);

		// get pointer to function
		LPFN_GETSERVINGNETWORK pFn = (LPFN_GETSERVINGNETWORK)GetProcAddress_W(m_hQCDll, FUNC_GetServingNetwork);

		// execute function
		if (pFn)
		{
			STRUCT_GetServingNetwork sQcParam;
			// clear structure
			memset(&sQcParam, 0, sizeof(STRUCT_GetServingNetwork));
			sQcParam.RadioIfacesSize = MAX_RInt;
			sQcParam.NameSize = MAX_Name;

			ULONG nQcRet = pFn(&sQcParam.RegistrationState, 
							  &sQcParam.CSDomain, 
							  &sQcParam.PSDomain, 
							  &sQcParam.RAN, 
							  &sQcParam.RadioIfacesSize, 
							  sQcParam.RadioIfaces, 
							  &sQcParam.Roaming, 
							  &sQcParam.MCC, 
							  &sQcParam.MNC, 
							  sQcParam.NameSize, 
							  sQcParam.Name);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (0 != memcmp(&sQcParam, &sParam, sizeof(STRUCT_GetServingNetwork)))
			{
				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 CGobiApiNas::FuncSwiGetServingNetwork(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncSwiGetServingNetwork", STATUSMSG_Send);

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

	// create structure for easy comparison later
	typedef struct 
	{
		ULONG   RegistrationState; 
		ULONG   CSDomain ; 
		ULONG   PSDomain; 
		ULONG   RAN; 
		BYTE    RadioIfacesSize;
		BYTE    RadioIfaces[MAX_RInt]; 
		ULONG   Roaming; 
		WORD    MCC; 
		WORD    MNC;
		BYTE	NameSize;
		CHAR    Name[MAX_Name];
        WORD SID;
        WORD NID;
	} STRUCT_GetServingNetwork;

	STRUCT_GetServingNetwork sParam;

	// clear structure
	memset(&sParam, 0, sizeof(STRUCT_GetServingNetwork));
	// initialize structure
	sParam.RadioIfacesSize = MAX_RInt;
	sParam.NameSize = MAX_Name;

	// call Sierra interface
	ULONG nRet = SwiGetServingNetwork(&sParam.RegistrationState, 
								   &sParam.CSDomain, 
								   &sParam.PSDomain, 
								   &sParam.RAN, 
								   &sParam.RadioIfacesSize, 
								   sParam.RadioIfaces, 
								   &sParam.Roaming, 
								   &sParam.MCC, 
								   &sParam.MNC, 
								   sParam.NameSize, 
								   sParam.Name,
								   &sParam.SID,
								   &sParam.NID);

	// display output in GUI
	CString strTemp;
	strTemp.Format(L"Result: %04d", nRet);
	ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

	if (!nRet)
	{
		strTemp.Format(L"RegState: %04d CSDomain: %04d PSDomain: %04d", sParam.RegistrationState, sParam.CSDomain, sParam.PSDomain);
		ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
		strTemp.Format(L"Roaming: %04d MCC: %04d MNC: %04d", sParam.Roaming, sParam.MCC, sParam.MNC);
		ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
		strTemp.Format(L"RAN: %d", sParam.RAN);
		ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

		strTemp.Format(L"Number of Radio Interfaces received: %d", sParam.RadioIfacesSize);
		ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

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

		TCHAR szStringU[MAX_Name] = L"";

		if (MultiByteToWideChar(CP_ACP, 0, sParam.Name, sParam.NameSize, szStringU, MAX_Name) == sParam.NameSize)
		{
			strTemp.Format(L"Network: %s", szStringU);
			ADDSTATUS(strTemp, STATUSMSG_Receive);
		}

		strTemp.Format(L"CDMA System ID: %d Network ID: %d ", sParam.SID, sParam.NID);
		ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
                
		bRet = TRUE;
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (GOBICMAPI*LPFN_GETSERVINGNETWORK) (ULONG*, ULONG*, ULONG*, ULONG*, BYTE*, BYTE*, ULONG*, WORD*, WORD*, BYTE, CHAR*);

		// get pointer to function
		LPFN_GETSERVINGNETWORK pFn = (LPFN_GETSERVINGNETWORK)GetProcAddress_W(m_hQCDll, FUNC_GetServingNetwork);

		// execute function
		if (pFn)
		{
			STRUCT_GetServingNetwork sQcParam;
			// clear structure
			memset(&sQcParam, 0, sizeof(STRUCT_GetServingNetwork));
			sQcParam.RadioIfacesSize = MAX_RInt;
			sQcParam.NameSize = MAX_Name;

			ULONG nQcRet = pFn(&sQcParam.RegistrationState, 
							  &sQcParam.CSDomain, 
							  &sQcParam.PSDomain, 
							  &sQcParam.RAN, 
							  &sQcParam.RadioIfacesSize, 
							  sQcParam.RadioIfaces, 
							  &sQcParam.Roaming, 
							  &sQcParam.MCC, 
							  &sQcParam.MNC, 
							  sQcParam.NameSize, 
							  sQcParam.Name);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (0 != memcmp(&sQcParam, &sParam, sizeof(STRUCT_GetServingNetwork)))
			{
				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 CGobiApiNas::FuncGetServingNetworkCapabilities(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	BOOL bRet = FALSE;
	ADDSTATUS(L"FuncGetServingNetworkCapabilities", STATUSMSG_Send);

	const BYTE MAX_DsCapabilities = 32; // Should be more than enough

	// create structure for easy comparison later
	typedef struct 
	{
		BYTE DataCapsSize;
		BYTE DataCaps[MAX_DsCapabilities];
	} STRUCT_GetServingNetworkCapabilities;

	STRUCT_GetServingNetworkCapabilities sParam;
	// clear structure
	memset(&sParam, 0, sizeof(STRUCT_GetServingNetworkCapabilities));
	// initialize structure
	sParam.DataCapsSize = MAX_DsCapabilities;

	// call Sierra interface
	ULONG nRet = GetServingNetworkCapabilities(&sParam.DataCapsSize, 
								               &sParam.DataCaps[0]);

	// display output in GUI
	CString strTemp;
	strTemp.Format(L"Result: %04d", nRet);
	ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

	if (!nRet)
	{
		strTemp.Format(L"Number of Capabilities received: %d", sParam.DataCapsSize);
		ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

		ULONG DataCap;
		for(ULONG i=0; i<sParam.DataCapsSize; i++)
		{
			DataCap = sParam.DataCaps[i];
			strTemp.Format(L"Capability %d is %04d", i+1, DataCap);
			ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
		}

		bRet = TRUE;
	}

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

		// get pointer to function
		LPFN_GETSERVINGNETWORKCAPABILITIES pFn = (LPFN_GETSERVINGNETWORKCAPABILITIES)GetProcAddress_W(m_hQCDll, 
			                                      FUNC_GetServingNetworkCapabilities);

		// execute function
		if (pFn)
		{
			STRUCT_GetServingNetworkCapabilities sQcParam;
			// clear structure
			memset(&sQcParam, 0, sizeof(STRUCT_GetServingNetworkCapabilities));
			sQcParam.DataCapsSize = MAX_DsCapabilities;

			ULONG nQcRet = pFn(&sQcParam.DataCapsSize, &sQcParam.DataCaps[0]);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (0 != memcmp(&sQcParam, &sParam, sizeof(STRUCT_GetServingNetworkCapabilities)))
			{
				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 CGobiApiNas::FuncGetSignalStrengths(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetSignalStrengths", STATUSMSG_Send);

	BOOL bRet = FALSE;
	const BYTE MAX_SStr = 0x20; // Wild guess 

	// create structure for easy comparison later
	typedef struct 
	{
		ULONG   ArraySize; 
		INT8    SignalStrength[MAX_SStr]; 
		ULONG   RadioInterface[MAX_SStr];
	} STRUCT_GetSignalStrengths;

	STRUCT_GetSignalStrengths sParam;
	// clear structure
	memset(&sParam, 0, sizeof(STRUCT_GetSignalStrengths));
	// initialize structure
	sParam.ArraySize = MAX_SStr;

	// call Sierra interface
	ULONG nRet = GetSignalStrengths(&sParam.ArraySize, 
								    &sParam.SignalStrength[0], 
								    &sParam.RadioInterface[0]);

	// display output in GUI
	CString strTemp;
	strTemp.Format(L"Result: %04d", nRet);
	ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

	if (!nRet)
	{
		strTemp.Format(L"#Sigstrengths: %d", sParam.ArraySize);
		ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

		// Now each pair in the array 
		for( ULONG i=0; i<sParam.ArraySize; i++ )
		{
			strTemp.Format(L"SignalStrength: %d, RadioIF: %d", sParam.SignalStrength[i], sParam.RadioInterface[i]);
			ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
		}

		bRet = TRUE;
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (GOBICMAPI*LPFN_GETSIGNALSTRENGTHS) (ULONG*, INT8*, ULONG*);

		// get pointer to function
		LPFN_GETSIGNALSTRENGTHS pFn = (LPFN_GETSIGNALSTRENGTHS)GetProcAddress_W(m_hQCDll, FUNC_GetSignalStrengths);

		// execute function
		if (pFn)
		{
			STRUCT_GetSignalStrengths sQcParam;
			// clear structure
			memset(&sQcParam, 0, sizeof(STRUCT_GetSignalStrengths));
			sQcParam.ArraySize = MAX_SStr;

			ULONG nQcRet = pFn(&sQcParam.ArraySize, 
							  &sQcParam.SignalStrength[0], 
							  &sQcParam.RadioInterface[0]);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (0 != memcmp(&sQcParam, &sParam, sizeof(STRUCT_GetSignalStrengths)))
			{
				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 CGobiApiNas::FuncPerformNetworkScan(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	BYTE        InstanceSize;
	const BYTE  INSTANCESIZE = 10;    // Assume up to 10 networks can be scanned
	const BYTE MAX_Name = 255;
	BOOL bRet = FALSE;

	ADDSTATUS(L"PerformNetworkScan", STATUSMSG_Send);
	ADDSTATUS(L"Please wait a moment...", STATUSMSG_Send);

	// create structure for easy comparison later
	typedef struct 
	{
		WORD    mMcc; 
		WORD    mMnc; 
		ULONG   mInUse;
		ULONG   mRoaming;
        ULONG	mForbidden;
		ULONG   mPreferred;
		CHAR    mDescription[MAX_Name];
	} STRUCT_PerformNetworkScan;

	STRUCT_PerformNetworkScan sParam[INSTANCESIZE];
	InstanceSize = INSTANCESIZE;

	// clear structure
	memset(&sParam[0], 0, sizeof(sParam));

	// call Sierra interface
	ULONG nRet = PerformNetworkScan(
		                   (BYTE*) &InstanceSize,
						   (BYTE*) &sParam[0]);

	// display output in GUI
	CString strTemp;
	strTemp.Format(L"Result: %04d", nRet);
	ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

	if (!nRet)
	{
		strTemp.Format(L"#NumInstances: %04d", InstanceSize);
		ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

		// Print each member of the array 
		for( ULONG i=0; i<InstanceSize; i++ )
		{
			strTemp.Format(L"NetworkScanResult: %d", i );
			ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
			strTemp.Format(L"Mcc: %d, Mnc: %d, InUse: %d, Roaming: %d, Forbidden: %d, Preferred: %d", 
				           sParam[i].mMcc, sParam[i].mMnc, sParam[i].mInUse, sParam[i].mRoaming, sParam[i].mForbidden, sParam[i].mPreferred);
			ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

		    TCHAR szStringU[MAX_Name] = L"";
            if (MultiByteToWideChar(CP_ACP, 0, &sParam[i].mDescription[0], MAX_Name, szStringU, MAX_Name) == MAX_Name) 
		    {
			    strTemp.Format(L"Network: %s", szStringU);
			    ADDSTATUS(strTemp, STATUSMSG_Receive);
		    }
		}

		bRet = TRUE;
	}

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

		// get pointer to function
		LPFN_PERFORMNETWORKSCAN pFn = (LPFN_PERFORMNETWORKSCAN)GetProcAddress_W(m_hQCDll, FUNC_PerformNetworkScan);

		// execute function
		if (pFn)
		{
			ADDSTATUS(L"Performing scan with QC DLL, please wait a moment...", STATUSMSG_Send);

			STRUCT_PerformNetworkScan sQcParam[INSTANCESIZE];
			// clear structure
			memset(&sQcParam[0], 0, sizeof(sQcParam));
            InstanceSize = INSTANCESIZE;
			ULONG nQcRet = pFn((BYTE*) &InstanceSize, (BYTE*) &sQcParam[0]);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (0 != memcmp(&sQcParam[0], &sParam[0], sizeof(STRUCT_PerformNetworkScan)))
			{
				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 CGobiApiNas::FuncPerformNetworkRATScan(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
    BYTE        InstanceSize;
    BYTE        RATInstanceSize;
    const BYTE  INSTANCESIZE = 10;    // Assume up to 10 networks can be scanned
    const BYTE MAX_Name = 255;
    BOOL bRet = FALSE;

    ADDSTATUS(L"FuncPerformNetworkRATScan", STATUSMSG_Send);
    ADDSTATUS(L"Please wait a moment...", STATUSMSG_Send);

    // create structure for easy comparison later
    typedef struct 
    {
        WORD    mMcc; 
        WORD    mMnc; 
        ULONG   mInUse;
        ULONG   mRoaming;
        ULONG	mForbidden;
        ULONG   mPreferred;
        CHAR    mDescription[MAX_Name];
    } STRUCT_PerformNetworkScan;

    typedef struct 
    {
        WORD    mMcc; 
        WORD    mMnc; 
        ULONG   mRAT;
    } STRUCT_PerformNetworkRATScan;

    STRUCT_PerformNetworkScan sParam[INSTANCESIZE];
    InstanceSize = INSTANCESIZE;

    STRUCT_PerformNetworkRATScan sParamRAT[INSTANCESIZE];
    RATInstanceSize = INSTANCESIZE;
        
    // clear structure
    memset(&sParam[0], 0, sizeof(sParam));
    memset(&sParamRAT[0], 0, sizeof(sParamRAT));

    // call Sierra interface
    ULONG nRet = PerformNetworkRATScan(
                            (BYTE*) &InstanceSize,
                            (BYTE*) &sParam[0],
                            (BYTE*) &RATInstanceSize,
                            (BYTE*) &sParamRAT[0]);

    // display output in GUI
    CString strTemp;
    strTemp.Format(L"Result: %04d", nRet);
    ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

    if (!nRet)
    {
        strTemp.Format(L"#NumInstances: %04d", InstanceSize);
        ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

        // Print each member of the array 
        for( ULONG i=0; i<InstanceSize; i++ )
        {
            strTemp.Format(L"NetworkScanResult: %d", i );
            ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
            strTemp.Format(L"Mcc: %d, Mnc: %d, InUse: %d, Roaming: %d, Forbidden: %d, Preferred: %d", 
                            sParam[i].mMcc, sParam[i].mMnc, sParam[i].mInUse, sParam[i].mRoaming, sParam[i].mForbidden, sParam[i].mPreferred);
            ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

            TCHAR szStringU[MAX_Name] = L"";
            if (MultiByteToWideChar(CP_ACP, 0, &sParam[i].mDescription[0], MAX_Name, szStringU, MAX_Name) == MAX_Name) 
            {
                strTemp.Format(L"Network: %s", szStringU);
                ADDSTATUS(strTemp, STATUSMSG_Receive);
            }
        }

        strTemp.Format(L"#NumRATInstances: %04d", RATInstanceSize);
        ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

        // Print each member of the array 
        for( ULONG i=0; i<RATInstanceSize; i++ )
        {
            strTemp.Format(L"No. %d: Mcc: %d, Mnc: %d, RAT: %d", i,
                            sParamRAT[i].mMcc, sParamRAT[i].mMnc, sParamRAT[i].mRAT);
            ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
        }
        bRet = TRUE;
    }

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

        // get pointer to function
        LPFN_PERFORMNETWORKRATSCAN pFn = (LPFN_PERFORMNETWORKRATSCAN)GetProcAddress_W(m_hQCDll, FUNC_PerformNetworkRATScan);

        // execute function
        if (pFn)
        {
            ADDSTATUS(L"Performing scan with QC DLL, please wait a moment...", STATUSMSG_Send);

            STRUCT_PerformNetworkScan sQcParam[INSTANCESIZE];
            STRUCT_PerformNetworkScan sQcRATParam[INSTANCESIZE];
            // clear structure
            memset(&sQcParam[0], 0, sizeof(sQcParam));
            memset(&sQcRATParam[0], 0, sizeof(sQcParam));
            InstanceSize = INSTANCESIZE;
            RATInstanceSize = INSTANCESIZE;
            ULONG nQcRet = pFn((BYTE*) &InstanceSize, (BYTE*) &sQcParam[0], (BYTE*) &RATInstanceSize, (BYTE*) &sQcRATParam[0]);

            if (nQcRet != nRet)
            {
                strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
                ADDSTATUS(strTemp, STATUSMSG_Error);
                bRet = FALSE;
            }
            else if (0 != memcmp(&sQcParam[0], &sParam[0], sizeof(STRUCT_PerformNetworkScan)))
            {
                ADDSTATUS(L"Response differs from Qualcomm DLL", STATUSMSG_Error);
                bRet = FALSE;
            }
            else if (0 != memcmp(&sQcRATParam[0], &sParamRAT[0], sizeof(STRUCT_PerformNetworkScan)))
            {
                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 CGobiApiNas::FuncInitiateNetworkRegistration(CParamList* pParams /*= NULL*/)
{
	BOOL bRet = FALSE;

	ADDSTATUS(L"FuncInitiateNetworkRegistration", STATUSMSG_Send);

	// create structure for easy comparison later
	typedef struct 
	{
		ULONG   regType; 
		WORD    mcc; 
		WORD    mnc;
		ULONG   rat;
	} STRUCT_InitiateNetworkRegistration;

	STRUCT_InitiateNetworkRegistration sParam;
	// clear structure
	memset(&sParam, 0, sizeof(STRUCT_InitiateNetworkRegistration));
	
	// initialize structure
	sParam.regType = _ttoi(pParams->GetValue(PARAM_RegType));
	sParam.mcc = (WORD)_ttoi(pParams->GetValue(PARAM_Mcc));
	sParam.mnc = (WORD)_ttoi(pParams->GetValue(PARAM_Mnc));
	sParam.rat = (WORD)_ttoi(pParams->GetValue(PARAM_Rat));

	// call Sierra interface
	ULONG nRet = InitiateNetworkRegistration(sParam.regType, sParam.mcc, sParam.mnc, sParam.rat);

	// display output in GUI
	CString strTemp;
	strTemp.Format(L"Result: %04d", nRet);
	ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
	if (!nRet)
	{
		strTemp.Format(L"Network registration initiated successfully");
		ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

		bRet = TRUE;
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (GOBICMAPI*LPFN_INITIATENETWORKREGISTRATION) (ULONG, WORD, WORD, ULONG);

		// get pointer to function
		LPFN_INITIATENETWORKREGISTRATION pFn = (LPFN_INITIATENETWORKREGISTRATION)GetProcAddress_W(m_hQCDll, FUNC_InitiateNetworkRegistration);

		// execute function
		if (pFn)
		{
			STRUCT_InitiateNetworkRegistration sQcParam;
			// clear structure
			memset(&sQcParam, 0, sizeof(STRUCT_InitiateNetworkRegistration));
		    // initialize structure
	        sQcParam.regType = 0x01;  // Automatic Registration
	        sQcParam.mcc = 0;         // Not applicable for Automatic
	        sQcParam.mnc = 0;
	        sQcParam.rat = 0;

			ULONG nQcRet = pFn(sQcParam.regType, sQcParam.mcc, sQcParam.mnc, sQcParam.rat);

			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 CGobiApiNas::FuncInitiateDomainAttach(CParamList* pParams /*= NULL*/)
{
	BOOL bRet = FALSE;

	ADDSTATUS(L"FuncInitiateDomainAttach", STATUSMSG_Send);

	// create structure for easy comparison later
	typedef struct 
	{
		ULONG   Attach;
	} STRUCT_InitiateDomainAttach;

	STRUCT_InitiateDomainAttach sParam;
	// clear structure
	memset(&sParam, 0, sizeof(STRUCT_InitiateDomainAttach));
	
	// initialize structure
	sParam.Attach = _ttoi(pParams->GetValue(PARAM_Action));

	// call Sierra interface
	ULONG nRet = InitiateDomainAttach(sParam.Attach);

	// display output in GUI
	CString strTemp;
	strTemp.Format(L"Result: %04d", nRet);
	ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
	if (!nRet)
	{
		strTemp.Format(L"Network attach/detach initiated");
		ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

		bRet = TRUE;
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (GOBICMAPI*LPFN_INITIATENDOMAINATTACH) (ULONG);

		// get pointer to function
		LPFN_INITIATENDOMAINATTACH pFn = (LPFN_INITIATENDOMAINATTACH)GetProcAddress_W(m_hQCDll, FUNC_InitiateDomainAttach);

		// execute function
		if (pFn)
		{
			STRUCT_InitiateDomainAttach sQcParam;
			// clear structure
			memset(&sQcParam, 0, sizeof(STRUCT_InitiateDomainAttach));
		    // initialize structure
	        sQcParam.Attach = 2;  // 1=Attach to network, 2=Detach from network

			ULONG nQcRet = pFn(sQcParam.Attach);

			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 CGobiApiNas::FuncGetHomeNetwork(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetHomeNetwork", STATUSMSG_Send);

	BOOL bRet = FALSE;
	const BYTE MAX_Name = 0xFF;

	// create structure for easy comparison later
	typedef struct 
	{
		WORD    MCC;
		WORD    MNC; 
		BYTE    NameSize;
		CHAR    Name[MAX_Name];
		WORD    SID;
		WORD    NID;
	} STRUCT_GetHomeNetwork;

	STRUCT_GetHomeNetwork sParam;
	// clear structure
	memset(&sParam, 0, sizeof(STRUCT_GetHomeNetwork));
	// initialize structure
	sParam.NameSize = MAX_Name;

	// call Sierra interface
	ULONG nRet = GetHomeNetwork(&sParam.MCC, 
								&sParam.MNC,
								sParam.NameSize, 
								&sParam.Name[0],
								&sParam.SID,
								&sParam.NID);

	// display output in GUI
	CString strTemp;
	strTemp.Format(L"Result: %04d", nRet);
	ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

	if (!nRet)
	{
		strTemp.Format(L"MCC: %d, MNC: %d, SID: %04d, NID: %04d", sParam.MCC, sParam.MNC, sParam.SID, sParam.NID);
		ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

		TCHAR szStringU[MAX_Name] = L"";

		if (MultiByteToWideChar(CP_ACP, 0, sParam.Name, sParam.NameSize, szStringU, MAX_Name) == sParam.NameSize)
		{
			strTemp.Format(L"Network: %s", szStringU);
			ADDSTATUS(strTemp, STATUSMSG_Receive);
		}

		bRet = TRUE;
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (GOBICMAPI*LPFN_GETHOMENETWORK) (WORD*, WORD*, BYTE, CHAR*, WORD*, WORD*);

		// get pointer to function
		LPFN_GETHOMENETWORK pFn = (LPFN_GETHOMENETWORK)GetProcAddress_W(m_hQCDll, FUNC_GetHomeNetwork);

		// execute function
		if (pFn)
		{
			STRUCT_GetHomeNetwork sQcParam;
			// clear structure
			memset(&sQcParam, 0, sizeof(STRUCT_GetHomeNetwork));
			sQcParam.NameSize = MAX_Name;

			ULONG nQcRet = pFn(&sQcParam.MCC,
							  &sQcParam.MNC,
							  sQcParam.NameSize,
							  &sQcParam.Name[0],
							  &sQcParam.SID,
							  &sQcParam.NID);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (0 != memcmp(&sQcParam, &sParam, sizeof(STRUCT_GetHomeNetwork)))
			{
				if (!nRet)
				{
	                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 CGobiApiNas::FuncGetNetworkPreference(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetNetworkPreference", STATUSMSG_Send);

	BOOL bRet = FALSE;

	// create structure for easy comparison later
	typedef struct 
	{
		ULONG   TechnologyPreference; 
		ULONG	Duration; 
		ULONG   PersistentTechnologyPref;
	} STRUCT_GetNetworkPreference;

	STRUCT_GetNetworkPreference sParam;
	// clear structure
	memset(&sParam, 0, sizeof(STRUCT_GetNetworkPreference));

	// call Sierra interface
	ULONG nRet = GetNetworkPreference(&sParam.TechnologyPreference, 
								      &sParam.Duration, 
								      &sParam.PersistentTechnologyPref);

	// display output in GUI
	CString strTemp;
	strTemp.Format(L"Result: %04d", nRet);
	ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

	if (!nRet)
	{
		strTemp.Format(L"Tech Pref: %02d, Duration: %04x", sParam.TechnologyPreference, sParam.Duration);
		ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
		strTemp.Format(L"Persistent Preference: %04d", sParam.PersistentTechnologyPref);
		ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
		bRet = TRUE;
	}

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

		// get pointer to function
		LPFN_GETNETWORKPREFERENCE pFn = (LPFN_GETNETWORKPREFERENCE)GetProcAddress_W(m_hQCDll, FUNC_GetNetworkPreference);

		// execute function
		if (pFn)
		{
			STRUCT_GetNetworkPreference sQcParam;
			// clear structure
			memset(&sQcParam, 0, sizeof(STRUCT_GetNetworkPreference));

			ULONG nQcRet = pFn(&sQcParam.TechnologyPreference, 
							  &sQcParam.Duration, 
							  &sQcParam.PersistentTechnologyPref);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (0 != memcmp(&sQcParam, &sParam, sizeof(STRUCT_GetNetworkPreference)))
			{
				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 CGobiApiNas::FuncSetNetworkPreference(CParamList* pParams /*= NULL*/)
{
	ADDSTATUS(L"FuncSetNetworkPreference", STATUSMSG_Send);

	BOOL bRet = FALSE;

	// create structure for easy comparison later
	typedef struct 
	{
		ULONG   TechnologyPreference; 
		ULONG	Duration; 
	} STRUCT_SetNetworkPreference;

	STRUCT_SetNetworkPreference sParam;
	// clear structure
	memset(&sParam, 0, sizeof(STRUCT_SetNetworkPreference));

	// display output in GUI
	CString strTemp;

	if (pParams)
	{
		sParam.TechnologyPreference = _ttoi(pParams->GetValue(PARAM_TechPref));
		sParam.Duration = _ttoi(pParams->GetValue(PARAM_Duration));
		strTemp.Format(L"TechPref: %d, Duration: %d", sParam.TechnologyPreference, sParam.Duration);
		ADDSTATUS(strTemp, STATUSMSG_Receive);
	}

	// call Sierra interface
	ULONG nRet = SetNetworkPreference(sParam.TechnologyPreference, 
								      sParam.Duration);

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

	if (!nRet)
	{
		strTemp.Format(L"Technology preferences set successfully" );
		bRet = TRUE;
	}

	return bRet;

}
BOOL CGobiApiNas::FuncSetCDMANetworkParameters(CParamList* pParams /*= NULL*/)
{
	ADDSTATUS(L"FuncSetCDMANetworkParameters", STATUSMSG_Send);
	CHAR SPC[SPCLength];
	BYTE forcedRev0;
	BYTE customSCP;
	ULONG Protocol;
	ULONG Broadcast;
	ULONG Application;
	ULONG Roaming;
	BOOL bRet = FALSE;

	WideCharToMultiByte(CP_ACP, 0, pParams->GetValue(PARAM_SPC), -1, SPC, SPCLength, 0, 0);
	forcedRev0 = (BYTE)_ttoi(pParams->GetValue(PARAM_ForceRev0));
	customSCP = (BYTE)_ttoi(pParams->GetValue(PARAM_CustomSCP));
	Protocol = _ttoi(pParams->GetValue(PARAM_Protocol));
	Broadcast = _ttoi(pParams->GetValue(PARAM_Broadcast));
	Application = _ttoi(pParams->GetValue(PARAM_Application));
	Roaming = _ttoi(pParams->GetValue(PARAM_Roaming));

	// call Sierra interface
	ULONG nRet = SetCDMANetworkParameters(SPC, &forcedRev0, &customSCP, &Protocol, &Broadcast, &Application, &Roaming   );

	// display output in GUI
	CString strTemp;
	strTemp.Format(L"Result: %04d", nRet);
	ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

	if (!nRet)
	{
		strTemp.Format(L"Network Paramters set successfully" );
		bRet = TRUE;
	}
	else
	{
		strTemp.Format(L"Network Paramters set failed" );
	}
	return bRet;
}
BOOL CGobiApiNas::FuncGetCDMANetworkParameters(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetCDMANetworkParameters", STATUSMSG_Send);

	typedef struct 
	{
		BYTE SCI;
		BYTE SCM;
		BYTE RegHomeSID;
		BYTE RegForeignSID;
		BYTE RegForeignNID;
		BYTE ForceRev0;
		BYTE CustomSCP;
		ULONG Protocol;
		ULONG Broadcast;
		ULONG Application;
		ULONG Roaming;
	} STRUCT_GetCDMANetworkParameters;
	
	BOOL bRet = FALSE;

	STRUCT_GetCDMANetworkParameters sParam;
	memset(&sParam, 0, sizeof(STRUCT_GetCDMANetworkParameters));

	// call Sierra interface
	ULONG nRet = GetCDMANetworkParameters(
		&sParam.SCI, 
		&sParam.SCM, 
		&sParam.RegHomeSID, 
		&sParam.RegForeignSID, 
		&sParam.RegForeignNID, 
		&sParam.ForceRev0, 
		&sParam.CustomSCP, 
		&sParam.Protocol, 
		&sParam.Broadcast, 
		&sParam.Application, 
		&sParam.Roaming );

	// display output in GUI
	CString strTemp;
	strTemp.Format(L"Result: %04d", nRet);
	ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

	if (!nRet)
	{
		strTemp.Format(L"SCI[%d] SCM[%d] ForceRev0[%d]", sParam.SCI, sParam.SCM, sParam.ForceRev0);
		ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
		strTemp.Format(L"RegHomeSID[%d] RegForeignSID[%d] RegForeignNID[%d]", sParam.RegHomeSID, sParam.RegForeignSID, sParam.RegForeignNID);
		ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
		strTemp.Format(L"CustomSCP[%d] Protocol[%d] Broadcast[%d] Application[%d]", sParam.CustomSCP, sParam.Protocol, sParam.Broadcast, sParam.Application);
		ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
		strTemp.Format(L"Roaming[%d]", sParam.Roaming);
		ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
		bRet = TRUE;
	}

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

		// get pointer to function
		LPFN_GETCDMANETWORKPARAMETERS pFn = (LPFN_GETCDMANETWORKPARAMETERS)GetProcAddress_W(m_hQCDll, FUNC_GetCDMANetworkParameters);

		// execute function
		if (pFn)
		{
			STRUCT_GetCDMANetworkParameters sQcParam;
			// clear structure
			memset(&sQcParam, 0, sizeof(STRUCT_GetCDMANetworkParameters));

			ULONG nQcRet = pFn(
				&sQcParam.SCI, 
				&sQcParam.SCM, 
				&sQcParam.RegHomeSID, 
				&sQcParam.RegForeignSID, 
				&sQcParam.RegForeignNID, 
				&sQcParam.ForceRev0, 
				&sQcParam.CustomSCP, 
				&sQcParam.Protocol, 
				&sQcParam.Broadcast, 
				&sQcParam.Application, 
				&sQcParam.Roaming );

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (0 != memcmp(&sQcParam, &sParam, sizeof(STRUCT_GetCDMANetworkParameters)))
			{
				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 CGobiApiNas::FuncSetACCOLC(CParamList* pParams /*= NULL*/)
{
	ADDSTATUS(L"FuncSetACCOLC", STATUSMSG_Send);
	CHAR SPC[SPCLength];
	BYTE accolc;
	BOOL bRet = FALSE;

	WideCharToMultiByte(CP_ACP, 0, pParams->GetValue(PARAM_SPC), -1, SPC, SPCLength, 0, 0);
	accolc = (BYTE)_ttoi(pParams->GetValue(PARAM_ACCOLC));

	CString strTemp;
	strTemp.Format(L"SPC[%s] accolc[%d]", pParams->GetValue(PARAM_SPC), accolc );
	ADDSTATUS(strTemp, STATUSMSG_Send);

	// call Sierra interface
	ULONG nRet = SetACCOLC(SPC, accolc);

	// display output in GUI
	strTemp.Format(L"Result: %04d", nRet);
	ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

	if (!nRet)
	{
		ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
		bRet = TRUE;
	}

	return bRet;
}

BOOL CGobiApiNas::FuncGetACCOLC(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetACCOLC", STATUSMSG_Send);
	BYTE accolc;
	BOOL bRet = FALSE;

	// call Sierra interface
	ULONG nRet = GetACCOLC(&accolc);

	// display output in GUI
	CString strTemp;
	strTemp.Format(L"Result: %04d", nRet);
	ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

	if (!nRet)
	{
		strTemp.Format(L"ACCOLC[%d]", accolc );
		ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
		bRet = TRUE;
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (GOBICMAPI*LPFN_GETACCOLC) (BYTE*);

		// get pointer to function
		LPFN_GETACCOLC pFn = (LPFN_GETACCOLC)GetProcAddress_W(m_hQCDll, FUNC_GetACCOLC);

		// execute function
		if (pFn)
		{
			BYTE QcAccolc;

			ULONG nQcRet = pFn(&QcAccolc);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (accolc != QcAccolc)
			{
				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 CGobiApiNas::FuncGetANAAAAuthenticationStatus(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetANAAAAuthenticationStatus", STATUSMSG_Send);
	ULONG ANAAAStatus;
	BOOL bRet = FALSE;

	// call Sierra interface
	ULONG nRet = GetANAAAAuthenticationStatus(&ANAAAStatus);

	// display output in GUI
	CString strTemp;
	strTemp.Format(L"Result: %4d", nRet);
	ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

	if (!nRet)
	{
		strTemp.Format(L"ANAAAStatus:%d ", ANAAAStatus );
		ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
		bRet = TRUE;
	}

	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (GOBICMAPI*LPFN_GETANAAAAUTHENTICATIONSTATUS) (ULONG*);

		// get pointer to function
		LPFN_GETANAAAAUTHENTICATIONSTATUS pFn = (LPFN_GETANAAAAUTHENTICATIONSTATUS)GetProcAddress_W(m_hQCDll, FUNC_GetANAAAAuthenticationStatus);

		// execute function
		if (pFn)
		{
			ULONG QcANAAAStatus;

			ULONG nQcRet = pFn(&QcANAAAStatus);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (ANAAAStatus != QcANAAAStatus)
			{
				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 CGobiApiNas::FuncGetRFInfo(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetRFInfo", STATUSMSG_Send);

	BYTE nSize = 10;
	const int MAX_BUFFER_SIZE = 120;
	BYTE  arParam[MAX_BUFFER_SIZE];  // RF info instance elements are comprised for three ULONGs (so this buffer holds 10 elements)
	BOOL bRet = FALSE;

	// clear structure
	memset(&arParam, 0, MAX_BUFFER_SIZE);

	// call Sierra interface
	ULONG nRet = GetRFInfo(&nSize, arParam);

	// display output in GUI
	CString strTemp;
	strTemp.Format(L"Result: %04d", nRet);
	ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

	if (!nRet)
	{
		strTemp.Format(L"num instances[%d]", nSize );
		ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);

		ULONG* pInfo = (ULONG *)arParam;

		for(int i = 0; i < nSize; i++)
		{
			// Each instance consists 3 ULONG
			strTemp.Format(L"IF #%i [%d]", i, *pInfo);
			ADDSTATUS(strTemp,STATUSMSG_Receive);
			pInfo++;
			strTemp.Format(L"Class [%d]", *pInfo);
			ADDSTATUS(strTemp,STATUSMSG_Receive);
			pInfo++;
			strTemp.Format(L"Channel [%d]", *pInfo);
			ADDSTATUS(strTemp,STATUSMSG_Receive);
			pInfo++;
		}
		bRet = TRUE;
	}

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

		// get pointer to function
		LPFN_GETRFINFO pFn = (LPFN_GETRFINFO)GetProcAddress_W(m_hQCDll, FUNC_GetRFInfo);

		// execute function
		if (pFn)
		{
			BYTE  arQcParam[MAX_BUFFER_SIZE];  // RF info instance elements are comprised for three ULONGs (so this buffer holds 10 elements)

			// clear structure
			memset(&arQcParam, 0, MAX_BUFFER_SIZE);

			ULONG nQcRet = pFn(&nSize, arQcParam);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = FALSE;
			}
			else if (0 != memcmp(&arQcParam, &arParam, MAX_BUFFER_SIZE))
			{
				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 CGobiApiNas::FuncGetPLMNMode(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
    ADDSTATUS(L"FuncGetPLMNMode", STATUSMSG_Send);

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

    ULONG nRet = GetPLMNMode(&nPLMNMode);
    if(!nRet)
    {
        strTemp.Format(L"PLMN Mode: %i Return: %04d ", nPLMNMode, nRet);
        ADDSTATUS(strTemp, STATUSMSG_Receive);
    }
    else
    {
        strTemp.Format(L"FuncGetPLMNMode ERROR[%d]", nRet);
        ADDSTATUS(strTemp, STATUSMSG_Receive);
    }
    bRet = (nRet == 0)?TRUE:FALSE;

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

        // function prototype
        typedef ULONG (GOBICMAPI*LPFN_GETPLMNMODE) (ULONG*);

        // get pointer to function
        LPFN_GETPLMNMODE pFn = (LPFN_GETPLMNMODE)GetProcAddress_W(m_hQCDll, FUNC_GetPLMNMode);

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

            if (nQcRet != nRet)
            {
                strTemp.Format(L"QC returned a different status code: %04d", nQcRet);
                ADDSTATUS(strTemp, STATUSMSG_Error);
                bRet = FALSE;
            }
            else if (qcPLMNMode != nPLMNMode)
            {
                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 CGobiApiNas::FuncGetPLMNName(CParamList* pParams /*= NULL*/)
{
    ADDSTATUS(L"FuncGetPLMNName", STATUSMSG_Send);

    const BYTE MAX_Name = 0xFF;
    BOOL    bRet = FALSE;
    CString strTemp;
    WORD    MCC = 0;
    WORD    MNC = 0;
    ULONG   nNamesSize = MAX_Name; 
    BYTE    pNames[MAX_Name];

    MCC = (WORD)_ttoi(pParams->GetValue(PARAM_Mcc));
    MNC = (WORD)_ttoi(pParams->GetValue(PARAM_Mnc));
    memset(pNames, 0, MAX_Name);
    
    ULONG nRet = GetPLMNName(MCC, MNC, &nNamesSize, pNames);
    if(!nRet)
    {
        strTemp.Format(L"PLMN Name Size: %i Return: %04d ", nNamesSize, nRet);
        ADDSTATUS(strTemp, STATUSMSG_Receive);
        
        BYTE* pWorker = (BYTE*)pNames;
        pWorker ++;
        BYTE nSPNameLen = *pWorker;
        if(nSPNameLen > 0)
        {
            BYTE CodeScheme = *(pWorker-1);
            CHAR szSPName[MAX_Name] = "";
            TCHAR szStringSPNameU[MAX_Name] = L"";
            memcpy(szSPName, pWorker+1, nSPNameLen);
            if (MultiByteToWideChar(CP_ACP, 0, szSPName, MAX_Name, szStringSPNameU, MAX_Name) == MAX_Name)
            {
                strTemp.Format(L"Service Provider Name: %s, CodeScheme: %d ", szStringSPNameU, CodeScheme);
                ADDSTATUS(strTemp, STATUSMSG_Receive);
            }
        }
        pWorker += nSPNameLen;
        pWorker += 4;
        
        BYTE nPLMNShortNameLen = *pWorker;
        if(nPLMNShortNameLen > 0)
        {
            typedef struct 
            {
                BYTE    NameCodeScheme;
                BYTE    NameCoutryInitial; 
                BYTE    NameSpareBits;
            } STRUCT_PLMNName;
            
            CHAR szPLMNShortName[MAX_Name] = "";
            TCHAR szStringPLMNShortNameU[MAX_Name] = L"";
            memcpy(szPLMNShortName, pWorker+1, nPLMNShortNameLen);
            if (MultiByteToWideChar(CP_ACP, 0, szPLMNShortName, MAX_Name, szStringPLMNShortNameU, MAX_Name) == MAX_Name)
            {
                strTemp.Format(L"PLMN Short Name: %s", szStringPLMNShortNameU);
                ADDSTATUS(strTemp, STATUSMSG_Receive);
            }
            STRUCT_PLMNName sPLMNShortName;
            memcpy(&sPLMNShortName, pWorker-3, sizeof(STRUCT_PLMNName));
            strTemp.Format(L"Coding: 0x%x, Country initials: 0x%x, Spare bits:0x%x",
                sPLMNShortName.NameCodeScheme,sPLMNShortName.NameCoutryInitial,sPLMNShortName.NameSpareBits);
            ADDSTATUS(strTemp, STATUSMSG_Receive);
            
        }
        
        pWorker = pWorker + nPLMNShortNameLen + 4;
        BYTE nPLMNLongNameLen = *pWorker;
        if(nPLMNLongNameLen > 0)
        {
            typedef struct 
            {
                BYTE    NameCodeScheme;
                BYTE    NameCoutryInitial; 
                BYTE    NameSpareBits;
            } STRUCT_PLMNName;
            CHAR szPLMNLongName[MAX_Name] = "";
            TCHAR szStringPLMNLongNameU[MAX_Name] = L"";
            memcpy(szPLMNLongName, pWorker+1, nPLMNLongNameLen);
            if (MultiByteToWideChar(CP_ACP, 0, szPLMNLongName, MAX_Name, szStringPLMNLongNameU, MAX_Name) == MAX_Name)
            {
                strTemp.Format(L"PLMN Long Name: %s", szStringPLMNLongNameU);
                ADDSTATUS(strTemp, STATUSMSG_Receive);
            }
            STRUCT_PLMNName sPLMNLongName;
            memcpy(&sPLMNLongName, pWorker-3, sizeof(STRUCT_PLMNName));
            strTemp.Format(L"Coding: 0x%x, Country initials: 0x%x, Spare bits:0x%x",
                sPLMNLongName.NameCodeScheme,sPLMNLongName.NameCoutryInitial,sPLMNLongName.NameSpareBits);
            ADDSTATUS(strTemp, STATUSMSG_Receive);
        }
    }
    else
    {
        strTemp.Format(L"FuncGetPLMNName ERROR[%d]", nRet);
        ADDSTATUS(strTemp, STATUSMSG_Receive);
    }
    bRet = (nRet == 0)?TRUE:FALSE;

    // Compare with QC DLL
    if (m_hQCDll)
    {
        ULONG qcNameSize = 0;
        BYTE *qcpNames = NULL;

        // function prototype
        typedef ULONG (GOBICMAPI*LPFN_GETPLMNAME) (WORD, WORD, ULONG*, BYTE*);

        // get pointer to function
        LPFN_GETPLMNAME pFn = (LPFN_GETPLMNAME)GetProcAddress_W(m_hQCDll, FUNC_GetPLMNName);

        // execute function
        if (pFn)
        {
            ULONG nQcRet = pFn(MCC, MNC, &qcNameSize, qcpNames);

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

    return bRet;
}

// NAS callback functions
static void GOBICALLBACK SignalStrengthCallback(INT8 signalStrength, ULONG radioInterface)
{
	CString strTemp;
	strTemp.Format(L"Signal strength: %d, radioInterface %d", signalStrength, radioInterface);
	ADDSTATUS(strTemp, STATUSMSG_Notif);  
}

static void GOBICALLBACK DataCapabilitiesCallback(BYTE dataCapsSize, BYTE* pDataCaps)
{
    UNREFERENCED_PARAMETER(pDataCaps);
	CString strTemp;
	strTemp.Format(L"DataCapsSize: %i", dataCapsSize);
	ADDSTATUS(strTemp, STATUSMSG_Notif);

	for (int i=0; i<dataCapsSize; i++)
	{
		strTemp.Format(L"Cap #%i: %i", i, (ULONG)*pDataCaps);
		pDataCaps += sizeof(ULONG);
		ADDSTATUS(strTemp, STATUSMSG_Notif);
	}
}

static void GOBICALLBACK RoamingIndicatorCallback(ULONG Roaming)
{
	CString strTemp;
	strTemp.Format(L"Roaming %04d", Roaming);
	ADDSTATUS(strTemp, STATUSMSG_Notif);  
}

static void GOBICALLBACK RFInfoCallback(ULONG nRadioInterface, ULONG nActiveBandClass, ULONG nActiveChannel)
{
	CString strTemp;
	strTemp.Format(L"RadioInterface: %04d ActiveBandClass: %04d ActiveChannel: %04d", nRadioInterface, nActiveBandClass, nActiveChannel);
	ADDSTATUS(strTemp, STATUSMSG_Notif);  

	ADDSTATUS(L"Calling FuncGetRFInfo from callback thread", STATUSMSG_Send);

	BYTE nSize = 10;
	const int MAX_BUFFER_SIZE = 120;
	BYTE  arParam[MAX_BUFFER_SIZE];  // RF info instance elements are comprised for three ULONGs (so this buffer holds 10 elements)
	//BOOL bRet = FALSE;

	// clear structure
	memset(&arParam, 0, MAX_BUFFER_SIZE);

	// call Sierra interface
	ULONG nRet = GetRFInfo(&nSize, arParam);

	// display output in GUI
	strTemp.Format(L"Result: %04d", nRet);
	ADDSTATUS(strTemp,(nRet==0)?STATUSMSG_Error:STATUSMSG_Receive);
}

static void GOBICALLBACK LURejectCallback(ULONG nServiceDomain, ULONG nRejectCause)
{
	CString strTemp;
	strTemp.Format(L"ServiceDomain: %04d RejectCause: %04d", nServiceDomain, nRejectCause);
	ADDSTATUS(strTemp, STATUSMSG_Notif);  
}

static void GOBICALLBACK PLMNModeCallback(ULONG mode)
{
    CString strTemp;
    strTemp.Format(L"PLMN Mode: %04d", mode);
    ADDSTATUS(strTemp, STATUSMSG_Notif);  
}

static void SWICALLBACK EcioCallback(INT8 nEcio, ULONG nRadioIf)
{
	CString strTemp;
	strTemp.Format(L"ECIO: -%d dBm, RadioIf: 0x%04x", nEcio/2, nRadioIf);
	ADDSTATUS(strTemp, STATUSMSG_Notif);  
}

static void SWICALLBACK SnirCallback(ULONG nSnir)
{
	CString strTemp;
	strTemp.Format(L"SNIR level: %d", nSnir);
	ADDSTATUS(strTemp, STATUSMSG_Notif);  
}

static void SWICALLBACK ErrorRateCallback(ULONG nErrorRate, ULONG nRadioIf)
{
	CString strTemp;
	strTemp.Format(L"Error rate: %d, RadioIf: 0x%04x", nErrorRate, nRadioIf);
	ADDSTATUS(strTemp, STATUSMSG_Notif);  
}

static void SWICALLBACK RsrqCallback(INT8 nRsrq, ULONG nRadioIf)
{
	CString strTemp;
	strTemp.Format(L"RSRQ: %d, RadioIf: 0x%04x", nRsrq, nRadioIf);
	ADDSTATUS(strTemp, STATUSMSG_Notif);  
}

static void SWICALLBACK SignalStrengthInfoCallback(
	INT8	nCdmaRssi,		   
	ULONG	nCdmaEcio,
	INT8	nHdrRssi,
	ULONG	nHdrEcio,
	ULONG	nHdrSinr,
	ULONG	nHdrIo,
	INT8	nGsmRssi,
	INT8	nWcdmaRssi,
	ULONG	nWcdmaEcio,
	INT8	nLteRssi,
	INT8	nLteRsrq,
	INT16	nLteRsrp,
	UINT8	nLteSnr )
{
	CString strTemp;
	strTemp.Format(L"CDMA RSSI: %i, ECIO: %i", nCdmaRssi, nCdmaEcio);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	strTemp.Format(L"HDR RSSI: %i, ECIO: %i, SINR: %i, IO: %i", nHdrRssi, nHdrEcio, nHdrSinr, nHdrIo);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	strTemp.Format(L"GSM RSSI: %i", nGsmRssi);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	strTemp.Format(L"WCDMA RSSI: %i, ECIO: %i", nWcdmaRssi, nWcdmaEcio);
	ADDSTATUS(strTemp, STATUSMSG_Receive);

	strTemp.Format(L"LTE RSSI: %i, RSRQ: %i, RSRP: %i, SNR: %i", nLteRssi, nLteRsrq, nLteRsrp, nLteSnr);
	ADDSTATUS(strTemp, STATUSMSG_Receive);
}

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

	ULONG ret = 0;

	if (0 != _ttoi(pParams->GetValue(PARAM_Enable)))
	{
		INT8 Thresholds[] = { -106, -100, -93, -86, -80 }; 
		ret = SetSignalStrengthCallback(SignalStrengthCallback, 5, Thresholds);
	}
	else
	{
		ret = SetSignalStrengthCallback(NULL, 0, NULL);
	}

	CString strTemp;
	strTemp.Format(L"Result: %04d", ret);

	return ADDSTATUS(strTemp, (0==ret)?STATUSMSG_Receive:STATUSMSG_Error);
}

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

	ULONG ret = 0;

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

	CString strTemp;
	strTemp.Format(L"Result: %04d", ret);

	return ADDSTATUS(strTemp, (0==ret)?STATUSMSG_Receive:STATUSMSG_Error);
}

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

	ULONG ret = 0;

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

	CString strTemp;
	strTemp.Format(L"Result: %04d", ret);

	return ADDSTATUS(strTemp, (0==ret)?STATUSMSG_Receive:STATUSMSG_Error);
}

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

	ULONG ret = 0;

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

	CString strTemp;
	strTemp.Format(L"Result: %04d", ret);

	return ADDSTATUS(strTemp, (0==ret)?STATUSMSG_Receive:STATUSMSG_Error);
}

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

	ULONG ret = 0;

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

	CString strTemp;
	strTemp.Format(L"Result: %04d", ret);

	return ADDSTATUS(strTemp, (0==ret)?STATUSMSG_Receive:STATUSMSG_Error);
}


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

    ULONG ret = 0;

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

    CString strTemp;
    strTemp.Format(L"Result: %04d", ret);

    return ADDSTATUS(strTemp, (0==ret)?STATUSMSG_Receive:STATUSMSG_Error);
}

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

	ULONG ret = 0;

	if (0 != _ttoi(pParams->GetValue(PARAM_Enable)))
	{
		ret = SwiSetEcioCallback(EcioCallback, (BYTE)_ttoi(pParams->GetValue(PARAM_Threshold)));
	}
	else
	{
		ret = SwiSetEcioCallback(NULL, 0);
	}

	CString strTemp;
	strTemp.Format(L"Result: %04d", ret);

	return ADDSTATUS(strTemp, (0==ret)?STATUSMSG_Receive:STATUSMSG_Error);
}

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

	ULONG ret = 0;

	if (0 != _ttoi(pParams->GetValue(PARAM_Enable)))
	{
		ret = SwiSetSnirCallback(SnirCallback, (BYTE)_ttoi(pParams->GetValue(PARAM_Threshold)));
	}
	else
	{
		ret = SwiSetSnirCallback(NULL, 0);
	}

	CString strTemp;
	strTemp.Format(L"Result: %04d", ret);

	return ADDSTATUS(strTemp, (0==ret)?STATUSMSG_Receive:STATUSMSG_Error);
}

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

	ULONG ret = 0;

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

	CString strTemp;
	strTemp.Format(L"Result: %04d", ret);

	return ADDSTATUS(strTemp, (0==ret)?STATUSMSG_Receive:STATUSMSG_Error);
}

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

	ULONG ret = 0;

	if (0 != _ttoi(pParams->GetValue(PARAM_Enable)))
	{
		ret = SwiSetRsrqCallback(RsrqCallback, (BYTE)_ttoi(pParams->GetValue(PARAM_Threshold)));
	}
	else
	{
		ret = SwiSetRsrqCallback(NULL, 0);
	}

	CString strTemp;
	strTemp.Format(L"Result: %04d", ret);

	return ADDSTATUS(strTemp, (0==ret)?STATUSMSG_Receive:STATUSMSG_Error);
}


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

	ULONG nRet = 0;
	INT8	nCdmaRssi;
	ULONG	nCdmaEcio;
	INT8	nHdrRssi;
	ULONG	nHdrEcio;
	ULONG	nHdrSinr;
	ULONG	nHdrIo;
	INT8	nGsmRssi;
	INT8	nWcdmaRssi;
	ULONG	nWcdmaEcio;
	INT8	nLteRssi;
	INT8	nLteRsrq;
	INT16	nLteRsrp;
	UINT8	nLteSnr;

	nRet = SwiGetSignalStrengthInfo(
		&nCdmaRssi, 
		&nCdmaEcio, 
		&nHdrRssi, 
		&nHdrEcio, 
		&nHdrSinr, 
		&nHdrIo, 
		&nGsmRssi, 
		&nWcdmaRssi, 
		&nWcdmaEcio, 
		&nLteRssi, 
		&nLteRsrq, 
		&nLteRsrp, 
		&nLteSnr);

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

	if (!nRet)
	{
		strTemp.Format(L"CDMA RSSI: %i, ECIO: %i", nCdmaRssi, nCdmaEcio);
		ADDSTATUS(strTemp, STATUSMSG_Receive);

		strTemp.Format(L"HDR RSSI: %i, ECIO: %i, SINR: %i, IO: %i", nHdrRssi, nHdrEcio, nHdrSinr, nHdrIo);
		ADDSTATUS(strTemp, STATUSMSG_Receive);

		strTemp.Format(L"GSM RSSI: %i", nGsmRssi);
		ADDSTATUS(strTemp, STATUSMSG_Receive);

		strTemp.Format(L"WCDMA RSSI: %i, ECIO: %i", nWcdmaRssi, nWcdmaEcio);
		ADDSTATUS(strTemp, STATUSMSG_Receive);

		strTemp.Format(L"LTE RSSI: %i, RSRQ: %i, RSRP: %i, SNR: %i", nLteRssi, nLteRsrq, nLteRsrp, nLteSnr);
		ADDSTATUS(strTemp, STATUSMSG_Receive);
	}

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

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

	ULONG ret = 0;

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

	CString strTemp;
	strTemp.Format(L"Result: %04d", ret);

	return ADDSTATUS(strTemp, (0==ret)?STATUSMSG_Receive:STATUSMSG_Error);
}