28import java.lang.ref.WeakReference;
29import java.nio.ByteOrder;
30import java.util.ArrayList;
32import java.util.Locale;
33import java.util.concurrent.atomic.AtomicBoolean;
35import org.direct_bt.AdapterStatusListener;
36import org.direct_bt.BDAddressAndType;
37import org.direct_bt.BDAddressType;
38import org.direct_bt.BTSecurityLevel;
39import org.direct_bt.BTDevice;
40import org.direct_bt.BTException;
41import org.direct_bt.BTGattChar;
42import org.direct_bt.BTGattService;
43import org.direct_bt.BTRole;
44import org.direct_bt.EInfoReport;
45import org.direct_bt.BTGattCharListener;
46import org.direct_bt.HCIStatusCode;
47import org.direct_bt.LE_PHYs;
48import org.direct_bt.PairingMode;
49import org.direct_bt.SMPIOCapability;
50import org.direct_bt.SMPIdentityResolvingKey;
51import org.direct_bt.SMPKeyBin;
52import org.direct_bt.SMPKeyMask;
53import org.direct_bt.SMPLinkKey;
54import org.direct_bt.SMPLongTermKey;
55import org.direct_bt.SMPPairingState;
56import org.direct_bt.SMPSignatureResolvingKey;
57import org.jau.io.PrintUtil;
58import org.jau.net.EUI48;
65 private final WeakReference<DBTAdapter> wbr_adapter;
69 private final long ts_creation;
70 volatile long ts_last_discovery;
71 volatile long ts_last_update;
72 volatile short hciConnHandle;
73 private volatile String name_cached;
74 final List<WeakReference<DBTGattService>> serviceCache =
new ArrayList<WeakReference<DBTGattService>>();
79 private final AtomicBoolean isClosing =
new AtomicBoolean(
false);
81 final AtomicBoolean isConnected =
new AtomicBoolean(
false);
84 final byte byteAddress[],
85 final byte byteAddressType,
86 final long ts_creation,
final String name)
88 super(nativeInstance, compHash(java.util.Arrays.hashCode(byteAddress), 31+byteAddressType));
89 this.wbr_adapter =
new WeakReference<DBTAdapter>(adptr);
90 this.visibleAddressAndType =
new BDAddressAndType(byteAddress, 0, byteAddressType);
93 throw new IllegalArgumentException(
"Unsupported given native addresstype "+byteAddressType);
95 this.ts_creation = ts_creation;
96 ts_last_discovery = ts_creation;
97 ts_last_update = ts_creation;
104 void updateAddress() {
105 final byte byteAddress[] = getAddressImpl();
106 final byte byteAddressType = getAddressTypeImpl();
107 if(
null != byteAddress && 0 != byteAddressType ) {
111 private native
byte[] getAddressImpl();
112 private native
byte getAddressTypeImpl();
119 if( !isClosing.compareAndSet(
false,
true) ) {
126 a.removeDiscoveredDevice(
this);
147 private native
byte getRoleImpl();
155 if (obj ==
null || !(obj instanceof
DBTDevice)) {
159 return addressAndType.
equals(other.addressAndType) ||
160 visibleAddressAndType.
equals(other.visibleAddressAndType);
174 final String v = getNameImpl();
179 private native String getNameImpl();
183 synchronized(serviceCache) {
184 if( !checkServiceCache(
true) ) {
187 for(
int srvIdx = serviceCache.size() - 1; srvIdx >= 0; srvIdx-- ) {
189 if(
null == service ) {
190 serviceCache.remove(srvIdx);
193 if( service.
getUUID().equals(service_uuid) ) {
212 synchronized(serviceCache) {
213 if( !checkServiceCache(
true) ) {
216 for(
int srvIdx = serviceCache.size() - 1; srvIdx >= 0; srvIdx-- ) {
219 serviceCache.remove(srvIdx);
233 private native
void initImpl();
239 return getAdapter().addStatusListenerImpl(
this, l);
244 return getAdapter().removeStatusListenerImpl(l);
258 final byte[] t = { resTx[0].
mask };
259 final byte[] r = { resRx[0].
mask };
265 private native
byte getConnectedLE_PHYImpl(
byte[] resTx,
byte[] resRx);
271 private native
byte setConnectedLE_PHYImpl(
final byte Tx,
final byte Rx);
275 return new LE_PHYs( getTxPhysImpl() );
277 private native
byte getTxPhysImpl();
281 return new LE_PHYs( getRxPhysImpl() );
283 private native
byte getRxPhysImpl();
287 if( isConnected.get() ) {
292 private native
byte disconnectImpl();
307 if( !isConnected.get() ) {
312 private native
byte connectDefaultImpl();
316 final short conn_interval_min,
final short conn_interval_max,
317 final short conn_latency,
final short timeout) {
318 if( !isConnected.get() ) {
320 if( 0 > le_scan_interval || 0 > le_scan_window || 0 > conn_interval_min ||
321 0 > conn_interval_max || 0 > conn_latency || 0 > timeout ) {
324 return HCIStatusCode.
get( connectLEImpl1(le_scan_interval, le_scan_window, conn_interval_min, conn_interval_max, conn_latency, timeout) );
329 private native
byte connectLEImpl0();
330 private native
byte connectLEImpl1(
final short le_scan_interval,
final short le_scan_window,
331 final short conn_interval_min,
final short conn_interval_max,
332 final short conn_latency,
final short timeout);
338 return new SMPKeyMask(getAvailableSMPKeysImpl(responder));
340 private final native
byte getAvailableSMPKeysImpl(
final boolean responder);
346 PrintUtil.fprintf_td(System.err,
"BTDevice::setSMPKeyBin(): Apply SMPKeyBin failed, device invalid: %s, %s",
371 PrintUtil.fprintf_td(System.err,
"BTDevice::setSMPKeyBin(): Apply SMPKeyBin failed, all invalid or sec level w/o LTK: %s, %s",
380 PrintUtil.fprintf_td(System.err,
"BTDevice::setSMPKeyBin(): Apply SMPKeyBin failed, local adapter role %s mismatch: %s, %s",
399 PrintUtil.println(System.err,
"BTDevice::setSMPKeyBin: Failure, device connected: "+
toString());
410 PrintUtil.println(System.err,
"BTDevice::setSMPKeyBin: Setting security failed: Device Connected/ing: "+bin.
toString()+
", "+
toString());
449 private final native
byte uploadKeysImpl();
469 getLongTermKeyImpl(responder, stream);
472 private final native
void getLongTermKeyImpl(
final boolean responder,
final byte[] sink);
478 setLongTermKeyImpl(stream);
480 private final native
void setLongTermKeyImpl(
final byte[] source);
485 getIdentityResolvingKeyImpl(responder, stream);
488 private final native
void getIdentityResolvingKeyImpl(
final boolean responder,
final byte[] sink);
494 setIdentityResolvingKeyImpl(stream);
496 private final native
void setIdentityResolvingKeyImpl(
final byte[] source);
501 getSignatureResolvingKeyImpl(responder, stream);
504 private final native
void getSignatureResolvingKeyImpl(
final boolean responder,
final byte[] sink);
510 setSignatureResolvingKeyImpl(stream);
512 private final native
void setSignatureResolvingKeyImpl(
final byte[] source);
517 getLinkKeyImpl(responder, stream);
520 private final native
void getLinkKeyImpl(
final boolean responder,
final byte[] sink);
526 setLinkKeyImpl(stream);
528 private final native
void setLinkKeyImpl(
final byte[] source);
534 private final native
byte unpairImpl();
540 private final native
byte getConnSecurityLevelImpl();
546 private final native
byte getConnIOCapabilityImpl();
550 return setConnSecurityImpl(sec_level.
value, io_cap.
value);
552 private final native
boolean setConnSecurityImpl(
final byte sec_level,
final byte io_cap);
556 return setConnSecurityAutoImpl( iocap_auto.
value );
558 private final native
boolean setConnSecurityAutoImpl(
final byte io_cap);
567 private native
byte setPairingPasskeyImpl(
final int passkey)
throws BTException;
573 private native
byte setPairingPasskeyNegativeImpl() throws
BTException;
579 private native
byte setPairingNumericComparisonImpl(
final boolean equal);
585 private native
byte getPairingModeImpl();
591 private native
byte getPairingStateImpl();
597 return "Device" +
"\u271D" +
"[address"+addressAndType+
", '"+name_cached+
598 "', connected["+isConnected.get()+
", 0x"+Integer.toHexString(hciConnHandle)+
"]]";
600 return toStringImpl();
602 private native String toStringImpl();
613 if(
DBTAdapter.PRINT_DEVICE_LISTS || DEBUG ) {
614 PrintUtil.fprintf_td(System.err,
"BTDevice::remove: %s",
toString());
619 private native
boolean removeImpl() throws
BTException;
622 public final
boolean isValid() {
return super.isNativeValid() ; }
628 List<BTGattService> services = getGattServicesImpl();
629 if(
null == services ) {
630 services =
new ArrayList<BTGattService>();
632 updateServiceCache(services);
634 }
catch (
final Throwable t) {
635 System.err.println(
"DBTDevice.getServices(): Caught "+t.getMessage()+
" on thread "+Thread.currentThread().toString()+
" on "+
toString());
640 return new ArrayList<BTGattService>();
642 private native List<BTGattService> getGattServicesImpl();
648 public native
boolean sendIndication(
final short char_value_handle,
final byte[] value);
653 return pingGATTImpl();
654 }
catch (
final Throwable t) {
655 System.err.println(
"DBTDevice.pingGATT(): Caught "+t.getMessage()+
" on thread "+Thread.currentThread().toString()+
" on "+
toString());
662 private native
boolean pingGATTImpl();
671 synchronized( eir_ ) {
676 private native
void getEIRImpl(
final EInfoReport eir);
680 synchronized( eir_ind_ ) {
681 getEIRIndImpl(eir_ind_);
685 private native
void getEIRIndImpl(
final EInfoReport eir);
689 synchronized( eir_scan_rsp_ ) {
690 getEIRScanRspImpl(eir_scan_rsp_);
691 return eir_scan_rsp_;
694 private native
void getEIRScanRspImpl(
final EInfoReport eir);
710 return addCharListenerImpl(listener,
null);
715 return addCharListenerImpl(listener, associatedCharacteristic);
730 final void clearServiceCache() {
731 synchronized(serviceCache) {
732 for(
int i = serviceCache.size() - 1; i >= 0; i-- ) {
733 serviceCache.get(i).clear();
734 serviceCache.remove(i);
738 private void updateServiceCache(
final List<BTGattService> services) {
739 synchronized(serviceCache) {
741 if(
null != services ) {
742 for(
final BTGattService service : services) {
743 serviceCache.add(
new WeakReference<DBTGattService>( (DBTGattService)service ) );
749 private final boolean checkServiceCache(
final boolean retrieveGattServices) {
750 synchronized(serviceCache) {
751 if( serviceCache.isEmpty() ) {
752 if( retrieveGattServices ) {
754 if( serviceCache.isEmpty() ) {
final void printDeviceLists()
Print the internally maintained BTDevice lists to stderr:
HCIStatusCode setPairingNumericComparison(final boolean equal)
Method sets the numeric comparison result, see PairingMode#NUMERIC_COMPARE_ini.
final EInfoReport getEIR()
Return the merged advertised EInfoReport for this remote device.
BDAddressAndType getVisibleAddressAndType()
Returns the devices' visible BDAddressAndType, i.e.
HCIStatusCode connectLE(final short le_scan_interval, final short le_scan_window, final short conn_interval_min, final short conn_interval_max, final short conn_latency, final short timeout)
Establish a HCI BDADDR_LE_PUBLIC or BDADDR_LE_RANDOM connection to this device.
SMPPairingState getPairingState()
Returns the current SMPPairingState.
final HCIStatusCode connectDefault()
jau.direct_bt: Establish a default HCI connection to this device, using certain default parameter.
final long getLastUpdateTimestamp()
Returns the timestamp in monotonic milliseconds when this device instance underlying data has been up...
final SMPLinkKey getLinkKey(final boolean responder)
Returns a copy of the Link Key (LK), valid after connection and SMP pairing has been completed.
native int getResponderSMPPassKey()
Returns the responder SMP passkey, ranging from [0..999999].
final HCIStatusCode disconnect()
jau.direct_bt: Disconnect the LE or BREDR peer's GATT and HCI connection.
final SMPIdentityResolvingKey getIdentityResolvingKey(final boolean responder)
Returns a copy of the Identity Resolving Key (IRK), valid after connection and SMP pairing has been c...
boolean addCharListener(final BTGattCharListener listener, final BTGattChar associatedCharacteristic)
Please use BTGattChar#addCharListener(BTGattCharListener) for clarity.
final SMPSignatureResolvingKey getSignatureResolvingKey(final boolean responder)
Returns a copy of the Signature Resolving Key (CSRK), valid after connection and SMP pairing has been...
final HCIStatusCode uploadKeys(final String smp_key_bin_path, final BTSecurityLevel req_min_level, final boolean verbose_)
Convenient combination of SMPKeyBin::read(), setSMPKeyBin() and uploadKeys() after validating given S...
final LE_PHYs getTxPhys()
Return the Tx LE_PHYs as notified via LE_PHY_UPDATE_COMPLETE or retrieved via getConnectedLE_PHY(LE_P...
HCIStatusCode setPairingPasskeyNegative()
Method replies with a negative passkey response, i.e.
HCIStatusCode getConnectedLE_PHY(final LE_PHYs[] resTx, final LE_PHYs[] resRx)
Request and return LE_PHYs bit for the given connection.
final BTRole getRole()
Return the fixed BTRole of this remote BTDevice.
boolean pingGATT()
Issues a GATT ping to the device, validating whether it is still reachable.
final long getCreationTimestamp()
Returns the timestamp in monotonic milliseconds when this device instance has been created,...
final HCIStatusCode uploadKeys(final SMPKeyBin bin, final BTSecurityLevel req_min_level)
Convenient combination of setSMPKeyBin() and uploadKeys() after validating given SMPKeyBin file and S...
BTGattChar findGattChar(final String char_uuid)
Find a BTGattChar by its char_uuid only.
final HCIStatusCode unpair()
Unpair this device from the adapter while staying connected.
String getName()
Returns the remote device name.
final boolean isValid()
Returns whether the device is valid, i.e.
BTGattService findGattService(final String service_uuid)
Find a BTGattService by its service_uuid.
native short getRSSI()
Returns Received Signal Strength Indicator (RSSI) in dBm with ±6 dB accuracy of device as recognized ...
final boolean setConnSecurityAuto(final SMPIOCapability iocap_auto)
Set automatic security negotiation of BTSecurityLevel and SMPIOCapability pairing mode.
List< BTGattService > getGattServices()
Returns a complete list of shared BTGattService available on this device, initially retrieved via GAT...
final HCIStatusCode uploadKeys()
Upload all set keys to the adapter for pre-pairing.
final BTSecurityLevel getConnSecurityLevel()
Return the BTSecurityLevel, determined when the connection is established.
final boolean setSMPKeyBin(final SMPKeyBin bin)
Copy all keys from the given SMPKeyBin into this BTDevice.
final long getLastDiscoveryTimestamp()
Returns the timestamp in monotonic milliseconds when this device instance has discovered or connected...
final String getResponderSMPPassKeyString()
Returns getResponderSMPPassKey() as a canonical string, e.g.
final void setIdentityResolvingKey(final SMPIdentityResolvingKey irk)
Sets the Identity Resolving Key (IRK) of this device for pre-paired encryption.
EInfoReport getEIRInd()
Return the latest advertised EInfoReport AD_IND variant for this remote device.
native boolean sendIndication(final short char_value_handle, final byte[] value)
Send an indication event consisting out of the given value representing the given characteristic valu...
final boolean getConnected()
Returns the connected state of the device.
BDAddressAndType getAddressAndType()
Returns the devices' unique EUI48 address and BDAddressType type tuple, might be its initially report...
native boolean removeCharListener(final BTGattCharListener l)
Remove the given BTGattCharListener from the listener list.
DBTAdapter getAdapter()
Returns the adapter on which this device was discovered or connected.
native void deleteImpl(long nativeInstance)
Deletes the native instance.Called via delete() and at this point this java reference has been remove...
final SMPLongTermKey getLongTermKey(final boolean responder)
Returns a copy of the long term key (LTK), valid after connection and SMP pairing has been completed.
native int removeAllAssociatedCharListener(final BTGattChar associatedCharacteristic)
Remove all BTGattCharListener from the list, which are associated to the given BTGattChar.
native int removeAllCharListener()
Remove all BTGattCharListener from the list.
void close()
Release the native memory associated with this object The object should not be used following a call ...
final boolean addStatusListener(final AdapterStatusListener l)
Add the given AdapterStatusListener to the list if not already present, listening only for events mat...
EInfoReport getEIRScanRsp()
Return the latest advertised EInfoReport AD_SCAN_RSP for this remote device.
boolean removeStatusListener(final AdapterStatusListener l)
Remove the given AdapterStatusListener from the list.
final void setLinkKey(final SMPLinkKey lk)
Sets the Link Key (LK) of this device for pre-paired encryption.
native short getTxPower()
Return Tx Power Level in dBm with ±6 dB accuracy of device as recognized at discovery and connect.
final SMPIOCapability getConnIOCapability()
Return the SMPIOCapability value, determined when the connection is established.
native boolean sendNotification(final short char_value_handle, final byte[] value)
Send a notification event consisting out of the given value representing the given characteristic val...
final void setSignatureResolvingKey(final SMPSignatureResolvingKey irk)
Sets the Signature Resolving Key (CSRK) of this device for pre-paired encryption.
BTGattChar findGattChar(final String service_uuid, final String char_uuid)
Find a BTGattChar by its service_uuid and char_uuid.
final boolean setConnSecurity(final BTSecurityLevel sec_level, final SMPIOCapability io_cap)
Sets the given BTSecurityLevel and SMPIOCapability used to connect to this device on the upcoming con...
final SMPKeyMask getAvailableSMPKeys(final boolean responder)
Returns the available SMPKeyMask.KeyType SMPKeyMask for the responder (LL slave) or initiator (LL mas...
final short getConnectionHandle()
Return the HCI connection handle to the LE or BREDR peer, zero if not connected.
final LE_PHYs getRxPhys()
Return the Rx LE_PHYs as notified via LE_PHY_UPDATE_COMPLETE or retrieved via getConnectedLE_PHY(LE_P...
final native boolean isConnSecurityAutoEnabled()
Returns true if automatic security negotiation has been enabled via setConnSecurityAuto(SMPIOCapabili...
boolean equals(final Object obj)
final void setLongTermKey(final SMPLongTermKey ltk)
Sets the Long Term Key (LTK) of this device for pre-paired encryption.
PairingMode getPairingMode()
Returns the current PairingMode used by the device.
HCIStatusCode setConnectedLE_PHY(final LE_PHYs Tx, final LE_PHYs Rx)
Sets preference of used LE_PHYs for the given connection.
boolean addCharListener(final BTGattCharListener listener)
Add the given BTGattCharListener to the listener list if not already present.
native boolean isPrePaired()
Returns true if this device has completed SMP pairing or keys are set via uploadKeys()
HCIStatusCode setPairingPasskey(final int passkey)
Method sets the given passkey entry, see PairingMode#PASSKEY_ENTRY_ini.
String getUUID()
Get the UUID of this service.
BTGattChar findGattChar(final String char_uuid)
Find a BTGattChar by its char_uuid.
static final boolean DEBUG
BTAdapter status listener for remote BTDevice discovery events: Added, updated and removed; as well a...
Unique Bluetooth EUI48 address and BDAddressType tuple.
final boolean equals(final Object obj)
If both types are of BDAddressAndType, it compares their EUI48 address and BDAddressType.
BTGattChar event listener for notification and indication events.
Collection of 'Extended Advertising Data' (EAD), 'Advertising Data' (AD) or 'Extended Inquiry Respons...
LE Transport PHY bit values (bitmask)
SMP Identity Resolving Key, used for platform agnostic persistence.
static final int byte_size
Size of the byte stream representation in bytes.
final void put(final byte[] sink, int pos)
Method transfers all bytes representing this instance into the given destination array at the given p...
Storage for SMP keys including required connection parameter per local adapter and remote device.
static SMPKeyBin read(final String fname, final boolean verbose_)
Create a new SMPKeyBin instance based upon stored file denoted by fname.
final boolean hasIRKInit()
final BDAddressAndType getRemoteAddrAndType()
Return the remote device address.
final BDAddressAndType getLocalAddrAndType()
Return the local adapter address.
final boolean hasLKResp()
final SMPLongTermKey getLTKResp()
final boolean hasCSRKResp()
final SMPSignatureResolvingKey getCSRKResp()
final boolean hasLTKResp()
final boolean hasLKInit()
final boolean hasLTKInit()
final SMPSignatureResolvingKey getCSRKInit()
final BTRole getLocalRole()
Return the local adapter BTRole.
final SMPLinkKey getLKInit()
final SMPLinkKey getLKResp()
final BTSecurityLevel getSecLevel()
final SMPIdentityResolvingKey getIRKResp()
final SMPLongTermKey getLTKInit()
final boolean hasCSRKInit()
final SMPIdentityResolvingKey getIRKInit()
final boolean hasIRKResp()
SMP Key Type for Distribution, indicates keys distributed in the Transport Specific Key Distribution ...
Local SMP Link Key, used for platform agnostic persistence, mapping to platform specific link keys fo...
static final int byte_size
Size of the byte stream representation in bytes.
final void put(final byte[] sink, int pos)
Method transfers all bytes representing this instance into the given destination array at the given p...
SMP Long Term Key, used for platform agnostic persistence.
static final int byte_size
Size of the byte stream representation in bytes (28)
final void put(final byte[] sink, int pos)
Method transfers all bytes representing this instance into the given destination array at the given p...
SMP Signature Resolving Key, used for platform agnostic persistence.
final void put(final byte[] sink, int pos)
Method transfers all bytes representing this instance into the given destination array at the given p...
static final int byte_size
Size of the byte stream representation in bytes.
Bluetooth address type constants.
BDADDR_UNDEFINED
Undefined.
Bluetooth roles from the perspective of the link layer (connection initiator).
static BTRole get(final String name)
Maps the specified name to a constant of BTRole.
final BTRole reverse()
Returns reversed roled.
Bluetooth Security Level.
NONE
No encryption and no authentication.
ENC_ONLY
Encryption and no authentication (no MITM).
static BTSecurityLevel get(final String name)
Maps the specified name to a constant of BTSecurityLevel.
BT Core Spec v5.2: Vol 1, Part F Controller Error Codes: 1.3 List of Error Codes.
CONNECTION_TERMINATED_BY_LOCAL_HOST
static HCIStatusCode get(final String name)
Maps the specified name to a constant of HCIStatusCode.
CONNECTION_ALREADY_EXISTS
Each enum represents a 'LE Transport PHY' bit value.
Bluetooth secure pairing mode.
static PairingMode get(final String name)
Maps the specified name to a constant of PairingMode.
NO_INPUT_NO_OUTPUT
No input not output, value 3.
static SMPIOCapability get(final String name)
Maps the specified name to a constant of SMPIOCapability.
SMP Pairing Process state definition.
static SMPPairingState get(final String name)
Maps the specified name to a constant of SMPPairingState.
BTDevice represents one remote Bluetooth device.
Representing a Gatt Characteristic object from the GATT client perspective.
Representing a Gatt Service object from the GATT client perspective.
BTGattChar findGattChar(String char_uuid)
Find a BTGattChar by its char_uuid.