1 /*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /*
18 * Adjust the controller's power states.
19 */
20 #include "PowerSwitch.h"
21 #include "NfcJniUtil.h"
22 #include "nfc_config.h"
23
24 #include <android-base/stringprintf.h>
25 #include <base/logging.h>
26
27 using android::base::StringPrintf;
28
29 namespace android {
30 void doStartupConfig();
31 }
32
33 extern bool gActivated;
34 extern bool nfc_debug_enabled;
35 extern SyncEvent gDeactivatedEvent;
36
37 PowerSwitch PowerSwitch::sPowerSwitch;
38 const PowerSwitch::PowerActivity PowerSwitch::DISCOVERY = 0x01;
39 const PowerSwitch::PowerActivity PowerSwitch::SE_ROUTING = 0x02;
40 const PowerSwitch::PowerActivity PowerSwitch::SE_CONNECTED = 0x04;
41 const PowerSwitch::PowerActivity PowerSwitch::HOST_ROUTING = 0x08;
42
43 /*******************************************************************************
44 **
45 ** Function: PowerSwitch
46 **
47 ** Description: Initialize member variables.
48 **
49 ** Returns: None
50 **
51 *******************************************************************************/
PowerSwitch()52 PowerSwitch::PowerSwitch()
53 : mCurrLevel(UNKNOWN_LEVEL),
54 mCurrDeviceMgtPowerState(NFA_DM_PWR_STATE_UNKNOWN),
55 mExpectedDeviceMgtPowerState(NFA_DM_PWR_STATE_UNKNOWN),
56 mDesiredScreenOffPowerState(0),
57 mCurrActivity(0) {}
58
59 /*******************************************************************************
60 **
61 ** Function: ~PowerSwitch
62 **
63 ** Description: Release all resources.
64 **
65 ** Returns: None
66 **
67 *******************************************************************************/
~PowerSwitch()68 PowerSwitch::~PowerSwitch() {}
69
70 /*******************************************************************************
71 **
72 ** Function: getInstance
73 **
74 ** Description: Get the singleton of this object.
75 **
76 ** Returns: Reference to this object.
77 **
78 *******************************************************************************/
getInstance()79 PowerSwitch& PowerSwitch::getInstance() { return sPowerSwitch; }
80
81 /*******************************************************************************
82 **
83 ** Function: initialize
84 **
85 ** Description: Initialize member variables.
86 **
87 ** Returns: None
88 **
89 *******************************************************************************/
initialize(PowerLevel level)90 void PowerSwitch::initialize(PowerLevel level) {
91 static const char fn[] = "PowerSwitch::initialize";
92
93 mMutex.lock();
94
95 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
96 "%s: level=%s (%u)", fn, powerLevelToString(level), level);
97 if (NfcConfig::hasKey(NAME_SCREEN_OFF_POWER_STATE))
98 mDesiredScreenOffPowerState =
99 (int)NfcConfig::getUnsigned(NAME_SCREEN_OFF_POWER_STATE);
100 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
101 "%s: desired screen-off state=%d", fn, mDesiredScreenOffPowerState);
102
103 switch (level) {
104 case FULL_POWER:
105 mCurrDeviceMgtPowerState = NFA_DM_PWR_MODE_FULL;
106 mCurrLevel = level;
107 break;
108
109 case UNKNOWN_LEVEL:
110 mCurrDeviceMgtPowerState = NFA_DM_PWR_STATE_UNKNOWN;
111 mCurrLevel = level;
112 break;
113
114 default:
115 LOG(ERROR) << StringPrintf("%s: not handled", fn);
116 break;
117 }
118 mMutex.unlock();
119 }
120
121 /*******************************************************************************
122 **
123 ** Function: getLevel
124 **
125 ** Description: Get the current power level of the controller.
126 **
127 ** Returns: Power level.
128 **
129 *******************************************************************************/
getLevel()130 PowerSwitch::PowerLevel PowerSwitch::getLevel() {
131 PowerLevel level = UNKNOWN_LEVEL;
132 mMutex.lock();
133 level = mCurrLevel;
134 mMutex.unlock();
135 return level;
136 }
137
138 /*******************************************************************************
139 **
140 ** Function: setLevel
141 **
142 ** Description: Set the controller's power level.
143 ** level: power level.
144 **
145 ** Returns: True if ok.
146 **
147 *******************************************************************************/
setLevel(PowerLevel newLevel)148 bool PowerSwitch::setLevel(PowerLevel newLevel) {
149 static const char fn[] = "PowerSwitch::setLevel";
150 bool retval = false;
151
152 mMutex.lock();
153
154 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
155 "%s: level=%s (%u)", fn, powerLevelToString(newLevel), newLevel);
156 if (mCurrLevel == newLevel) {
157 retval = true;
158 goto TheEnd;
159 }
160
161 if (mCurrLevel == UNKNOWN_LEVEL) {
162 LOG(ERROR) << StringPrintf("%s: unknown power level", fn);
163 goto TheEnd;
164 }
165
166 if ((mCurrLevel == LOW_POWER && newLevel == FULL_POWER) ||
167 (mCurrLevel == FULL_POWER && newLevel == LOW_POWER)) {
168 mMutex.unlock();
169 SyncEventGuard g(gDeactivatedEvent);
170 if (gActivated) {
171 DLOG_IF(INFO, nfc_debug_enabled)
172 << StringPrintf("%s: wait for deactivation", fn);
173 gDeactivatedEvent.wait();
174 }
175 mMutex.lock();
176 }
177
178 switch (newLevel) {
179 case FULL_POWER:
180 if (mCurrDeviceMgtPowerState == NFA_DM_PWR_MODE_OFF_SLEEP)
181 retval = setPowerOffSleepState(false);
182 break;
183
184 case LOW_POWER:
185 case POWER_OFF:
186 if (isPowerOffSleepFeatureEnabled())
187 retval = setPowerOffSleepState(true);
188 else if (mDesiredScreenOffPowerState ==
189 1) //.conf file desires full-power
190 {
191 mCurrLevel = FULL_POWER;
192 retval = true;
193 }
194 break;
195
196 default:
197 LOG(ERROR) << StringPrintf("%s: not handled", fn);
198 break;
199 }
200
201 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
202 "%s: actual power level=%s", fn, powerLevelToString(mCurrLevel));
203
204 TheEnd:
205 mMutex.unlock();
206 return retval;
207 }
208
setScreenOffPowerState(ScreenOffPowerState newState)209 bool PowerSwitch::setScreenOffPowerState(ScreenOffPowerState newState) {
210 DLOG_IF(INFO, nfc_debug_enabled)
211 << StringPrintf("PowerSwitch::setScreenOffPowerState: level=%s (%u)",
212 screenOffPowerStateToString(newState), newState);
213
214 mMutex.lock();
215 mDesiredScreenOffPowerState = (int)newState;
216 mMutex.unlock();
217
218 return true;
219 }
220
221 /*******************************************************************************
222 **
223 ** Function: setModeOff
224 **
225 ** Description: Set a mode to be deactive.
226 **
227 ** Returns: True if any mode is still active.
228 **
229 *******************************************************************************/
setModeOff(PowerActivity deactivated)230 bool PowerSwitch::setModeOff(PowerActivity deactivated) {
231 bool retVal = false;
232
233 mMutex.lock();
234 mCurrActivity &= ~deactivated;
235 retVal = mCurrActivity != 0;
236 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
237 "PowerSwitch::setModeOff(deactivated=0x%x) : mCurrActivity=0x%x",
238 deactivated, mCurrActivity);
239 mMutex.unlock();
240 return retVal;
241 }
242
243 /*******************************************************************************
244 **
245 ** Function: setModeOn
246 **
247 ** Description: Set a mode to be active.
248 **
249 ** Returns: True if any mode is active.
250 **
251 *******************************************************************************/
setModeOn(PowerActivity activated)252 bool PowerSwitch::setModeOn(PowerActivity activated) {
253 bool retVal = false;
254
255 mMutex.lock();
256 mCurrActivity |= activated;
257 retVal = mCurrActivity != 0;
258 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
259 "PowerSwitch::setModeOn(activated=0x%x) : mCurrActivity=0x%x", activated,
260 mCurrActivity);
261 mMutex.unlock();
262 return retVal;
263 }
264
265 /*******************************************************************************
266 **
267 ** Function: setPowerOffSleepState
268 **
269 ** Description: Adjust controller's power-off-sleep state.
270 ** sleep: whether to enter sleep state.
271 **
272 ** Returns: True if ok.
273 **
274 *******************************************************************************/
setPowerOffSleepState(bool sleep)275 bool PowerSwitch::setPowerOffSleepState(bool sleep) {
276 static const char fn[] = "PowerSwitch::setPowerOffSleepState";
277 DLOG_IF(INFO, nfc_debug_enabled)
278 << StringPrintf("%s: enter; sleep=%u", fn, sleep);
279 tNFA_STATUS stat = NFA_STATUS_FAILED;
280 bool retval = false;
281
282 if (sleep) // enter power-off-sleep state
283 {
284 // make sure the current power state is ON
285 if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_OFF_SLEEP) {
286 SyncEventGuard guard(mPowerStateEvent);
287 mExpectedDeviceMgtPowerState =
288 NFA_DM_PWR_MODE_OFF_SLEEP; // if power adjustment is ok, then this is
289 // the expected state
290 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: try power off", fn);
291 stat = NFA_PowerOffSleepMode(TRUE);
292 if (stat == NFA_STATUS_OK) {
293 mPowerStateEvent.wait();
294 mCurrLevel = LOW_POWER;
295 } else {
296 LOG(ERROR) << StringPrintf("%s: API fail; stat=0x%X", fn, stat);
297 goto TheEnd;
298 }
299 } else {
300 LOG(ERROR) << StringPrintf(
301 "%s: power is not ON; curr device mgt power state=%s (%u)", fn,
302 deviceMgtPowerStateToString(mCurrDeviceMgtPowerState),
303 mCurrDeviceMgtPowerState);
304 goto TheEnd;
305 }
306 } else // exit power-off-sleep state
307 {
308 // make sure the current power state is OFF
309 if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_FULL) {
310 SyncEventGuard guard(mPowerStateEvent);
311 mCurrDeviceMgtPowerState = NFA_DM_PWR_STATE_UNKNOWN;
312 mExpectedDeviceMgtPowerState =
313 NFA_DM_PWR_MODE_FULL; // if power adjustment is ok, then this is the
314 // expected state
315 DLOG_IF(INFO, nfc_debug_enabled)
316 << StringPrintf("%s: try full power", fn);
317 stat = NFA_PowerOffSleepMode(FALSE);
318 if (stat == NFA_STATUS_OK) {
319 mPowerStateEvent.wait();
320 if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_FULL) {
321 LOG(ERROR) << StringPrintf(
322 "%s: unable to full power; curr device mgt power stat=%s (%u)",
323 fn, deviceMgtPowerStateToString(mCurrDeviceMgtPowerState),
324 mCurrDeviceMgtPowerState);
325 goto TheEnd;
326 }
327 android::doStartupConfig();
328 mCurrLevel = FULL_POWER;
329 } else {
330 LOG(ERROR) << StringPrintf("%s: API fail; stat=0x%X", fn, stat);
331 goto TheEnd;
332 }
333 } else {
334 LOG(ERROR) << StringPrintf(
335 "%s: not in power-off state; curr device mgt power state=%s (%u)", fn,
336 deviceMgtPowerStateToString(mCurrDeviceMgtPowerState),
337 mCurrDeviceMgtPowerState);
338 goto TheEnd;
339 }
340 }
341
342 retval = true;
343 TheEnd:
344 DLOG_IF(INFO, nfc_debug_enabled)
345 << StringPrintf("%s: exit; return %u", fn, retval);
346 return retval;
347 }
348
349 /*******************************************************************************
350 **
351 ** Function: deviceMgtPowerStateToString
352 **
353 ** Description: Decode power level to a string.
354 ** deviceMgtPowerState: power level.
355 **
356 ** Returns: Text representation of power level.
357 **
358 *******************************************************************************/
deviceMgtPowerStateToString(uint8_t deviceMgtPowerState)359 const char* PowerSwitch::deviceMgtPowerStateToString(
360 uint8_t deviceMgtPowerState) {
361 switch (deviceMgtPowerState) {
362 case NFA_DM_PWR_MODE_FULL:
363 return "DM-FULL";
364 case NFA_DM_PWR_MODE_OFF_SLEEP:
365 return "DM-OFF";
366 default:
367 return "DM-unknown????";
368 }
369 }
370
371 /*******************************************************************************
372 **
373 ** Function: powerLevelToString
374 **
375 ** Description: Decode power level to a string.
376 ** level: power level.
377 **
378 ** Returns: Text representation of power level.
379 **
380 *******************************************************************************/
powerLevelToString(PowerLevel level)381 const char* PowerSwitch::powerLevelToString(PowerLevel level) {
382 switch (level) {
383 case UNKNOWN_LEVEL:
384 return "PS-UNKNOWN";
385 case FULL_POWER:
386 return "PS-FULL";
387 case LOW_POWER:
388 return "PS-LOW-POWER";
389 case POWER_OFF:
390 return "PS-POWER-OFF";
391 default:
392 return "PS-unknown????";
393 }
394 }
395
396 /*******************************************************************************
397 **
398 ** Function: screenOffPowerStateToString
399 **
400 ** Description: Decode power level to a string.
401 ** level: power level.
402 **
403 ** Returns: Text representation of power level.
404 **
405 *******************************************************************************/
screenOffPowerStateToString(ScreenOffPowerState state)406 const char* PowerSwitch::screenOffPowerStateToString(
407 ScreenOffPowerState state) {
408 switch (state) {
409 case POWER_STATE_OFF:
410 return "SOPS-POWER_OFF";
411 case POWER_STATE_FULL:
412 return "SOPS-FULL";
413 case POWER_STATE_CARD_EMULATION:
414 return "SOPS-CARD_EMULATION";
415 default:
416 return "SOPS-unknown????";
417 }
418 }
419
420 /*******************************************************************************
421 **
422 ** Function: abort
423 **
424 ** Description: Abort and unblock currrent operation.
425 **
426 ** Returns: None
427 **
428 *******************************************************************************/
abort()429 void PowerSwitch::abort() {
430 static const char fn[] = "PowerSwitch::abort";
431 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", fn);
432 SyncEventGuard guard(mPowerStateEvent);
433 mPowerStateEvent.notifyOne();
434 }
435
436 /*******************************************************************************
437 **
438 ** Function: deviceManagementCallback
439 **
440 ** Description: Callback function for the stack.
441 ** event: event ID.
442 ** eventData: event's data.
443 **
444 ** Returns: None
445 **
446 *******************************************************************************/
deviceManagementCallback(uint8_t event,tNFA_DM_CBACK_DATA * eventData)447 void PowerSwitch::deviceManagementCallback(uint8_t event,
448 tNFA_DM_CBACK_DATA* eventData) {
449 static const char fn[] = "PowerSwitch::deviceManagementCallback";
450
451 switch (event) {
452 case NFA_DM_PWR_MODE_CHANGE_EVT: {
453 tNFA_DM_PWR_MODE_CHANGE& power_mode = eventData->power_mode;
454 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
455 "%s: NFA_DM_PWR_MODE_CHANGE_EVT; status=0x%X; device mgt power "
456 "state=%s (0x%X)",
457 fn, power_mode.status,
458 sPowerSwitch.deviceMgtPowerStateToString(power_mode.power_mode),
459 power_mode.power_mode);
460 SyncEventGuard guard(sPowerSwitch.mPowerStateEvent);
461 if (power_mode.status == NFA_STATUS_OK) {
462 // the event data does not contain the newly configured power mode,
463 // so this code assigns the expected value
464 sPowerSwitch.mCurrDeviceMgtPowerState =
465 sPowerSwitch.mExpectedDeviceMgtPowerState;
466 }
467 sPowerSwitch.mPowerStateEvent.notifyOne();
468 } break;
469 }
470 }
471
472 /*******************************************************************************
473 **
474 ** Function: isPowerOffSleepFeatureEnabled
475 **
476 ** Description: Whether power-off-sleep feature is enabled in .conf file.
477 **
478 ** Returns: True if feature is enabled.
479 **
480 *******************************************************************************/
isPowerOffSleepFeatureEnabled()481 bool PowerSwitch::isPowerOffSleepFeatureEnabled() {
482 return mDesiredScreenOffPowerState == 0;
483 }
484