Direct-BT v3.3.0-1-gc2d430c
Direct-BT - Direct Bluetooth Programming.
DBTAdapter.java
Go to the documentation of this file.
1/**
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2020 Gothel Software e.K.
4 * Copyright (c) 2020 ZAFENA AB
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26package jau.direct_bt;
27
28import java.lang.ref.WeakReference;
29import java.nio.ByteOrder;
30import java.util.ArrayList;
31import java.util.Iterator;
32import java.util.List;
33import java.util.concurrent.atomic.AtomicBoolean;
34import java.util.concurrent.atomic.AtomicInteger;
35import java.util.concurrent.atomic.AtomicReference;
36
37import org.direct_bt.AdapterSettings;
38import org.direct_bt.AdapterStatusListener;
39import org.direct_bt.BDAddressAndType;
40import org.direct_bt.BDAddressType;
41import org.direct_bt.BTAdapter;
42import org.direct_bt.BTDevice;
43import org.direct_bt.BTException;
44import org.direct_bt.BTManager;
45import org.direct_bt.BTMode;
46import org.direct_bt.BTRole;
47import org.direct_bt.BTSecurityLevel;
48import org.direct_bt.DBGattServer;
49import org.direct_bt.DiscoveryPolicy;
50import org.direct_bt.EIRDataTypeSet;
51import org.direct_bt.EInfoReport;
52import org.direct_bt.HCIStatusCode;
53import org.direct_bt.HCIWhitelistConnectType;
54import org.direct_bt.LE_Features;
55import org.direct_bt.LE_PHYs;
56import org.direct_bt.PairingMode;
57import org.direct_bt.SMPIOCapability;
58import org.direct_bt.SMPPairingState;
59import org.direct_bt.ScanType;
60import org.jau.io.PrintUtil;
61import org.jau.net.EUI48;
62
63public class DBTAdapter extends DBTObject implements BTAdapter
64{
65 private static final boolean DEBUG = DBTManager.DEBUG;
66 /* pp */ static final boolean PRINT_DEVICE_LISTS = false;
67
68 private static AtomicInteger globThreadID = new AtomicInteger(0);
69 private static int discoverTimeoutMS = 100;
70
71 private final int dev_id;
72 /**
73 * The adapter's initially reported address by the system, which always reflects its public address, i.e. BDAddressType::BDADDR_LE_PUBLIC.
74 */
75 private final BDAddressAndType addressAndType;
76 private String name_cached;
77 /**
78 * Either the adapter's initially reported public address or a random address setup via HCI before scanning / discovery.
79 */
80 private final BDAddressAndType visibleAddressAndType;
81
82 private final Object discoveryLock = new Object();
83 private final Object discoveredDevicesLock = new Object();
84
85 private final AtomicBoolean isClosing = new AtomicBoolean(false);
86
87 private final AtomicBoolean powered_state = new AtomicBoolean(false); // AdapterSettings
88
89 private final AtomicReference<ScanType> currentMetaScanType = new AtomicReference<ScanType>(ScanType.NONE); // AdapterStatusListener and powerdOff
90
91 private final List<WeakReference<BTDevice>> discoveredDevices = new ArrayList<WeakReference<BTDevice>>();
92
93 private DBGattServer gattServerData = null;
94
95 /* pp */ DBTAdapter(final long nativeInstance,
96 final byte byteAddress[/*6*/],
97 final byte byteAddressType,
98 final String name, final int dev_id)
99 {
100 super(nativeInstance, compHash(java.util.Arrays.hashCode(byteAddress), 31+byteAddressType));
101 this.dev_id = dev_id;
102 this.addressAndType = new BDAddressAndType(byteAddress, 0, byteAddressType);
103 this.name_cached = name;
104 this.visibleAddressAndType = addressAndType;
105 addStatusListener(this.statusListener);
106 }
107
108 @Override
109 public final BTManager getManager() { return DBTManager.getManager(); }
110
111 @Override
112 public final BTRole getRole() {
113 return BTRole.get(getRoleImpl());
114 }
115 private native byte getRoleImpl();
116
117 @Override
118 public final BTMode getBTMode() {
119 return BTMode.get(getBTModeImpl());
120 }
121 private native byte getBTModeImpl();
122
123 @Override
124 public final void close() {
126 if( !isValid() ) {
127 return;
128 }
129 if( !isClosing.compareAndSet(false, true) ) {
130 return;
131 }
132 // mute all listener first
133 removeAllStatusListenerImpl();
134
136
137 final List<BTDevice> devices = getDiscoveredDevices();
138 for(final Iterator<BTDevice> id = devices.iterator(); id.hasNext(); ) {
139 final DBTDevice d = (DBTDevice) id.next();
140 d.close();
141 }
142
143 // done in native dtor: removeDevicesImpl();
144
145 poweredOff();
146
147 mngr.removeAdapter(this); // remove this instance from manager
148
149 super.close();
150 }
151
152 private final void poweredOff() {
153 powered_state.set(false);
154 currentMetaScanType.set(ScanType.NONE);
155 }
156
157 @Override
158 public final boolean equals(final Object obj)
159 {
160 if(this == obj) {
161 return true;
162 }
163 if (obj == null || !(obj instanceof DBTAdapter)) {
164 return false;
165 }
166 final DBTAdapter other = (DBTAdapter)obj;
167 return dev_id == other.dev_id && addressAndType.equals(other.addressAndType);
168 }
169
170 @Override
171 public final BDAddressAndType getAddressAndType() { return addressAndType; }
172
173 @Override
174 public final BDAddressAndType getVisibleAddressAndType() { return visibleAddressAndType; }
175
176 @Override
177 public final int getDevID() { return dev_id; }
178
179 @Override
180 public final native int getBTMajorVersion();
181
182 @Override
183 public final String getName() {
184 if( !isValid() ) {
185 return name_cached;
186 } else {
187 final String v = getNameImpl();
188 name_cached = v;
189 return v;
190 }
191 }
192 private native String getNameImpl();
193
194 @Override
195 public final String getShortName() {
196 if( !isValid() ) {
197 return name_cached;
198 } else {
199 final String v = getShortNameImpl();
200 name_cached = v;
201 return v;
202 }
203 }
204 private native String getShortNameImpl();
205
206 @Override
207 public final HCIStatusCode setName(final String name, final String short_name) {
208 return HCIStatusCode.get( setNameImpl(name, short_name) );
209 }
210 private native byte setNameImpl(final String name, String short_name);
211
212 @Override
213 public final BTDevice find(final String name, final BDAddressAndType addressAndType, final long timeoutMS) {
214 return findDeviceInCache(name, addressAndType);
215 }
216
217 @Override
218 public final BTDevice find(final String name, final BDAddressAndType addressAndType) {
219 return find(name, addressAndType, 0);
220 }
221
222 @Override
223 public final boolean isDeviceWhitelisted(final BDAddressAndType addressAndType) { return isDeviceWhitelistedImpl(addressAndType.address.b, addressAndType.type.value); }
224 private final native boolean isDeviceWhitelistedImpl(final byte[] address, byte address_type);
225
226 @Override
227 public final boolean addDeviceToWhitelist(final BDAddressAndType addressAndType,
228 final HCIWhitelistConnectType ctype,
229 final short conn_interval_min, final short conn_interval_max,
230 final short conn_latency, final short timeout) {
231 return addDeviceToWhitelistImpl1(addressAndType.address.b, addressAndType.type.value, ctype.value,
232 conn_interval_min, conn_interval_max, conn_latency, timeout);
233 }
234 private final native boolean addDeviceToWhitelistImpl1(final byte[] address, final byte address_type, final int ctype,
235 final short conn_interval_min, final short conn_interval_max,
236 final short conn_latency, final short timeout);
237
238 @Override
239 public final boolean addDeviceToWhitelist(final BDAddressAndType addressAndType,
240 final HCIWhitelistConnectType ctype) {
241 return addDeviceToWhitelistImpl2(addressAndType.address.b, addressAndType.type.value, ctype.value);
242 }
243 private native boolean addDeviceToWhitelistImpl2(final byte[] address, final byte address_type, final int ctype);
244
245 @Override
246 public final boolean removeDeviceFromWhitelist(final BDAddressAndType addressAndType) {
247 return removeDeviceFromWhitelistImpl(addressAndType.address.b, addressAndType.type.value);
248 }
249 private native boolean removeDeviceFromWhitelistImpl(final byte[] address, final byte address_type);
250
251 /* Unsupported */
252
253 @Override
255 return currentMetaScanType.get();
256 }
257
258 @Override
259 public final boolean isDiscovering() {
260 return ScanType.NONE != currentMetaScanType.get();
261 }
262
263 @Override
265 return gattServerData;
266 }
267
268 @Override
269 public final String toString() {
270 if( !isValid() ) {
271 return "Adapter" + "\u271D" + "["+addressAndType+", '"+name_cached+"', id "+dev_id+"]";
272 }
273 return toStringImpl();
274 }
275
276 /* Native callbacks */
277
278 /* Native functionality / properties */
279
280 private native String toStringImpl();
281
282 @Override
283 public final native boolean setPowered(final boolean power_on);
284
285 @Override
286 public final HCIStatusCode setPrivacy(final boolean enable) {
287 return HCIStatusCode.get( setPrivacyImpl( enable ) );
288 }
289 private native byte setPrivacyImpl(boolean enable);
290
291 @Override
292 public final native boolean getSecureConnectionsEnabled();
293
294 @Override
295 public final HCIStatusCode setSecureConnections(final boolean enable) {
296 return HCIStatusCode.get( setSecureConnectionsImpl(enable) );
297 }
298 private native byte setSecureConnectionsImpl(final boolean enable);
299
300 @Override
301 public final HCIStatusCode setDefaultConnParam(final short conn_interval_min, final short conn_interval_max,
302 final short conn_latency, final short supervision_timeout) {
303 return HCIStatusCode.get( setDefaultConnParamImpl(conn_interval_min, conn_interval_max,
304 conn_latency, supervision_timeout) );
305 }
306 private native byte setDefaultConnParamImpl(final short conn_interval_min, final short conn_interval_max,
307 final short conn_latency, final short supervision_timeout);
308
309 @Override
310 public final void setServerConnSecurity(final BTSecurityLevel sec_level, final SMPIOCapability io_cap) {
311 setServerConnSecurityImpl(sec_level.value, io_cap.value);
312 }
313 private final native void setServerConnSecurityImpl(final byte sec_level, final byte io_cap);
314
315 @Override
316 public final native void setSMPKeyPath(final String path);
317
318 @Override
319 public final HCIStatusCode initialize(final BTMode btMode, final boolean powerOn) {
320 return HCIStatusCode.get( initializeImpl(btMode.value, powerOn) );
321 }
322 private native byte initializeImpl(final byte btModeInt, final boolean powerOn);
323
324 @Override
325 public final native boolean isInitialized();
326
327 @Override
328 public final HCIStatusCode reset() {
329 return HCIStatusCode.get( resetImpl() );
330 }
331 private native byte resetImpl();
332
333 @Override
334 public final HCIStatusCode setDefaultLE_PHY(final LE_PHYs Tx, final LE_PHYs Rx) {
335 return HCIStatusCode.get( setDefaultLE_PHYImpl(Tx.mask, Rx.mask) );
336 }
337 private native byte setDefaultLE_PHYImpl(final byte Tx, final byte Rx);
338
339 @Override
340 public final BTDevice connectDevice(final BDAddressAndType addressAndType) {
341 return connectDeviceImpl(addressAndType.address.b, addressAndType.type.value);
342 }
343 private native BTDevice connectDeviceImpl(byte[] address, byte addressType);
344
345 @Override
346 public final boolean getPoweredState() { return powered_state.get(); }
347
348 @Override
349 public final boolean isPowered() { return isValid() && isPoweredImpl(); }
350 private native boolean isPoweredImpl();
351
352 @Override
353 public final boolean isSuspended() { return isValid() && isSuspendedImpl(); }
354 private native boolean isSuspendedImpl();
355
356 @Override
357 public final boolean isValid() { return super.isNativeValid() && isValidImpl(); }
358 private native boolean isValidImpl();
359
360 @Override
361 public final LE_Features getLEFeatures() {
362 return new LE_Features( getLEFeaturesImpl() );
363 }
364 private native long getLEFeaturesImpl();
365
366 /* internal */
367
368 @Override
369 protected native void deleteImpl(long nativeInstance);
370
371 @Override
373 return startDiscovery(null, DiscoveryPolicy.PAUSE_CONNECTED_UNTIL_READY, true /* le_scan_active */, (short)24, (short)24, (byte)0, true /* filter_dup */);
374 }
375 @Override
376 public final HCIStatusCode startDiscovery(final DiscoveryPolicy policy, final boolean le_scan_active) throws BTException {
377 return startDiscovery(null, policy, le_scan_active, (short)24, (short)24, (byte)0, true /* filter_dup */);
378 }
379 @Override
380 public final HCIStatusCode startDiscovery(final DBGattServer gattServerData,
381 final DiscoveryPolicy policy, final boolean le_scan_active,
382 final short le_scan_interval, final short le_scan_window,
383 final byte filter_policy,
384 final boolean filter_dup) throws BTException {
385 synchronized( discoveryLock ) {
386 // Ignoring 'isDiscovering', as native implementation also handles change of 'keepAlive'.
387 // The discoveredDevices shall always get cleared.
388 removeDiscoveredDevicesImpl2j();
389 // event callbacks will be generated by implementation
390 final HCIStatusCode res = HCIStatusCode.get(
391 startDiscoveryImpl(gattServerData, policy.value, le_scan_active, le_scan_interval, le_scan_window, filter_policy, filter_dup) );
392 if( PRINT_DEVICE_LISTS || DEBUG ) {
393 PrintUtil.fprintf_td(System.err, "BTAdapter::startDiscovery: res %s, %s", res, toString());
395 }
396 return res;
397 }
398 }
399 private native byte startDiscoveryImpl(final DBGattServer gattServerData,
400 final byte policy, final boolean le_scan_active,
401 final short le_scan_interval, final short le_scan_window,
402 final byte filter_policy,
403 final boolean filter_dup) throws BTException;
404
405 @Override
407 synchronized( discoveryLock ) {
408 // Ignoring 'isDiscovering', be consistent with startDiscovery
409 final HCIStatusCode res = HCIStatusCode.get( stopDiscoveryImpl() ); // event callbacks will be generated by implementation
410 if( PRINT_DEVICE_LISTS || DEBUG ) {
411 PrintUtil.fprintf_td(System.err, "BTAdapter::stopDiscovery: res %s, %s", res, toString());
413 }
414 return res;
415 }
416 }
417 private native byte stopDiscoveryImpl() throws BTException;
418
419 @Override
421 return DiscoveryPolicy.get( getCurrentDiscoveryPolicyImpl() );
422 }
423 private native byte getCurrentDiscoveryPolicyImpl();
424
425 @Override
426 public final native boolean removeDevicePausingDiscovery(final BTDevice device);
427
428 // std::vector<std::shared_ptr<direct_bt::HCIDevice>> discoveredDevices = adapter.getDiscoveredDevices();
429 private native List<BTDevice> getDiscoveredDevicesImpl();
430
431 @Override
432 public final int removeDiscoveredDevices() throws BTException {
433 final int cj = removeDiscoveredDevicesImpl2j();
434 final int cn = removeDiscoveredDevicesImpl1();
435 if( DEBUG ) {
436 if( cj != cn ) {
437 PrintUtil.println(System.err, "DBTAdapter::removeDevices: Unexpected discovered device count: Native "+cn+", callback "+cj);
438 }
439 }
440 return cn;
441 }
442 private native int removeDiscoveredDevicesImpl1() throws BTException;
443 private int removeDiscoveredDevicesImpl2j() {
444 synchronized(discoveredDevicesLock) {
445 final int n = discoveredDevices.size();
446 discoveredDevices.clear();
447 return n;
448 }
449 }
450 /* pp */ final boolean removeDiscoveredDevice(final BTDevice device) {
451 return removeDiscoveredDeviceImpl2j( device.getAddressAndType() );
452 }
453
454 @Override
455 public final boolean removeDiscoveredDevice(final BDAddressAndType addressAndType) {
456 final boolean cj = removeDiscoveredDeviceImpl2j(addressAndType);
457 final boolean cn = removeDiscoveredDeviceImpl1(addressAndType.address.b, addressAndType.type.value);
458 if( DEBUG ) {
459 if( cj != cn ) {
460 PrintUtil.println(System.err, "DBTAdapter::removeDevices("+addressAndType+"): Unexpected discovered device count: Native "+cn+", callback "+cj);
461 }
462 }
463 return cn;
464 }
465 private native boolean removeDiscoveredDeviceImpl1(final byte[] address, final byte addressType);
466
467 private boolean removeDiscoveredDeviceImpl2j(final BDAddressAndType addressAndType) {
468 synchronized(discoveredDevicesLock) {
469 for(final Iterator<WeakReference<BTDevice>> it = discoveredDevices.iterator(); it.hasNext();) {
470 final BTDevice d = it.next().get();
471 if( null == d ) {
472 it.remove();
473 } else if( d.getAddressAndType().equals(addressAndType) ) {
474 it.remove();
475 return true;
476 }
477 }
478 }
479 return false;
480 }
481 @Override
482 public final List<BTDevice> getDiscoveredDevices() {
483 final ArrayList<BTDevice> res = new ArrayList<BTDevice>();
484 synchronized(discoveredDevicesLock) {
485 for(final Iterator<WeakReference<BTDevice>> it = discoveredDevices.iterator(); it.hasNext();) {
486 final BTDevice d = it.next().get();
487 if( null == d ) {
488 it.remove();
489 } else {
490 res.add(d);
491 }
492 }
493 }
494 return res;
495 }
496 private final void cleanDiscoveredDevice() {
497 synchronized(discoveredDevicesLock) {
498 for(final Iterator<WeakReference<BTDevice>> it = discoveredDevices.iterator(); it.hasNext();) {
499 final BTDevice d = it.next().get();
500 if( null == d ) {
501 it.remove();
502 }
503 }
504 }
505 }
506
507 @Override
508 public final boolean addStatusListener(final AdapterStatusListener l) {
509 final boolean added = addStatusListenerImpl(null, l);
510 if( PRINT_DEVICE_LISTS || DEBUG ) {
511 PrintUtil.fprintf_td(System.err, "BTAdapter::addStatusListener: added %b, %s", added, toString());
513 }
514 return added;
515 }
516 /* pp */ native boolean addStatusListenerImpl(final BTDevice deviceOwnerAndMatch, final AdapterStatusListener l);
517
518 @Override
519 public final boolean removeStatusListener(final AdapterStatusListener l) {
520 boolean res = false;
521 if( !isClosing.get() ) {
522 res = removeStatusListenerImpl(l);
523 }
524 if( PRINT_DEVICE_LISTS || DEBUG ) {
525 PrintUtil.fprintf_td(System.err, "BTAdapter::removeStatusListener: removed %b, %s", res, toString());
527 }
528 return res;
529 }
530 /* pp */ native boolean removeStatusListenerImpl(final AdapterStatusListener l);
531
532 @Override
533 public final int removeAllStatusListener() {
534 final int r = removeAllStatusListenerImpl();
535 addStatusListener(this.statusListener); // preserve internal listener to maintain functionality!
536 return r - 1;
537 }
538 private native int removeAllStatusListenerImpl();
539
540 @Override
541 public final void printDeviceLists() {
542 printDeviceListsImpl();
543 List<WeakReference<BTDevice>> _discoveredDevices;
544 synchronized(discoveredDevicesLock) {
545 // Shallow (but expensive) copy to avoid java.util.ConcurrentModificationException while iterating: debug mode only
546 _discoveredDevices = new ArrayList<WeakReference<BTDevice>>(discoveredDevices);
547 }
548 final int sz = _discoveredDevices.size();
549 PrintUtil.fprintf_td(System.err, "- BTAdapter::DiscoveredDevicesJ: %d elements%s", sz, System.lineSeparator());
550 int idx = 0;
551 for(final Iterator<WeakReference<BTDevice>> it = _discoveredDevices.iterator(); it.hasNext(); ++idx) {
552 final BTDevice d = it.next().get();
553 if( null == d ) {
554 PrintUtil.fprintf_td(System.err, " - %d / %d: nil%s", (idx+1), sz, System.lineSeparator());
555 } else {
556 PrintUtil.fprintf_td(System.err, " - %d / %d: %s, name '%s'%s", (idx+1), sz,
557 d.getAddressAndType().toString(), d.getName(), System.lineSeparator());
558 }
559 }
560 }
561 private final native void printDeviceListsImpl();
562
563 ////////////////////////////////////
564
565 private final AdapterStatusListener statusListener = new AdapterStatusListener() {
566 @Override
567 public void adapterSettingsChanged(final BTAdapter a, final AdapterSettings oldmask, final AdapterSettings newmask,
568 final AdapterSettings changedmask, final long timestamp) {
569 final boolean initialSetting = oldmask.isEmpty();
570 if( DEBUG ) {
571 if( initialSetting ) {
572 PrintUtil.println(System.err, "Adapter.StatusListener.SETTINGS: "+oldmask+" -> "+newmask+", initial "+changedmask+" on "+a);
573 } else {
574 PrintUtil.println(System.err, "Adapter.StatusListener.SETTINGS: "+oldmask+" -> "+newmask+", changed "+changedmask+" on "+a);
575 }
576 }
577 if( initialSetting ) {
578 powered_state.set( newmask.isSet(AdapterSettings.SettingType.POWERED) );
579 return;
580 }
581 if( changedmask.isSet(AdapterSettings.SettingType.POWERED) ) {
582 final boolean _isPowered = newmask.isSet(AdapterSettings.SettingType.POWERED);
583 if( powered_state.compareAndSet(!_isPowered, _isPowered) ) {
584 if( !_isPowered ) {
585 poweredOff();
586 }
587 }
588 }
589 }
590 @Override
591 public void discoveringChanged(final BTAdapter adapter, final ScanType currentMeta, final ScanType changedType, final boolean changedEnabled, final DiscoveryPolicy policy, final long timestamp) {
592 if( DEBUG ) {
593 PrintUtil.println(System.err, "Adapter.StatusListener.DISCOVERING: meta "+currentMeta+", changed["+changedType+", enabled "+changedEnabled+", keepAlive "+policy+"] on "+adapter);
594 }
595 // meta ignores changes on temp disabled discovery
596 currentMetaScanType.set(currentMeta);
597 }
598 @Override
599 public boolean deviceFound(final BTDevice device, final long timestamp) {
600 synchronized(discoveredDevicesLock) {
601 cleanDiscoveredDevice();
602 discoveredDevices.add(new WeakReference<BTDevice>(device));
603 }
604 if( PRINT_DEVICE_LISTS || DEBUG ) {
605 PrintUtil.println(System.err, "Adapter.FOUND: discoveredDevices "+ discoveredDevices.size() + ": "+device+", on "+device.getAdapter());
606 }
607 return false;
608 }
609
610 @Override
611 public void deviceUpdated(final BTDevice device, final EIRDataTypeSet updateMask, final long timestamp) {
612 if( updateMask.isSet( EIRDataTypeSet.DataType.BDADDR ) ) {
613 ((DBTDevice)device).updateAddress();
614 }
615
616 final boolean rssiUpdated = updateMask.isSet( EIRDataTypeSet.DataType.RSSI );
617 final boolean mdUpdated = updateMask.isSet( EIRDataTypeSet.DataType.MANUF_DATA );
618 if( DEBUG && !rssiUpdated && !mdUpdated && 0 != updateMask.get(EIRDataTypeSet.EIR_DATA_TYPE_MASK) ) {
619 PrintUtil.println(System.err, "Adapter.UPDATED: "+updateMask+" of "+device+" on "+device.getAdapter());
620 }
621 // nop on discoveredDevices
622 }
623
624 @Override
625 public void deviceConnected(final BTDevice device, final boolean discovered, final long timestamp) {
626 if( DEBUG ) {
627 PrintUtil.println(System.err, "Adapter.CONNECTED (discovered "+discovered+"): "+device+" on "+device.getAdapter());
628 }
629 final DBTDevice device_ = (DBTDevice)device;
630 if( device_.isConnected.compareAndSet(false, true) ) {
631 // nop
632 }
633 }
634
635 @Override
636 public void devicePairingState(final BTDevice device, final SMPPairingState state, final PairingMode mode, final long timestamp) {
637 if( DEBUG ) {
638 PrintUtil.println(System.err, "Adapter.PAIRING_STATE: state "+state+", mode "+mode+": "+device);
639 }
640 }
641
642 @Override
643 public void deviceReady(final BTDevice device, final long timestamp) {
644 if( DEBUG ) {
645 PrintUtil.println(System.err, "Adapter.READY: "+device);
646 }
647 }
648
649 @Override
650 public void deviceDisconnected(final BTDevice device, final HCIStatusCode reason, final short handle, final long timestamp) {
651 if( DEBUG ) {
652 PrintUtil.println(System.err, "Adapter.DISCONNECTED: Reason "+reason+", old handle 0x"+Integer.toHexString(handle)+": "+device+" on "+device.getAdapter());
653 }
654 gattServerData = null;
655
656 final DBTDevice device_ = (DBTDevice)device;
657 if( device_.isConnected.compareAndSet(true, false) ) {
658 device_.clearServiceCache();
659 }
660 }
661
662 @Override
663 public String toString() {
664 return "AdapterStatusListener[adapter "+addressAndType.toString()+"]";
665 }
666
667 };
668
669 /* pp */ DBTDevice findDeviceInCache(final String name, final BDAddressAndType addressAndType) {
670 synchronized(discoveredDevicesLock) {
671 cleanDiscoveredDevice();
672
673 if( null == name && null == addressAndType ) {
674 // special case for 1st valid device
675 if( discoveredDevices.size() > 0 ) {
676 return (DBTDevice) discoveredDevices.get(0).get();
677 }
678 return null; // no device
679 }
680 for(int devIdx = discoveredDevices.size() - 1; devIdx >= 0; devIdx-- ) {
681 final DBTDevice device = (DBTDevice) discoveredDevices.get(devIdx).get();
682 if( null != name && null != addressAndType &&
683 device.getName().equals(name) &&
684 device.getAddressAndType().equals(addressAndType)
685 )
686 {
687 return device;
688 }
689 if( null != addressAndType &&
690 device.getAddressAndType().equals(addressAndType)
691 )
692 {
693 return device;
694 }
695 if( null != name &&
696 device.getName().equals(name)
697 )
698 {
699 return device;
700 }
701 }
702 return null;
703 }
704 }
705
706 @Override
707 public final HCIStatusCode startAdvertising(final DBGattServer gattServerData_,
708 final EInfoReport eir,
709 final EIRDataTypeSet adv_mask,
710 final EIRDataTypeSet scanrsp_mask,
711 final short adv_interval_min, final short adv_interval_max,
712 final byte adv_type, final byte adv_chan_map, final byte filter_policy) {
713 final HCIStatusCode res = HCIStatusCode.get( startAdvertising1Impl(gattServerData_, eir, adv_mask.mask, scanrsp_mask.mask,
714 adv_interval_min, adv_interval_max, adv_type, adv_chan_map, filter_policy) );
715 if( HCIStatusCode.SUCCESS == res ) {
716 gattServerData = gattServerData_;
717 }
718 return res;
719 }
720 private native byte startAdvertising1Impl(final DBGattServer gattServerData,
721 final EInfoReport eir,
722 final int adv_mask,
723 final int scanrsp_mask,
724 final short adv_interval_min, final short adv_interval_max,
725 final byte adv_type, final byte adv_chan_map, final byte filter_policy);
726
727 @Override
728 public final HCIStatusCode startAdvertising(final DBGattServer gattServerData_, final short adv_interval_min,
729 final short adv_interval_max, final byte adv_type, final byte adv_chan_map,
730 final byte filter_policy) {
731 final HCIStatusCode res = HCIStatusCode.get( startAdvertising2Impl(gattServerData_, adv_interval_min, adv_interval_max, adv_type, adv_chan_map, filter_policy) );
732 if( HCIStatusCode.SUCCESS == res ) {
733 gattServerData = gattServerData_;
734 }
735 return res;
736 }
737 private native byte startAdvertising2Impl(final DBGattServer gattServerData, final short adv_interval_min,
738 final short adv_interval_max, final byte adv_type, final byte adv_chan_map,
739 final byte filter_policy);
740
741 @Override
742 public final HCIStatusCode startAdvertising(final DBGattServer gattServerData) {
743 return startAdvertising(gattServerData, (short)640, (short)640, (byte)0, // AD_PDU_Type::ADV_IND,
744 (byte)0x07, (byte)0x00);
745 }
746
747 @Override
749 return HCIStatusCode.get( stopAdvertisingImpl() );
750 }
751 private native byte stopAdvertisingImpl();
752
753 @Override
754 public native boolean isAdvertising();
755
756}
final boolean isSuspended()
Returns whether the adapter is suspended, i.e.
final boolean equals(final Object obj)
final LE_Features getLEFeatures()
Return LE_Features for this controller.
final HCIStatusCode startDiscovery(final DiscoveryPolicy policy, final boolean le_scan_active)
Starts discovery using default arguments, see startDiscovery(DiscoveryPolicy, boolean,...
final HCIStatusCode startAdvertising(final DBGattServer gattServerData)
Starts advertising using all default arguments, see startAdvertising(short, short,...
final HCIStatusCode startDiscovery()
Starts discovery using all default arguments, see startDiscovery(DiscoveryPolicy, boolean,...
final int removeAllStatusListener()
Remove all AdapterStatusListener from the list.
final HCIStatusCode stopDiscovery()
Turns off device discovery if it is enabled.
final HCIStatusCode initialize(final BTMode btMode, final boolean powerOn)
Initialize the adapter with default values, including power-on.
final HCIStatusCode setDefaultConnParam(final short conn_interval_min, final short conn_interval_max, final short conn_latency, final short supervision_timeout)
Set default connection parameter of incoming connections for this adapter when in server mode,...
final BTDevice find(final String name, final BDAddressAndType addressAndType)
Find a BluetoothDevice.
final ScanType getCurrentScanType()
Returns the current meta discovering ScanType.
native void deleteImpl(long nativeInstance)
Deletes the native instance.
final boolean addDeviceToWhitelist(final BDAddressAndType addressAndType, final HCIWhitelistConnectType ctype)
Add the given device to the adapter's autoconnect whitelist.
final void printDeviceLists()
Print the internally maintained BTDevice lists to stderr:
native boolean isAdvertising()
Returns the adapter's current advertising state.
final boolean addDeviceToWhitelist(final BDAddressAndType addressAndType, final HCIWhitelistConnectType ctype, final short conn_interval_min, final short conn_interval_max, final short conn_latency, final short timeout)
Add the given device to the adapter's autoconnect whitelist.
final boolean removeStatusListener(final AdapterStatusListener l)
Remove the given AdapterStatusListener from the list.
final String toString()
final String getName()
Returns the name.
final boolean isValid()
Returns whether the adapter is valid, i.e.
final int getDevID()
Returns the BluetoothAdapter's internal temporary device id.
final native boolean isInitialized()
Returns true, if initialize(BTMode) has already been called for this adapter, otherwise false.
final HCIStatusCode startAdvertising(final DBGattServer gattServerData_, final EInfoReport eir, final EIRDataTypeSet adv_mask, final EIRDataTypeSet scanrsp_mask, final short adv_interval_min, final short adv_interval_max, final byte adv_type, final byte adv_chan_map, final byte filter_policy)
Starts advertising.
final void setServerConnSecurity(final BTSecurityLevel sec_level, final SMPIOCapability io_cap)
Sets the given ::BTSecurityLevel and ::SMPIOCapability for connecting device when in server (peripher...
final HCIStatusCode stopAdvertising()
Ends advertising.
final HCIStatusCode setPrivacy(final boolean enable)
Toggle adapter privacy address mode, i.e.
final BDAddressAndType getVisibleAddressAndType()
Returns the adapter's currently visible BDAddressAndType.
final List< BTDevice > getDiscoveredDevices()
Returns a list of discovered BluetoothDevices from this adapter.
final HCIStatusCode setSecureConnections(final boolean enable)
Enable or disable Secure Connections (SC) of the adapter.
final native boolean removeDevicePausingDiscovery(final BTDevice device)
Manual DiscoveryPolicy intervention point, allowing user to remove the ready device from the queue of...
final boolean isPowered()
Returns whether the adapter is valid, plugged in and powered.
final HCIStatusCode startDiscovery(final DBGattServer gattServerData, final DiscoveryPolicy policy, final boolean le_scan_active, final short le_scan_interval, final short le_scan_window, final byte filter_policy, final boolean filter_dup)
Starts discovery.
final int removeDiscoveredDevices()
Remove all the discovered devices found on this adapter.
final BTMode getBTMode()
Returns the current BTMode of this adapter.
final DBGattServer getGATTServerData()
Return the user's DBGattServer shared reference if in BTRole#Slave mode as set via and valid until su...
final boolean addStatusListener(final AdapterStatusListener l)
Add the given AdapterStatusListener to the list if not already present.
final native void setSMPKeyPath(final String path)
Set the adapter's persistent storage directory for SMPKeyBin files.
final HCIStatusCode startAdvertising(final DBGattServer gattServerData_, final short adv_interval_min, final short adv_interval_max, final byte adv_type, final byte adv_chan_map, final byte filter_policy)
Starts advertising.
final void close()
Release the native memory associated with this object The object should not be used following a call ...
final HCIStatusCode setDefaultLE_PHY(final LE_PHYs Tx, final LE_PHYs Rx)
Sets default preference of LE_PHYs.
final native boolean setPowered(final boolean power_on)
Sets the power state the adapter.
final boolean removeDeviceFromWhitelist(final BDAddressAndType addressAndType)
Remove the given device from the adapter's autoconnect whitelist.
final HCIStatusCode setName(final String name, final String short_name)
Sets the name and short-name.
final boolean getPoweredState()
Returns the power state the adapter.
final native boolean getSecureConnectionsEnabled()
Returns whether Secure Connections (SC) is enabled.
final String getShortName()
Returns the short name.
final DiscoveryPolicy getCurrentDiscoveryPolicy()
Return the current DiscoveryPolicy, set via startDiscovery(DiscoveryPolicy, boolean,...
final boolean isDeviceWhitelisted(final BDAddressAndType addressAndType)
Returns true, if the adapter's device is already whitelisted.
final BTRole getRole()
Return the current BTRole of this adapter.
final native int getBTMajorVersion()
Returns the Bluetooth major version of this adapter.
final boolean removeDiscoveredDevice(final BDAddressAndType addressAndType)
Discards matching discovered devices.
final boolean isDiscovering()
Returns true if the meta discovering state is not ScanType#NONE.
final BTDevice find(final String name, final BDAddressAndType addressAndType, final long timeoutMS)
Find a BluetoothDevice.
final BTManager getManager()
Returns the used singleton BTManager instance, used to create this adapter.
final HCIStatusCode reset()
Reset the adapter.
final BTDevice connectDevice(final BDAddressAndType addressAndType)
This method connects to device without need of performing General Discovery.
final BDAddressAndType getAddressAndType()
Returns the adapter's public BDAddressAndType.
void close()
Release the native memory associated with this object The object should not be used following a call ...
Definition: DBTDevice.java:115
static final boolean DEBUG
Definition: DBTManager.java:43
static final BTManager getManager()
Returns an instance of BluetoothManager, to be used instead of constructor.
Author: Sven Gothel sgothel@jausoft.com Copyright (c) 2020 Gothel Software e.K.
boolean isSet(final SettingType bit)
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.
Representing a complete list of Gatt Service objects from the GATT server perspective,...
Bit mask of 'Extended Inquiry Response' (EIR) data fields, indicating a set of related data.
Collection of 'Extended Advertising Data' (EAD), 'Advertising Data' (AD) or 'Extended Inquiry Respons...
LE Link Layer Feature Set (bitmask)
LE Transport PHY bit values (bitmask)
Definition: LE_PHYs.java:36
Bluetooth adapter operating mode.
Definition: BTMode.java:34
static BTMode get(final String name)
Maps the specified name to a constant of BTMode.
Definition: BTMode.java:57
final byte value
Definition: BTMode.java:44
Bluetooth roles from the perspective of the link layer (connection initiator).
Definition: BTRole.java:36
static BTRole get(final String name)
Maps the specified name to a constant of BTRole.
Definition: BTRole.java:57
Bluetooth Security Level.
Discovery policy defines the BTAdapter discovery mode after connecting a remote BTDevice:
static DiscoveryPolicy get(final byte value)
Maps the specified integer value to a constant of DiscoveryPolicy.
PAUSE_CONNECTED_UNTIL_READY
Pause discovery until all connected BTDevice reach readiness inclusive optional SMP pairing (~120ms) ...
BT Core Spec v5.2: Vol 1, Part F Controller Error Codes: 1.3 List of Error Codes.
static HCIStatusCode get(final String name)
Maps the specified name to a constant of HCIStatusCode.
SMP IO Capability value.
Meta ScanType as derived from BTMode with defined value mask consisting of BDAddressType bits.
Definition: ScanType.java:36
static ScanType get(final byte value)
Maps the specified integer value to a constant of ScanType.
Definition: ScanType.java:60
BTAdapter represents one local Bluetooth Controller.
Definition: BTAdapter.java:48
BTDevice represents one remote Bluetooth device.
Definition: BTDevice.java:47
String getName()
Returns the remote device name.
boolean remove()
Remove this device from the system (like an unpair).
BDAddressAndType getAddressAndType()
Returns the devices' unique EUI48 address and BDAddressType type tuple, might be its initially report...
A thread safe singleton handler of the BTAdapter manager, e.g.
Definition: BTManager.java:36