/*===========================================================================
                              OEMBattery.c

  OEM REFERENCE BATTERY SUPPORT ROUTINES
  
  This file contains a reference implementation of Battery support.
    
        Copyright © 1999-2004 QUALCOMM Incorporated.
               All Rights Reserved.
            QUALCOMM Proprietary/GTDR
============================================================================*/
/*===========================================================================
                      IMPORTED DECLARATIONS
===========================================================================*/
#include "OEMFeatures.h"

#ifdef FEATURE_BREW_BATTERY
#include "comdef.h"
#include "charger.h"
#include "vbatt.h"
#endif // FEATURE_BREW_BATTERY

#include "OEMHeap.h"
#include "OEMBattery.h"
#include "AEEStdLib.h"
#include "AEE_OEMDispatch.h"
#include "AEEBattery.h"

#define TIMEOUT_MS_PERIODICBATTCHECK                  1000

#ifdef FEATURE_BREW_BATTERY
#define BATTERY_LEVEL_WARN                            ((VBATT_SCALE*10)/100)
#define BATTERY_LEVEL_POWERDOWN                       ((VBATT_SCALE*5)/100)
#endif // FEATURE_BREW_BATTERY
/*===========================================================================
                 PRIVATE DATA DECLARATIONS
===========================================================================*/

struct _OEMBatteryMgr
{
   uint32                        dwBatteryStatus;
   uint32                        dwBatteryLevel;
   uint32                        dwChargerStatus;
   uint32                        dwExternalPower;
   uint32                        nRefs;
   uint32                        *pcbData[AEEBATTERY_ITEM_LAST];
   AEECallback                   *pcbOnInfoUpdate[AEEBATTERY_ITEM_LAST];
};

/*===========================================================================
                 PRIVATE METHOD DECLARATIONS
===========================================================================*/
static void OEMBattery_CancelBatteryItemListener(AEECallback *pcb);

static void OEMBattery_Init(void);
static void OEMBattery_Delete(void);
static void OEMBattery_PeriodicBatteryCheck(void * pUser);
static void OEMBattery_CheckBatteryStatus(uint32 * pdwBatteryStatus);
static void OEMBattery_CheckBatteryLevel(uint32 * pdwBatteryLevel);
static void OEMBattery_CheckChargerStatus(uint32 * pdwChargerStatus);
static void OEMBattery_CheckExternalPower(uint32 * pdwExternalPower);
/*===========================================================================
                 PRIVATE DATA DEFINITIONS
===========================================================================*/
static OEMBatteryMgr *gpBattery;

/*===========================================================================
                 PUBLIC METHOD DEFINITIONS
===========================================================================*/

/*===========================================================================
Manages singleton instance of gpBattery. Initializes gpBattery for first time and 
increases its reference count subsequently.
===========================================================================*/
int OEMBattery_New(OEMBatteryMgr **ppme)
{
   *ppme = 0;

   FARF(BATTERY, ("==>  OEMBattery_New"));

   if (gpBattery) 
   {
      ++gpBattery->nRefs;
   } 
   else 
   {
      gpBattery = (OEMBatteryMgr *)sys_malloc(sizeof(OEMBatteryMgr));
      
      if (!gpBattery) 
      {
         return ENOMEMORY;
      }

      gpBattery->nRefs = 1;
      gpBattery->dwBatteryStatus = AEEBATTERY_STATUS_UNKNOWN;
      gpBattery->dwBatteryLevel = 0;
      gpBattery->dwChargerStatus = AEEBATTERY_CHARGERSTATUS_UNKNOWN;
      gpBattery->dwExternalPower = 0;

      OEMBattery_Init();
   }
   
   *ppme = gpBattery;

   return SUCCESS;
}

/*===========================================================================
Inrecases reference count of gpBattery
===========================================================================*/
uint32 OEMBattery_AddRef(OEMBatteryMgr *pme)
{
   FARF(BATTERY, ("==>  OEMBattery_AddRef"));

   return ++pme->nRefs;
}

