summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/java/ScannerTinyB01.java46
-rw-r--r--examples/java/ScannerTinyB10.java103
-rw-r--r--java/direct_bt/tinyb/DBTAdapter.java90
-rw-r--r--java/direct_bt/tinyb/DBTDevice.java124
-rw-r--r--java/direct_bt/tinyb/DBTGattCharacteristic.java56
-rw-r--r--java/direct_bt/tinyb/DBTGattService.java68
-rw-r--r--java/direct_bt/tinyb/DBTManager.java139
7 files changed, 561 insertions, 65 deletions
diff --git a/examples/java/ScannerTinyB01.java b/examples/java/ScannerTinyB01.java
index e807b58d..c2f7a739 100644
--- a/examples/java/ScannerTinyB01.java
+++ b/examples/java/ScannerTinyB01.java
@@ -24,6 +24,7 @@
*/
import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
@@ -38,6 +39,7 @@ import org.tinyb.BluetoothGattCharacteristic;
import org.tinyb.BluetoothGattService;
import org.tinyb.BluetoothManager;
import org.tinyb.BluetoothNotification;
+import org.tinyb.BluetoothType;
import org.tinyb.BluetoothUtils;
import org.tinyb.EIRDataTypeSet;
import org.tinyb.GATTCharacteristicListener;
@@ -55,6 +57,7 @@ public class ScannerTinyB01 {
static final String EUI48_ANY_DEVICE = "00:00:00:00:00:00";
static String waitForDevice = EUI48_ANY_DEVICE;
+ static List<String> characteristicList = new ArrayList<String>();
public static void main(final String[] args) throws InterruptedException {
final boolean waitForEnter=false;
@@ -72,6 +75,8 @@ public class ScannerTinyB01 {
dev_id = Integer.valueOf(args[++i]).intValue();
} else if( arg.equals("-mac") && args.length > (i+1) ) {
waitForDevice = args[++i];
+ } else if( arg.equals("-char") && args.length > (i+1) ) {
+ characteristicList.add(args[++i]);
} else if( arg.equals("-mode") && args.length > (i+1) ) {
mode = Integer.valueOf(args[++i]).intValue();
} else if( arg.equals("-bluetoothManager") && args.length > (i+1) ) {
@@ -85,12 +90,13 @@ public class ScannerTinyB01 {
}
}
- System.err.println("Run with '[-dev_id <adapter-index>] [-mac <device_address>] [-mode <mode>] [-bluetoothManager <BluetoothManager-Implementation-Class-Name>]'");
+ System.err.println("Run with '[-dev_id <adapter-index>] [-mac <device_address>] (-char <uuid>)* [-mode <mode>] [-bluetoothManager <BluetoothManager-Implementation-Class-Name>]'");
}
System.err.println("BluetoothManager "+bluetoothManagerClazzName);
System.err.println("dev_id "+dev_id);
System.err.println("waitForDevice: "+waitForDevice);
+ System.err.println("characteristicList: "+Arrays.toString(characteristicList.toArray()));
System.err.println("mode "+mode);
if( waitForEnter ) {
@@ -241,7 +247,15 @@ public class ScannerTinyB01 {
matchingDiscoveredDeviceBucket[0] = null;
}
} else if( 1 == mode ) {
- sensor = adapter.find(null, waitForDevice, t0_discovery);
+ boolean timeout = false;
+ while( null == sensor && !timeout ) {
+ sensor = adapter.find(null, waitForDevice, t0_discovery);
+ if( null == sensor ) {
+ final long tn = BluetoothUtils.getCurrentMilliseconds();
+ timeout = ( tn - t0 ) > t0_discovery;
+ Thread.sleep(60);
+ }
+ }
} else {
boolean timeout = false;
while( null == sensor && !timeout ) {
@@ -310,6 +324,21 @@ public class ScannerTinyB01 {
if ( null == primServices || primServices.isEmpty() ) {
System.err.println("No BluetoothGattService found!");
} else {
+ {
+ for(final String characteristic : characteristicList) {
+ final BluetoothGattCharacteristic char0 = (BluetoothGattCharacteristic)
+ manager.find(BluetoothType.GATT_CHARACTERISTIC, null, characteristic, null, 1000);
+ final BluetoothGattCharacteristic char1 = (BluetoothGattCharacteristic)
+ manager.find(BluetoothType.GATT_CHARACTERISTIC, null, characteristic, sensor.getAdapter(), 1000);
+ final BluetoothGattCharacteristic char2 = (BluetoothGattCharacteristic)
+ manager.find(BluetoothType.GATT_CHARACTERISTIC, null, characteristic, sensor, 1000);
+ System.err.println("Char UUID "+characteristic);
+ //System.err.println(" over manager: "+char0);
+ System.err.println(" over adapter: "+char1);
+ System.err.println(" over device : "+char2);
+ }
+ }
+
final boolean addedCharacteristicListenerRes;
if( isDirectBT ) {
addedCharacteristicListenerRes =
@@ -330,10 +359,15 @@ public class ScannerTinyB01 {
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);
+ try {
+ 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);
+ } catch( final Exception ex) {
+ System.err.println("Caught "+ex.getMessage());
+ ex.printStackTrace();
+ }
}
}
}
diff --git a/examples/java/ScannerTinyB10.java b/examples/java/ScannerTinyB10.java
index 1d0c35c4..8d3d2b10 100644
--- a/examples/java/ScannerTinyB10.java
+++ b/examples/java/ScannerTinyB10.java
@@ -43,6 +43,7 @@ import org.tinyb.BluetoothGattCharacteristic;
import org.tinyb.BluetoothGattService;
import org.tinyb.BluetoothManager;
import org.tinyb.BluetoothNotification;
+import org.tinyb.BluetoothType;
import org.tinyb.BluetoothUtils;
import org.tinyb.EIRDataTypeSet;
import org.tinyb.GATTCharacteristicListener;
@@ -53,6 +54,8 @@ public class ScannerTinyB10 {
static final String EUI48_ANY_DEVICE = "00:00:00:00:00:00";
final List<String> waitForDevices = new ArrayList<String>();
+ final boolean isDirectBT;
+ final BluetoothManager manager;
long timestamp_t0;
@@ -61,11 +64,10 @@ public class ScannerTinyB10 {
boolean REMOVE_DEVICE = true;
boolean USE_WHITELIST = false;
final List<String> whitelist = new ArrayList<String>();
+ final List<String> characteristicList = new ArrayList<String>();
boolean SHOW_UPDATE_EVENTS = false;
- String bluetoothManagerClazzName = BluetoothFactory.DirectBTImplementationID.BluetoothManagerClassName;
-
int dev_id = 0; // default
Collection<String> devicesInProcessing = Collections.synchronizedCollection(new ArrayList<>());
@@ -221,6 +223,20 @@ public class ScannerTinyB10 {
"PERF: discovered to gatt-complete " + tdc5 + " ms (connect " + (tdc5 - td15) + " ms),"+System.lineSeparator()+
"PERF: adapter-init to gatt-complete " + td05 + " ms"+System.lineSeparator());
}
+ {
+ for(final String characteristic : characteristicList) {
+ final BluetoothGattCharacteristic char0 = (BluetoothGattCharacteristic)
+ manager.find(BluetoothType.GATT_CHARACTERISTIC, null, characteristic, null);
+ final BluetoothGattCharacteristic char1 = (BluetoothGattCharacteristic)
+ manager.find(BluetoothType.GATT_CHARACTERISTIC, null, characteristic, device.getAdapter());
+ final BluetoothGattCharacteristic char2 = (BluetoothGattCharacteristic)
+ manager.find(BluetoothType.GATT_CHARACTERISTIC, null, characteristic, device);
+ System.err.println("Char UUID "+characteristic);
+ System.err.println(" over manager: "+char0);
+ System.err.println(" over adapter: "+char1);
+ System.err.println(" over device : "+char2);
+ }
+ }
final boolean addedCharacteristicListenerRes =
BluetoothGattService.addCharacteristicListenerToAll(device, primServices, myCharacteristicListener);
System.err.println("Added GATTCharacteristicListener: "+addedCharacteristicListenerRes);
@@ -236,10 +252,15 @@ public class ScannerTinyB10 {
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);
+ try {
+ 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);
+ } catch( final Exception ex) {
+ System.err.println("Caught "+ex.getMessage());
+ ex.printStackTrace();
+ }
}
}
}
@@ -295,30 +316,29 @@ public class ScannerTinyB10 {
}
}
- public void runTest() {
- final boolean isDirectBT;
- final BluetoothManager manager;
- {
- BluetoothManager _manager = null;
- final BluetoothFactory.ImplementationIdentifier implID = BluetoothFactory.getImplementationIdentifier(bluetoothManagerClazzName);
- if( null == implID ) {
- System.err.println("Unable to find BluetoothManager "+bluetoothManagerClazzName);
- System.exit(-1);
- }
- isDirectBT = BluetoothFactory.DirectBTImplementationID.equals(implID);
- System.err.println("Using BluetoothManager "+bluetoothManagerClazzName);
- System.err.println("Using Implementation "+implID+", isDirectBT "+isDirectBT);
- 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;
+ public ScannerTinyB10(final String bluetoothManagerClazzName) {
+ BluetoothManager _manager = null;
+ final BluetoothFactory.ImplementationIdentifier implID = BluetoothFactory.getImplementationIdentifier(bluetoothManagerClazzName);
+ if( null == implID ) {
+ System.err.println("Unable to find BluetoothManager "+bluetoothManagerClazzName);
+ System.exit(-1);
}
+ isDirectBT = BluetoothFactory.DirectBTImplementationID.equals(implID);
+ System.err.println("Using BluetoothManager "+bluetoothManagerClazzName);
+ System.err.println("Using Implementation "+implID+", isDirectBT "+isDirectBT);
+ 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;
+ }
+
+ public void runTest() {
final BluetoothAdapter adapter;
{
final List<BluetoothAdapter> adapters = manager.getAdapters();
@@ -382,7 +402,17 @@ public class ScannerTinyB10 {
}
public static void main(final String[] args) throws InterruptedException {
- final ScannerTinyB10 test = new ScannerTinyB10();
+ String bluetoothManagerClazzName = BluetoothFactory.DirectBTImplementationID.BluetoothManagerClassName;
+ for(int i=0; i< args.length; i++) {
+ final String arg = args[i];
+ if( arg.equals("-bluetoothManager") && args.length > (i+1) ) {
+ bluetoothManagerClazzName = args[++i];
+ } else if( arg.equals("-debug") ) {
+ System.setProperty("org.tinyb.verbose", "true");
+ System.setProperty("org.tinyb.debug", "true");
+ }
+ }
+ final ScannerTinyB10 test = new ScannerTinyB10(bluetoothManagerClazzName);
boolean waitForEnter=false;
{
@@ -402,6 +432,8 @@ public class ScannerTinyB10 {
System.err.println("Whitelist + "+addr);
test.whitelist.add(addr);
test.USE_WHITELIST = true;
+ } else if( arg.equals("-char") && args.length > (i+1) ) {
+ test.characteristicList.add(args[++i]);
} else if( arg.equals("-disconnect") ) {
test.KEEP_CONNECTED = false;
} else if( arg.equals("-keepDevice") ) {
@@ -410,24 +442,19 @@ public class ScannerTinyB10 {
test.MULTI_MEASUREMENTS = Integer.valueOf(args[++i]).intValue();
} else if( arg.equals("-single") ) {
test.MULTI_MEASUREMENTS = -1;
- } else if( arg.equals("-debug") ) {
- System.setProperty("org.tinyb.verbose", "true");
- System.setProperty("org.tinyb.debug", "true");
- } else if( arg.equals("-bluetoothManager") && args.length > (i+1) ) {
- test.bluetoothManagerClazzName = args[++i];
}
}
-
- System.err.println("Run with '[-dev_id <adapter-index>] (-mac <device_address>)* [-disconnect] [-count <number>] [-single] (-wl <device_address>)* [-show_update_events] [-bluetoothManager <BluetoothManager-Implementation-Class-Name>]'");
+ System.err.println("Run with '[-dev_id <adapter-index>] (-mac <device_address>)* [-disconnect] [-count <number>] [-single] (-wl <device_address>)* (-char <uuid>)* [-show_update_events] [-bluetoothManager <BluetoothManager-Implementation-Class-Name>]'");
}
- System.err.println("BluetoothManager "+test.bluetoothManagerClazzName);
+ System.err.println("BluetoothManager "+bluetoothManagerClazzName);
System.err.println("MULTI_MEASUREMENTS "+test.MULTI_MEASUREMENTS);
System.err.println("KEEP_CONNECTED "+test.KEEP_CONNECTED);
System.err.println("REMOVE_DEVICE "+test.REMOVE_DEVICE);
System.err.println("USE_WHITELIST "+test.USE_WHITELIST);
System.err.println("dev_id "+test.dev_id);
System.err.println("waitForDevice: "+Arrays.toString(test.waitForDevices.toArray()));
+ System.err.println("characteristicList: "+Arrays.toString(test.characteristicList.toArray()));
if( waitForEnter ) {
System.err.println("Press ENTER to continue\n");
diff --git a/java/direct_bt/tinyb/DBTAdapter.java b/java/direct_bt/tinyb/DBTAdapter.java
index 4c924b6d..aa49a3f1 100644
--- a/java/direct_bt/tinyb/DBTAdapter.java
+++ b/java/direct_bt/tinyb/DBTAdapter.java
@@ -38,8 +38,12 @@ import org.tinyb.BluetoothAdapter;
import org.tinyb.BluetoothAddressType;
import org.tinyb.BluetoothDevice;
import org.tinyb.BluetoothException;
+import org.tinyb.BluetoothGattCharacteristic;
+import org.tinyb.BluetoothGattDescriptor;
+import org.tinyb.BluetoothGattService;
import org.tinyb.BluetoothManager;
import org.tinyb.BluetoothNotification;
+import org.tinyb.BluetoothObject;
import org.tinyb.BluetoothType;
import org.tinyb.EIRDataTypeSet;
import org.tinyb.HCIStatusCode;
@@ -129,8 +133,7 @@ public class DBTAdapter extends DBTObject implements BluetoothAdapter
@Override
public BluetoothDevice find(final String name, final String address, final long timeoutMS) {
- final BluetoothManager manager = DBTManager.getBluetoothManager();
- return (BluetoothDevice) manager.find(BluetoothType.DEVICE, name, address, this, timeoutMS);
+ return (DBTDevice) findInCache(name, address, BluetoothType.DEVICE);
}
@Override
@@ -489,4 +492,87 @@ public class DBTAdapter extends DBTObject implements BluetoothAdapter
}
}
};
+
+ /**
+ * Returns the matching {@link DBTObject} from the internal cache if found,
+ * otherwise {@code null}.
+ * <p>
+ * The returned {@link DBTObject} may be of type
+ * <ul>
+ * <li>{@link DBTDevice}</li>
+ * <li>{@link DBTGattService}</li>
+ * <li>{@link DBTGattCharacteristic}</li>
+ * <li>{@link DBTGattDescriptor}</li>
+ * </ul>
+ * or alternatively in {@link BluetoothObject} space
+ * <ul>
+ * <li>{@link BluetoothType#DEVICE} -> {@link BluetoothDevice}</li>
+ * <li>{@link BluetoothType#GATT_SERVICE} -> {@link BluetoothGattService}</li>
+ * <li>{@link BluetoothType#GATT_CHARACTERISTIC} -> {@link BluetoothGattCharacteristic}</li>
+ * <li>{@link BluetoothType#GATT_DESCRIPTOR} -> {@link BluetoothGattDescriptor}</li>
+ * </ul>
+ * </p>
+ * @param name name of the desired {@link BluetoothType#DEVICE device}.
+ * Maybe {@code null}.
+ * @param identifier EUI48 address of the desired {@link BluetoothType#DEVICE device}
+ * or UUID of the desired {@link BluetoothType#GATT_SERVICE service},
+ * {@link BluetoothType#GATT_CHARACTERISTIC characteristic} or {@link BluetoothType#GATT_DESCRIPTOR descriptor} to be found.
+ * Maybe {@code null}, in which case the first object of the desired type is being returned - if existing.
+ * @param type specify the type of the object to be found, either
+ * {@link BluetoothType#DEVICE device},
+ * {@link BluetoothType#GATT_SERVICE service}, {@link BluetoothType#GATT_CHARACTERISTIC characteristic}
+ * or {@link BluetoothType#GATT_DESCRIPTOR descriptor}.
+ * {@link BluetoothType#NONE none} means anything.
+ */
+ /* pp */ DBTObject findInCache(final String name, final String identifier, final BluetoothType type) {
+ final boolean anyType = BluetoothType.NONE == type;
+ final boolean deviceType = BluetoothType.DEVICE == type;
+ final boolean serviceType = BluetoothType.GATT_SERVICE == type;
+ final boolean charType = BluetoothType.GATT_CHARACTERISTIC== type;
+ final boolean descType = BluetoothType.GATT_DESCRIPTOR == type;
+
+ if( !anyType && !deviceType && !serviceType && !charType && !descType ) {
+ return null;
+ }
+ synchronized(discoveredDevicesLock) {
+ if( null == name && null == identifier && ( anyType || deviceType ) ) {
+ // special case for 1st valid device
+ if( discoveredDevices.size() > 0 ) {
+ return (DBTDevice) discoveredDevices.get(0);
+ }
+ return null; // no device
+ }
+ for(int devIdx = discoveredDevices.size() - 1; devIdx >= 0; devIdx-- ) {
+ final DBTDevice device = (DBTDevice) discoveredDevices.get(devIdx);
+ if( ( anyType || deviceType ) ) {
+ if( null != name && null != identifier &&
+ device.getName().equals(name) &&
+ device.getAddress().equals(identifier)
+ )
+ {
+ return device;
+ }
+ if( null != identifier &&
+ device.getAddress().equals(identifier)
+ )
+ {
+ return device;
+ }
+ if( null != name &&
+ device.getName().equals(name)
+ )
+ {
+ return device;
+ }
+ }
+ if( anyType || serviceType || charType || descType ) {
+ final DBTObject dbtObj = device.findInCache(identifier, type);
+ if( null != dbtObj ) {
+ return dbtObj;
+ }
+ }
+ }
+ return null;
+ }
+ }
}
diff --git a/java/direct_bt/tinyb/DBTDevice.java b/java/direct_bt/tinyb/DBTDevice.java
index 74547cef..a98636bb 100644
--- a/java/direct_bt/tinyb/DBTDevice.java
+++ b/java/direct_bt/tinyb/DBTDevice.java
@@ -26,6 +26,7 @@
package direct_bt.tinyb;
import java.lang.ref.WeakReference;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -36,9 +37,11 @@ import org.tinyb.BluetoothAddressType;
import org.tinyb.BluetoothDevice;
import org.tinyb.BluetoothException;
import org.tinyb.BluetoothGattCharacteristic;
+import org.tinyb.BluetoothGattDescriptor;
import org.tinyb.BluetoothGattService;
import org.tinyb.BluetoothManager;
import org.tinyb.BluetoothNotification;
+import org.tinyb.BluetoothObject;
import org.tinyb.BluetoothType;
import org.tinyb.EIRDataTypeSet;
import org.tinyb.GATTCharacteristicListener;
@@ -58,6 +61,7 @@ public class DBTDevice extends DBTObject implements BluetoothDevice
private volatile String name;
long ts_last_discovery;
long ts_last_update;
+ /* pp */ final List<WeakReference<DBTGattService>> serviceCache = new ArrayList<WeakReference<DBTGattService>>();
private final Object userCallbackLock = new Object();
@@ -127,6 +131,7 @@ public class DBTDevice extends DBTObject implements BluetoothDevice
@Override
public void deviceDisconnected(final BluetoothDevice device, final HCIStatusCode reason, final long timestamp) {
if( isConnected.compareAndSet(true, false) ) {
+ clearServiceCache();
synchronized(userCallbackLock) {
if( servicesResolved.compareAndSet(true, false) ) {
if( null != userServicesResolvedNotificationsCB ) {
@@ -246,6 +251,8 @@ public class DBTDevice extends DBTObject implements BluetoothDevice
disableTrustedNotifications();
// FIXME disableTrustedNotificationsImpl();
+ clearServiceCache();
+
final DBTAdapter a = getAdapter();
if( null != a ) {
a.removeStatusListener(statusListener);
@@ -297,9 +304,7 @@ public class DBTDevice extends DBTObject implements BluetoothDevice
@Override
public BluetoothGattService find(final String UUID, final long timeoutMS) {
- final BluetoothManager manager = DBTManager.getBluetoothManager();
- return (BluetoothGattService) manager.find(BluetoothType.GATT_SERVICE,
- null, UUID, this, timeoutMS);
+ return (DBTGattService) findInCache(UUID, BluetoothType.GATT_SERVICE);
}
@Override
@@ -583,7 +588,9 @@ public class DBTDevice extends DBTObject implements BluetoothDevice
@Override
public List<BluetoothGattService> getServices() {
try {
- return getServicesImpl();
+ final List<BluetoothGattService> services = getServicesImpl();
+ updateServiceCache(services);
+ return services;
} catch (final Throwable t) {
if(DEBUG) {
System.err.println("Caught "+t.getMessage()+" on thread "+Thread.currentThread().toString());
@@ -645,4 +652,113 @@ public class DBTDevice extends DBTObject implements BluetoothDevice
@Override
public native int removeAllCharacteristicListener();
+
+ /* local functionality */
+
+ private void clearServiceCache() {
+ synchronized(serviceCache) {
+ for(int i = serviceCache.size() - 1; i >= 0; i-- ) {
+ serviceCache.get(i).clear();
+ serviceCache.remove(i);
+ }
+ }
+ }
+ private void updateServiceCache(final List<BluetoothGattService> services) {
+ synchronized(serviceCache) {
+ clearServiceCache();
+ if( null != services ) {
+ for(final BluetoothGattService service : services) {
+ serviceCache.add( new WeakReference<DBTGattService>( (DBTGattService)service ) );
+ }
+ }
+ }
+ }
+
+ /* pp */ boolean checkServiceCache(final boolean getServices) {
+ synchronized(serviceCache) {
+ if( serviceCache.isEmpty() ) {
+ if( getServices ) {
+ getServices();
+ if( serviceCache.isEmpty() ) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ /**
+ * Returns the matching {@link DBTObject} from the internal cache if found,
+ * otherwise {@code null}.
+ * <p>
+ * The returned {@link DBTObject} may be of type
+ * <ul>
+ * <li>{@link DBTGattService}</li>
+ * <li>{@link DBTGattCharacteristic}</li>
+ * <li>{@link DBTGattDescriptor}</li>
+ * </ul>
+ * or alternatively in {@link BluetoothObject} space
+ * <ul>
+ * <li>{@link BluetoothType#GATT_SERVICE} -> {@link BluetoothGattService}</li>
+ * <li>{@link BluetoothType#GATT_CHARACTERISTIC} -> {@link BluetoothGattCharacteristic}</li>
+ * <li>{@link BluetoothType#GATT_DESCRIPTOR} -> {@link BluetoothGattDescriptor}</li>
+ * </ul>
+ * </p>
+ * @param uuid UUID of the desired {@link BluetoothType#GATT_SERVICE service},
+ * {@link BluetoothType#GATT_CHARACTERISTIC characteristic} or {@link BluetoothType#GATT_DESCRIPTOR descriptor} to be found.
+ * Maybe {@code null}, in which case the first object of the desired type is being returned - if existing.
+ * @param type specify the type of the object to be found, either
+ * {@link BluetoothType#GATT_SERVICE service}, {@link BluetoothType#GATT_CHARACTERISTIC characteristic}
+ * or {@link BluetoothType#GATT_DESCRIPTOR descriptor}.
+ * {@link BluetoothType#NONE none} means anything.
+ */
+ /* pp */ DBTObject findInCache(final String uuid, final BluetoothType type) {
+ final boolean anyType = BluetoothType.NONE == type;
+ final boolean serviceType = BluetoothType.GATT_SERVICE == type;
+ final boolean charType = BluetoothType.GATT_CHARACTERISTIC== type;
+ final boolean descType = BluetoothType.GATT_DESCRIPTOR == type;
+
+ if( !anyType && !serviceType && !charType && !descType ) {
+ return null;
+ }
+ synchronized(serviceCache) {
+ if( !checkServiceCache(true) ) {
+ return null;
+ }
+
+ if( null == uuid && ( anyType || serviceType ) ) {
+ // special case for 1st valid service ref
+ while( !serviceCache.isEmpty() ) {
+ final DBTGattService service = serviceCache.get(0).get();
+ if( null == service ) {
+ serviceCache.remove(0);
+ } else {
+ return service;
+ }
+ }
+ return null; // empty valid service refs
+ }
+ for(int srvIdx = serviceCache.size() - 1; srvIdx >= 0; srvIdx-- ) {
+ final DBTGattService service = serviceCache.get(srvIdx).get();
+ if( null == service ) {
+ serviceCache.remove(srvIdx); // remove dead ref
+ continue; // cont w/ next service
+ }
+ if( ( anyType || serviceType ) && service.getUUID().equals(uuid) ) {
+ return service;
+ }
+ if( anyType || charType || descType ) {
+ final DBTObject dbtObj = service.findInCache(uuid, type);
+ if( null != dbtObj ) {
+ return dbtObj;
+ }
+ }
+ }
+ return null;
+ }
+ }
+
}
diff --git a/java/direct_bt/tinyb/DBTGattCharacteristic.java b/java/direct_bt/tinyb/DBTGattCharacteristic.java
index 272735e0..0233eff9 100644
--- a/java/direct_bt/tinyb/DBTGattCharacteristic.java
+++ b/java/direct_bt/tinyb/DBTGattCharacteristic.java
@@ -35,6 +35,7 @@ import org.tinyb.BluetoothGattDescriptor;
import org.tinyb.BluetoothGattService;
import org.tinyb.BluetoothManager;
import org.tinyb.BluetoothNotification;
+import org.tinyb.BluetoothObject;
import org.tinyb.BluetoothType;
import org.tinyb.BluetoothUtils;
import org.tinyb.GATTCharacteristicListener;
@@ -73,7 +74,7 @@ public class DBTGattCharacteristic extends DBTObject implements BluetoothGattCha
/* Optional Client Characteristic Configuration index within descriptorList */
private final int clientCharacteristicsConfigIndex;
- private final List<BluetoothGattDescriptor> descriptorList;
+ /* pp */ final List<BluetoothGattDescriptor> descriptorList;
private byte[] cachedValue = null;
private BluetoothNotification<byte[]> valueNotificationCB = null;
@@ -194,9 +195,10 @@ public class DBTGattCharacteristic extends DBTObject implements BluetoothGattCha
@Override
public BluetoothGattDescriptor find(final String UUID, final long timeoutMS) {
- final BluetoothManager manager = DBTManager.getBluetoothManager();
- return (BluetoothGattDescriptor) manager.find(BluetoothType.GATT_DESCRIPTOR,
- null, UUID, this, timeoutMS);
+ if( !checkServiceCache() ) {
+ return null;
+ }
+ return (DBTGattDescriptor) findInCache(UUID, BluetoothType.GATT_DESCRIPTOR);
}
@Override
@@ -331,4 +333,50 @@ public class DBTGattCharacteristic extends DBTObject implements BluetoothGattCha
@Override
protected native void deleteImpl(long nativeInstance);
+ /* local functionality */
+
+ /* pp */ boolean checkServiceCache() {
+ final DBTGattService service = wbr_service.get();
+ if( null == service ) {
+ return false;
+ }
+ final DBTDevice device = service.wbr_device.get();
+ return null != device && device.checkServiceCache(false);
+ }
+
+ /**
+ * Returns the matching {@link DBTObject} from the internal cache if found,
+ * otherwise {@code null}.
+ * <p>
+ * The returned {@link DBTObject} may be of type
+ * <ul>
+ * <li>{@link DBTGattDescriptor}</li>
+ * </ul>
+ * or alternatively in {@link BluetoothObject} space
+ * <ul>
+ * <li>{@link BluetoothType#GATT_DESCRIPTOR} -> {@link BluetoothGattDescriptor}</li>
+ * </ul>
+ * </p>
+ * @param uuid UUID of the desired
+ * {@link BluetoothType#GATT_DESCRIPTOR descriptor} to be found.
+ * Maybe {@code null}, in which case the first object of the desired type is being returned - if existing.
+ * @param type specify the type of the object to be found, a {@link BluetoothType#GATT_DESCRIPTOR descriptor}.
+ * {@link BluetoothType#NONE none} means anything.
+ */
+ /* pp */ DBTObject findInCache(final String uuid, final BluetoothType type) {
+ final boolean anyType = BluetoothType.NONE == type;
+ final boolean descType = BluetoothType.GATT_DESCRIPTOR == type;
+
+ if( !anyType && !descType ) {
+ return null;
+ }
+ final int size = descriptorList.size();
+ for(int i = 0; i < size; i++ ) {
+ final DBTGattDescriptor descr = (DBTGattDescriptor) descriptorList.get(i);
+ if( null == uuid || descr.getUUID().equals(uuid) ) {
+ return descr;
+ }
+ }
+ return null;
+ }
}
diff --git a/java/direct_bt/tinyb/DBTGattService.java b/java/direct_bt/tinyb/DBTGattService.java
index 98081e25..4dbcc71e 100644
--- a/java/direct_bt/tinyb/DBTGattService.java
+++ b/java/direct_bt/tinyb/DBTGattService.java
@@ -30,8 +30,10 @@ import java.util.List;
import org.tinyb.BluetoothDevice;
import org.tinyb.BluetoothGattCharacteristic;
+import org.tinyb.BluetoothGattDescriptor;
import org.tinyb.BluetoothGattService;
import org.tinyb.BluetoothManager;
+import org.tinyb.BluetoothObject;
import org.tinyb.BluetoothType;
public class DBTGattService extends DBTObject implements BluetoothGattService
@@ -43,7 +45,7 @@ public class DBTGattService extends DBTObject implements BluetoothGattService
private final String type_uuid;
private final short handleStart;
private final short handleEnd;
- private final List<BluetoothGattCharacteristic> characteristicList;
+ /* pp */ final List<BluetoothGattCharacteristic> characteristicList;
/* pp */ DBTGattService(final long nativeInstance, final DBTDevice device, final boolean isPrimary,
final String type_uuid, final short handleStart, final short handleEnd)
@@ -81,14 +83,15 @@ public class DBTGattService extends DBTObject implements BluetoothGattService
@Override
public BluetoothGattCharacteristic find(final String UUID, final long timeoutMS) {
- final BluetoothManager manager = DBTManager.getBluetoothManager();
- return (DBTGattCharacteristic) manager.find(BluetoothType.GATT_CHARACTERISTIC,
- null, UUID, this, timeoutMS);
+ if( !checkServiceCache() ) {
+ return null;
+ }
+ return (DBTGattCharacteristic) findInCache(UUID, BluetoothType.GATT_CHARACTERISTIC);
}
@Override
public BluetoothGattCharacteristic find(final String UUID) {
- return find(UUID, 0);
+ return find(UUID, 0);
}
@Override
@@ -132,4 +135,59 @@ public class DBTGattService extends DBTObject implements BluetoothGattService
@Override
protected native void deleteImpl(long nativeInstance);
+
+ /* local functionality */
+
+ /* pp */ boolean checkServiceCache() {
+ final DBTDevice device = wbr_device.get();
+ return null != device && device.checkServiceCache(false);
+ }
+
+ /**
+ * Returns the matching {@link DBTObject} from the internal cache if found,
+ * otherwise {@code null}.
+ * <p>
+ * The returned {@link DBTObject} may be of type
+ * <ul>
+ * <li>{@link DBTGattCharacteristic}</li>
+ * <li>{@link DBTGattDescriptor}</li>
+ * </ul>
+ * or alternatively in {@link BluetoothObject} space
+ * <ul>
+ * <li>{@link BluetoothType#GATT_CHARACTERISTIC} -> {@link BluetoothGattCharacteristic}</li>
+ * <li>{@link BluetoothType#GATT_DESCRIPTOR} -> {@link BluetoothGattDescriptor}</li>
+ * </ul>
+ * </p>
+ * @param uuid UUID of the desired
+ * {@link BluetoothType#GATT_CHARACTERISTIC characteristic} or {@link BluetoothType#GATT_DESCRIPTOR descriptor} to be found.
+ * Maybe {@code null}, in which case the first object of the desired type is being returned - if existing.
+ * @param type specify the type of the object to be found, either
+ * {@link BluetoothType#GATT_CHARACTERISTIC characteristic}
+ * or {@link BluetoothType#GATT_DESCRIPTOR descriptor}.
+ * {@link BluetoothType#NONE none} means anything.
+ */
+ /* pp */ DBTObject findInCache(final String uuid, final BluetoothType type) {
+ final boolean anyType = BluetoothType.NONE == type;
+ final boolean charType = BluetoothType.GATT_CHARACTERISTIC== type;
+ final boolean descType = BluetoothType.GATT_DESCRIPTOR == type;
+
+ if( !anyType && !charType && !descType ) {
+ return null;
+ }
+ final int characteristicSize = characteristicList.size();
+ for(int charIdx = 0; charIdx < characteristicSize; charIdx++ ) {
+ final DBTGattCharacteristic characteristic = (DBTGattCharacteristic) characteristicList.get(charIdx);
+ if( ( anyType || charType ) && ( null == uuid || characteristic.getUUID().equals(uuid) ) ) {
+ return characteristic;
+ }
+ if( anyType || descType ) {
+ final DBTObject dbtObj = characteristic.findInCache(uuid, type);
+ if( null != dbtObj ) {
+ return dbtObj;
+ }
+ }
+ }
+ return null;
+ }
+
}
diff --git a/java/direct_bt/tinyb/DBTManager.java b/java/direct_bt/tinyb/DBTManager.java
index b9d99a4c..8dee59a5 100644
--- a/java/direct_bt/tinyb/DBTManager.java
+++ b/java/direct_bt/tinyb/DBTManager.java
@@ -35,6 +35,8 @@ import org.tinyb.BluetoothAdapter;
import org.tinyb.BluetoothDevice;
import org.tinyb.BluetoothException;
import org.tinyb.BluetoothFactory;
+import org.tinyb.BluetoothGattCharacteristic;
+import org.tinyb.BluetoothGattDescriptor;
import org.tinyb.BluetoothGattService;
import org.tinyb.BluetoothObject;
import org.tinyb.BluetoothManager;
@@ -158,12 +160,9 @@ public class DBTManager implements BluetoothManager
public BluetoothType getBluetoothType() { return BluetoothType.NONE; }
- private DBTObject find(final int type, final String name, final String identifier, final BluetoothObject parent, final long milliseconds)
- { throw new UnsupportedOperationException(); } // FIXME
-
@Override
public DBTObject find(final BluetoothType type, final String name, final String identifier, final BluetoothObject parent, final long timeoutMS) {
- return find(type.ordinal(), name, identifier, parent, timeoutMS);
+ return findInCache((DBTObject)parent, type, name, identifier);
}
@Override
@@ -174,13 +173,19 @@ public class DBTManager implements BluetoothManager
@SuppressWarnings("unchecked")
@Override
public <T extends BluetoothObject> T find(final String name, final String identifier, final BluetoothObject parent, final long timeoutMS) {
- return (T) find(DBTObject.class_type().ordinal(), name, identifier, parent, timeoutMS);
+ // Due to generic type erasure, we cannot determine the matching BluetoothType for the return parameter,
+ // hence this orig TinyB API method is rather misleading than useful.
+ throw new UnsupportedOperationException("Generic return type 'find' won't be implemented.");
+ // return (T) find(BluetoothType.NONE, name, identifier, parent, timeoutMS);
}
@SuppressWarnings("unchecked")
@Override
public <T extends BluetoothObject> T find(final String name, final String identifier, final BluetoothObject parent) {
- return (T) find(name, identifier, parent, 0);
+ // Due to generic type erasure, we cannot determine the matching BluetoothType for the return parameter,
+ // hence this orig TinyB API method is rather misleading than useful.
+ throw new UnsupportedOperationException("Generic return type 'find' won't be implemented.");
+ // return (T) find(BluetoothType.NONE, name, identifier, parent, 0);
}
@Override
@@ -317,4 +322,126 @@ public class DBTManager implements BluetoothManager
deleteImpl(nativeInstance);
}
+ /**
+ * Returns the matching {@link DBTObject} from the internal cache if found,
+ * otherwise {@code null}.
+ * <p>
+ * The returned {@link DBTObject} may be of type
+ * <ul>
+ * <li>{@link DBTAdapter}</li>
+ * <li>{@link DBTDevice}</li>
+ * <li>{@link DBTGattService}</li>
+ * <li>{@link DBTGattCharacteristic}</li>
+ * <li>{@link DBTGattDescriptor}</li>
+ * </ul>
+ * or alternatively in {@link BluetoothObject} space
+ * <ul>
+ * <li>{@link BluetoothType#ADAPTER} -> {@link BluetoothAdapter}</li>
+ * <li>{@link BluetoothType#DEVICE} -> {@link BluetoothDevice}</li>
+ * <li>{@link BluetoothType#GATT_SERVICE} -> {@link BluetoothGattService}</li>
+ * <li>{@link BluetoothType#GATT_CHARACTERISTIC} -> {@link BluetoothGattCharacteristic}</li>
+ * <li>{@link BluetoothType#GATT_DESCRIPTOR} -> {@link BluetoothGattDescriptor}</li>
+ * </ul>
+ * </p>
+ * @param name name of the desired {@link BluetoothType#ADAPTER adapter} or {@link BluetoothType#DEVICE device}.
+ * Maybe {@code null}.
+ * @param identifier EUI48 address of the desired {@link BluetoothType#ADAPTER adapter} or {@link BluetoothType#DEVICE device}
+ * or UUID of the desired {@link BluetoothType#GATT_SERVICE service},
+ * {@link BluetoothType#GATT_CHARACTERISTIC characteristic} or {@link BluetoothType#GATT_DESCRIPTOR descriptor} to be found.
+ * Maybe {@code null}, in which case the first object of the desired type is being returned - if existing.
+ * @param type specify the type of the object to be found, either
+ * {@link BluetoothType#ADAPTER adapter}, {@link BluetoothType#DEVICE device},
+ * {@link BluetoothType#GATT_SERVICE service}, {@link BluetoothType#GATT_CHARACTERISTIC characteristic}
+ * or {@link BluetoothType#GATT_DESCRIPTOR descriptor}.
+ * {@link BluetoothType#NONE none} means anything.
+ */
+ /* pp */ DBTObject findInCache(final String name, final String identifier, final BluetoothType type) {
+ final boolean anyType = BluetoothType.NONE == type;
+ final boolean adapterType = BluetoothType.ADAPTER == type;
+
+ if( null == name && null == identifier && ( anyType || adapterType ) ) {
+ // special case for 1st valid adapter
+ if( adapters.size() > 0 ) {
+ return (DBTAdapter) adapters.get(0);
+ }
+ return null; // no adapter
+ }
+ for(int devIdx = adapters.size() - 1; devIdx >= 0; devIdx-- ) {
+ final DBTAdapter adapter = (DBTAdapter) adapters.get(devIdx);
+ if( ( anyType || adapterType ) ) {
+ if( null != name && null != identifier &&
+ adapter.getName().equals(name) &&
+ adapter.getAddress().equals(identifier)
+ )
+ {
+ return adapter;
+ }
+ if( null != identifier &&
+ adapter.getAddress().equals(identifier)
+ )
+ {
+ return adapter;
+ }
+ if( null != name &&
+ adapter.getName().equals(name)
+ )
+ {
+ return adapter;
+ }
+ }
+ final DBTObject dbtObj = adapter.findInCache(name, identifier, type);
+ if( null != dbtObj ) {
+ return dbtObj;
+ }
+ }
+ return null;
+ }
+
+ /* pp */ DBTObject findInCache(final DBTObject parent, final BluetoothType type, final String name, final String identifier) {
+ if( null == parent ) {
+ return findInCache(name, identifier, type);
+ }
+ final boolean anyType = BluetoothType.NONE == type;
+ final boolean deviceType = BluetoothType.DEVICE == type;
+ final boolean serviceType = BluetoothType.GATT_SERVICE == type;
+ final boolean charType = BluetoothType.GATT_CHARACTERISTIC== type;
+ final boolean descType = BluetoothType.GATT_DESCRIPTOR == type;
+
+ final BluetoothType parentType = parent.getBluetoothType();
+
+ if( BluetoothType.ADAPTER == parentType &&
+ ( anyType || deviceType || serviceType || charType || descType )
+ )
+ {
+ return ((DBTAdapter) parent).findInCache(name, identifier, type);
+ }
+ if( BluetoothType.DEVICE == parentType &&
+ ( anyType || serviceType || charType || descType )
+ )
+ {
+ return ((DBTDevice) parent).findInCache(identifier, type);
+ }
+ if( BluetoothType.GATT_SERVICE == parentType &&
+ ( anyType || charType || descType )
+ )
+ {
+ final DBTGattService service = (DBTGattService) parent;
+ if( !service.checkServiceCache() ) {
+ return null;
+ }
+ return service.findInCache(identifier, type);
+ }
+ if( BluetoothType.GATT_CHARACTERISTIC == parentType &&
+ ( anyType || descType )
+ )
+ {
+ final DBTGattCharacteristic characteristic = (DBTGattCharacteristic) parent;
+ if( !characteristic.checkServiceCache() ) {
+ return null;
+ }
+ return characteristic.findInCache(identifier, type);
+ }
+ return null;
+ }
+
}