#include "StdAfx.h"
#include "GobiApiFwMgmt.h"

#include "StdAfx.h"
#include <GobiApi.h>
#include "GobiApiDms.h"
#include "FuncList.h"
#include "StatusCtrl.h"
#include "GobiImageMgmtAPI.h"
#include "GobiConnectionMgmtAPI.h"

#define FUNC_GetFirmwareInfo		L"GetFirmwareInfo"
#define FUNC_GetImageStoreW			L"GetImageStoreW"
#define FUNC_UpgradeFirmware2kW		L"UpgradeFirmware2kW"
#define FUNC_GetImageInfo			L"GetImageInfo"
#define FUNC_SetImagesPreference	L"SetImagesPreference"
#define FUNC_GetImagesPreference	L"GetImagesPreference"
#define FUNC_GetStoredImages		L"GetStoredImages"
#define FUNC_DeleteStoredImage		L"DeleteStoredImage"
#define FUNC_ResetDevice			L"ResetDevice"
#define FUNC_GetBARMode				L"GetBARMode"
#define FUNC_SetBARMode				L"SetBARMode"
#define FUNC_DeleteAllImage			L"DeleteAllImage"

#define PARAM_ImagePath			L"ImagePath"
#define PARAM_ImageIdModem		L"Modem ImageId"
#define PARAM_BuildIdModem		L"Modem BuildId"
#define PARAM_ImageIdPri		L"Pri ImageId"
#define PARAM_BuildIdPri		L"Pri BuildId"
#define PARAM_ForceDownload		L"ForceDownload"
#define PARAM_ModemIndex		L"ModemIndex"
#define PARAM_ImageType			L"ImageType"
#define PARAM_ImageId			L"ImageId"
#define PARAM_BuildId			L"BuildId"

CParamList CGobiApiFwMgmt::m_sUpgradeFirmware2kW;
CParamList CGobiApiFwMgmt::m_sGetImageInfo;
CParamList CGobiApiFwMgmt::m_sSetImagesPreference;
CParamList CGobiApiFwMgmt::m_sDeleteStoredImages;
CParamList CGobiApiFwMgmt::m_sDeleteAllImageType;

#define LEN_IMAGE_ID		16
#define LEN_BUILD_ID		32
#define MAX_IMAGE_LIST_SIZE 2560

const TableFuncEntry CGobiApiFwMgmt::m_TableFunc[] = 
{
	{FUNC_GetFirmwareInfo,		FuncGetFirmwareInfo},
	{FUNC_GetImageStoreW,		FuncGetImageStoreW},
	{FUNC_UpgradeFirmware2kW,	FuncUpgradeFirmware2kW, &m_sUpgradeFirmware2kW },
	{FUNC_GetImageInfo,			FuncGetImageInfo,		&m_sGetImageInfo },
	{FUNC_GetImagesPreference,	FuncGetImagesPreference},
	{FUNC_SetImagesPreference,	FuncSetImagesPreference,&m_sSetImagesPreference },
	{FUNC_GetStoredImages,		FuncGetStoredImages},
	{FUNC_DeleteStoredImage,	FuncDeleteStoredImages, &m_sDeleteStoredImages },
	{FUNC_ResetDevice,			FuncResetDevice},
	{FUNC_GetBARMode,			FuncGetBARMode},
	{FUNC_SetBARMode,			FuncSetBARMode},
	{FUNC_DeleteAllImage,		FuncDeleteAllImages, &m_sDeleteAllImageType},
	{FUNC_EndOfList}
};

