#include "StdAfx.h"
#include "Gobi.h"
#define MAX_LENGTH 1024

#define MAX_BUILD_IMAGE_LENGTH 256

CGobi::CGobi(void)
{
  m_hGobiApi = NULL; 
  m_pFnConnect = NULL;
  m_pFnDisconnect = NULL;
  m_pFnGetServingNetwork = NULL;
  m_pFnGetVoiceNumber = NULL;
  m_pFnUpgradeFirmware2kW = NULL;
  m_pFnSetPower = NULL;
  m_pFnSetImagesPreference = NULL;
  m_pFnGetImagesPreference = NULL;

}

CGobi::~CGobi(void)
{
}

// Helper function to convert ASCII hex characters to binary
unsigned char hex2bin(unsigned char h, unsigned char l)
{
	h |= 0x20; // to lower
	h -= 0x30;
	h -= -(h > 9) & 0x27;
	l |= 0x20;
	l -= 0x30;
	l -= -(l > 9) & 0x27;
	return h << 4 | l;
}

// WinCE helper function
FARPROC WINAPI GetProcAddress_W(__in HMODULE hModule, __in LPCWSTR lpProcName)
{
#ifndef UNDER_CE
  const int nAsciiLen = 256;
  CHAR szAscii[nAsciiLen] =  "";

  WideCharToMultiByte(CP_ACP, 0, lpProcName, -1, szAscii, nAsciiLen, 0, 0);

  return GetProcAddress(hModule, szAscii);
#else
  return GetProcAddress(hModule, lpProcName);
#endif
}

BOOL CGobi::Initialize()
{
  m_hGobiApi = LoadLibrary(L"GobiApi.dll");

  if (m_hGobiApi != NULL)
  {
    // Function names
    LPCWSTR QCWWAN_CONNECT = L"QCWWANConnect";
    LPCWSTR QCWWAN_DISCONNECT = L"QCWWANDisconnect";
    LPCWSTR QCWWAN_GET_SRV_NETWORK = L"GetServingNetwork";
    LPCWSTR QCWWAN_GET_VOICE_NUMBER = L"GetVoiceNumber";
    LPCWSTR QCWWAN_UPGRADE_FIRMWARE2KW = L"UpgradeFirmware2kW";
    LPCWSTR QCWWAN_SET_POWER = L"SetPower";
    LPCWSTR QCWWAN_SET_IMAGES_PREFERENCE = L"SetImagesPreference";
    LPCWSTR QCWWAN_GET_IMAGES_PREFERENCE = L"GetImagesPreference";
    FARPROC pFN = 0;

    pFN = ::GetProcAddress_W(m_hGobiApi, QCWWAN_CONNECT);
    m_pFnConnect = (tFNConnect)pFN;

    pFN = ::GetProcAddress_W(m_hGobiApi, QCWWAN_DISCONNECT);
    m_pFnDisconnect = (tFNDisconnect)pFN;

    pFN = ::GetProcAddress_W(m_hGobiApi, QCWWAN_GET_SRV_NETWORK);
    m_pFnGetServingNetwork = (tFNGetServingNetwork)pFN;

    pFN = ::GetProcAddress_W(m_hGobiApi, QCWWAN_GET_VOICE_NUMBER);
    m_pFnGetVoiceNumber = (tFNGetVoiceNumber)pFN;

    pFN = ::GetProcAddress_W(m_hGobiApi, QCWWAN_UPGRADE_FIRMWARE2KW);
    m_pFnUpgradeFirmware2kW = (tFNUpgradeFirmware2kW)pFN;

    pFN = ::GetProcAddress_W(m_hGobiApi, QCWWAN_SET_POWER );
    m_pFnSetPower= (tFNSetPower)pFN;

    pFN = ::GetProcAddress_W(m_hGobiApi, QCWWAN_SET_IMAGES_PREFERENCE );
    m_pFnSetImagesPreference = (tFNSetImagesPreference)pFN;
	
	pFN = ::GetProcAddress_W(m_hGobiApi, QCWWAN_GET_IMAGES_PREFERENCE );
    m_pFnGetImagesPreference = (tFNGetImagesPreference)pFN;
  }
  else {
    return FALSE; //something went wrong
  }

  if (!m_pFnConnect || // something went wrong, then rest to NULL and ret False
    !m_pFnDisconnect ||
    !m_pFnGetServingNetwork || 
    !m_pFnGetVoiceNumber ||
    !m_pFnUpgradeFirmware2kW || 
    !m_pFnSetPower ||
    !m_pFnSetImagesPreference ||
    !m_pFnGetImagesPreference)
  {
    m_pFnConnect = NULL;
    m_pFnDisconnect = NULL;
    m_pFnGetServingNetwork = NULL;
    m_pFnGetVoiceNumber = NULL;
    m_pFnUpgradeFirmware2kW = NULL;
    m_pFnSetPower = NULL;
    m_pFnSetImagesPreference = NULL;
    m_pFnGetImagesPreference = NULL;
    return FALSE; 
  }
  return TRUE;
}

