• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (C) 2023 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  *  Provide extensions for the implementation of the Nfc Charging
17  */
18 
19 package com.android.nfc.wlc;
20 
21 import android.content.Context;
22 import android.nfc.NdefMessage;
23 import android.nfc.NdefRecord;
24 import android.sysprop.NfcProperties;
25 import android.util.Log;
26 
27 import com.android.nfc.DeviceHost;
28 import com.android.nfc.DeviceHost.TagEndpoint;
29 import com.android.nfc.NfcService;
30 
31 import java.math.*;
32 import java.util.Arrays;
33 import java.util.HashMap;
34 import java.util.Map;
35 
36 public class NfcCharging {
37     static final boolean DBG = NfcProperties.debug_enabled().orElse(true);
38     private static final String TAG = "NfcWlcChargingActivity";
39 
40     static final String VERSION = "1.0.0";
41 
42     private Context mContext;
43     public static final byte[] WLCCAP = {0x57, 0x4c, 0x43, 0x43, 0x41, 0x50};
44     public static final byte[] WLCCTL = {0x57, 0x4c, 0x43, 0x43, 0x54, 0x4C};
45     public static final byte[] WLCSTAI = {0x57, 0x4c, 0x43, 0x53, 0x54, 0x41, 0x49};
46     public static final byte[] USIWLC = {0x75, 0x73, 0x69, 0x3A, 0x77, 0x6C, 0x63};
47     public static final byte[] WLCPI = {0x57, 0x4c, 0x43, 0x49, 0x4e, 0x46};
48 
49     public static final String BatteryLevel = "Battery Level";
50     public static final String ReceivePower = "Receive Power";
51     public static final String ReceiveVoltage = "Receive Voltage";
52     public static final String ReceiveCurrent = "Receive Current";
53     public static final String TemperatureBattery = "Temperature Battery";
54     public static final String TemperatureListener = "Temperature Listener";
55     public static final String VendorId = "Vendor Id";
56     public static final String State = "State";
57     public static final int DISCONNECTED = 0;
58     public static final int CONNECTED_NOT_CHARGING = 1;
59     public static final int CONNECTED_CHARGING = 2;
60 
61     static final byte MODE_REQ_STATIC = 0;
62     static final byte MODE_REQ_NEGOTIATED = 1;
63     static final byte MODE_REQ_BATTERY_FULL = 2;
64 
65     static final int MODE_NON_AUTONOMOUS_WLCP = 0;
66 
67     int mWatchdogTimeout = 1;
68     int mUpdatedBatteryLevel = -1;
69     int mLastState = -1;
70 
71     int WLCState = 0;
72 
73     // WLCCAP
74     int WlcCap_ModeReq = 0;
75     int Nwt_max = 0;
76     int WlcCap_NegoWait = 0;
77     int WlcCap_RdConf = 0;
78     int TNdefRdWt = 0;
79 
80     int WlcCap_NdefRdWt = 0;
81     int WlcCap_CapWt = 0;
82     int TCapWt = 0;
83     int WlcCap_NdefWrTo = 0;
84     int TNdefWrTo = 0;
85     int WlcCap_NdefWrWt = 0;
86     int TNdefWrWt = 0;
87 
88     int mNwcc_retry = 0;
89     int mNretry = 0;
90 
91     // WLCCTL
92     int WlcCtl_ErrorFlag = 0;
93     int WlcCtl_BatteryStatus = 0;
94     int mCnt = -1;
95     int WlcCtl_Cnt_new = 0;
96     int WlcCtl_WptReq = 0;
97     int WlcCtl_WptDuration = 0;
98     int TWptDuration = 0;
99     int WlcCtl_WptInfoReq = 0;
100     int WlcCtl_PowerAdjReq = 0;
101     int WlcCtl_BatteryLevel = 0xFF;
102     int WlcCtl_HoldOffWt = 0;
103     int THoldOffWt = 0;
104 
105     int WlcCtl_ReceivePower = 0;
106     int WlcCtl_ReceiveVoltage = 0;
107     int WlcCtl_TemperatureBattery = 0;
108     int WlcCtl_TemperatureWlcl = 0;
109 
110     // WLCINF
111     int Ptx = 100;
112 
113     // state machine
114     private static final int STATE_2 = 0; // Read WLC_CAP
115     private static final int STATE_6 = 1; // Static WPT
116     private static final int STATE_8 = 2; // Handle NEGO_WAIT
117     private static final int STATE_11 = 3; // Write WLCP_INFO
118     private static final int STATE_12 = 4; // Read WLCL_CTL
119     private static final int STATE_16 = 5; // Read confirmation
120     private static final int STATE_17 = 6; // Check WPT requested
121     private static final int STATE_21 = 7; // Handle WPT
122     private static final int STATE_22 = 8; // Handle INFO_REQ
123     private static final int STATE_24 = 9; // Handle removal detection
124     private static final int STATE_21_1 = 10; // Handle WPT time completed
125     private static final int STATE_21_2 = 11; // Handle FOD detection/removal
126 
127     private DeviceHost mNativeNfcManager;
128     NdefMessage mNdefMessage;
129     byte[] mNdefPayload;
130     byte[] mNdefPayload2;
131     byte[] mNdefType;
132     TagEndpoint TagHandler;
133 
134     public boolean NfcChargingOnGoing = false;
135     public boolean NfcChargingMode = false;
136     public boolean WLCL_Presence = false;
137 
138     public boolean mFirstOccurrence = true;
139 
140     Map<String, Integer> WlcDeviceInfo = new HashMap<>();
141 
startWlcPowerTransfer(int power_adj_req, int wpt_time_int)142     private native boolean startWlcPowerTransfer(int power_adj_req, int wpt_time_int);
143 
enableWlc(int enable)144     private native boolean enableWlc(int enable);
145 
146     private PresenceCheckWatchdog mWatchdogWlc;
147 
NfcCharging(Context context, DeviceHost mDeviceHost)148     public NfcCharging(Context context, DeviceHost mDeviceHost) {
149         if (DBG) Log.d(TAG, "NfcCharging - Constructor");
150         mContext = context;
151         mNativeNfcManager = mDeviceHost;
152 
153         resetInternalValues();
154 
155         mNdefMessage = null;
156         mNdefPayload = null;
157         mNdefPayload2 = null;
158     }
159 
160     private static final char[] hexArray = "0123456789ABCDEF".toCharArray();
161 
bytesToHex(byte[] bytes)162     public static String bytesToHex(byte[] bytes) {
163         char[] hexChars = new char[bytes.length * 2];
164         for (int j = 0; j < bytes.length; j++) {
165             int v = bytes[j] & 0xFF;
166             hexChars[j * 2] = hexArray[v >>> 4];
167             hexChars[j * 2 + 1] = hexArray[v & 0x0F];
168         }
169         return new String(hexChars);
170     }
171 
resetInternalValues()172     public void resetInternalValues() {
173         if (DBG) Log.d(TAG, "resetInternalValues");
174         mCnt = -1;
175         mNretry = 0;
176         WlcCap_ModeReq = 0;
177         WlcCtl_BatteryLevel = -1;
178         WlcCtl_ReceivePower = -1;
179         WlcCtl_ReceiveVoltage = -1;
180         WlcCtl_TemperatureBattery = -1;
181         WlcCtl_TemperatureWlcl = -1;
182         mUpdatedBatteryLevel = -1;
183         mLastState = -1;
184         WlcDeviceInfo.put(BatteryLevel, -1);
185         WlcDeviceInfo.put(ReceivePower, -1);
186         WlcDeviceInfo.put(ReceiveVoltage, -1);
187         WlcDeviceInfo.put(ReceiveCurrent, -1);
188         WlcDeviceInfo.put(TemperatureBattery, -1);
189         WlcDeviceInfo.put(TemperatureListener, -1);
190         WlcDeviceInfo.put(VendorId, -1);
191         WlcDeviceInfo.put(State, -1);
192 
193         WlcCtl_ErrorFlag = 0;
194         mFirstOccurrence = true;
195     }
196 
197     DeviceHost.TagDisconnectedCallback callbackTagDisconnection =
198             new DeviceHost.TagDisconnectedCallback() {
199                 @Override
200                 public void onTagDisconnected() {
201                     Log.d(TAG, "onTagDisconnected");
202                     disconnectNfcCharging();
203                     WLCState = STATE_2;
204                     NfcChargingOnGoing = false;
205                     if (WLCL_Presence == true) {
206                         WLCL_Presence = false;
207                         if (DBG) Log.d(TAG, "onTagDisconnected: Nfc Charging Listener lost");
208                     }
209                     NfcService.getInstance().sendScreenMessageAfterNfcCharging();
210                 }
211             };
212 
startNfcCharging(TagEndpoint t)213     public boolean startNfcCharging(TagEndpoint t) {
214         if (DBG) Log.d(TAG, "startNfcCharging: " + VERSION);
215         boolean NfcChargingEnabled = false;
216 
217         TagHandler = t;
218         NfcChargingEnabled = enableWlc(MODE_NON_AUTONOMOUS_WLCP);
219         if (DBG) Log.d(TAG, "startNfcCharging: NfcChargingEnabled=" + NfcChargingEnabled);
220 
221         if (NfcChargingEnabled) {
222             WLCL_Presence = true;
223             WLCState = STATE_2;
224             startNfcChargingPresenceChecking(50);
225             return true;
226         } else {
227             return false;
228         }
229     }
230 
stopNfcCharging()231     public void stopNfcCharging() {
232         if (DBG) Log.d(TAG, "stopNfcCharging: " + VERSION);
233 
234         NfcChargingOnGoing = false;
235         resetInternalValues();
236 
237         mLastState = DISCONNECTED;
238         WlcDeviceInfo.put(State, mLastState);
239         NfcService.getInstance().onWlcData(WlcDeviceInfo);
240         disconnectPresenceCheck();
241 
242         NfcChargingMode = false;
243 
244         // Restart the polling loop
245 
246         TagHandler.disconnect();
247         // Disable discovery and restart polling loop only if not screen state change pending
248         if (!NfcService.getInstance().sendScreenMessageAfterNfcCharging()) {
249             if (DBG) {
250                 Log.d(TAG, "stopNfcCharging: No pending screen state change, "
251                         + "stop Nfc charging presence check");
252             }
253             stopNfcChargingPresenceChecking();
254         }
255     }
256 
checkWlcCapMsg(NdefMessage ndefMsg)257     public boolean checkWlcCapMsg(NdefMessage ndefMsg) {
258         if (DBG) Log.d(TAG, "checkWlcCapMsg: enter");
259         boolean status = true;
260         NdefRecord[] ndefRecords = null;
261         long mDeviceId = 0;
262         int mVendorId = 0;
263         Byte ControlByte = 0;
264         if (ndefMsg != null) {
265             mNdefMessage = ndefMsg;
266             try {
267                 ndefRecords = mNdefMessage.getRecords();
268                 if (ndefRecords != null && ndefRecords.length > 0) {
269                     if (DBG) {
270                         Log.d(TAG, "checkWlcCapMsg: number of ndefRecords = "
271                                 + ndefRecords.length);
272                     }
273                     mNdefType = ndefRecords[0].getType();
274 
275                     if (mNdefType != null) {
276                         mNdefPayload = ndefRecords[0].getPayload();
277                         if (mNdefPayload != null && mNdefType != null) {
278                             if (!Arrays.equals(mNdefType, WLCCAP)) {
279                                 if (DBG) Log.d(TAG, "checkWlcCapMsg: NdefType not WLC_CAP");
280                                 return (status = false);
281                             }
282                             if (DBG) {
283                                 Log.d(TAG, "checkWlcCapMsg: mNdefType = " + bytesToHex(mNdefType));
284                             }
285                         } else {
286                             return (status = false);
287                         }
288                     } else {
289                         Log.e(TAG, "checkWlcCapMsg: NdefType null");
290                         return (status = false);
291                     }
292                 } else {
293                     Log.e(TAG, "checkWlcCapMsg: ndefRecords == null or ndefRecords.length = 0)");
294                     return (status = false);
295                 }
296             } catch (Exception e) {
297                 Log.e(TAG, "checkWlcCapMsg: Error in getRecords " + e);
298                 NfcChargingOnGoing = false;
299                 TagHandler.startPresenceChecking(125, callbackTagDisconnection);
300             }
301 
302             if ((mNdefPayload[1] & 0xC0) == 0xC0) {
303                 if (DBG) Log.d(TAG, "checkWlcCapMsg: Wrong Mode Req");
304                 return (status = false);
305             }
306 
307             WlcCap_ModeReq = (mNdefPayload[1] >> 6) & 0x3;
308             Nwt_max = (mNdefPayload[1] >> 2) & 0xF;
309             WlcCap_NegoWait = (mNdefPayload[1] >> 1) & 0x1;
310             if (DBG) Log.d(TAG, "checkWlcCapMsg: WlcCap_NegoWait = " + WlcCap_NegoWait);
311             if (DBG) Log.d(TAG, "checkWlcCapMsg: Nwt_max = " + Nwt_max);
312             WlcCap_RdConf = mNdefPayload[1] & 0x1;
313 
314             WlcCap_CapWt = (mNdefPayload[2] & 0x1F);
315             if (WlcCap_CapWt > 0x13) WlcCap_CapWt = 0x13;
316             TCapWt = (int) Math.pow(2, (WlcCap_CapWt + 3));
317             if (TCapWt < 250) TCapWt = 250;
318             if (DBG) Log.d(TAG, "checkWlcCapMsg: TCapWt = " + TCapWt);
319             TNdefRdWt = (int) (mNdefPayload[3] & 0xFF) * 10;
320             if (mNdefPayload[3] == 0 || mNdefPayload[3] == (byte)0xFF) TNdefRdWt = 2540;
321             if (DBG) Log.d(TAG, "checkWlcCapMsg: TNdefRdWt = " + TNdefRdWt);
322             WlcCap_NdefWrTo = mNdefPayload[4];
323             if (WlcCap_NdefWrTo == 0 || WlcCap_NdefWrTo > 4) WlcCap_NdefWrTo = 4;
324             TNdefWrTo = (int) Math.pow(2, (WlcCap_NdefWrTo + 5));
325             if (DBG) Log.d(TAG, "checkWlcCapMsg: TNdefWrTo = " + TNdefWrTo);
326             TNdefWrWt = mNdefPayload[5];
327             if (TNdefWrWt > 0x0A) TNdefWrWt = 0x0A;
328             if (DBG) Log.d(TAG, "checkWlcCapMsg: TNdefWrWt = " + TNdefWrWt);
329 
330             Log.d(TAG, "checkWlcCapMsg: " + ndefRecords.length + " NdefRecords");
331             if (ndefRecords != null && ndefRecords.length > 1) {
332                 for (int i = 1; i < ndefRecords.length; i++) {
333                     mNdefType = ndefRecords[i].getType();
334                     if (DBG) Log.d(TAG, "checkWlcCapMsg: mNdefType = " + bytesToHex(mNdefType));
335                     mNdefPayload2 = ndefRecords[i].getPayload();
336                     if (mNdefPayload2 != null && mNdefType != null) {
337                         if (Arrays.equals(mNdefType, WLCSTAI)) {
338                             checkWlcStaiMsg(mNdefPayload2);
339                         } else if (Arrays.equals(mNdefType, USIWLC)) {
340                             if (DBG) {
341                                 Log.d(TAG,
342                                         "checkWlcCapMsg: mNdefPayload USIWLC = "
343                                                 + bytesToHex(mNdefPayload2) + " length = "
344                                                 + mNdefPayload2.length);
345                             }
346 
347                             if (mNdefPayload2.length > 8) {
348                                 mVendorId = (mNdefPayload2[8] << 8 | mNdefPayload2[7]) >> 4;
349                                 Log.d(TAG, "checkWlcCapMsg: VendorId = "
350                                         + Integer.toHexString(mVendorId));
351                                 WlcDeviceInfo.put(VendorId, mVendorId);
352                                 mDeviceId = (long) ((mNdefPayload2[7] & 0x0F)) << 48;
353                                 for (int j = 6; j > 0; j--) {
354                                     mDeviceId |= (long) (mNdefPayload2[j] & 0xFF) << ((j - 1) * 8);
355                                 }
356                                 if (DBG) {
357                                     Log.d(TAG, "checkWlcCapMsg: DeviceId = "
358                                             + Long.toHexString(mDeviceId));
359                                 }
360                             }
361                         }
362                     }
363                 }
364             }
365             NfcChargingOnGoing = true;
366         } else {
367             status = false;
368         }
369         if (WlcDeviceInfo.get(BatteryLevel) > (mUpdatedBatteryLevel + 5)) {
370             NfcService.getInstance().onWlcData(WlcDeviceInfo);
371             mUpdatedBatteryLevel = WlcDeviceInfo.get(BatteryLevel);
372         }
373         if (DBG) Log.d(TAG, "checkWlcCapMsg: exit, status = " + status);
374         return status;
375     }
376 
checkWlcCtlMsg(NdefMessage mNdefMessage)377     public boolean checkWlcCtlMsg(NdefMessage mNdefMessage) {
378         if (DBG) Log.d(TAG, "checkWlcCtlMsg: enter");
379 
380         boolean status = true;
381         NdefRecord[] ndefRecords = null;
382 
383         if (mNdefMessage != null) {
384             if (DBG) Log.d(TAG, "checkWlcCtlMsg: ndefMessage non null");
385             try {
386                 ndefRecords = mNdefMessage.getRecords();
387                 if (ndefRecords != null && ndefRecords.length > 0) {
388                     mNdefType = ndefRecords[0].getType();
389                     mNdefPayload = ndefRecords[0].getPayload();
390                     if (mNdefPayload != null && mNdefType != null) {
391                         if (!Arrays.equals(mNdefType, NfcCharging.WLCCTL)) {
392                             return (status = false);
393                         }
394                         if (DBG) {
395                             Log.d(TAG, "checkWlcCtlMsg: mNdefType = " + bytesToHex(mNdefType));
396                         }
397                     } else {
398                         return (status = false);
399                     }
400                 } else {
401                     return (status = false);
402                 }
403             } catch (Exception e) {
404                 Log.e(TAG, "checkWlcCtlMsg: Error in getRecords " + e);
405                 NfcChargingOnGoing = false;
406                 TagHandler.startPresenceChecking(125, callbackTagDisconnection);
407             }
408             WlcCtl_ErrorFlag = (mNdefPayload[0] >> 7);
409             WlcCtl_BatteryStatus = (mNdefPayload[0] & 0x18) >> 3;
410             WlcCtl_Cnt_new = (mNdefPayload[0] & 0x7);
411             WlcCtl_WptReq = (mNdefPayload[1] & 0xC0) >> 6;
412             if (WlcCtl_WptReq > 1) WlcCtl_WptReq = 0;
413 
414             WlcCtl_WptDuration = (mNdefPayload[1] & 0x3e) >> 1;
415             if (WlcCtl_WptDuration > 0x13) WlcCtl_WptReq = 0x13;
416             if (DBG) Log.d(TAG, "checkWlcCtlMsg: WlcCtl_WptDuration = " + WlcCtl_WptDuration);
417             TWptDuration = (int) Math.pow(2, (WlcCtl_WptDuration + 3));
418             WlcCtl_WptInfoReq = (mNdefPayload[1] & 0x1);
419             if (WlcCtl_WptReq == 0) WlcCtl_WptInfoReq = 0;
420 
421             if ((mNdefPayload[2] <= 0x14) || (mNdefPayload[2] >= (byte)0xF6)) {
422                 WlcCtl_PowerAdjReq = mNdefPayload[2];
423             } else {
424                 WlcCtl_PowerAdjReq = 0;
425             }
426 
427             if (DBG) Log.d(TAG, "checkWlcCtlMsg: WlcCtl_PowerAdjReq = " + WlcCtl_PowerAdjReq);
428 
429             if ((mNdefPayload[3] < 0x64) && (WlcCtl_BatteryStatus == 0x1)) {
430                 WlcCtl_BatteryLevel = mNdefPayload[3];
431                 WlcDeviceInfo.put(BatteryLevel, WlcCtl_BatteryLevel);
432                 if (DBG) {
433                     Log.d(TAG, "checkWlcCtlMsg: WlcCtl_BatteryLevel = " + WlcCtl_BatteryLevel);
434                 }
435             }
436 
437             if (mNdefPayload[5] > 0xF) {
438                 WlcCtl_HoldOffWt = 0xF;
439             } else {
440                 WlcCtl_HoldOffWt = mNdefPayload[5];
441             }
442             THoldOffWt = (int) WlcCtl_HoldOffWt * 2;
443 
444             if (DBG) Log.d(TAG, "checkWlcCtlMsg: " + ndefRecords.length + " NdefRecords");
445             if (ndefRecords != null && ndefRecords.length > 1) {
446                 for (int i = 1; i < ndefRecords.length; i++) {
447                     mNdefType = ndefRecords[i].getType();
448                     if (DBG) {
449                         Log.d(TAG, "checkWlcCtlMsg: mNdefType = " + bytesToHex(mNdefType));
450                     }
451                     mNdefPayload2 = ndefRecords[i].getPayload();
452                     if (mNdefPayload2 != null && mNdefType != null) {
453                         if (Arrays.equals(mNdefType, WLCSTAI)) {
454                             checkWlcStaiMsg(mNdefPayload2);
455                         }
456                     }
457                 }
458             }
459 
460         } else {
461             status = false;
462         }
463 
464         if (WlcDeviceInfo.get(BatteryLevel) > (mUpdatedBatteryLevel + 5)) {
465             NfcService.getInstance().onWlcData(WlcDeviceInfo);
466             mUpdatedBatteryLevel = WlcDeviceInfo.get(BatteryLevel);
467         }
468         if (DBG) Log.d(TAG, "checkWlcCtlMsg: status = " + status);
469         return status;
470     }
471 
checkWlcStaiMsg(byte[] mPayload)472     public void checkWlcStaiMsg(byte[] mPayload) {
473         Byte ControlByte = 0;
474         if (DBG) {
475             Log.d(TAG, "checkWlcStaiMsg: mNdefPayload WLCSTAI = " + bytesToHex(mPayload));
476         }
477         ControlByte = mPayload[0];
478         int pos = 0;
479         if (((ControlByte & 0x01) == 0x01) && pos < mPayload.length) {
480             pos++;
481             WlcCtl_BatteryLevel = mPayload[pos];
482             WlcDeviceInfo.put(BatteryLevel, (int) mPayload[pos]);
483             if (DBG) {
484                 Log.d(TAG, "checkWlcStaiMsg: WlcCtl_BatteryLevel = "
485                         + WlcDeviceInfo.get(BatteryLevel));
486             }
487         }
488         if (((ControlByte & 0x02) == 0x02) && pos < mPayload.length) {
489             pos++;
490             WlcCtl_ReceivePower = mPayload[pos];
491             WlcDeviceInfo.put(ReceivePower, (int) mPayload[pos]);
492         }
493         if (((ControlByte & 0x04) == 0x04) && pos < mPayload.length) {
494             pos++;
495             WlcCtl_ReceiveVoltage = mPayload[pos];
496             WlcDeviceInfo.put(ReceiveVoltage, (int) mPayload[pos]);
497         }
498         if (((ControlByte & 0x08) == 0x08) && pos < mPayload.length) {
499             pos++;
500             WlcCtl_TemperatureBattery = mPayload[pos];
501             WlcDeviceInfo.put(TemperatureBattery, (int) mPayload[pos]);
502         }
503         if (((ControlByte & 0x10) == 0x10) && pos < mPayload.length) {
504             pos++;
505             WlcCtl_TemperatureWlcl = mPayload[pos];
506             WlcDeviceInfo.put(TemperatureListener, (int) mPayload[pos]);
507         }
508     }
509 
sendWLCPI(TagEndpoint tag, NdefMessage ndefMsg)510     public void sendWLCPI(TagEndpoint tag, NdefMessage ndefMsg) {
511         NdefMessage WLCP_INFO =
512                 constructWLCPI(
513                     (byte) Ptx,
514                     (byte) 0x00,
515                     (byte) 0x00,
516                     (byte) 0x00,
517                     (byte) 0x00,
518                     (byte) 0x00);
519         if (tag.writeNdef(WLCP_INFO.toByteArray())) {
520             Log.d(TAG, "sendWLCPI: Write NDEF success");
521         } else {
522             Log.d(TAG, "sendWLCPI: Write NDEF Error");
523         }
524     }
525 
constructWLCPI( byte ptx, byte power_class, byte tps, byte cps, byte nmsi, byte nmsd)526     public NdefMessage constructWLCPI(
527             byte ptx, byte power_class, byte tps, byte cps, byte nmsi, byte nmsd) {
528         byte[] WLCPI_payload = {ptx, power_class, tps, cps, nmsi, nmsd};
529 
530         NdefRecord WLCP_INFO_RECORD =
531                 new NdefRecord(NdefRecord.TNF_WELL_KNOWN, WLCPI, new byte[] {}, WLCPI_payload);
532 
533         NdefMessage WLCP_INFO = new NdefMessage(WLCP_INFO_RECORD);
534 
535         return WLCP_INFO;
536     }
537 
sendEmptyNdef()538     public void sendEmptyNdef() {
539         NdefRecord WLCP_RD_CONF_RECORD = new NdefRecord(NdefRecord.TNF_EMPTY, null, null, null);
540 
541         NdefMessage WLCP_RD_CONF = new NdefMessage(WLCP_RD_CONF_RECORD);
542         if (TagHandler.writeNdef(WLCP_RD_CONF.toByteArray())) {
543             Log.d(TAG, "sendEmptyNdef: Write NDEF success");
544         } else {
545             Log.d(TAG, "sendEmptyNdef: Write NDEF Error");
546         }
547     }
548 
stopNfcChargingPresenceChecking()549     public synchronized void stopNfcChargingPresenceChecking() {
550         if (mWatchdogWlc != null) {
551             mWatchdogWlc.end(true);
552         }
553     }
554 
startNfcChargingPresenceChecking(int presenceCheckDelay)555     public synchronized void startNfcChargingPresenceChecking(int presenceCheckDelay) {
556         // Once we start presence checking, we allow the upper layers
557         // to know the tag is in the field.
558         if (mWatchdogWlc != null) {
559             if (DBG) Log.d(TAG, "startNfcChargingPresenceChecking: mWatchDog non null");
560         }
561         if (mWatchdogWlc == null) {
562             if (DBG) {
563                 Log.d(TAG, "startNfcChargingPresenceChecking: mWatchdogWlc about to start...");
564             }
565             mWatchdogWlc = new PresenceCheckWatchdog(presenceCheckDelay);
566             mWatchdogWlc.start();
567         }
568     }
569 
570     class PresenceCheckWatchdog extends Thread {
571         private int watchdogTimeout;
572 
573         private boolean isPresent = true;
574         private boolean isStopped = false;
575         private boolean isPaused = false;
576         private boolean doCheck = true;
577         private boolean isFull = false;
578 
PresenceCheckWatchdog(int presenceCheckDelay)579         public PresenceCheckWatchdog(int presenceCheckDelay) {
580             watchdogTimeout = presenceCheckDelay;
581         }
582 
pause()583         public synchronized void pause() {
584             isPaused = true;
585             doCheck = false;
586             this.notifyAll();
587             if (DBG) Log.d(TAG, "pause: isPaused = " + isPaused);
588         }
589 
setTimeout(int timeout)590         public synchronized void setTimeout(int timeout) {
591             if (DBG) Log.d(TAG, "setTimeout: PresenceCheckWatchdog watchdogTimeout " + timeout);
592             watchdogTimeout = timeout;
593         }
594 
full()595         public synchronized void full() {
596             isFull = true;
597             this.notifyAll();
598         }
599 
lost()600         public synchronized void lost() {
601             isPresent = false;
602             if (DBG) Log.d(TAG, "lost: PresenceCheckWatchdog isPresent " + isPresent);
603             doCheck = false;
604             this.notifyAll();
605         }
606 
doResume()607         public synchronized void doResume() {
608             isPaused = false;
609             // We don't want to resume presence checking immediately,
610             // but go through at least one more wait period.
611             doCheck = false;
612             this.notifyAll();
613             if (DBG) Log.d(TAG, "doResume: isPaused = " + isPaused);
614         }
615 
end(boolean disableCallback)616         public synchronized void end(boolean disableCallback) {
617             isStopped = true;
618             if (DBG) Log.d(TAG, "end: PresenceCheckWatchdog end isStopped = " + isStopped);
619             doCheck = false;
620             if (disableCallback) {
621                 //  tagDisconnectedCallback = null;
622             }
623             this.notifyAll();
624         }
625 
626         @Override
run()627         public void run() {
628             synchronized (this) {
629                 if (DBG) Log.d(TAG, "run: Starting WLC flow");
630                 while (isPresent && !isStopped && !isFull) {
631                     if (DBG) {
632                         Log.d(TAG, "run: isPresent= "
633                                 + isPresent
634                                 + " isStopped= "
635                                 + isStopped
636                                 + " isFull= "
637                                 + isFull);
638                     }
639                     try {
640                         if (watchdogTimeout > 0) {
641                             this.wait(watchdogTimeout);
642                         }
643 
644                         watchdogTimeout = HandleWLCState();
645                         if (DBG) Log.d(TAG, "run: Next watchdog timeout : " + watchdogTimeout);
646                     } catch (InterruptedException e) {
647                         // Activity detected, loop
648                         if (DBG) Log.d(TAG, "run: Interrupted thread: " + WLCState);
649                     }
650                 }
651             }
652             synchronized (NfcCharging.this) {
653                 isPresent = false;
654                 NfcChargingOnGoing = false;
655                 if (DBG) {
656                     Log.d(TAG, "run: WLC state machine interrupted, NfcChargingOnGoing is "
657                             + NfcChargingOnGoing);
658                 }
659                 resetInternalValues();
660             }
661             mLastState = DISCONNECTED;
662             WlcDeviceInfo.put(State, mLastState);
663             NfcService.getInstance().onWlcData(WlcDeviceInfo);
664             disconnectPresenceCheck();
665             if (DBG) Log.d(TAG, "run: disconnectPresenceCheck done");
666 
667             // Restart the polling loop
668             NfcChargingMode = false;
669             TagHandler.disconnect();
670             // Disable discovery and restart polling loop only if not screen state change pending
671             if (!NfcService.getInstance().sendScreenMessageAfterNfcCharging()) {
672                 if (DBG) {
673                     Log.d(TAG,
674                             "run: No pending screen state change, "
675                                     + "stop Nfc charging presence check");
676                 }
677                 stopNfcChargingPresenceChecking();
678             }
679 
680             if (DBG) Log.d(TAG, "run: Stopping background presence check");
681         }
682     }
683 
disconnectPresenceCheck()684     public boolean disconnectPresenceCheck() {
685         boolean result = false;
686         PresenceCheckWatchdog watchdog;
687         if (DBG) Log.d(TAG, "disconnectPresenceCheck");
688         synchronized (this) {
689             watchdog = mWatchdogWlc;
690         }
691         if (watchdog != null) {
692             // Watchdog has already disconnected or will do it
693             watchdog.end(false);
694             synchronized (this) {
695                 mWatchdogWlc = null;
696             }
697         }
698         result = true;
699         return result;
700     }
701 
HandleWLCState()702     public int HandleWLCState() {
703         int wt = 1;
704         switch (WLCState) {
705             case STATE_2:
706                 // SM2
707                 if (DBG) {
708                     Log.d(TAG, "HandleWLCState: STATE_2 (" + convert_state_2_str(STATE_2) + ")");
709                 }
710                 if (mLastState != CONNECTED_CHARGING) {
711                     mLastState = CONNECTED_CHARGING;
712                     WlcDeviceInfo.put(State, mLastState);
713                     NfcService.getInstance().onWlcData(WlcDeviceInfo);
714                 }
715                 if (TagHandler != null) {
716                     if (!mFirstOccurrence) {
717                         mNdefMessage = TagHandler.getNdef();
718                     }
719                     if (mNdefMessage != null) {
720                         if (!mFirstOccurrence) {
721                             if (!checkWlcCapMsg(mNdefMessage)) {
722                                 if (mWatchdogWlc != null) {
723                                     mWatchdogWlc.lost();
724                                 }
725                                 WLCL_Presence = false;
726                                 Log.d(TAG, "HandleWLCState: WLC_CAP : Presence Check FAILED ");
727                                 break;
728                             }
729                         } else {
730                             mFirstOccurrence = false;
731                         }
732                         if (WlcCap_ModeReq == MODE_REQ_BATTERY_FULL) {
733                             mWatchdogWlc.full();
734                             NfcChargingOnGoing = false;
735                             if (DBG) {
736                                 Log.d(TAG, "HandleWLCState: MODE_REQ is BATTERY_FULL, "
737                                         + "NfcChargingOnGoing is "
738                                             + NfcChargingOnGoing);
739                             }
740                             wt = TCapWt;
741                             WLCState = STATE_24;
742                             WlcDeviceInfo.put(BatteryLevel, 0x64);
743                             mUpdatedBatteryLevel = WlcDeviceInfo.get(BatteryLevel);
744                             WlcDeviceInfo.put(State, mLastState);
745                             mLastState = CONNECTED_NOT_CHARGING;
746                             NfcService.getInstance().onWlcData(WlcDeviceInfo);
747                             if (DBG) Log.d(TAG, "HandleWLCState: Battery full");
748                             break;
749 
750                         } else if (WlcCap_ModeReq == MODE_REQ_STATIC
751                                 || mNativeNfcManager.isMultiTag()) {
752                             if (DBG) Log.d(TAG, "HandleWLCState: Static mode");
753                             wt = 0; // TCapWt;
754 
755                             WLCState = STATE_6;
756                             break;
757 
758                         } else {
759                             if (DBG) Log.d(TAG, "HandleWLCState: Negotiated mode");
760                             wt = 5;
761 
762                             WLCState = STATE_8;
763                             break;
764                         }
765                     } else {
766                         if (mWatchdogWlc != null) {
767                             mWatchdogWlc.lost();
768                         }
769                         WLCL_Presence = false;
770                         if (DBG) Log.d(TAG, "HandleWLCState: WLC_CAP: Presence Check FAILED");
771                     }
772                 }
773                 break;
774 
775             case STATE_6:
776                 // SM6
777                 if (DBG) {
778                     Log.d(TAG, "HandleWLCState: STATE_6 (" + convert_state_2_str(STATE_6) + ")");
779                 }
780 
781                 WLCState = STATE_2;
782                 wt = TCapWt + 5000;
783                 startWlcPowerTransfer(WlcCtl_PowerAdjReq, WlcCap_CapWt);
784                 break;
785 
786             case STATE_8:
787                 // SM8
788                 if (DBG) {
789                     Log.d(TAG, "HandleWLCState: STATE_8 (" + convert_state_2_str(STATE_8) + ")");
790                 }
791 
792                 if (WlcCap_NegoWait == 1) {
793                     if (mNretry > Nwt_max) {
794                         if (mWatchdogWlc != null) {
795                             mWatchdogWlc.lost();
796                         }
797                         WLCL_Presence = false;
798                         if (DBG) {
799                             Log.d(TAG,
800                                     "HandleWLCState: WLCCAP :too much retry, conclude procedure ");
801                         }
802                         WLCState = STATE_2;
803                         wt = 1;
804                         break;
805                     } else {
806                         mNretry += 1;
807                         if (DBG) Log.d(TAG, "HandleWLCState: mNretry = " + mNretry);
808                         wt = TCapWt;
809                         WLCState = STATE_2;
810                         break;
811                     }
812                 }
813                 WLCState = STATE_11;
814                 wt = 5;
815 
816                 break;
817 
818             case STATE_11:
819                 // SM11
820                 if (DBG) {
821                     Log.d(TAG, "HandleWLCState: STATE_11 (" + convert_state_2_str(STATE_11) + ")");
822                 }
823                 sendWLCPI(TagHandler, null);
824                 if (DBG) Log.d(TAG, "HandleWLCState: end writing WLCP_INFO");
825                 wt = TNdefRdWt + 20;
826                 WLCState = STATE_12;
827                 break;
828 
829             case STATE_12:
830                 // SM12-SM15
831                 if (DBG) {
832                     Log.d(TAG, "HandleWLCState: STATE_12 ("
833                             + convert_state_2_str(STATE_12) + ")");
834                 }
835 
836                 if (TagHandler != null) {
837                     mNdefMessage = TagHandler.getNdef();
838                     if (mNdefMessage != null) {
839                         if (checkWlcCtlMsg(mNdefMessage)) {
840                             if (DBG) {
841                                 Log.d(TAG, "HandleWLCState: WlcCtl_Cnt_new: "
842                                         + WlcCtl_Cnt_new
843                                         + "(mCnt +1)%8) = "
844                                         + ((mCnt + 1) % 7));
845                             }
846 
847                             if (mCnt == -1) {
848                                 mCnt = WlcCtl_Cnt_new;
849                             } else if (WlcCtl_Cnt_new == mCnt) {
850                                 if (mNwcc_retry < 3) {
851                                     wt = 30; // Twcc,retry
852                                     mNwcc_retry++;
853                                     break;
854                                 } else if (mNwcc_retry == 3) {
855                                     // go to error
856                                     if (DBG) {
857                                         Log.d(TAG,
858                                                 "HandleWLCState: WLCL_CTL : "
859                                                         + "Max mNwcc_retry reached");
860                                     }
861                                     mNwcc_retry = 0;
862                                     if (mWatchdogWlc != null) {
863                                         mWatchdogWlc.lost();
864                                     }
865                                     break;
866                                 }
867 
868                                 WLCL_Presence = false;
869                                 if (DBG) {
870                                     Log.d(TAG, "HandleWLCState: WLCL_CTL : "
871                                             + "Presence Check Failed ");
872                                 }
873                             }
874                             mNwcc_retry = 0;
875                             mCnt = WlcCtl_Cnt_new;
876                             if (WlcCap_RdConf == 1) {
877                                 WLCState = STATE_16;
878                                 wt = TNdefWrWt;
879                                 break;
880                             }
881                             wt = 1;
882                             WLCState = STATE_17;
883                         } else {
884                             if (mNwcc_retry < 3) {
885                                 wt = 30; // Twcc,retry
886                                 mNwcc_retry++;
887                                 break;
888                             } else if (mNwcc_retry == 3) {
889                                 // go to error
890                                 if (DBG) {
891                                     Log.d(TAG,
892                                             "HandleWLCState: WLCL_CTL not valid: "
893                                                     + "Max mNwcc_retry reached");
894                                 }
895                                 mNwcc_retry = 0;
896                                 if (mWatchdogWlc != null) {
897                                     mWatchdogWlc.lost();
898                                 }
899                                 break;
900                             }
901 
902                             WLCL_Presence = false;
903                             if (DBG) {
904                                 Log.d(TAG, "HandleWLCState: WLCL_CTL : Presence Check Failed ");
905                             }
906                         }
907                     } else {
908                         // no more tag
909                         if (mWatchdogWlc != null) {
910                             mWatchdogWlc.lost();
911                         }
912                         WLCL_Presence = false;
913                         if (DBG) Log.d(TAG, " WLCL_CTL : Presence Check Failed ");
914                     }
915                 } else {
916                     // conclude - go to error
917                 }
918                 break;
919 
920             case STATE_16:
921                 // SM16
922                 if (DBG) {
923                     Log.d(TAG, "HandleWLCState: STATE_16 (" + convert_state_2_str(STATE_16) + ")");
924                 }
925 
926                 sendEmptyNdef();
927                 WLCState = STATE_17;
928                 wt = 1;
929                 break;
930 
931             case STATE_17:
932                 // SM17
933                 if (DBG) {
934                     Log.d(TAG, "HandleWLCState: STATE_17 (" + convert_state_2_str(STATE_17) + ")");
935                 }
936 
937                 if (WlcCtl_WptReq == 0x0) {
938                     // No Power transfer Required
939                     if (DBG) Log.d(TAG, "HandleWLCState: No power transfer required");
940                     // go to presence check SM24
941                     WLCState = STATE_24;
942                     wt = TWptDuration;
943                     if (TWptDuration > 4000) {
944                         TagHandler.startPresenceChecking(200, callbackTagDisconnection);
945                     }
946                     break;
947                 }
948 
949                 // Adjust WPT
950                 WLCState = STATE_21;
951                 wt = 1 + THoldOffWt;
952                 break;
953 
954             case STATE_21:
955                 // SM21
956                 if (DBG) {
957                     Log.d(TAG, "HandleWLCState: STATE_21 (" + convert_state_2_str(STATE_21) + ")");
958                 }
959                 startWlcPowerTransfer(WlcCtl_PowerAdjReq, WlcCtl_WptDuration);
960                 WLCState = STATE_22;
961                 wt = TWptDuration + 5000;
962                 break;
963 
964             case STATE_22:
965                 // SM22
966                 if (DBG) {
967                     Log.d(TAG, "HandleWLCState: STATE_22 (" + convert_state_2_str(STATE_22) + ")");
968                 }
969                 if (WlcCtl_WptInfoReq == 1) {
970                     WLCState = STATE_11;
971                     break;
972                 }
973                 WLCState = STATE_12;
974                 wt = 0;
975                 break;
976 
977             case STATE_24:
978                 // SM24
979                 if (DBG) {
980                     Log.d(TAG, "HandleWLCState: STATE_24 (" + convert_state_2_str(STATE_24) + ")");
981                 }
982 
983                 TagHandler.stopPresenceChecking();
984                 WLCState = STATE_2;
985                 NfcChargingOnGoing = false;
986                 if (mWatchdogWlc != null) {
987                     mWatchdogWlc.lost();
988                 }
989                 wt = 1;
990                 break;
991 
992             case STATE_21_1:
993                 // Stop WPT
994                 if (DBG) Log.d(TAG, "HandleWLCState: Time completed");
995                 WLCState = STATE_22;
996                 wt = 0;
997                 break;
998 
999             case STATE_21_2:
1000                 // Stop WPT
1001                 if (DBG) Log.d(TAG, "HandleWLCState: STATE_21_2 (exit)");
1002                 WLCState = STATE_2;
1003                 NfcChargingOnGoing = false;
1004 
1005                 if (mWatchdogWlc != null) {
1006                     mWatchdogWlc.lost();
1007                 }
1008                 wt = 0;
1009                 break;
1010         }
1011 
1012         return wt;
1013     }
1014 
disconnectNfcCharging()1015     public void disconnectNfcCharging() {
1016         Log.d(TAG, "disconnectNfcCharging");
1017         NfcChargingOnGoing = false;
1018         NfcChargingMode = false;
1019         resetInternalValues();
1020         disconnectPresenceCheck();
1021         if (TagHandler != null) {
1022             TagHandler.disconnect();
1023         }
1024     }
1025 
onWlcStopped(int wpt_end_condition)1026     public void onWlcStopped(int wpt_end_condition) {
1027         Log.d(TAG, "onWlcStopped");
1028 
1029         switch (wpt_end_condition) {
1030             case 0x0:
1031                 // Time completed
1032                 mWatchdogWlc.setTimeout(0);
1033                 if (WlcCap_ModeReq == MODE_REQ_NEGOTIATED) {
1034                     WLCState = STATE_21_1;
1035                 } else {
1036                     WLCState = STATE_2;
1037                 }
1038                 mWatchdogWlc.interrupt();
1039                 if (DBG) Log.d(TAG, "onWlcStopped: Time completed");
1040                 break;
1041 
1042             case 0x1:
1043                 // FOD detection or Removal
1044                 mWatchdogWlc.setTimeout(0);
1045                 if (WlcCap_ModeReq == MODE_REQ_NEGOTIATED) {
1046                     WLCState = STATE_21_2;
1047                 } else {
1048                     WLCState = STATE_2;
1049                 }
1050                 mWatchdogWlc.interrupt();
1051                 if (DBG) Log.d(TAG, "onWlcStopped: FOD detection or removal");
1052                 break;
1053 
1054             case 0x3:
1055             default:
1056                 // Error
1057                 mWatchdogWlc.setTimeout(0);
1058                 WLCState = STATE_21_2;
1059                 mWatchdogWlc.interrupt();
1060                 if (DBG) Log.d(TAG, "onWlcStopped: FOD error detection");
1061                 break;
1062         }
1063     }
1064 
onEndpointRemoved(int reason)1065     public void onEndpointRemoved(int reason) {
1066         Log.d(TAG, "onEndpointRemoved");
1067 
1068         mWatchdogWlc.setTimeout(0);
1069         WLCState = STATE_2;
1070         mWatchdogWlc.interrupt();
1071     }
1072 
convert_state_2_str(int state)1073     public String convert_state_2_str(int state) {
1074         switch (state) {
1075             case STATE_2:
1076                 return "Read WLC_CAP";
1077             case STATE_6:
1078                 return "Static WPT";
1079             case STATE_8:
1080                 return "Handle NEGO_WAIT?";
1081             case STATE_11:
1082                 return "Write WLCP_INFO";
1083             case STATE_12:
1084                 return "Read WLCL_CTL";
1085             case STATE_16:
1086                 return "Read confirmation?";
1087             case STATE_17:
1088                 return "Check WPT requested?";
1089             case STATE_21:
1090                 return "Handle WPT";
1091             case STATE_22:
1092                 return "Handle INFO_REQ?";
1093             case STATE_24:
1094                 return "Handle removal detection";
1095             case STATE_21_1:
1096                 return "Handle WPT time completed";
1097             case STATE_21_2:
1098                 return "Handle FOD detection/removal";
1099 
1100             default:
1101                 return "Unknown";
1102         }
1103     }
1104 }
1105