/*****************************************************************************
 * Copyright (C) Gemalto M2M GmbH
 *****************************************************************************
 * Project: IMC-RIL-Driver
 *****************************************************************************
 * Author : Wireless Modules RD SW A2
 *****************************************************************************
 * $Workfile: Y:/z_ms-d/src/working/Quinn/RilDrv/PowerManager.h $
 * $Revision: /main/ms-d/34 $
 *     $Date: 2013-10-01 14:15:14 $
 *   $Author: pmackent $
 *****************************************************************************
 * Target:
 *  Microsoft Windows Mobile 5.0
 *****************************************************************************
 * Description:
 *  Gemalto IMC RIL
 *****************************************************************************
 *
 * $Log: Y:/z_ms-d/src/working/Quinn/RilDrv/PowerManager.h$ 
 * 
 * /main/ms-d/34   2013-10-01 14:15:14   pmackent 
 * Handle case of failing AT^SMONI on EHS5
 *
 * /main/ms-d/33   2012-11-19 16:40:10   pmackent
 * Avoid sending power off notification during ACQDB reset (IPIS100083325)
 *
 * /main/ms-d/32   2012-11-15 11:46:29   pmackent
 * Avoid sending AT+CSQ in D3 power state (IPIS100083487)
 *
 * /main/ms-d/31   2012-04-02 15:28:31   ctna0450
 * Added possibility to handle HC25 NDIS start indication with SDPORT 3
 *
 * /main/ms-d/30   2012-02-22 13:27:02   ctna0256
 * Encapsulate use of Intel AT command set
 *
 * /main/ms-d/29   2012-02-17 11:13:07   ctna0256
 * Remove CFUN=7 mode (its not a bug, its a feature)
 *
 * /main/ms-d/28   2012-02-14 15:13:10   ctna0256
 * Handle URCs within responses.
 *
 * /main/ms-d/27   2012-02-10 10:00:24   ctna0256
 * Reset module if CFUN7 mode is detected (IPIS100077391)
 *
 * /main/ms-d/26   2012-01-04 15:36:55   ctna0256
 * Outsource XML configuration to external application.
 * Improve CDMA configuration mode.
 *
 * /main/ms-d/25   2011-10-17 11:34:35   ctna0256
 * Workaround for restart on exit and AT+CPIN? timing issues of PH8 Rel2
 *
 * /main/ms-d/24   2011-02-01 14:49:18   ctna0256
 * Allow combination of resilience and CSQ notification mode
 *
 * /main/ms-d/23   2010-12-13 10:00:35   ctna0256
 * Allow configuration of SDPORT timeout
 *
 * /main/ms-d/22   2010-11-26 10:26:21   ctna0256
 * Introducing firmware update for PH8
 *
 * /main/ms-d/21   2010-11-04 15:47:05   ctna0256
 * New configuration of SDPORT, C-IMEI and SVN
 *
 * /main/ms-d/20   2010-08-16 09:18:34   ctna0256
 * New flight mode command in Uranus
 *
 * /main/ms-d/19   2010-07-22 14:44:52   ctna0256
 * Allow setting of default behaviour for incoming text messages
 *
 * /main/ms-d/18   2010-05-05 11:00:43   ctna0256
 * Option to tread power level D1 differently
 *
 * /main/ms-d/17   2009-07-28 10:40:44   ctna0256
 * Better handling of the case "suspend during initialization" (IPIS100056850)
 *
 * /main/ms-d/16   2009-05-28 11:36:45   ctna0256
 * Remove "Siemens" from RIL
 *
 * /main/ms-d/15   2009-05-19 13:17:31   ctna0256
 * New registry keys for restart on exit
 *
 * /main/ms-d/14   2008-08-26 14:26:46   ctna0256
 * Merged RIL_RADIO_RESILIENCE option from Classic-RIL
 *
 * /main/ms-d/13   2008-08-22 10:25:15   ctna0256
 * Set Cinterion copyright text
 *
 * /main/ms-d/12   2008-08-21 09:35:05   ctna0256
 * Prepared for new disclaimer handling
 *
 * /main/ms-d/11   2007-11-26 17:05:50   kr36712
 * integration of GPS support
 * use of the mux protocol
 *
 * /main/ms-d/10   2007-11-21 13:35:05   mp49210
 * Lint compatibility
 *
 * /main/ms-d/9   2007-11-08 09:08:27   mp49210
 * Use own GPRS suspend connection default timeout
 *
 * /main/ms-d/8   2007-11-07 09:20:08   mp49210
 * New GPRS Suspend Delay
 *
 * /main/ms-d/7   2007-11-02 18:34:46   ht37010
 * fix for EPIC 21310: corrected handling of ForcePowerOff during TurnOnModule
 *
 * /main/ms-d/6   2007-07-10 09:03:13   mp49210
 * End data mode before sending AT^SMSO
 *
 * /main/ms-d/5   2006-12-13 17:02:55   wm36264
 * Removed obsolete WaitForModuleStart()
 *
 * /main/ms-d/4   2006-11-01 14:20:03   wm36264
 * Simplyfied handling of new airplane mode
 *
 * /main/ms-d/3   2006-11-01 10:29:37   mp49210
 * New AT+CFUN handling in Quinn
 *
 * /main/ms-d/2   2006-10-30 10:26:30   wm36264
 * Removed unused stuff
 *
 * /main/ms-d/1   2006-10-25 16:51:22   wm36264
 * First transformation from classic RIL
 *
*/