// helper function
void Bin2Ascii(BYTE* pId, const UINT nLength, LPWSTR pAscii)
{
	// Convert ImageID from hex to ASCII for printing to log
	BYTE hexStr[] = "0123456789ABCDEF";
	char* pBuf = (char*)malloc(nLength*2);	// temporary work buffer
	ZeroMemory(pBuf, nLength*2);
	UINT positionInBuffer = 0;				// position in buffer
	const BYTE* pPos = NULL;				// temporary pointer to traverse data

	// loop through entire data
	for (UINT i=1; i<=nLength; i++)
	{
		// Get pointer to data (BYTE)
		pPos = pId+(i-1);

		// copy hex digits to the buffer
		pBuf[positionInBuffer++] = hexStr[((*pPos) & 0xf0) >> 4];	// MS nibble
		pBuf[positionInBuffer++] = hexStr[((*pPos) & 0x0f)];		// LS nibble
	}

	MultiByteToWideChar(CP_ACP, 0, pBuf, nLength*2, pAscii, nLength*2);

	free (pBuf);
}

CGobiApiFwMgmt::CGobiApiFwMgmt(HMODULE hQCDll)
{
    UNREFERENCED_PARAMETER(hQCDll);
	// Define default image store path
#ifdef UNDER_CE
	m_sUpgradeFirmware2kW.Add(PARAM_ImagePath, L"\\Storage Card\\Images\\Sierra\\2");
	m_sGetImageInfo.Add(PARAM_ImagePath, L"\\Storage Card\\Images\\Sierra\\2");
#else
	m_sUpgradeFirmware2kW.Add(PARAM_ImagePath, L"C:\\Program Files\\Sierra Wireless Inc\\Gobi\\Images\\3000\\Generic\\2");
	m_sGetImageInfo.Add(PARAM_ImagePath, L"C:\\Program Files\\Sierra Wireless Inc\\Gobi\\Images\\3000\\Generic\\2");
#endif

	m_sSetImagesPreference.Add(PARAM_ForceDownload, L"0");
	m_sSetImagesPreference.Add(PARAM_ModemIndex, L"FF");
	m_sSetImagesPreference.Add(PARAM_ImageIdModem, L"1c7b1f77db3538dfda552a0bfa02a596");
	m_sSetImagesPreference.Add(PARAM_BuildIdModem, L"D3200-STSUGNZ-1547");
	m_sSetImagesPreference.Add(PARAM_ImageIdPri, L"45b343f687f72cc7cb6eac49093090b5");
	m_sSetImagesPreference.Add(PARAM_BuildIdPri, L"D3200-STSUGNZ-1547");

	m_sDeleteStoredImages.Add(PARAM_ImageType, L"1");
	m_sDeleteStoredImages.Add(PARAM_ImageId, L"3186AEDAFE1A4F7A1EE20BC4D9620511");
	m_sDeleteStoredImages.Add(PARAM_BuildId, L"D3200-STSUVH-1564");
	m_sDeleteAllImageType.Add(PARAM_ImageType, L"1");
}

CGobiApiFwMgmt::~CGobiApiFwMgmt(void)
{
}

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

	int iIndex = 0;

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

	return TRUE;
}

