• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  *  Copyright 2018 NXP
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 #define LOG_TAG "NfccPowerTracker"
19 #include "NfccPowerTracker.h"
20 #include "phNxpNciHal_ext.h"
21 #include <assert.h>
22 #include <fstream>
23 #include <iostream>
24 #include <log/log.h>
25 #include <sstream>
26 #include <stdio.h>
27 #include <sys/file.h>
28 #include <sys/time.h>
29 using namespace std;
30 
31 extern bool nfc_debug_enabled;
32 extern phNxpNciHal_Control_t nxpncihal_ctrl;
33 static const uint64_t PWR_TRK_ERROR_MARGIN_IN_MILLISEC = 60000;
34 static const std::string POWER_TRACKER_LOG_FILE =
35     "/data/vendor/nfc/nfc_power_state.txt";
36 static const uint16_t TIMER_COUNT_MASK = 0x7FFF;
37 
NfccPowerTracker()38 NfccPowerTracker::NfccPowerTracker() {
39   mIsFirstPwrTrkNtfRecvd = false;
40   mLastPowerTrackAborted = false;
41   /*Default standby time*/
42   mStandbyTimePerDiscLoopInMillisec = 1000;
43 }
~NfccPowerTracker()44 NfccPowerTracker::~NfccPowerTracker() {}
45 
46 /*******************************************************************************
47 **
48 ** Function         NfccPowerTracker::getInstance
49 **
50 ** Description      access class singleton
51 **
52 ** Returns          pointer to the singleton object
53 **
54 *******************************************************************************/
getInstance()55 NfccPowerTracker &NfccPowerTracker::getInstance() {
56   static NfccPowerTracker sPwrInstance;
57   return sPwrInstance;
58 }
59 /*******************************************************************************
60 **
61 ** Function         Initialize
62 **
63 ** Description      get all prerequisite information from NFCC needed for
64 **                  Power tracker calculations.
65 **
66 ** Returns          void
67 **
68 *******************************************************************************/
Initialize()69 void NfccPowerTracker::Initialize() {
70   /*get total duration of discovery loop from NFCC using GET CONFIG command*/
71   uint8_t cmdGetConfigDiscLoopDuration[] = {0x20, 0x03, 0x02, 0x01, 0x00};
72   int status = phNxpNciHal_send_ext_cmd(sizeof(cmdGetConfigDiscLoopDuration),
73                                         cmdGetConfigDiscLoopDuration);
74   if (status != 0) {
75     ALOGD_IF(nfc_debug_enabled, "NfccPowerTracker::Initialize: failed");
76     return;
77   }
78   /*Check for valid get config response and update stanby time*/
79   if (nxpncihal_ctrl.p_rx_data[0] == 0x40 &&
80       nxpncihal_ctrl.p_rx_data[1] == 0x03 &&
81       nxpncihal_ctrl.p_rx_data[2] == 0x06 &&
82       nxpncihal_ctrl.p_rx_data[3] == 0x00 &&
83       nxpncihal_ctrl.p_rx_data[4] == 0x01 &&
84       nxpncihal_ctrl.p_rx_data[5] == 0x00 &&
85       nxpncihal_ctrl.p_rx_data[6] == 0x02) {
86     mStandbyTimePerDiscLoopInMillisec = (uint32_t)(
87         (nxpncihal_ctrl.p_rx_data[8] << 8) | nxpncihal_ctrl.p_rx_data[7]);
88     ALOGD_IF(nfc_debug_enabled, "mStandbyTimePerDiscLoopInMillisec value : %d",
89              mStandbyTimePerDiscLoopInMillisec);
90   }
91 }
92 
93 /*******************************************************************************
94 **
95 ** Function         TimeDiff
96 **
97 ** Description      Computes time difference in milliseconds.
98 **
99 ** Returns          Time difference in milliseconds
100 **
101 *******************************************************************************/
TimeDiff(struct timespec start,struct timespec end)102 uint64_t NfccPowerTracker::TimeDiff(struct timespec start,
103                                     struct timespec end) {
104   uint64_t startTimeInMillisec =
105       start.tv_sec * 1000 + (start.tv_nsec / 1000000);
106   uint64_t endTimeInMillisec = end.tv_sec * 1000 + (end.tv_nsec / 1000000);
107 
108   assert(startTimeInMillisec > endTimeInMillisec);
109   return (endTimeInMillisec - startTimeInMillisec);
110 }
111 
112 /*******************************************************************************
113 **
114 ** Function         NfccPowerTracker::ProcessCmd
115 **
116 ** Description      Parse the commands going to NFCC,
117 **                  get the time at which power relevant commands are sent
118 **                  (ex:Screen state/OMAPI session)is sent and
119 **                  log/cache the timestamp to file
120 **
121 ** Returns          void
122 **
123 *******************************************************************************/
ProcessCmd(uint8_t * cmd,uint16_t len)124 void NfccPowerTracker::ProcessCmd(uint8_t *cmd, uint16_t len) {
125   ALOGD_IF(nfc_debug_enabled,
126            "NfccPowerTracker::ProcessCmd: Enter,Recieved len :%d", len);
127   bool screenStateCommand;
128   if (cmd[0] == 0x20 && cmd[1] == 0x09) {
129     screenStateCommand = true;
130   } else {
131     screenStateCommand = false;
132   }
133 
134   if (screenStateCommand && (cmd[3] == 0x00 || cmd[3] == 0x02)) {
135     /* Command for Screen State On-Locked or Unlocked */
136     clock_gettime(CLOCK_BOOTTIME, &mLastScreenOnTimeStamp);
137     mIsLastUpdateScreenOn = true;
138   } else if (screenStateCommand && (cmd[3] == 0x01 || cmd[3] == 0x03)) {
139     /* Command for Screen State OFF-locked or Unlocked */
140     clock_gettime(CLOCK_BOOTTIME, &mLastScreenOffTimeStamp);
141     mIsLastUpdateScreenOn = false;
142   } else if (cmd[0] == 0x20 && cmd[1] == 0x02 && cmd[2] == 0x05 &&
143              cmd[3] == 0x01 && cmd[4] == 0x00 && cmd[5] == 0x02) {
144     /* Command to update duration of discovery loop */
145     mStandbyTimePerDiscLoopInMillisec = (cmd[7] << 8 | cmd[6]);
146     ALOGD_IF(nfc_debug_enabled, "mStandbyTimePerDiscLoopInMillisec value : %d",
147              mStandbyTimePerDiscLoopInMillisec);
148   }
149 }
150 
151 /*******************************************************************************
152 **
153 ** Function         NfccPowerTracker::ProcessNtf
154 **
155 ** Description      Parse the Notifications coming from NFCC,
156 **                  get the time at which power relevant notifications are
157 **                  received
158 **                  (ex:RF ON-OFF/ACTIVATE-DEACTIVATE NTF/PROP_PWR_TRACKINFO)
159 **                  calculate error in standby time by comparing the
160 **                  expectated value from NFC HAL and received value from NFCC.
161 **                  Cache relevant info (timestamps) to file
162 **
163 ** Returns          void
164 **
165 *******************************************************************************/
ProcessNtf(uint8_t * rsp,uint16_t rsp_len)166 void NfccPowerTracker::ProcessNtf(uint8_t *rsp, uint16_t rsp_len) {
167   ALOGD_IF(nfc_debug_enabled, "NfccPowerTracker::ProcessNtf: Enter");
168 
169   /* Screen State Notification recieved */
170   if ((rsp[0] == 0x6F && rsp[1] == 0x05)) {
171     ProcessPowerTrackNtf(rsp, rsp_len);
172   } else if (rsp[0] == 0x61 && rsp[1] == 0x05) {
173     /*Activation notification received. Calculate the time NFCC is
174     active in Reader/P2P/CE duration */
175     clock_gettime(CLOCK_BOOTTIME, &mActiveTimeStart);
176     if (!mIsLastUpdateScreenOn) {
177       mActiveInfo.totalTransitions++;
178     }
179   } else if (rsp[0] == 0x61 && rsp[1] == 0x06) {
180     /* Deactivation notification received Calculate the time NFCC is
181     active in Reader/P2P/CE duration.Time between Activation and
182     Deacivation gives the active time*/
183     clock_gettime(CLOCK_BOOTTIME, &mActiveTimeEnd);
184     mActiveDurationFromLastScreenUpdate +=
185         TimeDiff(mActiveTimeStart, mActiveTimeEnd);
186     if (!mIsLastUpdateScreenOn) {
187       mStandbyInfo.totalTransitions++;
188     }
189     ALOGD_IF(nfc_debug_enabled, "mActiveDurationFromLastScreenUpdate: %llu",
190              (unsigned long long)mActiveDurationFromLastScreenUpdate);
191   }
192 }
193 
194 /*******************************************************************************
195 **
196 ** Function         ProcessPowerTrackNtf
197 **
198 ** Description      Process Power Tracker notification and update timingInfo to
199 **                  Log File.
200 **
201 ** Returns          void
202 **
203 *******************************************************************************/
ProcessPowerTrackNtf(uint8_t * rsp,uint16_t rsp_len)204 void NfccPowerTracker::ProcessPowerTrackNtf(uint8_t *rsp, uint16_t rsp_len) {
205   /* Enable Power Tracking computations after 1st Power tracker notification
206    * is received. */
207   if (!mIsFirstPwrTrkNtfRecvd) {
208     mIsFirstPwrTrkNtfRecvd = true;
209     ifstream ifile(POWER_TRACKER_LOG_FILE.c_str());
210     if ((bool)ifile == true) {
211       mLastPowerTrackAborted = true;
212     }
213     return;
214   }
215 
216   /*Duration between screen state change is taken as reference for calculating
217   active and standby time*/
218   uint64_t totalDuration = 0;
219   totalDuration =
220       mIsLastUpdateScreenOn
221           ? TimeDiff(mLastScreenOffTimeStamp, mLastScreenOnTimeStamp)
222           : TimeDiff(mLastScreenOnTimeStamp, mLastScreenOffTimeStamp);
223   if (totalDuration == 0)
224     return;
225 
226   /*Calculate Active and Standby time based on the pollCount provided in the
227   Power tracker Notification from NFCC*/
228   uint16_t sPollCount = (TIMER_COUNT_MASK & ((rsp[5] << 8) | rsp[4]));
229   ALOGD_IF(nfc_debug_enabled,
230            "Poll/Timer count recived from FW is %d and rsp_len :%d", sPollCount,
231            rsp_len);
232   uint64_t standbyTime = 0, activeTime = 0;
233   if (mIsLastUpdateScreenOn) {
234     activeTime = sPollCount * ACTIVE_TIME_PER_TIMER_COUNT_IN_MILLISEC;
235     /*Check for errors in count provided by NFCC*/
236     uint64_t error = (activeTime > mActiveDurationFromLastScreenUpdate)
237                          ? (activeTime - mActiveDurationFromLastScreenUpdate)
238                          : (mActiveDurationFromLastScreenUpdate - activeTime);
239     if (error > PWR_TRK_ERROR_MARGIN_IN_MILLISEC) {
240       ALOGD_IF(nfc_debug_enabled,
241                "Active Time Error observed with value is %llu",
242                (unsigned long long)error);
243       mErrorInStandbyInfo.residencyInMsecSinceBoot += error;
244     }
245     standbyTime = (totalDuration > activeTime) ? (totalDuration - activeTime)
246                                                : (activeTime - totalDuration);
247     if (rsp[3]) {
248       /*If notification trigger is counter overflow, update the screen on
249       timestamp as there is no screen state change*/
250       clock_gettime(CLOCK_BOOTTIME, &mLastScreenOnTimeStamp);
251     }
252     mActiveInfo.totalTransitions++;
253   } else {
254     standbyTime = (sPollCount * mStandbyTimePerDiscLoopInMillisec);
255     activeTime = totalDuration > standbyTime ? (totalDuration - standbyTime)
256                                              : (standbyTime - totalDuration);
257     if (rsp[3]) {
258       /*If notification trigger is counter overflow, update the screen off
259       timestamp as there is no screen state change*/
260       clock_gettime(CLOCK_BOOTTIME, &mLastScreenOffTimeStamp);
261     }
262     /*Total transitions in screen on -> Screen Off window is same as poll count
263     provided by NFCC, as, there is transition in each discovery loop*/
264     mActiveInfo.totalTransitions += sPollCount;
265     /*1 additional transition for screen state update*/
266     mStandbyInfo.totalTransitions += (sPollCount + 1);
267   }
268 
269   ALOGD_IF(nfc_debug_enabled,
270            "activeTime: %llu, standbyTime: %llu, totalDuration :%llu",
271            (unsigned long long)activeTime, (unsigned long long)standbyTime,
272            (unsigned long long)totalDuration);
273   if (mLastPowerTrackAborted) {
274     ALOGD_IF(nfc_debug_enabled,
275              "Last Hal service aborted,so retrive the power info data and "
276              "continue\n");
277     /*Read the file content and store in mActiveInfo.residencyInMsecSinceBoot
278     and mStandbyInfo.residencyInMsecSinceBoot*/
279     if (ReadPowerStateLog()) {
280       mLastPowerTrackAborted = false;
281     }
282   }
283   mStandbyInfo.residencyInMsecSinceBoot += standbyTime;
284   mActiveInfo.residencyInMsecSinceBoot += activeTime;
285   UpdatePowerStateLog(mStandbyInfo, mActiveInfo);
286   mActiveDurationFromLastScreenUpdate = 0;
287 }
288 /*******************************************************************************
289 **
290 ** Function         NfccPowerTracker::UpdatePowerStateLog
291 **
292 ** Description      update the powerstate related information in log file
293 **
294 ** Returns          void
295 **
296 *******************************************************************************/
UpdatePowerStateLog(NfccPowerStateInfo_t mStandbyInfo,NfccPowerStateInfo_t mActiveInfo)297 void NfccPowerTracker::UpdatePowerStateLog(NfccPowerStateInfo_t mStandbyInfo,
298                                            NfccPowerStateInfo_t mActiveInfo) {
299   FILE *fp;
300   const string PWR_TRK_LOG_FILE_VERSION = "1.0";
301   /*Write the Active and standby timestamp into the file*/
302   fp = fopen(POWER_TRACKER_LOG_FILE.c_str(), "w");
303   if (fp == NULL) {
304     ALOGD_IF(nfc_debug_enabled, "Failed to Open Pwr Tracker Info File\n");
305     return;
306   }
307   ostringstream PwrTrackerInfo;
308   PwrTrackerInfo << "Version: " << PWR_TRK_LOG_FILE_VERSION.c_str() << endl;
309   PwrTrackerInfo << "NFC {" << endl;
310   PwrTrackerInfo << " { " << STR_ACTIVE
311                  << std::to_string(mActiveInfo.residencyInMsecSinceBoot) << " }"
312                  << endl;
313   PwrTrackerInfo << " { " << STR_STANDBY
314                  << std::to_string(mStandbyInfo.residencyInMsecSinceBoot)
315                  << " }" << endl;
316   PwrTrackerInfo << "}";
317   ALOGD_IF(nfc_debug_enabled,
318            "mActiveInfo.residencyInMsecSinceBoot: %llu, "
319            "mActiveInfo.totalTransitions: %llu,"
320            "mStandbyInfo.residencyInMsecSinceBoot "
321            ":%llu,mStandbyInfo.totalTransitions: %llu"
322            "mErrorInStandbyInfo.residencyInMsecSinceBoot: %llu",
323            (unsigned long long)mActiveInfo.residencyInMsecSinceBoot,
324            (unsigned long long)mActiveInfo.totalTransitions,
325            (unsigned long long)mStandbyInfo.residencyInMsecSinceBoot,
326            (unsigned long long)mStandbyInfo.totalTransitions,
327            (unsigned long long)mErrorInStandbyInfo.residencyInMsecSinceBoot);
328   string PwrInfo = PwrTrackerInfo.str();
329   if (!TryLockFile(fp)) {
330     ALOGD_IF(nfc_debug_enabled,
331              "Failed to Lock PwrTracker File.Skipping update\n");
332     fclose(fp);
333     return;
334   }
335   fwrite(PwrInfo.c_str(), sizeof(char), PwrInfo.length(), fp);
336   fflush(fp);
337   UnlockFile(fp);
338   fclose(fp);
339 }
340 /*******************************************************************************
341  **
342  ** Function         ReadPowerStateLog
343  **
344  ** Description      Retrieve powerstate related information from log file.
345  **
346  ** Returns          true if read successful, false otherwise.
347  **
348  *******************************************************************************/
ReadPowerStateLog()349 bool NfccPowerTracker::ReadPowerStateLog() {
350   ifstream pwrStateFileStream;
351   string itemName;
352   ALOGD_IF(nfc_debug_enabled, "NfccPowerTracker::ReadPowerStateLog: Enter \n");
353   pwrStateFileStream.open(POWER_TRACKER_LOG_FILE.c_str());
354   if (pwrStateFileStream.fail()) {
355     ALOGE("Error: %s", strerror(errno));
356     return false;
357   }
358 
359   /*Check for required string(time in millisec) in the log file and convert it
360     to integer*/
361   while (pwrStateFileStream >> itemName) {
362     if (STR_ACTIVE.compare(itemName) == 0) {
363       pwrStateFileStream >> itemName;
364       mActiveInfo.residencyInMsecSinceBoot = stoull(itemName.c_str(), nullptr);
365     } else if (STR_STANDBY.compare(itemName) == 0) {
366       pwrStateFileStream >> itemName;
367       mStandbyInfo.residencyInMsecSinceBoot = stoull(itemName.c_str(), nullptr);
368     }
369   }
370 
371   ALOGD_IF(nfc_debug_enabled,
372            "Value retrieved from Powertracker file is"
373            "activeTime: %llu and standbyTime: %llu\n",
374            (unsigned long long)mActiveInfo.residencyInMsecSinceBoot,
375            (unsigned long long)mStandbyInfo.residencyInMsecSinceBoot);
376   pwrStateFileStream.close();
377   return true;
378 }
379 /*******************************************************************************
380 **
381 ** Function         Pause
382 **
383 ** Description      Pause Power state Information Tracking,Tracking will resume
384 **                  once next power tracker notification is recieved as part of
385 **                  ProcessNtf.
386 **
387 ** Returns          void
388 **
389 *******************************************************************************/
Pause()390 void NfccPowerTracker::Pause() { mIsFirstPwrTrkNtfRecvd = false; }
391 
392 /*******************************************************************************
393 **
394 ** Function         Reset
395 **
396 ** Description      Stop power track information processing and delete
397 **                  power tracker log file.
398 **
399 ** Returns          void
400 **
401 *******************************************************************************/
Reset()402 void NfccPowerTracker::Reset() {
403   ALOGD_IF(nfc_debug_enabled, "NfccPowerTracker::Reset enter");
404   if (remove(POWER_TRACKER_LOG_FILE.c_str()) != 0) {
405     ALOGD_IF(nfc_debug_enabled, "Error deleting Power tracker file");
406   }
407 }
408 /*******************************************************************************
409 **
410 ** Function         TryLockFile
411 **
412 ** Description      Lock PowerTracker log file. Any application trying to read
413 **                  from PowerTracker log file shall acquire lock before reading
414 **                  to avoid inconsistent data.
415 **
416 ** Returns          true if locking was successful
417 **                  false if there was a failure to lock PowerTracker log file.
418 *******************************************************************************/
TryLockFile(FILE * fp)419 bool NfccPowerTracker::TryLockFile(FILE *fp) {
420   uint8_t retryCount = 5;
421   do {
422     if (!flock(fileno(fp), LOCK_EX | LOCK_NB))
423       return true;
424     usleep(10000); /*10 millisec*/
425   } while (retryCount--);
426 
427   return false;
428 }
429 /*******************************************************************************
430 **
431 ** Function         UnlockFile
432 **
433 ** Description      Unlock previously locked PowerTracker log file.
434 **
435 ** Returns          void
436 **
437 *******************************************************************************/
UnlockFile(FILE * fp)438 void NfccPowerTracker::UnlockFile(FILE *fp) { flock(fileno(fp), LOCK_UN); }
439