//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2008 Gemalto M2M GmbH
// Copyright (C) 2006-2008 Siemens AG
//
// Version: 1.0
// Date:    dummy
//
//////////////////////////////////////////////////////////////////////////////

#define SHUTDOWN_TIMEOUT                  90000
#define FLIGHTMODE_TIMEOUT                30000
#define POWER_LOCK_TIMEOUT                (SHUTDOWN_TIMEOUT + FLIGHTMODE_TIMEOUT)
#define IDLE_TIMER_RESET_CYCLE            10000
#define ENABLEURC_RETRIES                 2
#define ENABLEURC_RETRIES_DELAY           3000
#define WAIT_FOR_START_TIMEOUT            30000
#define DEFAULT_SUSPEND_CSD_TIMEOUT       10000
#define DEFAULT_SUSPEND_GPRS_TIMEOUT      1000
#define ADDITIONAL_CSD_SUSPEND_PERIOD     1000
#define ADDITIONAL_GPRS_SUSPEND_PERIOD    1000
#define PWR_QUEUE_SIZE                    5
#define MIN_ABNWSELECTION_TIMEOUT         10000
#define WAIT_AFTER_SDPORT_SETTING         3500
#define RESILIENCE_POLLING_INTERVAL       10000
#define SYSSTART_MESSAGE_BUFFER           64

#define FLIGHTMODE_CMD_ON                 "AT+CFUN=4\r"
#define FLIGHTMODE_CMD_OFF                "AT+CFUN=1\r"
#define FLIGHTMODE_SCFG_CMD_ON             "AT^SCFG=MEopMode/Airplane,\"on\"\r"
#define FLIGHTMODE_SCFG_CMD_OFF            "AT^SCFG=MEopMode/Airplane,\"off\"\r"
#define FLIGHTMODE_CMD(fOnOff)            (SPECIAL_FLIGHT_MODE_CMD ? (fOnOff ? FLIGHTMODE_SCFG_CMD_ON : FLIGHTMODE_SCFG_CMD_OFF) : (fOnOff ? FLIGHTMODE_CMD_ON : FLIGHTMODE_CMD_OFF))