UINT CGobiApiFwMgmt::ExecuteFunctions(CFuncList* pFuncList, UINT &nTotalExec)
{
	TBD_FUNCTION(CGobiApiFwMgmt::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);

			if (!m_TableFunc[iIndex].pFunc(&sParams))
				m_nNumErrors++;
			nTotalExec++;
		}

		iIndex++;
	}

	return m_nNumErrors;
}

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

	BOOL bRet = FALSE;

	typedef struct 
	{
		ULONG nFirmwareId;
		ULONG nTechnology;
		ULONG nCarrier;
		ULONG nRegion;
		ULONG nGps;
	} STRUCT_FirmwareInfo;

	STRUCT_FirmwareInfo sFwInfo;
	ZeroMemory(&sFwInfo, sizeof(STRUCT_FirmwareInfo));

	ULONG nRet = GetFirmwareInfo(&sFwInfo.nFirmwareId, &sFwInfo.nTechnology, &sFwInfo.nCarrier, &sFwInfo.nRegion, &sFwInfo.nGps);

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

	if (!nRet)
	{
		strTemp.Format(L"FwId: 0x%x Tech: %i Carrier: %i Region: %i Gps: %i", 
			sFwInfo.nFirmwareId, 
			sFwInfo.nTechnology, 
			sFwInfo.nCarrier, 
			sFwInfo.nRegion, 
			sFwInfo.nGps);
		ADDSTATUS(strTemp, STATUSMSG_Receive);
		bRet = TRUE;
	}

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

		// get pointer to function
		LPFN_GETFIRMWAREINFO pFn = (LPFN_GETFIRMWAREINFO)GetProcAddress_W(m_hQCDll, FUNC_GetFirmwareInfo);

		// execute function
		if (pFn)
		{
			STRUCT_FirmwareInfo sQcFwInfo;
			ZeroMemory(&sQcFwInfo, sizeof(STRUCT_FirmwareInfo));

			ULONG nQcRet = pFn(&sQcFwInfo.nFirmwareId, &sQcFwInfo.nTechnology, &sQcFwInfo.nCarrier, &sQcFwInfo.nRegion, &sQcFwInfo.nGps);

			if (nQcRet != nRet)
			{
				strTemp.Format(L"QC returned a different status code: 0x%04x", nQcRet);
				ADDSTATUS(strTemp, STATUSMSG_Error);
				bRet = TRUE;
			}
			else if (0 != memcmp(&sQcFwInfo, &sFwInfo, sizeof(STRUCT_FirmwareInfo)))
			{
				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 CGobiApiFwMgmt::FuncGetImageInfo(CParamList* pParams /*= NULL*/)
{
    ULONG firmwareId = ULONG_MAX;
    ULONG technology = ULONG_MAX;;
    ULONG carrier    = ULONG_MAX;
    ULONG region     = ULONG_MAX;
    ULONG GPS        = ULONG_MAX;
    CString strTemp;
    CString imagePath;
    imagePath = pParams->GetValue(PARAM_ImagePath);

    ADDSTATUS(L"FuncGetImageInfo", STATUSMSG_Send);

    ULONG result = GetImageInfoW(imagePath.GetBuffer(imagePath.GetLength()), &firmwareId, &technology, &carrier, &region, &GPS);

    if(!result)
    {
        strTemp.Format(L"FwId: 0x%x Tech: %i Carrier: %i Region: %i Gps: %i", 
            firmwareId, technology, carrier, region, GPS);
        ADDSTATUS(strTemp, STATUSMSG_Receive);
        return (TRUE);
    }
    else
    {
		strTemp.Format(L"GetImageInfoW failed: %d", result);
		ADDSTATUS(strTemp, STATUSMSG_Error);
        return (FALSE);
	}
}

BOOL CGobiApiFwMgmt::FuncGetImageStoreW(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	WORD pathSize = MAX_PATH;
	WCHAR path[MAX_PATH] = L"";
	CString strTemp;

	ADDSTATUS(L"FuncGetImageStoreW", STATUSMSG_Send);
	ULONG nResult = GetImageStoreW(	pathSize, path);

	if(!nResult) 
	{
		strTemp.Format(L"Image store path[%d]: %s", pathSize, path);
		ADDSTATUS(strTemp, STATUSMSG_Receive);
	}
	else
	{
		strTemp.Format(L"GetImageInfoW failed: %d", nResult);
		ADDSTATUS(strTemp, STATUSMSG_Error);
	}

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

BOOL CGobiApiFwMgmt::FuncUpgradeFirmware2kW(CParamList* pParams)
{
	CString strTemp;
	CString defaultPath;
	ULONG   result;
	defaultPath = pParams->GetValue(PARAM_ImagePath);

	result = UpgradeFirmware2kW(defaultPath.GetBuffer(defaultPath.GetLength()));
	defaultPath.ReleaseBuffer();
	
	if(!result)
	{
		strTemp.Format(L"UpgradeFirmware2kW Success[%d]", result);
		ADDSTATUS(strTemp, STATUSMSG_Receive);
		return(TRUE);
	}

	strTemp.Format(L"UpgradeFirmware2kW ERROR[%d]", result);
	ADDSTATUS(strTemp, STATUSMSG_Error);
	return(FALSE);
}

// Helper function to convert ASCII hex characters to binary
extern unsigned char hex2bin(unsigned char h, unsigned char l);

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

	const ULONG MAX_BUF_SIZE = 256;

	ULONG nImageListSize = MAX_BUF_SIZE;
	BYTE* pImageList = (BYTE*)malloc(MAX_BUF_SIZE);

	if (!pImageList)
	{
		ADDSTATUS(L"Failed to allocate memory", STATUSMSG_Error);
		return FALSE;
	}

	ULONG result = GetImagesPreference(&nImageListSize, pImageList);

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

	if (!result)
	{
		BYTE* pWorker = (BYTE*)pImageList;
		CString szResp;

		BYTE nListSize = *pWorker++;
		szResp.Format(L"ImageListSize (BYTES): %d, ListSize (elements): %d", nImageListSize, nListSize);
		ADDSTATUS(szResp, STATUSMSG_Receive);
		
		// cycle through image list elements
		for (int i=0; i<nListSize; i++)
		{
			//B26065 [GobiTestApp] Missing output parameter ImageType for GetImagesPreference
			BYTE ImageType = *pWorker++;
			szResp.Format(L"    ImageType: %d", ImageType);
			ADDSTATUS(szResp, STATUSMSG_Receive);
			WCHAR szImageId[LEN_IMAGE_ID*2+1] = L"";	// + 1 for NULL character
			Bin2Ascii(pWorker, LEN_IMAGE_ID, szImageId);
			szResp.Format(L"    ImageID: %s", szImageId);
			ADDSTATUS(szResp, STATUSMSG_Receive);
			pWorker = pWorker + LEN_IMAGE_ID;
			BYTE nBuildIdLength = *pWorker++;
			szResp.Format(L"    BuildIDLength: %d", nBuildIdLength);
			ADDSTATUS(szResp, STATUSMSG_Receive);
			WCHAR szBuildID[MAX_PATH] = L"";
			MultiByteToWideChar(CP_ACP, 0, (LPSTR)pWorker, nBuildIdLength, szBuildID, nBuildIdLength);
			szResp.Format(L"    BuildID: %s", szBuildID);
			ADDSTATUS(szResp, STATUSMSG_Receive);
			pWorker = pWorker + nBuildIdLength;
		}
	}

	free (pImageList);
	return result?FALSE:TRUE;
}

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

	const ULONG MAX_Elements = 2;
	const ULONG MAX_BUF_SIZE = 256;

	BYTE* pImageList = (BYTE*)malloc(MAX_BUF_SIZE);
	BYTE* pImageTypes = (BYTE*)malloc(MAX_BUF_SIZE);
	BYTE* pWorkerPointer = pImageList;

	if (!pImageList || !pImageTypes)
	{
		ADDSTATUS(L"Failed to allocate memory", STATUSMSG_Error);
		return FALSE;
	}

	// Create image list of 2 items: modem and PRI
	*pWorkerPointer = MAX_Elements;
	pWorkerPointer++;

	/////////////////////////////////////////////////////////////////
	// Update modem element
	*pWorkerPointer = 0; // modem
	*pWorkerPointer++;
	CW2A szImageIdModem(pParams->GetValue(PARAM_ImageIdModem));
	
	// convert ASCII hex string to binary
	int iIndex = 0;
	for(int i=0; i<(int)strlen(szImageIdModem); i+=2) 
	{
		*pWorkerPointer = hex2bin(szImageIdModem[i], szImageIdModem[i+1]);
		pWorkerPointer++;
		iIndex++;
	}

	CString szBuildId = pParams->GetValue(PARAM_BuildIdModem);
	BYTE nBuildIdLen = (BYTE)szBuildId.GetLength();
	*pWorkerPointer = nBuildIdLen;
	pWorkerPointer++;
	WideCharToMultiByte(CP_ACP, 0, szBuildId, -1, (LPSTR)pWorkerPointer, szBuildId.GetLength(), 0, 0);
	pWorkerPointer += nBuildIdLen;

	/////////////////////////////////////////////////////////////////
	// Update PRI element
	*pWorkerPointer = 1; // PRI
	*pWorkerPointer++;
	CW2A szImageIdPri(pParams->GetValue(PARAM_ImageIdPri));

	// convert ASCII hex string to binary
	iIndex = 0;
	for(int i=0; i<(int)strlen(szImageIdPri); i+=2) 
	{
		*pWorkerPointer = hex2bin(szImageIdPri[i], szImageIdPri[i+1]);
		pWorkerPointer++;
		iIndex++;
	}

	szBuildId = pParams->GetValue(PARAM_BuildIdPri);
	nBuildIdLen = (BYTE)szBuildId.GetLength();
	*pWorkerPointer = nBuildIdLen;
	pWorkerPointer++;
	WideCharToMultiByte(CP_ACP, 0, szBuildId, -1, (LPSTR)pWorkerPointer, szBuildId.GetLength(), 0, 0);
	pWorkerPointer += nBuildIdLen;
	
	/////////////////////////////////////////////////////////////////
	// Update remaining items
	ULONG nImgListSize = (ULONG)(pWorkerPointer - pImageList);
	ULONG nImageTypesSize = MAX_Elements;
	CString szModemIndex = pParams->GetValue(PARAM_ModemIndex);
	BYTE nModemIndex = 0xFF;
	
	if (-1 == szModemIndex.Find(L"FF"))
		nModemIndex = (BYTE)_wtoi(szModemIndex);

	ULONG result = SetImagesPreference(
						nImgListSize, 
						pImageList, 
						_wtoi(pParams->GetValue(PARAM_ForceDownload)), 
						nModemIndex,
						&nImageTypesSize,
						pImageTypes);

    if (!result)
    {
        CString szResp;
        szResp.Format(L"Result: %d, Number of images need to be downloaded: %d", result, nImageTypesSize);
        ADDSTATUS(szResp, STATUSMSG_Receive);

        BYTE* pWorker = (BYTE*)pImageTypes;
        // cycle through image type elements
        for (ULONG i=0; i<nImageTypesSize; i++)
        {
            BYTE ImageType = *pWorker++;
            szResp.Format(L"    ImageType: %d need to be downloaded", ImageType);
            ADDSTATUS(szResp, STATUSMSG_Receive);
        }
    }

	free (pImageList);
	free (pImageTypes);
	return result?FALSE:TRUE;
}

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

	VOID* pImageList = malloc(MAX_IMAGE_LIST_SIZE);

	ULONG nImageListSize = MAX_IMAGE_LIST_SIZE;

	ULONG nRet = GetStoredImages(&nImageListSize, (BYTE*)pImageList);

	if (!nRet)
	{
		BYTE* pWorker = (BYTE*)pImageList;
		CString szResp;

		BYTE nListSize = *pWorker++;
		szResp.Format(L"ImageListSize (BYTES): %d, ListSize (elements): %d", nImageListSize, nListSize);
		ADDSTATUS(szResp, STATUSMSG_Receive);

		// cycle through image list elements
		for (int i=0; i<nListSize; i++)
		{
			BYTE ImageType = *pWorker++;
			BYTE MaxImages = *pWorker++;
			BYTE ExecutingImage = *pWorker++;
			BYTE ImageIdSize = *pWorker++;
			szResp.Format(L"ImageType: %d, MaxImages: %d, ExecutingImage: %d, ImageIdSize: %d", 
				ImageType, MaxImages, ExecutingImage, ImageIdSize);
			ADDSTATUS(szResp, STATUSMSG_Receive);

			// cycle through image ID list elements
			for (int j=0; j<ImageIdSize; j++)
			{
				BYTE StoreIndex = *pWorker++;
				BYTE FailureCount = *pWorker++;
				szResp.Format(L"    StorageIndex: %d, FailureCount: %d", StoreIndex, FailureCount);
				ADDSTATUS(szResp, STATUSMSG_Receive);
				WCHAR szImageId[LEN_IMAGE_ID*2+1] = L"";	// + 1 for NULL character
				Bin2Ascii(pWorker, LEN_IMAGE_ID, szImageId);
				szResp.Format(L"    ImageID: %s", szImageId);
				ADDSTATUS(szResp, STATUSMSG_Receive);
				pWorker = pWorker + LEN_IMAGE_ID;
				BYTE nBuildIdLength = *pWorker++;
				szResp.Format(L"    BuildIDLength: %d", nBuildIdLength);
				ADDSTATUS(szResp, STATUSMSG_Receive);
				WCHAR szBuildID[MAX_PATH] = L"";
				MultiByteToWideChar(CP_ACP, 0, (LPSTR)pWorker, nBuildIdLength, szBuildID, nBuildIdLength);
				szResp.Format(L"    BuildID: %s", szBuildID);
				ADDSTATUS(szResp, STATUSMSG_Receive);
				pWorker = pWorker + nBuildIdLength;
			}
		}
	}

	free (pImageList);

	return (nRet?STATUSMSG_Error:STATUSMSG_Receive);
}

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

	ULONG nImageInfoSize = 0;
	const ULONG MAX_BUF_SIZE = 64;

	BYTE* pImageInfo = (BYTE*)malloc(MAX_BUF_SIZE);
	BYTE* pWorker = pImageInfo;

	if (!pImageInfo)
	{
		ADDSTATUS(L"Failed to allocate memory", STATUSMSG_Error);
		return FALSE;
	}

	// Create image list of 1 item
	// Get image type
	*pWorker++ = (BYTE)_ttoi(pParams->GetValue(PARAM_ImageType));

	// Get image ID
	CW2A szImageId(pParams->GetValue(PARAM_ImageId));

	// convert ASCII hex string to binary
	int iIndex = 0;
	for(int i=0; i<(int)strlen(szImageId); i+=2) 
	{
		*pWorker = hex2bin(szImageId[i], szImageId[i+1]);
		pWorker++;
		iIndex++;
	}

	// Get build ID
	CString szBuildId = pParams->GetValue(PARAM_BuildId);
	BYTE nBuildIdLen = (BYTE)szBuildId.GetLength();
	*pWorker++ = nBuildIdLen;
	WideCharToMultiByte(CP_ACP, 0, szBuildId, -1, (LPSTR)pWorker, szBuildId.GetLength(), 0, 0);

	// Calculate ImageInfoSize.
	// Everything but BuildID is static size
	nImageInfoSize = 18 + nBuildIdLen;
	
	ULONG result = DeleteStoredImage(nImageInfoSize, pImageInfo);

	CString strTemp;

	strTemp.Format(L"Result: %d", result);
	ADDSTATUS(strTemp, (result)?STATUSMSG_Error:STATUSMSG_Receive);

	free (pImageInfo);
	return result?FALSE:TRUE;
}

