You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
447 lines
17 KiB
447 lines
17 KiB
/******************************************************************************
|
|
*
|
|
* Copyright 2018 NXP
|
|
*
|
|
* 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.
|
|
*
|
|
******************************************************************************/
|
|
#define LOG_TAG "NfccPowerTracker"
|
|
#include "NfccPowerTracker.h"
|
|
#include <assert.h>
|
|
#include <log/log.h>
|
|
#include <stdio.h>
|
|
#include <sys/file.h>
|
|
#include <sys/time.h>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include "phNxpNciHal_ext.h"
|
|
using namespace std;
|
|
|
|
extern bool nfc_debug_enabled;
|
|
extern phNxpNciHal_Control_t nxpncihal_ctrl;
|
|
static const uint64_t PWR_TRK_ERROR_MARGIN_IN_MILLISEC = 60000;
|
|
static const std::string POWER_TRACKER_LOG_FILE =
|
|
"/data/vendor/nfc/nfc_power_state.txt";
|
|
static const uint16_t TIMER_COUNT_MASK = 0x7FFF;
|
|
|
|
NfccPowerTracker::NfccPowerTracker() {
|
|
mIsLastUpdateScreenOn = false;
|
|
mIsFirstPwrTrkNtfRecvd = false;
|
|
mLastPowerTrackAborted = false;
|
|
/*Default standby time*/
|
|
mStandbyTimePerDiscLoopInMillisec = 1000;
|
|
}
|
|
NfccPowerTracker::~NfccPowerTracker() {}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function NfccPowerTracker::getInstance
|
|
**
|
|
** Description access class singleton
|
|
**
|
|
** Returns pointer to the singleton object
|
|
**
|
|
*******************************************************************************/
|
|
NfccPowerTracker& NfccPowerTracker::getInstance() {
|
|
static NfccPowerTracker sPwrInstance;
|
|
return sPwrInstance;
|
|
}
|
|
/*******************************************************************************
|
|
**
|
|
** Function Initialize
|
|
**
|
|
** Description get all prerequisite information from NFCC needed for
|
|
** Power tracker calculations.
|
|
**
|
|
** Returns void
|
|
**
|
|
*******************************************************************************/
|
|
void NfccPowerTracker::Initialize() {
|
|
/*get total duration of discovery loop from NFCC using GET CONFIG command*/
|
|
uint8_t cmdGetConfigDiscLoopDuration[] = {0x20, 0x03, 0x02, 0x01, 0x00};
|
|
int status = phNxpNciHal_send_ext_cmd(sizeof(cmdGetConfigDiscLoopDuration),
|
|
cmdGetConfigDiscLoopDuration);
|
|
if (status != 0) {
|
|
ALOGD_IF(nfc_debug_enabled, "NfccPowerTracker::Initialize: failed");
|
|
return;
|
|
}
|
|
/*Check for valid get config response and update stanby time*/
|
|
if (nxpncihal_ctrl.p_rx_data[0] == 0x40 &&
|
|
nxpncihal_ctrl.p_rx_data[1] == 0x03 &&
|
|
nxpncihal_ctrl.p_rx_data[2] == 0x06 &&
|
|
nxpncihal_ctrl.p_rx_data[3] == 0x00 &&
|
|
nxpncihal_ctrl.p_rx_data[4] == 0x01 &&
|
|
nxpncihal_ctrl.p_rx_data[5] == 0x00 &&
|
|
nxpncihal_ctrl.p_rx_data[6] == 0x02) {
|
|
mStandbyTimePerDiscLoopInMillisec = (uint32_t)(
|
|
(nxpncihal_ctrl.p_rx_data[8] << 8) | nxpncihal_ctrl.p_rx_data[7]);
|
|
ALOGD_IF(nfc_debug_enabled, "mStandbyTimePerDiscLoopInMillisec value : %d",
|
|
mStandbyTimePerDiscLoopInMillisec);
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function TimeDiff
|
|
**
|
|
** Description Computes time difference in milliseconds.
|
|
**
|
|
** Returns Time difference in milliseconds
|
|
**
|
|
*******************************************************************************/
|
|
uint64_t NfccPowerTracker::TimeDiff(struct timespec start,
|
|
struct timespec end) {
|
|
uint64_t startTimeInMillisec =
|
|
start.tv_sec * 1000 + (start.tv_nsec / 1000000);
|
|
uint64_t endTimeInMillisec = end.tv_sec * 1000 + (end.tv_nsec / 1000000);
|
|
|
|
assert(startTimeInMillisec > endTimeInMillisec);
|
|
return (endTimeInMillisec - startTimeInMillisec);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function NfccPowerTracker::ProcessCmd
|
|
**
|
|
** Description Parse the commands going to NFCC,
|
|
** get the time at which power relevant commands are sent
|
|
** (ex:Screen state/OMAPI session)is sent and
|
|
** log/cache the timestamp to file
|
|
**
|
|
** Returns void
|
|
**
|
|
*******************************************************************************/
|
|
void NfccPowerTracker::ProcessCmd(uint8_t* cmd, uint16_t len) {
|
|
ALOGD_IF(nfc_debug_enabled,
|
|
"NfccPowerTracker::ProcessCmd: Enter, Received len :%d", len);
|
|
bool screenStateCommand;
|
|
|
|
if (len < 4) {
|
|
android_errorWriteLog(0x534e4554, "153879824");
|
|
return;
|
|
}
|
|
if (cmd[0] == 0x20 && cmd[1] == 0x09) {
|
|
screenStateCommand = true;
|
|
} else {
|
|
screenStateCommand = false;
|
|
if (len < 8) {
|
|
android_errorWriteLog(0x534e4554, "153879824");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (screenStateCommand && (cmd[3] == 0x00 || cmd[3] == 0x02)) {
|
|
/* Command for Screen State On-Locked or Unlocked */
|
|
clock_gettime(CLOCK_BOOTTIME, &mLastScreenOnTimeStamp);
|
|
mIsLastUpdateScreenOn = true;
|
|
} else if (screenStateCommand && (cmd[3] == 0x01 || cmd[3] == 0x03)) {
|
|
/* Command for Screen State OFF-locked or Unlocked */
|
|
clock_gettime(CLOCK_BOOTTIME, &mLastScreenOffTimeStamp);
|
|
mIsLastUpdateScreenOn = false;
|
|
} else if (cmd[0] == 0x20 && cmd[1] == 0x02 && cmd[2] == 0x05 &&
|
|
cmd[3] == 0x01 && cmd[4] == 0x00 && cmd[5] == 0x02) {
|
|
/* Command to update duration of discovery loop */
|
|
mStandbyTimePerDiscLoopInMillisec = (cmd[7] << 8 | cmd[6]);
|
|
ALOGD_IF(nfc_debug_enabled, "mStandbyTimePerDiscLoopInMillisec value : %d",
|
|
mStandbyTimePerDiscLoopInMillisec);
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function NfccPowerTracker::ProcessNtf
|
|
**
|
|
** Description Parse the Notifications coming from NFCC,
|
|
** get the time at which power relevant notifications are
|
|
** received
|
|
** (ex:RF ON-OFF/ACTIVATE-DEACTIVATE NTF/PROP_PWR_TRACKINFO)
|
|
** calculate error in standby time by comparing the
|
|
** expectated value from NFC HAL and received value from NFCC.
|
|
** Cache relevant info (timestamps) to file
|
|
**
|
|
** Returns void
|
|
**
|
|
*******************************************************************************/
|
|
void NfccPowerTracker::ProcessNtf(uint8_t* rsp, uint16_t rsp_len) {
|
|
ALOGD_IF(nfc_debug_enabled, "NfccPowerTracker::ProcessNtf: Enter");
|
|
|
|
/* Screen State Notification recieved */
|
|
if ((rsp[0] == 0x6F && rsp[1] == 0x05)) {
|
|
ProcessPowerTrackNtf(rsp, rsp_len);
|
|
} else if (rsp[0] == 0x61 && rsp[1] == 0x05) {
|
|
/*Activation notification received. Calculate the time NFCC is
|
|
active in Reader/P2P/CE duration */
|
|
clock_gettime(CLOCK_BOOTTIME, &mActiveTimeStart);
|
|
if (!mIsLastUpdateScreenOn) {
|
|
mActiveInfo.totalTransitions++;
|
|
}
|
|
} else if (rsp[0] == 0x61 && rsp[1] == 0x06) {
|
|
/* Deactivation notification received Calculate the time NFCC is
|
|
active in Reader/P2P/CE duration.Time between Activation and
|
|
Deacivation gives the active time*/
|
|
clock_gettime(CLOCK_BOOTTIME, &mActiveTimeEnd);
|
|
mActiveDurationFromLastScreenUpdate +=
|
|
TimeDiff(mActiveTimeStart, mActiveTimeEnd);
|
|
if (!mIsLastUpdateScreenOn) {
|
|
mStandbyInfo.totalTransitions++;
|
|
}
|
|
ALOGD_IF(nfc_debug_enabled, "mActiveDurationFromLastScreenUpdate: %llu",
|
|
(unsigned long long)mActiveDurationFromLastScreenUpdate);
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function ProcessPowerTrackNtf
|
|
**
|
|
** Description Process Power Tracker notification and update timingInfo to
|
|
** Log File.
|
|
**
|
|
** Returns void
|
|
**
|
|
*******************************************************************************/
|
|
void NfccPowerTracker::ProcessPowerTrackNtf(uint8_t* rsp, uint16_t rsp_len) {
|
|
/* Enable Power Tracking computations after 1st Power tracker notification
|
|
* is received. */
|
|
if (!mIsFirstPwrTrkNtfRecvd) {
|
|
mIsFirstPwrTrkNtfRecvd = true;
|
|
ifstream ifile(POWER_TRACKER_LOG_FILE.c_str());
|
|
if ((bool)ifile == true) {
|
|
mLastPowerTrackAborted = true;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*Duration between screen state change is taken as reference for calculating
|
|
active and standby time*/
|
|
uint64_t totalDuration = 0;
|
|
totalDuration =
|
|
mIsLastUpdateScreenOn
|
|
? TimeDiff(mLastScreenOffTimeStamp, mLastScreenOnTimeStamp)
|
|
: TimeDiff(mLastScreenOnTimeStamp, mLastScreenOffTimeStamp);
|
|
if (totalDuration == 0) return;
|
|
|
|
/*Calculate Active and Standby time based on the pollCount provided in the
|
|
Power tracker Notification from NFCC*/
|
|
uint16_t sPollCount = (TIMER_COUNT_MASK & ((rsp[5] << 8) | rsp[4]));
|
|
ALOGD_IF(nfc_debug_enabled,
|
|
"Poll/Timer count recived from FW is %d and rsp_len :%d", sPollCount,
|
|
rsp_len);
|
|
uint64_t standbyTime = 0, activeTime = 0;
|
|
if (mIsLastUpdateScreenOn) {
|
|
activeTime = sPollCount * ACTIVE_TIME_PER_TIMER_COUNT_IN_MILLISEC;
|
|
/*Check for errors in count provided by NFCC*/
|
|
uint64_t error = (activeTime > mActiveDurationFromLastScreenUpdate)
|
|
? (activeTime - mActiveDurationFromLastScreenUpdate)
|
|
: (mActiveDurationFromLastScreenUpdate - activeTime);
|
|
if (error > PWR_TRK_ERROR_MARGIN_IN_MILLISEC) {
|
|
ALOGD_IF(nfc_debug_enabled,
|
|
"Active Time Error observed with value is %llu",
|
|
(unsigned long long)error);
|
|
mErrorInStandbyInfo.residencyInMsecSinceBoot += error;
|
|
}
|
|
standbyTime = (totalDuration > activeTime) ? (totalDuration - activeTime)
|
|
: (activeTime - totalDuration);
|
|
if (rsp[3]) {
|
|
/*If notification trigger is counter overflow, update the screen on
|
|
timestamp as there is no screen state change*/
|
|
clock_gettime(CLOCK_BOOTTIME, &mLastScreenOnTimeStamp);
|
|
}
|
|
mActiveInfo.totalTransitions++;
|
|
} else {
|
|
standbyTime = (sPollCount * ((uint64_t)mStandbyTimePerDiscLoopInMillisec));
|
|
activeTime = totalDuration > standbyTime ? (totalDuration - standbyTime)
|
|
: (standbyTime - totalDuration);
|
|
if (rsp[3]) {
|
|
/*If notification trigger is counter overflow, update the screen off
|
|
timestamp as there is no screen state change*/
|
|
clock_gettime(CLOCK_BOOTTIME, &mLastScreenOffTimeStamp);
|
|
}
|
|
/*Total transitions in screen on -> Screen Off window is same as poll count
|
|
provided by NFCC, as, there is transition in each discovery loop*/
|
|
mActiveInfo.totalTransitions += sPollCount;
|
|
/*1 additional transition for screen state update*/
|
|
mStandbyInfo.totalTransitions += (sPollCount + 1);
|
|
}
|
|
|
|
ALOGD_IF(nfc_debug_enabled,
|
|
"activeTime: %llu, standbyTime: %llu, totalDuration :%llu",
|
|
(unsigned long long)activeTime, (unsigned long long)standbyTime,
|
|
(unsigned long long)totalDuration);
|
|
if (mLastPowerTrackAborted) {
|
|
ALOGD_IF(nfc_debug_enabled,
|
|
"Last Hal service aborted,so retrive the power info data and "
|
|
"continue\n");
|
|
/*Read the file content and store in mActiveInfo.residencyInMsecSinceBoot
|
|
and mStandbyInfo.residencyInMsecSinceBoot*/
|
|
if (ReadPowerStateLog()) {
|
|
mLastPowerTrackAborted = false;
|
|
}
|
|
}
|
|
mStandbyInfo.residencyInMsecSinceBoot += standbyTime;
|
|
mActiveInfo.residencyInMsecSinceBoot += activeTime;
|
|
UpdatePowerStateLog(mStandbyInfo, mActiveInfo);
|
|
mActiveDurationFromLastScreenUpdate = 0;
|
|
}
|
|
/*******************************************************************************
|
|
**
|
|
** Function NfccPowerTracker::UpdatePowerStateLog
|
|
**
|
|
** Description update the powerstate related information in log file
|
|
**
|
|
** Returns void
|
|
**
|
|
*******************************************************************************/
|
|
void NfccPowerTracker::UpdatePowerStateLog(NfccPowerStateInfo_t mStandbyInfo,
|
|
NfccPowerStateInfo_t mActiveInfo) {
|
|
FILE* fp;
|
|
const string PWR_TRK_LOG_FILE_VERSION = "1.0";
|
|
/*Write the Active and standby timestamp into the file*/
|
|
fp = fopen(POWER_TRACKER_LOG_FILE.c_str(), "w");
|
|
if (fp == NULL) {
|
|
ALOGD_IF(nfc_debug_enabled, "Failed to Open Pwr Tracker Info File\n");
|
|
return;
|
|
}
|
|
ostringstream PwrTrackerInfo;
|
|
PwrTrackerInfo << "Version: " << PWR_TRK_LOG_FILE_VERSION.c_str() << endl;
|
|
PwrTrackerInfo << "NFC {" << endl;
|
|
PwrTrackerInfo << " { " << STR_ACTIVE
|
|
<< std::to_string(mActiveInfo.residencyInMsecSinceBoot) << " }"
|
|
<< endl;
|
|
PwrTrackerInfo << " { " << STR_STANDBY
|
|
<< std::to_string(mStandbyInfo.residencyInMsecSinceBoot)
|
|
<< " }" << endl;
|
|
PwrTrackerInfo << "}";
|
|
ALOGD_IF(nfc_debug_enabled,
|
|
"mActiveInfo.residencyInMsecSinceBoot: %llu, "
|
|
"mActiveInfo.totalTransitions: %llu,"
|
|
"mStandbyInfo.residencyInMsecSinceBoot "
|
|
":%llu,mStandbyInfo.totalTransitions: %llu"
|
|
"mErrorInStandbyInfo.residencyInMsecSinceBoot: %llu",
|
|
(unsigned long long)mActiveInfo.residencyInMsecSinceBoot,
|
|
(unsigned long long)mActiveInfo.totalTransitions,
|
|
(unsigned long long)mStandbyInfo.residencyInMsecSinceBoot,
|
|
(unsigned long long)mStandbyInfo.totalTransitions,
|
|
(unsigned long long)mErrorInStandbyInfo.residencyInMsecSinceBoot);
|
|
string PwrInfo = PwrTrackerInfo.str();
|
|
if (!TryLockFile(fp)) {
|
|
ALOGD_IF(nfc_debug_enabled,
|
|
"Failed to Lock PwrTracker File.Skipping update\n");
|
|
fclose(fp);
|
|
return;
|
|
}
|
|
fwrite(PwrInfo.c_str(), sizeof(char), PwrInfo.length(), fp);
|
|
fflush(fp);
|
|
UnlockFile(fp);
|
|
fclose(fp);
|
|
}
|
|
/*******************************************************************************
|
|
**
|
|
** Function ReadPowerStateLog
|
|
**
|
|
** Description Retrieve powerstate related information from log file.
|
|
**
|
|
** Returns true if read successful, false otherwise.
|
|
**
|
|
*******************************************************************************/
|
|
bool NfccPowerTracker::ReadPowerStateLog() {
|
|
ifstream pwrStateFileStream;
|
|
string itemName;
|
|
ALOGD_IF(nfc_debug_enabled, "NfccPowerTracker::ReadPowerStateLog: Enter \n");
|
|
pwrStateFileStream.open(POWER_TRACKER_LOG_FILE.c_str());
|
|
if (pwrStateFileStream.fail()) {
|
|
ALOGE("Error: %s", strerror(errno));
|
|
return false;
|
|
}
|
|
|
|
/*Check for required string(time in millisec) in the log file and convert it
|
|
to integer*/
|
|
while (pwrStateFileStream >> itemName) {
|
|
if (STR_ACTIVE.compare(itemName) == 0) {
|
|
pwrStateFileStream >> itemName;
|
|
mActiveInfo.residencyInMsecSinceBoot = stoull(itemName.c_str(), nullptr);
|
|
} else if (STR_STANDBY.compare(itemName) == 0) {
|
|
pwrStateFileStream >> itemName;
|
|
mStandbyInfo.residencyInMsecSinceBoot = stoull(itemName.c_str(), nullptr);
|
|
}
|
|
}
|
|
|
|
ALOGD_IF(nfc_debug_enabled,
|
|
"Value retrieved from Powertracker file is"
|
|
"activeTime: %llu and standbyTime: %llu\n",
|
|
(unsigned long long)mActiveInfo.residencyInMsecSinceBoot,
|
|
(unsigned long long)mStandbyInfo.residencyInMsecSinceBoot);
|
|
pwrStateFileStream.close();
|
|
return true;
|
|
}
|
|
/*******************************************************************************
|
|
**
|
|
** Function Pause
|
|
**
|
|
** Description Pause Power state Information Tracking,Tracking will resume
|
|
** once next power tracker notification is recieved as part of
|
|
** ProcessNtf.
|
|
**
|
|
** Returns void
|
|
**
|
|
*******************************************************************************/
|
|
void NfccPowerTracker::Pause() { mIsFirstPwrTrkNtfRecvd = false; }
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function Reset
|
|
**
|
|
** Description Stop power track information processing and delete
|
|
** power tracker log file.
|
|
**
|
|
** Returns void
|
|
**
|
|
*******************************************************************************/
|
|
void NfccPowerTracker::Reset() {
|
|
ALOGD_IF(nfc_debug_enabled, "NfccPowerTracker::Reset enter");
|
|
if (remove(POWER_TRACKER_LOG_FILE.c_str()) != 0) {
|
|
ALOGD_IF(nfc_debug_enabled, "Error deleting Power tracker file");
|
|
}
|
|
}
|
|
/*******************************************************************************
|
|
**
|
|
** Function TryLockFile
|
|
**
|
|
** Description Lock PowerTracker log file. Any application trying to read
|
|
** from PowerTracker log file shall acquire lock before reading
|
|
** to avoid inconsistent data.
|
|
**
|
|
** Returns true if locking was successful
|
|
** false if there was a failure to lock PowerTracker log file.
|
|
*******************************************************************************/
|
|
bool NfccPowerTracker::TryLockFile(FILE* fp) {
|
|
uint8_t retryCount = 5;
|
|
do {
|
|
if (!flock(fileno(fp), LOCK_EX | LOCK_NB)) return true;
|
|
usleep(10000); /*10 millisec*/
|
|
} while (retryCount--);
|
|
|
|
return false;
|
|
}
|
|
/*******************************************************************************
|
|
**
|
|
** Function UnlockFile
|
|
**
|
|
** Description Unlock previously locked PowerTracker log file.
|
|
**
|
|
** Returns void
|
|
**
|
|
*******************************************************************************/
|
|
void NfccPowerTracker::UnlockFile(FILE* fp) { flock(fileno(fp), LOCK_UN); }
|