void CGobi::Deinit()
{
  if (m_pFnConnect || 
    m_pFnDisconnect ||
    m_pFnGetServingNetwork || 
    m_pFnGetVoiceNumber ||
    m_pFnUpgradeFirmware2kW || 
    m_pFnSetPower ||
    m_pFnSetImagesPreference ||
    m_pFnGetImagesPreference)
  {
    m_pFnConnect = NULL;
    m_pFnDisconnect = NULL;
    m_pFnGetServingNetwork = NULL;
    m_pFnGetVoiceNumber = NULL;
    m_pFnUpgradeFirmware2kW = NULL;
    m_pFnSetPower = NULL;
    m_pFnSetImagesPreference = NULL;
    m_pFnGetImagesPreference = NULL;
  }
}


int fileExists(TCHAR * file)
{
   WIN32_FIND_DATA FindFileData;
   HANDLE handle = FindFirstFile(file, &FindFileData) ;
   int found = handle != INVALID_HANDLE_VALUE;
   if(found) 
   {
       FindClose(&handle);
   }
   return found;
}


//
//note:  commented out code in the following function is for use when using the UpgradeFirmwareW2k Gobi API
//
DWORD CGobi::DoFirmwareUpgrade(int iNewCarrier)  
{
  DWORD ret=0;
  LONG lResult = ERROR_SUCCESS;
  HKEY hKey ;
  DWORD   dwValue, dwType, dwLen= 0; 
  DWORD   dwForceFWDownload = 1; //this will default to the old method of firmware download via UpgradeFirmware2k()
  WCHAR pDestinationPath[MAX_LENGTH];
  memset(pDestinationPath, NULL, sizeof(WCHAR)*MAX_LENGTH);

  char szImageID[MAX_BUILD_IMAGE_LENGTH];
  memset(szImageID, NULL, MAX_BUILD_IMAGE_LENGTH);
  WCHAR pImageID[MAX_BUILD_IMAGE_LENGTH];
  memset(pImageID, NULL, sizeof(WCHAR)*MAX_BUILD_IMAGE_LENGTH);
  WCHAR pBuildID[MAX_BUILD_IMAGE_LENGTH];
  memset(pBuildID, NULL, sizeof(WCHAR)*MAX_BUILD_IMAGE_LENGTH);
  WCHAR pPriImageID[MAX_BUILD_IMAGE_LENGTH];
  memset(pPriImageID, NULL, sizeof(WCHAR)*MAX_BUILD_IMAGE_LENGTH);
  WCHAR pPriBuildID[MAX_BUILD_IMAGE_LENGTH];
  memset(pPriBuildID, NULL, sizeof(WCHAR)*MAX_BUILD_IMAGE_LENGTH);



  WCHAR pRegistryKey[MAX_BUILD_IMAGE_LENGTH];
  memset(pRegistryKey, NULL, sizeof(WCHAR)* MAX_BUILD_IMAGE_LENGTH);



  dwLen = MAX_LENGTH - 1;
  lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\Sierra Wireless Inc\\QDL"), 0, 0 , &hKey );
  if(lResult == ERROR_SUCCESS)
  {
    lResult = RegQueryValueEx(hKey,_T("FwRootLocation"),0, &dwType,(LPBYTE)&pDestinationPath, &dwLen);
    if(lResult == ERROR_SUCCESS)
    {
	  TCHAR AMSSFilename[MAX_PATH];
	  TCHAR UQCNFilename[MAX_PATH];
	  wsprintf(AMSSFilename, L"%s\\%s\\%d\\amss.mbn", pDestinationPath, FwAvalible[iNewCarrier].FolderName, FwAvalible[iNewCarrier].FwSlot);
	  wsprintf(UQCNFilename, L"%s\\%s\\%d\\uqcn.mbn", pDestinationPath, FwAvalible[iNewCarrier].FolderName, FwAvalible[iNewCarrier].FwSlot);
	  if (!(fileExists(AMSSFilename) && fileExists(UQCNFilename)))
	  {
		  ret=1;
		  goto Error;
	  }

	  dwValue = FwAvalible[iNewCarrier].FwSlot;
      RegSetValueEx(hKey, _T("CarrierIndex"),  0,  REG_DWORD, (const BYTE*)&dwValue, sizeof(DWORD));

    }
    else
    {
      RETAILMSG(1,(_T("\r\nCGobi::DoFirmwareUpgrade:: Failed to open the HKLM\\Software\\Sierra Wireless Inc\\QDL\\FirmwareLocation registry key, error = %d!!!\n"), lResult));
	  ret=1;
      goto Error;
    }

    //11290 - Read the ForceFWDownload registry key
    lResult = RegQueryValueEx(hKey,_T("ForceFWDownload"),0, &dwType,(BYTE*)&dwForceFWDownload, &dwLen);
    if(lResult != ERROR_SUCCESS)
    {
      dwForceFWDownload = 1; //default
      RETAILMSG(1,(_T("\r\nCGobi::DoFirmwareUpgrade:: Failed to open the HKLM\\Software\\Sierra Wireless Inc\\QDL\\ForceFWDownload registry key, error = %d!!!\n"), lResult));
    }
    if(dwForceFWDownload == 0)//11290 - Just set the images preference and reset the modem
    {
      RETAILMSG(1,(_T("\r\nCGobi::DoFirmwareUpgrade:: ForceFWDownload = %d!!!\n"), dwForceFWDownload));
      //Read the ImageID, BuildID registry keys for the firmware to be switched to
      wsprintf(pRegistryKey, _T("%s%d"),_T("ModemImageID"), dwValue);
      dwLen = MAX_BUILD_IMAGE_LENGTH -1;
      lResult = RegQueryValueEx(hKey,pRegistryKey,0, &dwType,(BYTE*)&pImageID, &dwLen);
      if(lResult != ERROR_SUCCESS)
      {
        RETAILMSG(1,(_T("\r\nCGobi::DoFirmwareUpgrade:: Failed to open the HKLM\\Software\\Sierra Wireless Inc\\QDL\\%s registry key, error = %d!!!\n"), pRegistryKey,lResult));
		ret = 3;
        goto Error;
      }
      else
      {
        RETAILMSG(1,(_T("\r\nCGobi::DoFirmwareUpgrade:: %s registry key = %s!!!"), pRegistryKey,pImageID));
      }
      
      memset(pRegistryKey, NULL, sizeof(WCHAR)* MAX_BUILD_IMAGE_LENGTH);

      wsprintf(pRegistryKey, _T("%s%d"),_T("ModemBuildID"), dwValue);
      dwLen = MAX_BUILD_IMAGE_LENGTH -1;
      lResult = RegQueryValueEx(hKey,pRegistryKey,0, &dwType,(LPBYTE)&pBuildID, &dwLen);
      if(lResult != ERROR_SUCCESS)
      {
        RETAILMSG(1,(_T("\r\nCGobi::DoFirmwareUpgrade:: Failed to open the HKLM\\Software\\Sierra Wireless Inc\\QDL\\%s registry key, error = %d!!!\n"), pRegistryKey,lResult));
		ret = 4;
        goto Error;
      }
      else
      {
        RETAILMSG(1,(_T("\r\nCGobi::DoFirmwareUpgrade:: %s registry key = %s!!!\n"), pRegistryKey,pBuildID));
      }

      memset(pRegistryKey, NULL, sizeof(WCHAR)* MAX_BUILD_IMAGE_LENGTH);

      wsprintf(pRegistryKey, _T("%s%d"),_T("PRIImageID"), dwValue);
      dwLen = MAX_BUILD_IMAGE_LENGTH -1;
      lResult = RegQueryValueEx(hKey,pRegistryKey,0, &dwType,(LPBYTE)&pPriImageID, &dwLen);
      if(lResult != ERROR_SUCCESS)
      {
        RETAILMSG(1,(_T("\r\nCGobi::DoFirmwareUpgrade:: Failed to open the HKLM\\Software\\Sierra Wireless Inc\\QDL\\%s registry key, error = %d!!!\n"), pRegistryKey,lResult));
		ret = 5;
        goto Error;
      }
      else
      {
        RETAILMSG(1,(_T("\r\nCGobi::DoFirmwareUpgrade:: %s registry key = %s!!!\n"), pRegistryKey,pPriImageID));
      }

      memset(pRegistryKey, NULL, sizeof(WCHAR)* MAX_BUILD_IMAGE_LENGTH);

      wsprintf(pRegistryKey, _T("%s%d"),_T("PRIBuildID"), dwValue);
      dwLen = MAX_BUILD_IMAGE_LENGTH -1;
      lResult = RegQueryValueEx(hKey,pRegistryKey,0, &dwType,(LPBYTE)&pPriBuildID, &dwLen);
      if(lResult != ERROR_SUCCESS)
      {
        RETAILMSG(1,(_T("\r\nCGobi::DoFirmwareUpgrade:: Failed to open the HKLM\\Software\\Sierra Wireless Inc\\QDL\\%s registry key, error = %d!!!\n"), pRegistryKey,lResult));
		ret = 6;
        goto Error;
      }
      else
      {
        RETAILMSG(1,(_T("\r\nCGobi::DoFirmwareUpgrade:: %s registry key = %s!!!\n"), pRegistryKey,pPriBuildID));
      }

/////////Now prepare everything to call SetImagePreference

      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;

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

      /////////////////////////////////////////////////////////////////
      // Update modem element
      *pWorkerPointer = 0; // modem
      *pWorkerPointer++;
    //convert the Modem image ID from Wide char to multi byte
      wcstombs(szImageID,pImageID, _tcslen(pImageID));
      int iIndex = 0;
      for(int i=0; i<(int)strlen(szImageID); i+=2) 
      {
        *pWorkerPointer = hex2bin(szImageID[i], szImageID[i+1]);
        pWorkerPointer++;
        iIndex++;
      }
      BYTE nBuildIdLen = _tcslen(pBuildID);
      *pWorkerPointer = nBuildIdLen;
      pWorkerPointer++;
      wcstombs((LPSTR)pWorkerPointer,pBuildID, _tcslen(pBuildID));
      //WideCharToMultiByte(CP_ACP, 0, szBuildId, -1, (LPSTR)pWorkerPointer, szBuildId.GetLength(), 0, 0);
      pWorkerPointer += nBuildIdLen;

      // Update PRI element

      *pWorkerPointer = 1; // PRI
      *pWorkerPointer++;
    //convert the PRI image ID from Wide char to multi byte
      memset(szImageID, NULL, MAX_BUILD_IMAGE_LENGTH);
      wcstombs(szImageID,pPriImageID, _tcslen(pPriImageID));
      // convert ASCII hex string to binary
      iIndex = 0;
      for(int i=0; i<(int)strlen(szImageID); i+=2) 
      {
        *pWorkerPointer = hex2bin(szImageID[i], szImageID[i+1]);
        pWorkerPointer++;
        iIndex++;
      }

      nBuildIdLen = _tcslen(pPriBuildID);
      *pWorkerPointer = nBuildIdLen;
      pWorkerPointer++;
      wcstombs((LPSTR)pWorkerPointer,pPriBuildID, _tcslen(pPriBuildID));
      //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;
      BYTE nModemIndex = FwAvalible[iNewCarrier].FwSlot;


      ULONG result = m_pFnSetImagesPreference(
                nImgListSize, 
                pImageList, 
                0, 
                nModemIndex,
                &nImageTypesSize,
                pImageTypes);
      if (!result)
      {
          RETAILMSG(1,(_T("\r\nCGobi::DoFirmwareUpgrade:: Result: %d, Number of images need to be downloaded: %d!!!\n"), result, nImageTypesSize));
          BYTE* pWorker = (BYTE*)pImageTypes;
          // cycle through image type elements
          for (ULONG i=0; i<nImageTypesSize; i++)
          {
              BYTE ImageType = *pWorker++;
              RETAILMSG(1,(_T("\r\nCGobi::DoFirmwareUpgrade:: ImageType: %d needs to be downloaded!!!\n"), ImageType));
          }
      }
      else
      {
        RETAILMSG(1, (_T("\r\nCGobi::DoFirmwareUpgrade:: The image is already present on modem\n")));
      }

      free (pImageList);
      free (pImageTypes);
      //reset the modem to put the firmware change to effect
      result = m_pFnSetPower(3);//take modem to offline mode
      if(result)//failed
      {
        RETAILMSG(1, (_T("\r\nCGobi::DoFirmwareUpgrade:: Failed to put the modem to offline mode\n")));
		ret = 7;
      }
      Sleep(1000);
      result = m_pFnSetPower(4);//reset the modem
      if(result)//failed
      {
        RETAILMSG(1, (_T("\r\nCGobi::DoFirmwareUpgrade:: Failed to reset the modem\n")));
		ret = 8;
      }
    }//if(dwForceFWDownload == 0)
    else //this will default to traditional way of firmware download
    {      
      RETAILMSG(1,(_T("\r\nCGobi::DoFirmwareUpgrade:: ForceFWDownload = %d!!!\n"), dwForceFWDownload));
      wsprintf(pDestinationPath, _T("%s\\%s\\%d"),pDestinationPath, FwAvalible[iNewCarrier].FolderName, FwAvalible[iNewCarrier].FwSlot);
      ret = m_pFnUpgradeFirmware2kW(pDestinationPath);
    }
  }
  else
  {
    RETAILMSG(1,(_T("\r\nCGobi::DoFirmwareUpgrade:: Failed to open the HKLM\\Software\\Sierra Wireless Inc\\QDL registry key, error = %d!!!\n"), lResult));
	ret = 9;
    goto Error;
  }

Error:
  RegCloseKey(hKey);
  return ret;
}