/*===========================================================================
Decreases reference count of gpBattery. Frees object when reference count reaches
zero
===========================================================================*/
uint32 OEMBattery_Release(OEMBatteryMgr *pme)
{
   FARF(BATTERY, ("==>  OEMBattery_Release"));

   if( --pme->nRefs ) 
      return pme->nRefs;

   OEMBattery_Delete();
   return 0;
}

/*===========================================================================
Decreases reference count of gpBattery. Frees object when reference count reaches
zero
===========================================================================*/
int OEMBattery_GetBatteryItem(OEMBatteryMgr *pme, uint32 dwItemID, uint32 *pdwData)
{
   int nErr = SUCCESS;

   if (!gpBattery)
   {
      return EFAILED;
   }

   switch (dwItemID)
   {
      case AEEBATTERY_ITEM_STATUS:
         *pdwData = gpBattery->dwBatteryStatus;
         break;

      case AEEBATTERY_ITEM_LEVEL:
         *pdwData = gpBattery->dwBatteryLevel;
         break;

      case AEEBATTERY_ITEM_CHARGERSTATUS:
         *pdwData = gpBattery->dwChargerStatus;
         break;

      case AEEBATTERY_ITEM_EXTPWR:
         *pdwData = gpBattery->dwExternalPower;
         break;

      default:
         nErr = EBADPARM;
         break;
   }
   return nErr;
}

/*===========================================================================
Called by AEEBattery to register callback to be invoked on change in battery
status
===========================================================================*/
void OEMBattery_OnBatteryItemUpdate(OEMBatteryMgr *pme, uint32 dwItemID, AEECallback *pcb)
{
   FARF(BATTERY, ("==>  OEMBattery_OnBatteryStatusUpdate"));

   // Make sure that its not there in any other list
   CALLBACK_Cancel(pcb);

   pcb->pfnCancel = OEMBattery_CancelBatteryItemListener;
   pcb->pCancelData = (void *)dwItemID;
   
   pme->pcbOnInfoUpdate[dwItemID] = pcb;
}

/*===========================================================================
Cancels Battery item listener callback
===========================================================================*/
static void OEMBattery_CancelBatteryItemListener(AEECallback *pcb)
{
   FARF(BATTERY, ("==>  OEMBattery_CancelBatteryItemListener"));

   //Verify that it is me set as the cancel function.
   //Cross-task cancellations need this check.
   if(pcb->pfnCancel != OEMBattery_CancelBatteryItemListener)
      return;
  
   if (gpBattery)
      gpBattery->pcbOnInfoUpdate[(uint32)pcb->pCancelData] = NULL;

   pcb->pCancelData = 0;
   pcb->pfnCancel   = 0;
}

/*===========================================================================
Starts periodic battery check
===========================================================================*/
static void OEMBattery_Init(void)
{
   // Start periodic battery check
   OEMBattery_PeriodicBatteryCheck(NULL);
}

/*===========================================================================
Stops periodic battery check
===========================================================================*/
static void OEMBattery_Delete(void)
{
   // Cancel periodic battery check timer
   AEE_CancelTimer(OEMBattery_PeriodicBatteryCheck, NULL);

   sys_free(gpBattery);
   gpBattery = NULL;
}

