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