BOOL CGobi::GetVoiceNumberInfo(TCHAR * szVoiceNum)
{
  const BYTE MAX_Size = 0x0F;
  BYTE   voiceNumberSize = MAX_Size; 
  CHAR   pVoiceNumber[MAX_Size];
  BYTE   minSize = MAX_Size;  // don't care
  CHAR   pMIN[MAX_Size] = " "; // don't care

  ULONG nRet = m_pFnGetVoiceNumber(voiceNumberSize, pVoiceNumber, minSize, pMIN);
  if (!nRet) // GobiAPI always returns 0x0000 for success
  {
    MultiByteToWideChar(CP_ACP, MB_COMPOSITE, pVoiceNumber, MAX_Size, szVoiceNum, MAX_Size);
    return TRUE;
  }
  else
    // their were problems
    return FALSE;
}


DWORD CGobi::GetNetworkInfo(TCHAR * szTechType, TCHAR * szNetStatus)
{
  // Update network info
  const BYTE MAX_RInt = 0x10;
  const BYTE MAX_Size = 0xFF;

  ULONG   RegistrationState; 
  ULONG   CSDomain ; 
  ULONG   PSDomain; 
  ULONG   RAN; 
  BYTE    RadioIfacesSize = MAX_RInt; 
  BYTE    RadioIfaces[MAX_RInt]; 
  ULONG   Roaming; 
  WORD    MCC; 
  WORD    MNC;
  BYTE  NameSize = MAX_Size;
  CHAR    Name[MAX_Size] = " ";
  DWORD   dwIndex = 0;
  HKEY phKey = NULL;
  DWORD dwLen = 24;

  if (!m_pFnGetServingNetwork(&RegistrationState, 
    &CSDomain, 
    &PSDomain, 
    &RAN, 
    &RadioIfacesSize, 
    RadioIfaces, 
    &Roaming, 
    &MCC, 
    &MNC, 
    NameSize, 
    Name)
    )
  {
    // FOR CDMA Carrier szCarrierName is not populated, so access registry to find out carrier
    if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\Sierra Wireless Inc\\QDL"), 0, 0 , &phKey ))
    {
        if(ERROR_SUCCESS == RegQueryValueEx(phKey, _T("CarrierIndex"),  0,  0, (LPBYTE)&dwIndex, &dwLen))
        {
            RETAILMSG(1,(_T("CarrierIndex registry key = %d"),dwIndex));
        }
        else
        {
            RETAILMSG(1,(_T("Failed to open the HKLM\\SW\\SWI\\QDL\\CarrierIndex registry value!!!")));
        }
        RegCloseKey(phKey);
    }
    else
    {
      RETAILMSG(1,(_T("Failed to open the HKLM\\SW\\SWI\\QDL registry key!!!")));
    }

    // get tech in use
    if (RAN == 1)
    {
      CHAR szRAN[MAX_Size] = "CDMA";
      MultiByteToWideChar(CP_ACP, MB_COMPOSITE, szRAN, MAX_Size, szTechType, MAX_Size);
    }
    else if (RAN == 2)
    {
      CHAR szRAN[MAX_Size] = "UMTS";
      MultiByteToWideChar(CP_ACP, MB_COMPOSITE, szRAN, MAX_Size, szTechType, MAX_Size);
    }
    else
    {
      CHAR szRAN[MAX_Size] = "Unknown";
      MultiByteToWideChar(CP_ACP, MB_COMPOSITE, szRAN, MAX_Size, szTechType, MAX_Size);
    }
    // get network status 
    if (Roaming == 0)
    {
      CHAR szRoaming[MAX_Size] = "Roaming";
      MultiByteToWideChar(CP_ACP, MB_COMPOSITE, szRoaming, MAX_Size, szNetStatus, MAX_Size);
    }
    else if (Roaming == 1)
    {
      CHAR szRoaming[MAX_Size] = "Home";
      MultiByteToWideChar(CP_ACP, MB_COMPOSITE, szRoaming, MAX_Size, szNetStatus, MAX_Size);
    }
    else
    {
      CHAR szRoaming[MAX_Size] = "Unknown";
      MultiByteToWideChar(CP_ACP, MB_COMPOSITE, szRoaming, MAX_Size, szNetStatus, MAX_Size);
    }
  }
  return dwIndex; 
}