#define MODEMSTATE_GPSON                  (MODEMSTATE_MAX + 1)
#define MODEMSTATE_GPSOFF                 (MODEMSTATE_MAX + 2)
#define INVALID_MODEM_STATE               (MODEMSTATE_MAX + 3)
#define DEFAULT_URCCONFIG                 MODEMSTATE_URCCONFIG_CALL_SMS
#define IS_VALID_MODEMSTATE(State)        ((State >= MODEMSTATE_MIN) && (State <= (MODEMSTATE_MAX + 2)))
#define IS_URCSTATE(State)                (IS_URCCONFIG(State) || (State == MODEMSTATE_POWERON))
#define IS_URCCONFIG(State)               ((State == MODEMSTATE_URCCONFIG_CALL) || \
                                           (State == MODEMSTATE_URCCONFIG_CALL_SMS) || \
                                           (State == MODEMSTATE_URCCONFIG_CALL_SMS_CGREG) || \
                                           (State == MODEMSTATE_URCCONFIG_CALL_SMS_REG))
#define PWR_STATE_TXT(State)              TEXT(#State)
#ifdef RIL_HANDLE_D1_AS_D0
#define IS_DEVICEON(State)                ((State == D0) || (State == D1))
#else
#define IS_DEVICEON(State)                (State == D0)
#endif

// When polling with AT+CSQ is activated, the notifications have to be turned off.
#ifdef RIL_USE_CSQPOLLING
#ifdef RIL_USE_CSQ_NOTIFICATIONS
#undef RIL_USE_CSQ_NOTIFICATIONS
#endif
#endif

class CRilInstanceHandle;
class CRilHandle;

//////////////////////////////////////////////////////////////////////////////
// Class for power commands
//////////////////////////////////////////////////////////////////////////////
class CPowerCmd : public CCommand {
public:
#ifdef RIL_RADIO_RESILIENCE
  CPowerCmd(DWORD dwCmd, CRilInstanceHandle* pHandle, CEDEVICE_POWER_STATE NewPwrState, CEDEVICE_POWER_STATE OldPwrState, BOOL fEquCmd, BOOL fUrcInit, BOOL fDelayCmd = FALSE);
#else
  CPowerCmd(DWORD dwCmd, CRilInstanceHandle* pHandle, CEDEVICE_POWER_STATE NewPwrState, CEDEVICE_POWER_STATE OldPwrState, BOOL fEquCmd, BOOL fUrcInit);
#endif
  ~CPowerCmd();
  DWORD                 GetCmd(void) const { return m_dwCmd; };
  CEDEVICE_POWER_STATE  GetNewPowerState(void) const { return m_NewPwrState; };
  CEDEVICE_POWER_STATE  GetOldPowerState(void) const { return m_OldPwrState; };
  BOOL                  IsPowerCmd(void) const { return (m_NewPwrState != PwrDeviceUnspecified); };
  BOOL                  IsSuspendCmd(void) const;
  BOOL                  IsResumeCmd(void) const;
  BOOL                  IsEquipmentStateCmd(void) const { return m_fEquCmd; };
  BOOL                  IsGpsCmd(void) const { return ((m_dwCmd == MODEMSTATE_GPSON) || (m_dwCmd == MODEMSTATE_GPSOFF)); };
  BOOL                  IsUrcCmd(void) const { return (!IsPowerCmd() && !IsEquipmentStateCmd() && !IsGpsCmd()); };
  BOOL                  IsUrcInit(void) const { return m_fUrcInit; };
  BOOL                  IsBlocking(void) const { return (m_hFinishEvent != 0); };
  HANDLE                GetFinishEvent(void) const { return m_hFinishEvent; };
  void                  SetFinishEvent(HANDLE hEvent) { m_hFinishEvent = hEvent; };
  HANDLE                InheritFinishEvent(void);
  const TCHAR*          GetCmdName(void) const;
  const TCHAR*          GetCmdType(void) const;
#ifdef RIL_RADIO_RESILIENCE
  BOOL                  IsDelayCmd(void) { return m_fDelay; }
#endif

private:
  DWORD                 m_dwCmd;
  CEDEVICE_POWER_STATE  m_NewPwrState;
  CEDEVICE_POWER_STATE  m_OldPwrState;
  HANDLE                m_hFinishEvent;
  BOOL                  m_fUrcInit;
  BOOL                  m_fEquCmd;
#ifdef RIL_RADIO_RESILIENCE
  BOOL                  m_fDelay;
#endif
};

