/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Adjust the controller's power states.
*/
#include "OverrideLog.h"
#include "PowerSwitch.h"
#include "NfcJniUtil.h"
#include "config.h"
#include "SecureElement.h"
namespace android
{
void doStartupConfig ();
}
extern bool gActivated;
extern SyncEvent gDeactivatedEvent;
PowerSwitch PowerSwitch::sPowerSwitch;
const PowerSwitch::PowerActivity PowerSwitch::DISCOVERY=0x01;
const PowerSwitch::PowerActivity PowerSwitch::SE_ROUTING=0x02;
const PowerSwitch::PowerActivity PowerSwitch::SE_CONNECTED=0x04;
const PowerSwitch::PowerActivity PowerSwitch::HOST_ROUTING=0x08;
/*******************************************************************************
**
** Function: PowerSwitch
**
** Description: Initialize member variables.
**
** Returns: None
**
*******************************************************************************/
PowerSwitch::PowerSwitch ()
: mCurrLevel (UNKNOWN_LEVEL),
mCurrDeviceMgtPowerState (NFA_DM_PWR_STATE_UNKNOWN),
mExpectedDeviceMgtPowerState (NFA_DM_PWR_STATE_UNKNOWN),
mDesiredScreenOffPowerState (0),
mCurrActivity(0)
{
}
/*******************************************************************************
**
** Function: ~PowerSwitch
**
** Description: Release all resources.
**
** Returns: None
**
*******************************************************************************/
PowerSwitch::~PowerSwitch ()
{
}
/*******************************************************************************
**
** Function: getInstance
**
** Description: Get the singleton of this object.
**
** Returns: Reference to this object.
**
*******************************************************************************/
PowerSwitch& PowerSwitch::getInstance ()
{
return sPowerSwitch;
}
/*******************************************************************************
**
** Function: initialize
**
** Description: Initialize member variables.
**
** Returns: None
**
*******************************************************************************/
void PowerSwitch::initialize (PowerLevel level)
{
static const char fn [] = "PowerSwitch::initialize";
unsigned long num = 0;
mMutex.lock ();
ALOGD ("%s: level=%s (%u)", fn, powerLevelToString(level), level);
if (GetNumValue (NAME_SCREEN_OFF_POWER_STATE, &num, sizeof(num)))
mDesiredScreenOffPowerState = (int) num;
ALOGD ("%s: desired screen-off state=%d", fn, mDesiredScreenOffPowerState);
switch (level)
{
case FULL_POWER:
mCurrDeviceMgtPowerState = NFA_DM_PWR_MODE_FULL;
mCurrLevel = level;
break;
case UNKNOWN_LEVEL:
mCurrDeviceMgtPowerState = NFA_DM_PWR_STATE_UNKNOWN;
mCurrLevel = level;
break;
default:
ALOGE ("%s: not handled", fn);
break;
}
mMutex.unlock ();
}
/*******************************************************************************
**
** Function: getLevel
**
** Description: Get the current power level of the controller.
**
** Returns: Power level.
**
*******************************************************************************/
PowerSwitch::PowerLevel PowerSwitch::getLevel ()
{
PowerLevel level = UNKNOWN_LEVEL;
mMutex.lock ();
level = mCurrLevel;
mMutex.unlock ();
return level;
}
/*******************************************************************************
**
** Function: setLevel
**
** Description: Set the controller's power level.
** level: power level.
**
** Returns: True if ok.
**
*******************************************************************************/
bool PowerSwitch::setLevel (PowerLevel newLevel)
{
static const char fn [] = "PowerSwitch::setLevel";
bool retval = false;
mMutex.lock ();
ALOGD ("%s: level=%s (%u)", fn, powerLevelToString(newLevel), newLevel);
if (mCurrLevel == newLevel)
{
retval = true;
goto TheEnd;
}
if (mCurrLevel == UNKNOWN_LEVEL)
{
ALOGE ("%s: unknown power level", fn);
goto TheEnd;
}
if ( (mCurrLevel == LOW_POWER && newLevel == FULL_POWER) ||
(mCurrLevel == FULL_POWER && newLevel == LOW_POWER) )
{
mMutex.unlock ();
SyncEventGuard g (gDeactivatedEvent);
if (gActivated)
{
ALOGD("%s: wait for deactivation", fn);
gDeactivatedEvent.wait ();
}
mMutex.lock ();
}
switch (newLevel)
{
case FULL_POWER:
if (mCurrDeviceMgtPowerState == NFA_DM_PWR_MODE_OFF_SLEEP)
retval = setPowerOffSleepState (false);
break;
case LOW_POWER:
case POWER_OFF:
if (isPowerOffSleepFeatureEnabled())
retval = setPowerOffSleepState (true);
else if (mDesiredScreenOffPowerState == 1) //.conf file desires full-power
{
mCurrLevel = FULL_POWER;
retval = true;
}
break;
default:
ALOGE ("%s: not handled", fn);
break;
}
TheEnd:
mMutex.unlock ();
return retval;
}
/*******************************************************************************
**
** Function: setModeOff
**
** Description: Set a mode to be deactive.
**
** Returns: True if any mode is still active.
**
*******************************************************************************/
bool PowerSwitch::setModeOff (PowerActivity deactivated)
{
bool retVal = false;
mMutex.lock ();
mCurrActivity &= ~deactivated;
retVal = mCurrActivity != 0;
ALOGD ("PowerSwitch::setModeOff(deactivated=0x%x) : mCurrActivity=0x%x", deactivated, mCurrActivity);
mMutex.unlock ();
return retVal;
}
/*******************************************************************************
**
** Function: setModeOn
**
** Description: Set a mode to be active.
**
** Returns: True if any mode is active.
**
*******************************************************************************/
bool PowerSwitch::setModeOn (PowerActivity activated)
{
bool retVal = false;
mMutex.lock ();
mCurrActivity |= activated;
retVal = mCurrActivity != 0;
ALOGD ("PowerSwitch::setModeOn(activated=0x%x) : mCurrActivity=0x%x", activated, mCurrActivity);
mMutex.unlock ();
return retVal;
}
/*******************************************************************************
**
** Function: setPowerOffSleepState
**
** Description: Adjust controller's power-off-sleep state.
** sleep: whether to enter sleep state.
**
** Returns: True if ok.
**
*******************************************************************************/
bool PowerSwitch::setPowerOffSleepState (bool sleep)
{
static const char fn [] = "PowerSwitch::setPowerOffSleepState";
ALOGD ("%s: enter; sleep=%u", fn, sleep);
tNFA_STATUS stat = NFA_STATUS_FAILED;
bool retval = false;
if (sleep) //enter power-off-sleep state
{
//make sure the current power state is ON
if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_OFF_SLEEP)
{
SyncEventGuard guard (mPowerStateEvent);
mExpectedDeviceMgtPowerState = NFA_DM_PWR_MODE_OFF_SLEEP; //if power adjustment is ok, then this is the expected state
ALOGD ("%s: try power off", fn);
stat = NFA_PowerOffSleepMode (TRUE);
if (stat == NFA_STATUS_OK)
{
mPowerStateEvent.wait ();
mCurrLevel = LOW_POWER;
}
else
{
ALOGE ("%s: API fail; stat=0x%X", fn, stat);
goto TheEnd;
}
}
else
{
ALOGE ("%s: power is not ON; curr device mgt power state=%s (%u)", fn,
deviceMgtPowerStateToString (mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState);
goto TheEnd;
}
}
else //exit power-off-sleep state
{
//make sure the current power state is OFF
if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_FULL)
{
SyncEventGuard guard (mPowerStateEvent);
mCurrDeviceMgtPowerState = NFA_DM_PWR_STATE_UNKNOWN;
mExpectedDeviceMgtPowerState = NFA_DM_PWR_MODE_FULL; //if power adjustment is ok, then this is the expected state
ALOGD ("%s: try full power", fn);
stat = NFA_PowerOffSleepMode (FALSE);
if (stat == NFA_STATUS_OK)
{
mPowerStateEvent.wait ();
if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_FULL)
{
ALOGE ("%s: unable to full power; curr device mgt power stat=%s (%u)", fn,
deviceMgtPowerStateToString (mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState);
goto TheEnd;
}
android::doStartupConfig ();
mCurrLevel = FULL_POWER;
}
else
{
ALOGE ("%s: API fail; stat=0x%X", fn, stat);
goto TheEnd;
}
}
else
{
ALOGE ("%s: not in power-off state; curr device mgt power state=%s (%u)", fn,
deviceMgtPowerStateToString (mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState);
goto TheEnd;
}
}
retval = true;
TheEnd:
ALOGD ("%s: exit; return %u", fn, retval);
return retval;
}
/*******************************************************************************
**
** Function: deviceMgtPowerStateToString
**
** Description: Decode power level to a string.
** deviceMgtPowerState: power level.
**
** Returns: Text representation of power level.
**
*******************************************************************************/
const char* PowerSwitch::deviceMgtPowerStateToString (UINT8 deviceMgtPowerState)
{
switch (deviceMgtPowerState)
{
case NFA_DM_PWR_MODE_FULL:
return "DM-FULL";
case NFA_DM_PWR_MODE_OFF_SLEEP:
return "DM-OFF";
default:
return "DM-unknown????";
}
}
/*******************************************************************************
**
** Function: powerLevelToString
**
** Description: Decode power level to a string.
** level: power level.
**
** Returns: Text representation of power level.
**
*******************************************************************************/
const char* PowerSwitch::powerLevelToString (PowerLevel level)
{
switch (level)
{
case UNKNOWN_LEVEL:
return "PS-UNKNOWN";
case FULL_POWER:
return "PS-FULL";
case LOW_POWER:
return "PS-LOW-POWER";
case POWER_OFF:
return "PS-POWER-OFF";
default:
return "PS-unknown????";
}
}
/*******************************************************************************
**
** Function: abort
**
** Description: Abort and unblock currrent operation.
**
** Returns: None
**
*******************************************************************************/
void PowerSwitch::abort ()
{
static const char fn [] = "PowerSwitch::abort";
ALOGD ("%s", fn);
SyncEventGuard guard (mPowerStateEvent);
mPowerStateEvent.notifyOne ();
}
/*******************************************************************************
**
** Function: deviceManagementCallback
**
** Description: Callback function for the stack.
** event: event ID.
** eventData: event's data.
**
** Returns: None
**
*******************************************************************************/
void PowerSwitch::deviceManagementCallback (UINT8 event, tNFA_DM_CBACK_DATA* eventData)
{
static const char fn [] = "PowerSwitch::deviceManagementCallback";
switch (event)
{
case NFA_DM_PWR_MODE_CHANGE_EVT:
{
tNFA_DM_PWR_MODE_CHANGE& power_mode = eventData->power_mode;
ALOGD ("%s: NFA_DM_PWR_MODE_CHANGE_EVT; status=0x%X; device mgt power state=%s (0x%X)", fn,
power_mode.status, sPowerSwitch.deviceMgtPowerStateToString (power_mode.power_mode),
power_mode.power_mode);
SyncEventGuard guard (sPowerSwitch.mPowerStateEvent);
if (power_mode.status == NFA_STATUS_OK)
{
//the event data does not contain the newly configured power mode,
//so this code assigns the expected value
sPowerSwitch.mCurrDeviceMgtPowerState = sPowerSwitch.mExpectedDeviceMgtPowerState;
}
sPowerSwitch.mPowerStateEvent.notifyOne ();
}
break;
}
}
/*******************************************************************************
**
** Function: isPowerOffSleepFeatureEnabled
**
** Description: Whether power-off-sleep feature is enabled in .conf file.
**
** Returns: True if feature is enabled.
**
*******************************************************************************/
bool PowerSwitch::isPowerOffSleepFeatureEnabled ()
{
return mDesiredScreenOffPowerState == 0;
}