diff options
Diffstat (limited to 'halimpl/utils/NfccPowerTracker.cpp')
| -rw-r--r-- | halimpl/utils/NfccPowerTracker.cpp | 438 |
1 files changed, 438 insertions, 0 deletions
diff --git a/halimpl/utils/NfccPowerTracker.cpp b/halimpl/utils/NfccPowerTracker.cpp new file mode 100644 index 0000000..99f2b8a --- /dev/null +++ b/halimpl/utils/NfccPowerTracker.cpp @@ -0,0 +1,438 @@ +/****************************************************************************** + * + * 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 "phNxpNciHal_ext.h" +#include <assert.h> +#include <fstream> +#include <iostream> +#include <log/log.h> +#include <sstream> +#include <stdio.h> +#include <sys/file.h> +#include <sys/time.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() { + 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,Recieved len :%d", len); + bool screenStateCommand; + if (cmd[0] == 0x20 && cmd[1] == 0x09) { + screenStateCommand = true; + } else { + screenStateCommand = false; + } + + 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 * 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); } |