//////////////////////////////////////////////////////////////////////////////
// The power manager itself
//////////////////////////////////////////////////////////////////////////////
class CPowerManager {
public:
  CPowerManager();
  ~CPowerManager();

  void            Init(CRilHandle* pRilHandle);
  void            Deinit(void);

  BOOL            EnterPowerState(CRilInstanceHandle* pHandle, CEDEVICE_POWER_STATE NewPwrState);
  BOOL            EnterEquipmentState(CRilInstanceHandle* pHandle, DWORD dwNewState, BOOL fDelay = FALSE);
  BOOL            EnterUrcState(CRilInstanceHandle* pHandle, DWORD dwNewUrcState, BOOL fInit = FALSE);
  BOOL            EnterGpsState(BOOL fEnable);
  BOOL            ForcePowerOff(BOOL bReboot = FALSE);
  BOOL            ShutdownFinished(LPRILEQUIPMENTSTATE pRes);
  BOOL            SysstartFinished(LPRILEQUIPMENTSTATE pRes, BOOL fFlightMode);
  void            FillPowerCapsStruct(PPOWER_CAPABILITIES pPpc) const;
  void            FillEquipmentStateStruct(RILEQUIPMENTSTATE * pres, DWORD dwEqState) const;
  DWORD           GetEquipmentState(void) { SYNCBLOCK(m_csPowerState); return GetEquipmentFromModemState(m_dwOldModemState); };
  BOOL            IsRadioOff(void) { SYNCBLOCK(m_csRadioOn); return !m_fRadioOn; };
  CEDEVICE_POWER_STATE GetPowerState(void)  { SYNCBLOCK(m_csPowerState); return m_PowerState; };
  void            EnableCmdRequeueWait(void) { (void)ResetEvent(m_hATCmdRequeueEvent); return; };
  void            DisableCmdRequeueWait(void) { (void)SetEvent(m_hATCmdRequeueEvent); };
  BOOL            WaitCmdRequeue(DWORD dwDelay) { return (WaitForSingleObject(m_hATCmdRequeueEvent, dwDelay) == WAIT_TIMEOUT); };
  BOOL            UnlockPowerState(void) { return SetEvent(m_hRadioOnOffMutex); };
  BOOL            IsPowerOffForced(void) const { return m_fPowerOffForced; };
  void            SetPreliminaryURCInitState(BOOL bURCState) { m_fPreUrcInitialized = bURCState; return; };
  DWORD           GetLastModuleStart(void) const { return m_dwLastModuleStart; }
  DWORD           GetCurrentModemState(void) const { return m_dwModemState; }

private:
  BOOL            SendMuxCmd(DWORD dwCmd) const;
  DWORD           GetMaxLatencyTime(DWORD dwStateFrom, DWORD dwStateTo) const;
  DWORD           GetMaxPowerConsumption(DWORD dwModemState) const;
  DWORD           GetEquipmentFromModemState(DWORD dwModemState) const;
  BOOL            GenerateEquipmentNotification(const CPowerCmd* pCmd, DWORD dwEquipmentState);
  BOOL            LockPowerState(void) { return (ResetEvent(m_hRadioOnOffMutex)); };
  BOOL            WaitAndLockPowerState(void);
  BOOL            WaitPowerState(void);
  void            EmptyCmdQueue(void);
  void            EmptyATCmdQueues(void) const;
  BOOL            TurnOffModule(CPowerCmd* pCmd);
  BOOL            TurnOnModule(const CPowerCmd* pCmd, BOOL fActiveFlightMode, BOOL fFullReinit);
  BOOL            StartReinitialization(const CPowerCmd* pCmd);
  BOOL            EnsureActiveFlightMode(BOOL fEnter);
  BOOL            SwitchActiveFlightMode(BOOL fEnter);
  BOOL            SwitchModuleOn(BOOL fActiveFlightMode);
  BOOL            WaitForModuleStart(COM_PORT_TYPE PortType) const;
  CRilHandle*     GetRilDevice(const CRilInstanceHandle* pHandle);
  void            SwitchIdleTimerReset(BOOL fOnOff);
  void            SwitchUnattendedMode(BOOL fOnOff);
  static HRESULT  ParseGetRegStatusAll(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam);
  static HRESULT  ParseGetRegStatusAllError(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam, DWORD& dwCode);
  static HRESULT  ParseGetRegStatusCdma(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam);
  static HRESULT  ParseGetSMSPhase(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam);
  BOOL            SwitchUrcState(const CPowerCmd* pCmd);
  DWORD           CmdQueueHandler(void);
  void            HandleShutdownError(BOOL fSendNotification = TRUE);
  void            SwitchRingOnIncomingData(const CPowerCmd* pCmd, BOOL fEnable);
  BOOL            CheckCmdPreCondition(const CPowerCmd* pCmd, BOOL fFlightModeFromGps);
  const char*     GetSMSSettingOnSuspend() const;
  static DWORD WINAPI CmdQueueThread(LPVOID lpParameter);
  static DWORD WINAPI IdleTimerResetThread(LPVOID lpParameter);
  static DWORD WINAPI ShutdownFinishThread(LPVOID lpParameter);
#ifdef RIL_USE_CSQ_NOTIFICATIONS
#ifdef RIL_RADIO_RESILIENCE
  static DWORD WINAPI ResiliencePollingThread(LPVOID lpParameter);
  DWORD           ResiliencePollingHandler(void);
#endif
#endif
#ifdef RIL_CATCH_NDIS_START_MSG
static DWORD WINAPI CatchNdisMsgThread(LPVOID lpParameter);
#endif