/*===========================================================================
Makes battery check and calls status update callbacks
===========================================================================*/
static void OEMBattery_PeriodicBatteryCheck(void * pUser)
{
   uint32 dwBatteryStatus = AEEBATTERY_STATUS_UNKNOWN;
   uint32 dwBatteryLevel = 0;
   uint32 dwChargerStatus = AEEBATTERY_CHARGERSTATUS_UNKNOWN;
   uint32 dwExternalPower = 0;

   // Check Battery Status
   OEMBattery_CheckBatteryStatus(&dwBatteryStatus);
   if (gpBattery->dwBatteryStatus != dwBatteryStatus)
   {
      gpBattery->dwBatteryStatus = dwBatteryStatus;
      AEE_SVC_RESUME(gpBattery->pcbOnInfoUpdate[AEEBATTERY_ITEM_STATUS]);
   }
   
   // Check Battery Level
   OEMBattery_CheckBatteryLevel(&dwBatteryLevel);
   if (gpBattery->dwBatteryLevel != dwBatteryLevel)
   {
      gpBattery->dwBatteryLevel = dwBatteryLevel;
      AEE_SVC_RESUME(gpBattery->pcbOnInfoUpdate[AEEBATTERY_ITEM_LEVEL]);
   }
   
   // Check Charger Status
   OEMBattery_CheckChargerStatus(&dwChargerStatus);
   if (gpBattery->dwChargerStatus != dwChargerStatus)
   {
      gpBattery->dwChargerStatus = dwChargerStatus;
      AEE_SVC_RESUME(gpBattery->pcbOnInfoUpdate[AEEBATTERY_ITEM_CHARGERSTATUS]);
   }
   
   // Check External Power
   OEMBattery_CheckExternalPower(&dwExternalPower);
   if (gpBattery->dwExternalPower != dwExternalPower)
   {
      gpBattery->dwExternalPower = dwExternalPower;
      AEE_SVC_RESUME(gpBattery->pcbOnInfoUpdate[AEEBATTERY_ITEM_EXTPWR]);
   }

   // Start periodic battery check timer
   (void) AEE_SetSysTimer(TIMEOUT_MS_PERIODICBATTCHECK, 
                          OEMBattery_PeriodicBatteryCheck,
                          NULL);
}

#ifdef FEATURE_BREW_BATTERY
/*===========================================================================
   Checks Battery Status
===========================================================================*/
static void OEMBattery_CheckBatteryStatus(uint32 * pdwBatteryStatus)
{   
   if (pdwBatteryStatus)
   {
      uint8 level = vbatt_read();

      if (level < BATTERY_LEVEL_POWERDOWN)
      {
         *pdwBatteryStatus = AEEBATTERY_STATUS_POWERDOWN;
      }
      else if (level < BATTERY_LEVEL_WARN)
      {
         *pdwBatteryStatus = AEEBATTERY_STATUS_LOW;
      }
      else
      {
         *pdwBatteryStatus = AEEBATTERY_STATUS_NORMAL;
      }
   }
}

/*===========================================================================
   Checks Battery Level
===========================================================================*/
static void OEMBattery_CheckBatteryLevel(uint32 * pdwBatteryLevel)
{
   if (pdwBatteryLevel)
   {
      *pdwBatteryLevel = ((VBATT_SCALE << 16)|vbatt_read());
   }
}

/*===========================================================================
   Checks Charger Status
===========================================================================*/
static void OEMBattery_CheckChargerStatus(uint32 * pdwChargerStatus)
{  
   if (pdwChargerStatus)
   {
      if (!chg_is_charger_valid())
         *pdwChargerStatus = AEEBATTERY_CHARGERSTATUS_NO_CHARGER;

      if (chg_is_charging() == TRUE )
         *pdwChargerStatus = AEEBATTERY_CHARGERSTATUS_CHARGING;
   }
}

/*===========================================================================
   Checks External Power
===========================================================================*/
static void OEMBattery_CheckExternalPower(uint32 * pdwExternalPower)
{
   if (pdwExternalPower)
   {
      *pdwExternalPower = (chg_is_charger_valid() ? 1 : 0);
   }
}
#else
static void OEMBattery_CheckBatteryStatus(uint32 * pdwBatteryStatus)
{
}

static void OEMBattery_CheckBatteryLevel(uint32 * pdwBatteryLevel)
{
}

static void OEMBattery_CheckChargerStatus(uint32 * pdwChargerStatus)
{
}

static void OEMBattery_CheckExternalPower(uint32 * pdwExternalPower)
{
}
#endif // FEATURE_BREW_BATTERY