diff options
author | Sven Gothel <[email protected]> | 2020-06-18 06:48:14 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2020-06-18 06:48:14 +0200 |
commit | 0ce725700a4e26e65f578fd1b1800d0bf85e289e (patch) | |
tree | bc7bdcf169d589cd13c0b10717bbaa9ea0a515eb /examples/java | |
parent | b1126329e0bf84bb583027ca18b5e0e2a191e90e (diff) |
Add debugging tool ScannerTinyB02; ScannerTinyB01 adds any device option.
Diffstat (limited to 'examples/java')
-rw-r--r-- | examples/java/CMakeLists.txt | 7 | ||||
-rw-r--r-- | examples/java/ScannerTinyB01.java | 24 | ||||
-rw-r--r-- | examples/java/ScannerTinyB02.java | 427 |
3 files changed, 448 insertions, 10 deletions
diff --git a/examples/java/CMakeLists.txt b/examples/java/CMakeLists.txt index 17f3045e..3956a103 100644 --- a/examples/java/CMakeLists.txt +++ b/examples/java/CMakeLists.txt @@ -36,6 +36,13 @@ add_custom_command(TARGET ScannerTinyB01 COMMAND cp "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/ScannerTinyB01.dir/ScannerTinyB01.class" "${CMAKE_CURRENT_BINARY_DIR}" ) +add_jar(ScannerTinyB02 SOURCES ScannerTinyB02.java INCLUDE_JARS "${CMAKE_CURRENT_BINARY_DIR}/../../java/tinyb2.jar" ENTRY_POINT Notification) + +add_custom_command(TARGET ScannerTinyB02 + POST_BUILD + COMMAND cp "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/ScannerTinyB02.dir/ScannerTinyB02.class" "${CMAKE_CURRENT_BINARY_DIR}" +) + add_jar(ScannerTinyB10 SOURCES ScannerTinyB10.java INCLUDE_JARS "${CMAKE_CURRENT_BINARY_DIR}/../../java/tinyb2.jar" ENTRY_POINT Notification) add_custom_command(TARGET ScannerTinyB10 diff --git a/examples/java/ScannerTinyB01.java b/examples/java/ScannerTinyB01.java index 0f392efe..9d6c8e18 100644 --- a/examples/java/ScannerTinyB01.java +++ b/examples/java/ScannerTinyB01.java @@ -59,6 +59,7 @@ public class ScannerTinyB01 { int factory = 0; int dev_id = 0; // default int mode = 0; + int max_loops = 1; boolean forever = false; { for(int i=0; i< args.length; i++) { @@ -76,13 +77,12 @@ public class ScannerTinyB01 { t0_discovery = Long.valueOf(args[++i]).longValue(); } else if( arg.equals("-forever") ) { forever = true; + } else if( arg.equals("-loops") && args.length > (i+1) ) { + max_loops = Integer.valueOf(args[++i]).intValue(); } } - System.err.println("Run with '[-dev_id <adapter-index>] -mac <device_address> [-mode <mode>] [-factory <BluetoothManager-Factory-Implementation-Class>]'"); - if ( EUI48_ANY_DEVICE.equals(waitForDevice) ) { - System.exit(-1); - } + System.err.println("Run with '[-dev_id <adapter-index>] [-mac <device_address>] [-mode <mode>] [-factory <BluetoothManager-Factory-Implementation-Class>]'"); } System.err.println("dev_id "+dev_id); @@ -142,7 +142,7 @@ public class ScannerTinyB01 { @Override public void deviceFound(final BluetoothDevice device, final long timestamp) { - final boolean matches = device.getAddress().equals(waitForDevice); + final boolean matches = EUI48_ANY_DEVICE.equals(waitForDevice) || device.getAddress().equals(waitForDevice); System.err.println("****** FOUND__: "+device.toString()+" - match "+matches); System.err.println("Status Adapter:"); System.err.println(device.getAdapter().toString()); @@ -157,13 +157,13 @@ public class ScannerTinyB01 { @Override public void deviceUpdated(final BluetoothDevice device, final EIRDataTypeSet updateMask, final long timestamp) { - final boolean matches = device.getAddress().equals(waitForDevice); + final boolean matches = EUI48_ANY_DEVICE.equals(waitForDevice) || device.getAddress().equals(waitForDevice); System.err.println("****** UPDATED: "+updateMask+" of "+device+" - match "+matches); } @Override public void deviceConnected(final BluetoothDevice device, final long timestamp) { - final boolean matches = device.getAddress().equals(waitForDevice); + final boolean matches = EUI48_ANY_DEVICE.equals(waitForDevice) || device.getAddress().equals(waitForDevice); System.err.println("****** CONNECTED: "+device+" - matches "+matches); } @@ -202,7 +202,7 @@ public class ScannerTinyB01 { int loop = 0; try { - do { + while( forever || loop < max_loops ) { loop++; System.err.println("****** Loop "+loop); @@ -235,12 +235,15 @@ public class ScannerTinyB01 { final List<BluetoothDevice> devices = adapter.getDevices(); for(final Iterator<BluetoothDevice> id = devices.iterator(); id.hasNext() && !timeout; ) { final BluetoothDevice d = id.next(); - if(d.getAddress().equals(waitForDevice)) { + if( EUI48_ANY_DEVICE.equals(waitForDevice) || d.getAddress().equals(waitForDevice) ) { sensor = d; break; } + } + if( null == sensor ) { final long tn = BluetoothUtils.getCurrentMilliseconds(); timeout = ( tn - t0 ) > t0_discovery; + Thread.sleep(60); } } } @@ -251,6 +254,7 @@ public class ScannerTinyB01 { } System.err.println("Found device in "+(t1-t0)+" ms: "); printDevice(sensor); + adapter.stopDiscovery(); final BooleanNotification connectedNotification = new BooleanNotification("Connected", t1); @@ -322,7 +326,7 @@ public class ScannerTinyB01 { } sensor.disconnect(); System.err.println("ScannerTinyB01 04 ...: "+adapter); - } while( forever ); + } } catch (final Throwable t) { System.err.println("Caught: "+t.getMessage()); t.printStackTrace(); diff --git a/examples/java/ScannerTinyB02.java b/examples/java/ScannerTinyB02.java new file mode 100644 index 00000000..764ba2f4 --- /dev/null +++ b/examples/java/ScannerTinyB02.java @@ -0,0 +1,427 @@ +/** + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import org.tinyb.AdapterSettings; +import org.tinyb.BluetoothAdapter; +import org.tinyb.BluetoothDevice; +import org.tinyb.AdapterStatusListener; +import org.tinyb.BluetoothException; +import org.tinyb.BluetoothFactory; +import org.tinyb.BluetoothGattCharacteristic; +import org.tinyb.BluetoothGattService; +import org.tinyb.BluetoothManager; +import org.tinyb.BluetoothNotification; +import org.tinyb.BluetoothUtils; +import org.tinyb.EIRDataTypeSet; +import org.tinyb.GATTCharacteristicListener; +import org.tinyb.HCIStatusCode; + +/** + * Test and debugging application for certain situation. + * <p> + * Code will in 'in flux' and is not intended as an example. + * </p> + */ +public class ScannerTinyB02 { + static { + System.setProperty("org.tinyb.verbose", "true"); + } + /** 10,000 milliseconds */ + static long TO_DISCOVER = 10000; + + static final String EUI48_ANY_DEVICE = "00:00:00:00:00:00"; + static String waitForDevice = EUI48_ANY_DEVICE; + + public static void main(final String[] args) throws InterruptedException { + final boolean waitForEnter=false; + long t0_discovery = TO_DISCOVER; + int factory = 0; + int dev_id = 0; // default + int mode = 3; + int max_loops = 5; + boolean forever = false; + { + for(int i=0; i< args.length; i++) { + final String arg = args[i]; + + if( arg.equals("-dev_id") && args.length > (i+1) ) { + dev_id = Integer.valueOf(args[++i]).intValue(); + } else if( arg.equals("-mac") && args.length > (i+1) ) { + waitForDevice = args[++i]; + } else if( arg.equals("-mode") && args.length > (i+1) ) { + mode = Integer.valueOf(args[++i]).intValue(); + } else if( arg.equals("-factory") && args.length > (i+1) ) { + factory = Integer.valueOf(args[++i]).intValue(); + } else if( arg.equals("-t0_discovery") && args.length > (i+1) ) { + t0_discovery = Long.valueOf(args[++i]).longValue(); + } else if( arg.equals("-forever") ) { + forever = true; + } else if( arg.equals("-loops") && args.length > (i+1) ) { + max_loops = Integer.valueOf(args[++i]).intValue(); + } + } + + System.err.println("Run with '[-dev_id <adapter-index>] [-mac <device_address>] [-mode <mode>] [-factory <BluetoothManager-Factory-Implementation-Class>]'"); + } + + System.err.println("dev_id "+dev_id); + System.err.println("waitForDevice: "+waitForDevice); + + if( waitForEnter ) { + System.err.println("Press ENTER to continue\n"); + try{ System.in.read(); + } catch(final Exception e) { } + } + + final BluetoothFactory.ImplementationIdentifier implID = 0 == factory ? BluetoothFactory.DirectBTImplementationID : BluetoothFactory.DBusImplementationID; + final BluetoothManager manager; + { + BluetoothManager _manager = null; + try { + _manager = BluetoothFactory.getBluetoothManager( implID ); + } catch (BluetoothException | NoSuchMethodException | SecurityException + | IllegalAccessException | IllegalArgumentException + | InvocationTargetException | ClassNotFoundException e) { + System.err.println("Unable to instantiate BluetoothManager via "+implID); + e.printStackTrace(); + System.exit(-1); + } + manager = _manager; + } + final BluetoothAdapter adapter; + { + final List<BluetoothAdapter> adapters = manager.getAdapters(); + for(int i=0; i < adapters.size(); i++) { + System.err.println("Adapter["+i+"]: "+adapters.get(i)); + } + if( adapters.size() <= dev_id ) { + System.err.println("No adapter dev_id "+dev_id+" available, adapter count "+adapters.size()); + System.exit(-1); + } + adapter = adapters.get(dev_id); + } + + final BluetoothDevice[] matchingDiscoveredDeviceBucket = { null }; + + final AdapterStatusListener statusListener = new AdapterStatusListener() { + @Override + public void adapterSettingsChanged(final BluetoothAdapter adapter, final AdapterSettings oldmask, + final AdapterSettings newmask, final AdapterSettings changedmask, final long timestamp) { + System.err.println("****** SETTINGS: "+oldmask+" -> "+newmask+", changed "+changedmask); + System.err.println("Status Adapter:"); + System.err.println(adapter.toString()); + } + + @Override + public void discoveringChanged(final BluetoothAdapter adapter, final boolean enabled, final boolean keepAlive, final long timestamp) { + System.err.println("****** DISCOVERING: enabled "+enabled+", keepAlive "+keepAlive+" on "+adapter); + System.err.println("Status Adapter:"); + System.err.println(adapter.toString()); + } + + @Override + public void deviceFound(final BluetoothDevice device, final long timestamp) { + final boolean matches = EUI48_ANY_DEVICE.equals(waitForDevice) || device.getAddress().equals(waitForDevice); + System.err.println("****** FOUND__: "+device.toString()+" - match "+matches); + System.err.println("Status Adapter:"); + System.err.println(device.getAdapter().toString()); + + if( matches ) { + synchronized(matchingDiscoveredDeviceBucket) { + matchingDiscoveredDeviceBucket[0] = device; + matchingDiscoveredDeviceBucket.notifyAll(); + } + } + } + + @Override + public void deviceUpdated(final BluetoothDevice device, final EIRDataTypeSet updateMask, final long timestamp) { + final boolean matches = EUI48_ANY_DEVICE.equals(waitForDevice) || device.getAddress().equals(waitForDevice); + System.err.println("****** UPDATED: "+updateMask+" of "+device+" - match "+matches); + } + + @Override + public void deviceConnected(final BluetoothDevice device, final long timestamp) { + final boolean matches = EUI48_ANY_DEVICE.equals(waitForDevice) || device.getAddress().equals(waitForDevice); + System.err.println("****** CONNECTED: "+device+" - matches "+matches); + } + + @Override + public void deviceDisconnected(final BluetoothDevice device, final HCIStatusCode reason, final long timestamp) { + System.err.println("****** DISCONNECTED: Reason "+reason+": "+device+" on "+device.getAdapter()); + } + }; + adapter.addStatusListener(statusListener, null); + + final long timestamp_t0 = BluetoothUtils.getCurrentMilliseconds(); + + adapter.enableDiscoverableNotifications(new BooleanNotification("Discoverable", timestamp_t0)); + + adapter.enableDiscoveringNotifications(new BooleanNotification("Discovering", timestamp_t0)); + + adapter.enablePairableNotifications(new BooleanNotification("Pairable", timestamp_t0)); + + adapter.enablePoweredNotifications(new BooleanNotification("Powered", timestamp_t0)); + + final GATTCharacteristicListener myCharacteristicListener = new GATTCharacteristicListener() { + @Override + public void notificationReceived(final BluetoothGattCharacteristic charDecl, + final byte[] value, final long timestamp) { + System.err.println("****** GATT notificationReceived: "+charDecl+ + ", value "+BluetoothUtils.bytesHexString(value, true, true)); + } + + @Override + public void indicationReceived(final BluetoothGattCharacteristic charDecl, + final byte[] value, final long timestamp, final boolean confirmationSent) { + System.err.println("****** GATT indicationReceived: "+charDecl+ + ", value "+BluetoothUtils.bytesHexString(value, true, true)); + } + }; + + int loop = 0; + try { + while( forever || loop < max_loops ) { + loop++; + System.err.println("****** Loop "+loop); + + final long t0 = BluetoothUtils.getCurrentMilliseconds(); + + final boolean discoveryStarted = true; // adapter.startDiscovery(true); + { + final Thread lalaTask = new Thread( new Runnable() { + @Override + public void run() { + adapter.startDiscovery(true); + } + }, "lala"); + lalaTask.setDaemon(true); // detach thread + lalaTask.start(); + } + + System.err.println("The discovery started: " + (discoveryStarted ? "true" : "false") + " for mac "+waitForDevice+", mode "+mode); + if( !discoveryStarted ) { + break; + } + BluetoothDevice sensor = null; + + if( 0 == mode ) { + synchronized(matchingDiscoveredDeviceBucket) { + boolean timeout = false; + while( !timeout && null == matchingDiscoveredDeviceBucket[0] ) { + matchingDiscoveredDeviceBucket.wait(t0_discovery); + final long tn = BluetoothUtils.getCurrentMilliseconds(); + timeout = ( tn - t0 ) > t0_discovery; + } + sensor = matchingDiscoveredDeviceBucket[0]; + matchingDiscoveredDeviceBucket[0] = null; + } + } else if( 1 == mode ) { + sensor = adapter.find(null, waitForDevice, t0_discovery); + } else { + boolean timeout = false; + while( null == sensor && !timeout ) { + final List<BluetoothDevice> devices = adapter.getDevices(); + int i=0; + for(final Iterator<BluetoothDevice> id = devices.iterator(); id.hasNext() && !timeout; ) { + final BluetoothDevice d = id.next(); + final boolean match = EUI48_ANY_DEVICE.equals(waitForDevice) || d.getAddress().equals(waitForDevice); + System.err.println("****** Has "+i+"/"+devices.size()+": match "+match+": "+d.toString()); + i++; + if( match ) { + sensor = d; + break; + } + } + if( null == sensor ) { + final long tn = BluetoothUtils.getCurrentMilliseconds(); + timeout = ( tn - t0 ) > t0_discovery; + System.err.print("."); + Thread.sleep(60); + } + } + } + final long t1 = BluetoothUtils.getCurrentMilliseconds(); + if (sensor == null) { + System.err.println("No sensor found within "+(t1-t0)+" ms"); + continue; // forever loop + } + System.err.println("Found device in "+(t1-t0)+" ms: "); + printDevice(sensor); + + // adapter.stopDiscovery(); + { + final Thread lalaTask = new Thread( new Runnable() { + @Override + public void run() { + adapter.stopDiscovery(); + } + }, "lala"); + lalaTask.setDaemon(true); // detach thread + lalaTask.start(); + } + + final BooleanNotification connectedNotification = new BooleanNotification("Connected", t1); + final BooleanNotification servicesResolvedNotification = new BooleanNotification("ServicesResolved", t1); + sensor.enableConnectedNotifications(connectedNotification); + sensor.enableServicesResolvedNotifications(servicesResolvedNotification); + + final long t2 = BluetoothUtils.getCurrentMilliseconds(); + final long t3; + if ( sensor.connect() ) { + t3 = BluetoothUtils.getCurrentMilliseconds(); + System.err.println("Sensor connected: "+(t3-t2)+" ms, total "+(t3-t0)+" ms"); + System.err.println("Sensor connectedNotification: "+connectedNotification.getValue()); + } else { + t3 = BluetoothUtils.getCurrentMilliseconds(); + System.out.println("Could not connect device: "+(t3-t2)+" ms, total "+(t3-t0)+" ms"); + // we tolerate the failed immediate connect, as it might happen at a later time + } + + synchronized( servicesResolvedNotification ) { + while( !servicesResolvedNotification.getValue() ) { + final long tn = BluetoothUtils.getCurrentMilliseconds(); + if( tn - t3 > 20000 ) { + break; // 20s TO + } + servicesResolvedNotification.wait(); + } + } + final long t4; + if ( servicesResolvedNotification.getValue() ) { + t4 = BluetoothUtils.getCurrentMilliseconds(); + System.err.println("Sensor servicesResolved: "+(t4-t3)+" ms, total "+(t4-t0)+" ms"); + } else { + t4 = BluetoothUtils.getCurrentMilliseconds(); + System.out.println("Could not connect device: "+(t4-t3)+" ms, total "+(t4-t0)+" ms"); + System.exit(-1); + } + + if( true ) { + final BluetoothDevice _sensor = sensor; + final Thread lalaTask = new Thread( new Runnable() { + @Override + public void run() { + _sensor.disconnect(); + } + }, "lala"); + lalaTask.setDaemon(true); // detach thread + lalaTask.start(); + + // Thread.sleep(60); + // sensor.connect(); + continue; + } else { + final List<BluetoothGattService> primServices = sensor.getServices(); + if ( null == primServices || primServices.isEmpty() ) { + System.err.println("No BluetoothGattService found!"); + } else { + final boolean addedCharacteristicListenerRes = + BluetoothGattService.addCharacteristicListenerToAll(sensor, primServices, myCharacteristicListener); + System.err.println("Added GATTCharacteristicListener: "+addedCharacteristicListenerRes); + + int i=0, j=0; + for(final Iterator<BluetoothGattService> srvIter = primServices.iterator(); srvIter.hasNext(); i++) { + final BluetoothGattService primService = srvIter.next(); + System.err.printf(" [%02d] Service %s\n", i, primService.toString()); + System.err.printf(" [%02d] Service Characteristics\n", i); + final List<BluetoothGattCharacteristic> serviceCharacteristics = primService.getCharacteristics(); + for(final Iterator<BluetoothGattCharacteristic> charIter = serviceCharacteristics.iterator(); charIter.hasNext(); j++) { + final BluetoothGattCharacteristic serviceChar = charIter.next(); + System.err.printf(" [%02d.%02d] Decla: %s\n", i, j, serviceChar.toString()); + final List<String> properties = Arrays.asList(serviceChar.getFlags()); + if( properties.contains("read") ) { + final byte[] value = serviceChar.readValue(); + final String svalue = BluetoothUtils.decodeUTF8String(value, 0, value.length); + System.err.printf(" [%02d.%02d] Value: %s ('%s')\n", + i, j, BluetoothUtils.bytesHexString(value, true, true), svalue); + } + } + } + Thread.sleep(1000); // FIXME: Wait for notifications + + final boolean remRes = BluetoothGattService.removeCharacteristicListenerFromAll(sensor, primServices, myCharacteristicListener); + System.err.println("Removed GATTCharacteristicListener: "+remRes); + } + sensor.disconnect(); + System.err.println("ScannerTinyB01 04 ...: "+adapter); + } + } + } catch (final Throwable t) { + System.err.println("Caught: "+t.getMessage()); + t.printStackTrace(); + } + + System.err.println("ScannerTinyB01 02 clear listener etc .. "); + adapter.removeStatusListener(statusListener); + adapter.disableDiscoverableNotifications(); + adapter.disableDiscoveringNotifications(); + adapter.disablePairableNotifications(); + adapter.disablePoweredNotifications(); + + System.err.println("ScannerTinyB01 03 close: "+adapter); + adapter.close(); + System.err.println("ScannerTinyB01 04"); + manager.shutdown(); + System.err.println("ScannerTinyB01 XX"); + } + private static void printDevice(final BluetoothDevice device) { + System.err.println("Address = " + device.getAddress()); + System.err.println(" Name = " + device.getName()); + System.err.println(" Connected = " + device.getConnected()); + System.err.println(); + } + static class BooleanNotification implements BluetoothNotification<Boolean> { + private final long t0; + private final String name; + private boolean v; + + public BooleanNotification(final String name, final long t0) { + this.t0 = t0; + this.name = name; + this.v = false; + } + + @Override + public void run(final Boolean v) { + synchronized(this) { + final long t1 = BluetoothUtils.getCurrentMilliseconds(); + this.v = v.booleanValue(); + System.out.println("###### "+name+": "+v+" in td "+(t1-t0)+" ms!"); + this.notifyAll(); + } + } + public boolean getValue() { + synchronized(this) { + return v; + } + } + } +} |