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