  CEDEVICE_POWER_STATE  m_PowerState;
  DWORD                 m_dwModemState;
  DWORD                 m_dwNewModemState;
  DWORD                 m_dwOldModemState;
  DWORD                 m_dwInitUrcState;
  BOOL                  m_fOngoing;
  CRITICAL_SECTION      m_csPowerState;
  CRITICAL_SECTION      m_csForcePower;
  CRITICAL_SECTION      m_csUnattended;
  CRITICAL_SECTION      m_csRadioOn;
  CRilHandle*           m_pRilHandle;
  HANDLE                m_hShutdownThread;
  HANDLE                m_hRadioOnOffMutex;
  HANDLE                m_hATCmdRequeueEvent;
  HANDLE                m_hIdleResetLeaveEvent;
  BOOL                  m_fUrcInitialized;
  BOOL                  m_fPreUrcInitialized;
  BOOL                  m_fPowerOffForced;
  BOOL                  m_fUnattendedMode;
  BOOL                  m_fIdleTimerReset;
  BOOL                  m_fRadioOn;
  DWORD                 m_dwRegStatusCache;
  DWORD                 m_dwGPRSRegStatusCache;
  UINT                  m_nSMSPhase;
  UINT                  m_nCNMIMode;
  UINT                  m_nLAC;
  UINT                  m_nCI;
  HANDLE                m_hCmdQueueExitEvent;
  HANDLE                m_hCmdQueueThread;
#ifdef RIL_USE_CSQ_NOTIFICATIONS
#ifdef RIL_RADIO_RESILIENCE
  HANDLE                m_hResiliencePollingThread;
#endif
#endif
#ifdef RIL_RADIO_RESILIENCE
  UINT                  m_nRestartCount;
#endif
  DWORD                 m_dwLastModuleStart;
  CQueue<CPowerCmd, PWR_QUEUE_SIZE> m_CmdQueue;
};

// Currently access to the CPowerManager is realized via a single global variable
extern CPowerManager g_PowerManager;

