26import java.lang.reflect.InvocationTargetException;
27import java.nio.charset.StandardCharsets;
28import java.util.ArrayList;
29import java.util.Arrays;
30import java.util.Iterator;
33import org.direct_bt.AdapterSettings;
34import org.direct_bt.AdapterStatusListener;
35import org.direct_bt.BDAddressAndType;
36import org.direct_bt.BTMode;
37import org.direct_bt.BTSecurityLevel;
38import org.direct_bt.BTAdapter;
39import org.direct_bt.BTDevice;
40import org.direct_bt.BTException;
41import org.direct_bt.BTFactory;
42import org.direct_bt.BTManager;
43import org.direct_bt.BTSecurityRegistry;
44import org.direct_bt.BTUtils;
45import org.direct_bt.DBGattChar;
46import org.direct_bt.DBGattDesc;
47import org.direct_bt.DBGattServer;
48import org.direct_bt.DBGattService;
49import org.direct_bt.DBGattValue;
50import org.direct_bt.DiscoveryPolicy;
51import org.direct_bt.EIRDataTypeSet;
52import org.direct_bt.EInfoReport;
53import org.direct_bt.GAPFlags;
54import org.direct_bt.GattCharPropertySet;
55import org.direct_bt.HCIStatusCode;
56import org.direct_bt.LE_Features;
57import org.direct_bt.LE_PHYs;
58import org.direct_bt.PairingMode;
59import org.direct_bt.SMPIOCapability;
60import org.direct_bt.SMPPairingState;
61import org.direct_bt.ScanType;
62import org.jau.io.PrintUtil;
63import org.jau.net.EUI48;
64import org.jau.sys.Clock;
65import org.jau.util.BasicTypes;
76 EUI48 useAdapter = EUI48.ALL_DEVICE;
80 boolean use_SC =
true;
81 String adapter_name =
"TestDev001_J";
82 String adapter_short_name =
"TDev001J";
85 boolean SHOW_UPDATE_EVENTS =
false;
86 boolean RUN_ONLY_ONCE =
false;
87 private final Object sync_lock =
new Object();
88 private volatile BTDevice connectedDevice;
90 volatile int servedConnections = 0;
92 private final void setDevice(
final BTDevice cd) {
93 synchronized( sync_lock ) {
99 synchronized( sync_lock ) {
100 return connectedDevice;
104 private boolean matches(
final BTDevice device) {
106 return null != d ? d.
equals(device) :
false;
108 boolean matches(
final List<BDAddressAndType> cont,
final BDAddressAndType mac) {
109 for(
final Iterator<BDAddressAndType> it = cont.iterator(); it.hasNext(); ) {
110 if( it.next().matches(mac) ) {
117 static Thread executeOffThread(
final Runnable runobj,
final String threadName,
final boolean detach) {
118 final Thread t =
new Thread( runobj, threadName );
125 static Thread executeOffThread(
final Runnable runobj,
final boolean detach) {
126 final Thread t =
new Thread( runobj );
134 static String DataServiceUUID =
"d0ca6bf3-3d50-4760-98e5-fc5883e93712";
135 static String StaticDataUUID =
"d0ca6bf3-3d51-4760-98e5-fc5883e93712";
136 static String CommandUUID =
"d0ca6bf3-3d52-4760-98e5-fc5883e93712";
137 static String ResponseUUID =
"d0ca6bf3-3d53-4760-98e5-fc5883e93712";
138 static String PulseDataUUID =
"d0ca6bf3-3d54-4760-98e5-fc5883e93712";
149 new ArrayList<DBGattDesc>( ),
153 new ArrayList<DBGattDesc>( ),
161 new ArrayList<DBGattDesc>( ),
165 new ArrayList<DBGattDesc>( ),
169 new ArrayList<DBGattDesc>( ),
173 new ArrayList<DBGattDesc>( ),
177 new ArrayList<DBGattDesc>( ),
181 new ArrayList<DBGattDesc>( ),
221 final boolean initialSetting = oldmask.
isEmpty();
222 if( initialSetting ) {
223 PrintUtil.println(System.err,
"****** SETTINGS: "+oldmask+
" -> "+newmask+
", initial "+changedmask);
225 PrintUtil.println(System.err,
"****** SETTINGS: "+oldmask+
" -> "+newmask+
", changed "+changedmask);
227 PrintUtil.println(System.err,
"Status Adapter:");
228 PrintUtil.println(System.err, adapter.
toString());
229 if( !initialSetting &&
234 executeOffThread( () -> { startAdvertising(adapter,
"powered-on"); },
241 PrintUtil.println(System.err,
"****** DISCOVERING: meta "+currentMeta+
", changed["+changedType+
", enabled "+changedEnabled+
", policy "+policy+
"] on "+adapter);
245 public boolean deviceFound(
final BTDevice device,
final long timestamp) {
246 PrintUtil.println(System.err,
"****** FOUND__-1: NOP "+device.
toString());
253 PrintUtil.println(System.err,
"****** UPDATED (ADDR-RESOLVED): "+updateMask+
" of "+device);
254 }
else if( SHOW_UPDATE_EVENTS ) {
255 PrintUtil.println(System.err,
"****** UPDATED: "+updateMask+
" of "+device);
260 public void deviceConnected(
final BTDevice device,
final boolean discovered,
final long timestamp) {
261 PrintUtil.println(System.err,
"****** CONNECTED (discovered "+discovered+
"): "+device.
toString());
262 final boolean available =
null == getDevice();
270 PrintUtil.println(System.err,
"****** PAIRING_STATE: state "+state+
", mode "+mode+
": "+device);
278 case REQUESTED_BY_RESPONDER:
281 case FEATURE_EXCHANGE_STARTED:
284 case FEATURE_EXCHANGE_COMPLETED:
287 case PASSKEY_EXPECTED: {
297 case NUMERIC_COMPARE_EXPECTED: {
306 case PASSKEY_NOTIFY: {
307 PrintUtil.println(System.err,
"****** ");
308 PrintUtil.println(System.err,
"****** ");
309 PrintUtil.println(System.err,
"****** Confirm on your device "+device.
getName());
311 PrintUtil.println(System.err,
"****** ");
312 PrintUtil.println(System.err,
"****** ");
318 case KEY_DISTRIBUTION:
330 public void deviceReady(
final BTDevice device,
final long timestamp) {
331 PrintUtil.println(System.err,
"****** READY-1: NOP " + device.
toString());
335 public void deviceDisconnected(
final BTDevice device,
final HCIStatusCode reason,
final short handle,
final long timestamp) {
337 PrintUtil.println(System.err,
"****** DISCONNECTED (count "+servedConnections+
"): Reason "+reason+
", old handle 0x"+Integer.toHexString(handle)+
": "+device+
" on "+device.
getAdapter());
338 final boolean match = matches(device);
342 executeOffThread( () -> { processDisconnectedDevice(device); },
347 public String toString() {
348 return "AdapterStatusListener[user, per-adapter]";
352 class MyGATTServerListener
extends DBGattServer.Listener {
353 private final Thread pulseSenderThread;
354 private volatile boolean stopPulseSenderFlag =
false;
356 private volatile short handlePulseDataNotify = 0;
357 private volatile short handlePulseDataIndicate = 0;
358 private volatile short handleResponseDataNotify = 0;
359 private volatile short handleResponseDataIndicate = 0;
361 private int usedMTU = 23;
363 private void clear() {
364 synchronized( sync_lock ) {
365 handlePulseDataNotify = 0;
366 handlePulseDataIndicate = 0;
367 handleResponseDataNotify = 0;
368 handleResponseDataIndicate = 0;
375 private boolean shallStopPulseSender() {
376 synchronized( sync_lock ) {
377 return stopPulseSenderFlag;
380 private void pulseSender() {
381 while( !shallStopPulseSender() ) {
383 final BTDevice connectedDevice_ = getDevice();
384 if(
null != connectedDevice_ && connectedDevice_.
getConnected() ) {
385 if( 0 != handlePulseDataNotify || 0 != handlePulseDataIndicate ) {
386 final String data = String.format(
"Dynamic Data Example. Elapsed Milliseconds: %,9d", Clock.elapsedTimeMillis());
387 final byte[] v = data.getBytes(StandardCharsets.UTF_8);
388 if( 0 != handlePulseDataNotify ) {
389 final boolean res = connectedDevice_.
sendNotification(handlePulseDataNotify, v);
390 PrintUtil.fprintf_td(System.err,
"****** GATT::sendNotification: PULSE (res %b) to %s\n", res, connectedDevice_.
toString());
392 if( 0 != handlePulseDataIndicate ) {
393 final boolean res = connectedDevice_.
sendIndication(handlePulseDataIndicate, v);
394 PrintUtil.fprintf_td(System.err,
"****** GATT::sendIndication: PULSE (res %b) to %s\n", res, connectedDevice_.
toString());
399 if( shallStopPulseSender() ) {
404 }
catch (
final InterruptedException e) { }
408 void sendResponse(
final byte[] data) {
409 final BTDevice connectedDevice_ = getDevice();
410 if(
null != connectedDevice_ && connectedDevice_.
getConnected() ) {
411 if( 0 != handleResponseDataNotify || 0 != handleResponseDataIndicate ) {
412 if( 0 != handleResponseDataNotify ) {
413 final boolean res = connectedDevice_.
sendNotification(handleResponseDataNotify, data);
414 PrintUtil.fprintf_td(System.err,
"****** GATT::sendNotification (res %b): %s to %s\n",
415 res, BasicTypes.bytesHexString(data, 0, data.length,
true ), connectedDevice_.
toString());
417 if( 0 != handleResponseDataIndicate ) {
418 final boolean res = connectedDevice_.
sendIndication(handleResponseDataIndicate, data);
419 PrintUtil.fprintf_td(System.err,
"****** GATT::sendIndication (res %b): %s to %s\n",
420 res, BasicTypes.bytesHexString(data, 0, data.length,
true ), connectedDevice_.
toString());
426 public MyGATTServerListener() {
427 pulseSenderThread = executeOffThread( () -> { pulseSender(); },
"GattServer-PulseSender",
false );
431 public void close() {
432 synchronized( sync_lock ) {
433 stopPulseSenderFlag =
true;
435 if( !pulseSenderThread.isDaemon() ) {
437 pulseSenderThread.join(1000);
438 }
catch (
final InterruptedException e) { }
444 public void connected(
final BTDevice device,
final int initialMTU) {
445 final boolean match = matches(device);
446 PrintUtil.fprintf_td(System.err,
"****** GATT::connected(match %b): initMTU %d, %s\n",
447 match, initialMTU, device.
toString());
449 synchronized( sync_lock ) {
450 usedMTU = initialMTU;
456 public void disconnected(
final BTDevice device) {
457 final boolean match = matches(device);
458 PrintUtil.fprintf_td(System.err,
"****** GATT::disconnected(match %b): %s\n", match, device.
toString());
465 public void mtuChanged(
final BTDevice device,
final int mtu) {
466 final boolean match = matches(device);
467 PrintUtil.fprintf_td(System.err,
"****** GATT::mtuChanged(match %b): %d -> %d, %s\n",
468 match, match ? (
int)usedMTU : 0, mtu, device.
toString());
470 synchronized( sync_lock ) {
478 final boolean match = matches(device);
479 PrintUtil.fprintf_td(System.err,
"****** GATT::readCharValue(match %b): to %s, from\n %s\n %s\n",
486 final boolean match = matches(device);
487 PrintUtil.fprintf_td(System.err,
"****** GATT::readDescValue(match %b): to %s, from\n %s\n %s\n %s\n",
494 final boolean match = matches(device);
495 final String value_s = BasicTypes.bytesHexString(value, 0, value.length,
true )+
497 PrintUtil.fprintf_td(System.err,
"****** GATT::writeCharValue(match %b): %s @ %d from %s, to\n %s\n %s\n",
498 match, value_s, value_offset,
506 final boolean match = matches(device);
508 PrintUtil.fprintf_td(System.err,
"****** GATT::writeCharValueDone(match %b): From %s, to\n %s\n %s\n Char-Value: %s\n",
513 ( 0 != handleResponseDataNotify || 0 != handleResponseDataIndicate ) )
515 executeOffThread( () -> { sendResponse( value.
data() ); },
true );
521 final byte[] value,
final int value_offset)
523 final boolean match = matches(device);
524 final String value_s = BasicTypes.bytesHexString(value, 0, value.length,
true )+
526 PrintUtil.fprintf_td(System.err,
"****** GATT::writeDescValue(match %b): %s @ %d from %s\n %s\n %s\n %s\n",
527 match, value_s, value_offset,
534 final boolean match = matches(device);
536 PrintUtil.fprintf_td(System.err,
"****** GATT::writeDescValueDone(match %b): From %s\n %s\n %s\n %s\n Desc-Value: %s\n",
542 final boolean notificationEnabled,
final boolean indicationEnabled)
544 final boolean match = matches(device);
546 PrintUtil.fprintf_td(System.err,
"****** GATT::clientCharConfigChanged(match %b): notify %b, indicate %b from %s\n %s\n %s\n %s\n Desc-Value: %s\n",
547 match, notificationEnabled, indicationEnabled,
553 if( value_type.equals( PulseDataUUID ) ) {
554 synchronized( sync_lock ) {
555 handlePulseDataNotify = notificationEnabled ? value_handle : 0;
556 handlePulseDataIndicate = indicationEnabled ? value_handle : 0;
558 }
else if( value_type.equals( ResponseUUID ) ) {
559 synchronized( sync_lock ) {
560 handleResponseDataNotify = notificationEnabled ? value_handle : 0;
561 handleResponseDataIndicate = indicationEnabled ? value_handle : 0;
567 static final short adv_interval_min=(short)160;
568 static final short adv_interval_max=(short)480;
569 static final byte adv_type=(byte)0;
570 static final byte adv_chan_map=(byte)0x07;
571 static final byte filter_policy=(byte)0x00;
573 private boolean stopAdvertising(
final BTAdapter adapter,
final String msg) {
575 PrintUtil.fprintf_td(System.err,
"****** Stop advertising (%s): Adapter not selected: %s\n", msg, adapter.
toString());
579 PrintUtil.println(System.err,
"****** Stop advertising ("+msg+
") result: "+status+
": "+adapter.
toString());
580 return HCIStatusCode.SUCCESS == status;
583 private boolean startAdvertising(
final BTAdapter adapter,
final String msg) {
585 PrintUtil.fprintf_td(System.err,
"****** Start advertising (%s): Adapter not selected: %s\n", msg, adapter.
toString());
591 PrintUtil.fprintf_td(System.err,
"initAdapter: LE_Features %s\n", le_feats.
toString());
597 PrintUtil.fprintf_td(System.err,
"initAdapter: Set Default LE PHY: status %s: Tx %s, Rx %s\n",
623 if(
null != gattDevNameChar ) {
624 final byte[] aname_bytes = adapter.
getName().getBytes(StandardCharsets.UTF_8);
625 gattDevNameChar.
setValue(aname_bytes, 0, aname_bytes.length, 0);
628 PrintUtil.println(System.err,
"****** Start advertising ("+msg+
"): EIR "+eir.
toString());
629 PrintUtil.println(System.err,
"****** Start advertising ("+msg+
"): adv "+adv_mask.
toString()+
", scanrsp "+scanrsp_mask.
toString());
632 adv_interval_min, adv_interval_max,
633 adv_type, adv_chan_map, filter_policy);
634 PrintUtil.println(System.err,
"****** Start advertising ("+msg+
") result: "+status+
": "+adapter.
toString());
635 PrintUtil.println(System.err, dbGattServer.
toFullString());
636 return HCIStatusCode.SUCCESS == status;
639 private void processDisconnectedDevice(
final BTDevice device) {
640 PrintUtil.println(System.err,
"****** Disconnected Device (count "+servedConnections+
"): Start "+device.
toString());
643 stopAdvertising(device.
getAdapter(),
"device-disconnected");
648 }
catch (
final InterruptedException e) { }
650 if( !RUN_ONLY_ONCE ) {
651 startAdvertising(device.
getAdapter(),
"device-disconnected");
654 PrintUtil.println(System.err,
"****** Disonnected Device: End "+device.
toString());
657 private boolean initAdapter(
final BTAdapter adapter) {
659 PrintUtil.fprintf_td(System.err,
"initAdapter: Adapter not selected: %s\n", adapter.
toString());
666 PrintUtil.fprintf_td(System.err,
"initAdapter: initialization failed: %s: %s\n",
667 status.toString(), adapter.
toString());
671 PrintUtil.fprintf_td(System.err,
"initAdapter: setPower.1 off failed: %s\n", adapter.
toString());
675 PrintUtil.println(System.err,
"initAdapter.1: "+adapter.
toString());
680 PrintUtil.fprintf_td(System.err,
"initAdapter: setLocalName OK: %s\n", adapter.
toString());
682 PrintUtil.fprintf_td(System.err,
"initAdapter: setLocalName failed: %s\n", adapter.
toString());
688 PrintUtil.fprintf_td(System.err,
"initAdapter: setSecureConnections OK: %s\n", adapter.
toString());
690 PrintUtil.fprintf_td(System.err,
"initAdapter: setSecureConnections failed: %s\n", adapter.
toString());
694 final short conn_min_interval = 8;
695 final short conn_max_interval = 40;
696 final short conn_latency = 0;
697 final short supervision_timeout = 50;
698 status = adapter.
setDefaultConnParam(conn_min_interval, conn_max_interval, conn_latency, supervision_timeout);
700 PrintUtil.fprintf_td(System.err,
"initAdapter: setDefaultConnParam OK: %s\n", adapter.
toString());
702 PrintUtil.fprintf_td(System.err,
"initAdapter: setDefaultConnParam UNKNOWN_COMMAND (ignored): %s\n", adapter.
toString());
704 PrintUtil.fprintf_td(System.err,
"initAdapter: setDefaultConnParam failed: %s, %s\n", status.toString(), adapter.
toString());
709 PrintUtil.fprintf_td(System.err,
"initAdapter: setPower.2 on failed: %s\n", adapter.
toString());
713 PrintUtil.println(System.err,
"initAdapter.2: "+adapter.
toString());
721 if( !startAdvertising(adapter,
"initAdapter") ) {
728 private final BTManager.ChangedAdapterSetListener myChangedAdapterSetListener =
731 public void adapterAdded(
final BTAdapter adapter) {
732 if(
null == chosenAdapter ) {
733 if( initAdapter( adapter ) ) {
734 chosenAdapter = adapter;
735 PrintUtil.println(System.err,
"****** Adapter ADDED__: InitOK: " + adapter);
737 PrintUtil.println(System.err,
"****** Adapter ADDED__: Ignored: " + adapter);
740 PrintUtil.println(System.err,
"****** Adapter ADDED__: Ignored (other): " + adapter);
745 public void adapterRemoved(
final BTAdapter adapter) {
746 if(
null != chosenAdapter && adapter == chosenAdapter ) {
747 chosenAdapter =
null;
748 PrintUtil.println(System.err,
"****** Adapter REMOVED: " + adapter);
750 PrintUtil.println(System.err,
"****** Adapter REMOVED (other): " + adapter);
756 timestamp_t0 = Clock.currentTimeMillis();
758 PrintUtil.println(System.err,
"****** Test Start");
760 final MyGATTServerListener listener =
new MyGATTServerListener();
765 while( !RUN_ONLY_ONCE || 0 == servedConnections ) {
768 }
catch (
final InterruptedException e) {
773 PrintUtil.println(System.err,
"****** Shutdown.01 (DBGattServer.remove-listener)");
776 PrintUtil.println(System.err,
"****** Test Shutdown.02 (listener.close)");
779 PrintUtil.println(System.err,
"****** Test Shutdown.03 (DBGattServer.close)");
780 dbGattServer.
close();
784 PrintUtil.println(System.err,
"****** Test End");
787 public static void main(
final String[] args)
throws InterruptedException {
788 for(
int i=0; i< args.length; i++) {
789 final String arg = args[i];
790 if( arg.equals(
"-debug") ) {
791 System.setProperty(
"org.tinyb.verbose",
"true");
792 System.setProperty(
"org.tinyb.debug",
"true");
793 }
else if( arg.equals(
"-verbose") ) {
794 System.setProperty(
"org.tinyb.verbose",
"true");
795 }
else if( arg.equals(
"-dbt_debug") && args.length > (i+1) ) {
796 System.setProperty(
"direct_bt.debug", args[++i]);
797 }
else if( arg.equals(
"-dbt_verbose") && args.length > (i+1) ) {
798 System.setProperty(
"direct_bt.verbose", args[++i]);
799 }
else if( arg.equals(
"-dbt_gatt") && args.length > (i+1) ) {
800 System.setProperty(
"direct_bt.gatt", args[++i]);
801 }
else if( arg.equals(
"-dbt_l2cap") && args.length > (i+1) ) {
802 System.setProperty(
"direct_bt.l2cap", args[++i]);
803 }
else if( arg.equals(
"-dbt_hci") && args.length > (i+1) ) {
804 System.setProperty(
"direct_bt.hci", args[++i]);
805 }
else if( arg.equals(
"-dbt_mgmt") && args.length > (i+1) ) {
806 System.setProperty(
"direct_bt.mgmt", args[++i]);
812 }
catch (
BTException | NoSuchMethodException | SecurityException
813 | IllegalAccessException | IllegalArgumentException
814 | InvocationTargetException | ClassNotFoundException e) {
815 System.err.println(
"Unable to instantiate Direct-BT BluetoothManager");
820 PrintUtil.println(System.err,
"Direct-BT BluetoothManager initialized!");
826 boolean waitForEnter=
false;
828 for(
int i=0; i< args.length; i++) {
829 final String arg = args[i];
831 if( arg.equals(
"-wait") ) {
833 }
else if( arg.equals(
"-show_update_events") ) {
834 test.SHOW_UPDATE_EVENTS =
true;
835 }
else if( arg.equals(
"-btmode") && args.length > (i+1) ) {
837 }
else if( arg.equals(
"-use_sc") && args.length > (i+1) ) {
838 test.use_SC = 0 != Integer.valueOf(args[++i]);
839 }
else if( arg.equals(
"-adapter") && args.length > (i+1) ) {
840 test.useAdapter =
new EUI48( args[++i] );
841 }
else if( arg.equals(
"-name") && args.length > (i+1) ) {
842 test.adapter_name = args[++i];
843 }
else if( arg.equals(
"-short_name") && args.length > (i+1) ) {
844 test.adapter_short_name = args[++i];
845 }
else if( arg.equals(
"-mtu") && args.length > (i+1) ) {
846 test.dbGattServer.
setMaxAttMTU( Integer.valueOf( args[++i] ) );
847 }
else if( arg.equals(
"-seclevel") && args.length > (i+1) ) {
848 final int sec_level_i = Integer.valueOf(args[++i]).intValue();
850 }
else if( arg.equals(
"-iocap") && args.length > (i+1) ) {
851 final int v = Integer.valueOf(args[++i]).intValue();
853 }
else if( arg.equals(
"-once") ) {
854 test.RUN_ONLY_ONCE =
true;
857 PrintUtil.println(System.err,
"Run with '[-btmode LE|BREDR|DUAL] [-use_sc 0|1] "+
858 "[-adapter <adapter_address>] "+
859 "[-name <adapter_name>] "+
860 "[-short_name <adapter_short_name>] "+
861 "[-seclevel <int_sec_level>]* "+
862 "[-iocap <int_iocap>]* "+
863 "[-mtu <max att_mtu>] " +
865 "[-verbose] [-debug] "+
866 "[-dbt_verbose true|false] "+
867 "[-dbt_debug true|false|adapter.event,gatt.data,hci.event,hci.scan_ad_eir,mgmt.event] "+
868 "[-dbt_mgmt cmd.timeout=3000,ringsize=64,...] "+
869 "[-dbt_hci cmd.complete.timeout=10000,cmd.status.timeout=3000,ringsize=64,...] "+
870 "[-dbt_gatt cmd.read.timeout=500,cmd.write.timeout=500,cmd.init.timeout=2500,ringsize=128,...] "+
871 "[-dbt_l2cap reader.timeout=10000,restart.count=0,...] "+
872 "[-shutdown <int>]'");
875 PrintUtil.println(System.err,
"SHOW_UPDATE_EVENTS "+test.SHOW_UPDATE_EVENTS);
876 PrintUtil.println(System.err,
"adapter "+test.useAdapter);
877 PrintUtil.println(System.err,
"adapter btmode "+test.btMode.toString());
878 PrintUtil.println(System.err,
"adapter SC "+test.use_SC);
879 PrintUtil.fprintf_td(System.err,
"name %s (short %s)\n", test.adapter_name, test.adapter_short_name);
880 PrintUtil.println(System.err,
"adapter mtu "+test.dbGattServer.
getMaxAttMTU());
881 PrintUtil.println(System.err,
"adapter sec_level "+test.adapter_sec_level);
882 PrintUtil.println(System.err,
"adapter io_cap "+test.adapter_sec_io_cap);
883 PrintUtil.println(System.err,
"once "+test.RUN_ONLY_ONCE);
884 PrintUtil.println(System.err,
"GattServer "+test.dbGattServer.
toString());
887 PrintUtil.println(System.err,
"Press ENTER to continue\n");
888 try{ System.in.read();
889 }
catch(
final Exception e) { }
Author: Sven Gothel sgothel@jausoft.com Copyright (c) 2021 Gothel Software e.K.
static final String SERVER_KEY_PATH
This Java peripheral BTRole::Slave GATT server example uses an event driven workflow.
static void main(final String[] args)
void runTest(final BTManager manager)
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.
One stop BTManager API entry point.
static native String getNativeVersion()
static final String getImplVersion()
Manifest's Attributes.Name#IMPLEMENTATION_VERSION or null if not available.
static final String getAPIVersion()
Manifest's Attributes.Name#SPECIFICATION_VERSION or null if not available.
static native String getNativeAPIVersion()
static synchronized BTManager getDirectBTManager()
Returns an initialized BluetoothManager instance using the DirectBT implementation.
Application toolkit providing BT security setup and its device association on a pattern matching basi...
static final int NO_PASSKEY
static BTSecurityRegistry.Entry getStartOf(final EUI48 addr, final String name)
Returns a matching BTSecurityRegistry.Entry,.
static String decodeUTF8String(final byte[] buffer, final int offset, final int size)
Decodes the given consecutive UTF-8 characters within buffer to String.
Selected standard GATT characteristic numbers in UUID16 format as defined.
static String SOFTWARE_REVISION_STRING
static String SERIAL_NUMBER_STRING
static String MANUFACTURER_NAME_STRING
static String MODEL_NUMBER_STRING
static String FIRMWARE_REVISION_STRING
static String HARDWARE_REVISION_STRING
static String DEVICE_NAME
Representing a Gatt Characteristic object from the GATT server perspective.
native DBGattValue getValue()
Return a copy of this characteristic's native DBGattValue value.
native short getValueHandle()
Characteristics Value Handle.
native boolean setValue(final byte[] source, final int source_pos, final int source_len, final int dest_pos)
Set this characteristic's native value.
Selected standard GATT descriptor numbers in UUID16 format as defined.
static final String USER_DESC
Representing a Gatt Characteristic Descriptor object from the GATT server perspective.
static DBGattDesc createClientCharConfig()
Return a newly constructed Client Characteristic Configuration with a zero uint16_t value of fixed le...
native DBGattValue getValue()
Return a copy of this characteristic descriptor's native DBGattValue value.
Representing a complete list of Gatt Service objects from the GATT server perspective,...
native void setMaxAttMTU(final int v)
Set maximum server Rx ATT_MTU, defaults to 512+1 limit.
boolean resetGattClientCharConfig(final String service_uuid, final String char_uuid)
native int getMaxAttMTU()
Used maximum server Rx ATT_MTU, defaults to 512+1.
DBGattChar findGattChar(final String service_uuid, final String char_uuid)
synchronized boolean removeListener(final Listener l)
synchronized boolean addListener(final Listener l)
Selected standard GATT service service numbers in UUID16 format as defined.
static String GENERIC_ACCESS
This service contains generic information about the device.
static String DEVICE_INFORMATION
This service exposes manufacturer and/or vendor information about a device.
Representing a Gatt Service object from the ::GATTRole::Server perspective.
A copy of the native GATT value of DBGattChar or DBGattDesc.
static DBGattValue make(final String name)
Convenience DBGattValue ctor function.
byte[] data()
Returns the actual data of this value.
Bit mask of 'Extended Inquiry Response' (EIR) data fields, indicating a set of related data.
boolean isSet(final DataType bit)
void set(final DataType bit)
Collection of 'Extended Advertising Data' (EAD), 'Advertising Data' (AD) or 'Extended Inquiry Respons...
native void setConnInterval(final short min, final short max)
Set slave connection interval range.
native String toString(final boolean includeServices)
final void addFlag(final GAPFlags.Bit f)
native void setName(final String name)
native void setServicesComplete(final boolean v)
native void addService(final String uuid)
Bit mask of 'Extended Inquiry Response' (EIR) data fields, indicating a set of related data.
Bit mask of GATT Characteristic Properties.
GattCharPropertySet set(final Type bit)
LE Link Layer Feature Set (bitmask)
LE Transport PHY bit values (bitmask)
Bits representing 'BTAdapter setting' data fields.
Bluetooth adapter operating mode.
DUAL
Dual Bluetooth mode, i.e.
static BTMode get(final String name)
Maps the specified name to a constant of BTMode.
Bluetooth Security Level.
UNSET
Security Level not set, value 0.
static BTSecurityLevel get(final String name)
Maps the specified name to a constant of BTSecurityLevel.
Discovery policy defines the BTAdapter discovery mode after connecting a remote BTDevice:
Each enum represents a 'Extended Inquiry Response' (EIR) data field type bit.
Each enum represents a 'Extended Inquiry Response' (EIR) data field type bit.
BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.1.1 Characteristic Properties.
BT Core Spec v5.2: Vol 1, Part F Controller Error Codes: 1.3 List of Error Codes.
Each enum represents a 'LE Transport PHY' bit value.
Bluetooth secure pairing mode.
UNSET
Denoting unset value, i.e.
static SMPIOCapability get(final String name)
Maps the specified name to a constant of SMPIOCapability.
SMP Pairing Process state definition.
Meta ScanType as derived from BTMode with defined value mask consisting of BDAddressType bits.
BTAdapter represents one local Bluetooth Controller.
boolean isInitialized()
Returns true, if initialize(BTMode) has already been called for this adapter, otherwise false.
LE_Features getLEFeatures()
Return LE_Features for this controller.
boolean setPowered(final boolean power_on)
Sets the power state the adapter.
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.
HCIStatusCode setSecureConnections(final boolean enable)
Enable or disable Secure Connections (SC) of the adapter.
String getName()
Returns the name.
void setSMPKeyPath(final String path)
Set the adapter's persistent storage directory for SMPKeyBin files.
void setServerConnSecurity(final BTSecurityLevel sec_level, final SMPIOCapability io_cap)
Sets the given ::BTSecurityLevel and ::SMPIOCapability for connecting device when in server (peripher...
boolean addStatusListener(final AdapterStatusListener listener)
Add the given AdapterStatusListener to the list if not already present.
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,...
HCIStatusCode setDefaultLE_PHY(final LE_PHYs Tx, final LE_PHYs Rx)
Sets default preference of LE_PHYs.
BDAddressAndType getAddressAndType()
Returns the adapter's public BDAddressAndType.
HCIStatusCode setName(String name, String short_name)
Sets the name and short-name.
boolean removeStatusListener(final AdapterStatusListener l)
Remove the given AdapterStatusListener from the list.
HCIStatusCode stopAdvertising()
Ends advertising.
int getBTMajorVersion()
Returns the Bluetooth major version of this adapter.
HCIStatusCode initialize(final BTMode btMode, boolean powerOn)
Initialize the adapter with default values, including power-on.
BTDevice represents one remote Bluetooth device.
HCIStatusCode setPairingNumericComparison(final boolean equal)
Method sets the numeric comparison result, see PairingMode#NUMERIC_COMPARE_ini.
BTAdapter getAdapter()
Returns the adapter on which this device was discovered or connected.
String getName()
Returns the remote device name.
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...
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...
boolean remove()
Remove this device from the system (like an unpair).
String getResponderSMPPassKeyString()
Returns getResponderSMPPassKey() as a canonical string, e.g.
boolean getConnected()
Returns the connected state of the device.
boolean equals(final Object obj)
If both types are of BTDevice, it compares their BDAddressAndType, see getAddressAndType().
HCIStatusCode setPairingPasskey(final int passkey)
Method sets the given passkey entry, see PairingMode#PASSKEY_ENTRY_ini.
BDAddressAndType getAddressAndType()
Returns the devices' unique EUI48 address and BDAddressType type tuple, might be its initially report...
Event listener to receive change events regarding the system's BTAdapter set, e.g.
A thread safe singleton handler of the BTAdapter manager, e.g.
void addChangedAdapterSetListener(final ChangedAdapterSetListener l)
Add the given ChangedAdapterSetListener to this manager.