BOOL CGobiApiFwMgmt::FuncResetDevice(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncResetDevice", STATUSMSG_Send);
	ULONG nRet = ResetDevice();
	CString strTemp;
	strTemp.Format(L"Result: %d", nRet);
	ADDSTATUS(strTemp, (nRet)?STATUSMSG_Error:STATUSMSG_Receive);

	return TRUE;
}

BOOL CGobiApiFwMgmt::FuncGetBARMode(CParamList* pParams /*= NULL*/)
{
    UNREFERENCED_PARAMETER(pParams);
	ADDSTATUS(L"FuncGetBARMode", STATUSMSG_Send);
	BOOL bRet = FALSE;
	ULONG DowloadMode = 0;

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

	if (!nRet)
    {
		// display IP address
		strTemp.Format(L"Download Mode: %d.", DowloadMode);
		ADDSTATUS(strTemp, (nRet==0)?STATUSMSG_Receive:STATUSMSG_Error);
        bRet = TRUE;
    }
	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (GOBICMAPI*LPFN_GETBARMODE) (ULONG*);

		// get pointer to function
		LPFN_GETBARMODE pFn = (LPFN_GETBARMODE)GetProcAddress_W(m_hQCDll, FUNC_GetBARMode);

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

			ULONG nQcRet = pFn(&qcDowloadMode);

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

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

	if (!nRet)
        bRet = TRUE;
	// Compare with QC DLL
	if (m_hQCDll)
	{
		// function prototype
		typedef ULONG (GOBICMAPI*LPFN_SETBARMODE) ();

		// get pointer to function
		LPFN_SETBARMODE pFn = (LPFN_SETBARMODE)GetProcAddress_W(m_hQCDll, FUNC_SetBARMode);

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

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

    BYTE DeleteImageType = (BYTE)_ttoi(pParams->GetValue(PARAM_ImageType));
	VOID* pImageList = malloc(MAX_IMAGE_LIST_SIZE);

	ULONG nImageListSize = MAX_IMAGE_LIST_SIZE;

	ULONG nRet = GetStoredImages(&nImageListSize, (BYTE*)pImageList);

	if (!nRet)
	{
		BYTE* pWorker = (BYTE*)pImageList;
		CString szResp;

		BYTE nListSize = *pWorker++;
		// cycle through image list elements
		for (int i=0; i<nListSize; i++)
		{
			BYTE ImageType = *pWorker++;
			*pWorker++; // escapeMaxImages
			*pWorker++; // escape ExecutingImage
			BYTE ImageIdSize = *pWorker++;

			// cycle through image ID list elements
			for (int j=0; j<ImageIdSize; j++)
			{
				*pWorker++; // escape StoreIndex
				*pWorker++; // escape FailureCount
				WCHAR szImageId[LEN_IMAGE_ID*2+1] = L"";	// + 1 for NULL character
				Bin2Ascii(pWorker, LEN_IMAGE_ID, szImageId);
				pWorker = pWorker + LEN_IMAGE_ID;
				BYTE nBuildIdLength = *pWorker++;
				WCHAR szBuildID[MAX_PATH] = L"";
				MultiByteToWideChar(CP_ACP, 0, (LPSTR)pWorker, nBuildIdLength, szBuildID, nBuildIdLength);
				pWorker = pWorker + nBuildIdLength;

				if(DeleteImageType == ImageType)
				{
					// if the
					if((DeleteImageType == 0)&&(wcscmp(szImageId, L"00000000000000000000000000000000") == 0))
					{
						continue;
					}
					ULONG nImageInfoSize = 0;
					const ULONG MAX_BUF_SIZE = 64;

					BYTE* pImageInfo = (BYTE*)malloc(MAX_BUF_SIZE);
					BYTE* pWorkerDelete = pImageInfo;

					if (!pImageInfo)
					{
						ADDSTATUS(L"Failed to allocate memory", STATUSMSG_Error);
						free (pImageList);
						return FALSE;
					}

					// Create image list of 1 item
					// Get image type
					*pWorkerDelete++ = DeleteImageType;

					// convert ASCII hex string to binary
					int iIndex = 0;
					for(int i=0; i<(int)wcslen(szImageId); i+=2) 
					{
						*pWorkerDelete = hex2bin((unsigned char)szImageId[i], (unsigned char)szImageId[i+1]);
						pWorkerDelete++;
						iIndex++;
					}

					// Get build ID
					*pWorkerDelete++ = nBuildIdLength;
					WideCharToMultiByte(CP_ACP, 0, szBuildID, -1, (LPSTR)pWorkerDelete, nBuildIdLength, 0, 0);

					// Calculate ImageInfoSize.
					// Everything but BuildID is static size
					nImageInfoSize = 18 + nBuildIdLength;
					
					szResp.Format(L"Deleting : %d, Build ID: %s", DeleteImageType, szBuildID);
					ADDSTATUS(szResp, STATUSMSG_Receive);

					ULONG result = DeleteStoredImage(nImageInfoSize, pImageInfo);

					CString strTemp;

					szResp.Format(L"Result: %d", result);
					ADDSTATUS(strTemp, (result)?STATUSMSG_Error:STATUSMSG_Receive);

					free (pImageInfo);
				}

			}
		}
	}

	free (pImageList);

	return (nRet?STATUSMSG_Error:STATUSMSG_Receive);
}
