summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2020-10-25 02:57:31 +0100
committerSven Gothel <[email protected]>2020-10-25 02:57:31 +0100
commite878104ae9950d7cbc44841e6c5c5f0b9c131304 (patch)
tree4113a6af50db87dcbc32a4e5dd58a5b5e1a253bd /examples
parent305a92e8f295298bc4dd3cb12f4b32b68d7bf0ae (diff)
Support Adapter removal and add @ runtime: Handle INDEX_ADDED and INDEX_REMOVED Mgmt events
C++ DBTManager detects INDEX_ADDED and INDEX_REMOVED Mgmt events @INDEX_ADDED reception in the event reader, a new processAdapterAdded() thread is spawned initializing the adapter as usual and maintaining adding its AdapterInfo artifact. Then all user INDEX_ADDED callbacks are called from this thread, after the new AdapterInfo entry has been added. @INDEX_REMOVED here the matching AdapterInfo entry is simply removed DBTAdapter naturally also listens to INDEX_REMOVED, simply closing its instance and hence rendering it isValid() = false. +++ On close(), Java's DBTAdapter will remove itself from the DBTManager's adapter list. This removal will happen automatically, if INDEX_REMOVED is received - see below. On the Java side, DBTManager listens to: @INDEX_REMOVED here the matching adapter instance is simply removed @INDEX_ADDED and @NEW_SETTINGS(POWERED) checks whether the matching adapter instance exists and creates a new one added to the adapters list if necessary. @NEW_SETTINGS(POWERED) has been added here as well, since a user could chose to close the adapter if POWERED off and hence removing itself from the DBTManager adapter list. Hence NEW_SETTINGS(POWERED) will add a new adapter instance, if none exists. +++ Due to this new concurrent use-case of the adapter list, the list is now a CopyOnWriteArrayList instance supporting lock-free fast reads. Mutations of the list occur rarely, hopefully ;-). On the C++, the AdapterInfo is a jau::cow_vector and the callbacks are store in a jau::cow_vector as well (MgmtAdapterEventCallbackList). Hence both share the same properties w/ the Java side: Fast lock-free reads.
Diffstat (limited to 'examples')
-rw-r--r--examples/direct_bt_scanner10/dbt_scanner10.cpp85
-rw-r--r--examples/java/DBTScanner10.java65
2 files changed, 98 insertions, 52 deletions
diff --git a/examples/direct_bt_scanner10/dbt_scanner10.cpp b/examples/direct_bt_scanner10/dbt_scanner10.cpp
index b89c498b..9a9d162b 100644
--- a/examples/direct_bt_scanner10/dbt_scanner10.cpp
+++ b/examples/direct_bt_scanner10/dbt_scanner10.cpp
@@ -506,40 +506,54 @@ static bool startDiscovery(DBTAdapter *a, std::string msg) {
return HCIStatusCode::SUCCESS == status;
}
-void test(int dev_id) {
- bool done = false;
-
- timestamp_t0 = getCurrentMilliseconds();
-
- DBTAdapter adapter(dev_id); // given dev_id >= 0 or default adapter (1st powered)
- if( !adapter.hasDevId() ) {
- fprintf(stderr, "Default adapter not available.\n");
- exit(1);
+static std::shared_ptr<DBTAdapter> createAdapter(const int dev_id0) {
+ // pre-validate dev_id availability
+ int dev_id;
+ DBTManager & mngr = DBTManager::get(BTMode::LE);
+ if( 0 > dev_id0 ) {
+ dev_id = mngr.getDefaultAdapterDevID();
+ } else if( nullptr != mngr.getAdapterInfo(dev_id0) ) {
+ dev_id = dev_id0;
+ } else {
+ dev_id = -1;
+ }
+ if( 0 > dev_id ) {
+ fprintf(stderr, "Adapter not available (1): Request %d, deduced %d\n", dev_id0, dev_id);
+ return nullptr;
}
- if( !adapter.isValid() ) {
- fprintf(stderr, "Adapter invalid.\n");
- exit(1);
+
+ std::shared_ptr<DBTAdapter> adapter(new DBTAdapter(dev_id)); // given dev_id >= 0 or default adapter (1st powered)
+ if( !adapter->hasDevId() ) {
+ fprintf(stderr, "Adapter not available (2): %d\n", dev_id); // should have been covered above
+ return nullptr;
}
- if( !adapter.isEnabled() ) {
- fprintf(stderr, "Adapter not enabled: device %s, address %s: %s\n",
- adapter.getName().c_str(), adapter.getAddressString().c_str(), adapter.toString().c_str());
- exit(1);
+ if( !adapter->isPowered() ) { // should have been covered above
+ fprintf(stderr, "Adapter not powered (2): %s\n", adapter->toString().c_str());
+ return nullptr;
}
- fprintf(stderr, "Using adapter: device %s, address %s: %s\n",
- adapter.getName().c_str(), adapter.getAddressString().c_str(), adapter.toString().c_str());
+ fprintf(stderr, "Using adapter: %s\n", adapter->toString().c_str());
- adapter.addStatusListener(std::shared_ptr<AdapterStatusListener>(new MyAdapterStatusListener()));
+ adapter->addStatusListener(std::shared_ptr<AdapterStatusListener>(new MyAdapterStatusListener()));
if( USE_WHITELIST ) {
for (auto it = WHITELIST.begin(); it != WHITELIST.end(); ++it) {
- bool res = adapter.addDeviceToWhitelist(*it, BDAddressType::BDADDR_LE_PUBLIC, HCIWhitelistConnectType::HCI_AUTO_CONN_ALWAYS);
+ bool res = adapter->addDeviceToWhitelist(*it, BDAddressType::BDADDR_LE_PUBLIC, HCIWhitelistConnectType::HCI_AUTO_CONN_ALWAYS);
fprintf(stderr, "Added to WHITELIST: res %d, address %s\n", res, it->toString().c_str());
}
} else {
- if( !startDiscovery(&adapter, "kick-off") ) {
- done = true;
+ if( !startDiscovery(adapter.get(), "kick-off") ) {
+ return nullptr;
}
}
+ return adapter;
+}
+
+void test(int dev_id) {
+ bool done = false;
+
+ timestamp_t0 = getCurrentMilliseconds();
+
+ std::shared_ptr<DBTAdapter> adapter = createAdapter(dev_id);
while( !done ) {
if( 0 == MULTI_MEASUREMENTS ||
@@ -552,14 +566,29 @@ void test(int dev_id) {
printDevicesProcessed("****** DevicesProcessed ");
done = true;
} else {
- std::this_thread::sleep_for(std::chrono::milliseconds(3000));
+ // validate existing adapter
+ if( nullptr != adapter ) {
+ if( !adapter->isValid() /* || !adapter->isPowered() */ ) {
+ // In case of removed adapter, not just powered-off (soft-reset)
+ // We could also close adapter on !isPowered() here, but its not required - adapter operational.
+ adapter->close();
+ adapter = nullptr; // purge
+ }
+ }
+ // re-create adapter if required
+ if( nullptr == adapter ) {
+ adapter = createAdapter(dev_id);
+ }
+ std::this_thread::sleep_for(std::chrono::milliseconds(2000));
}
}
- fprintf(stderr, "****** EOL Adapter's Devices - pre close\n");
- adapter.printSharedPtrListOfDevices();
- adapter.close();
- fprintf(stderr, "****** EOL Adapter's Devices - post close\n");
- adapter.printSharedPtrListOfDevices();
+ fprintf(stderr, "****** EOL Adapter's Devices - pre close: %s\n", adapter->toString().c_str());
+ if( nullptr != adapter ) {
+ adapter->printSharedPtrListOfDevices();
+ adapter->close();
+ fprintf(stderr, "****** EOL Adapter's Devices - post close\n");
+ adapter->printSharedPtrListOfDevices();
+ }
}
#include <cstdio>
diff --git a/examples/java/DBTScanner10.java b/examples/java/DBTScanner10.java
index 5988f5d6..7c490f24 100644
--- a/examples/java/DBTScanner10.java
+++ b/examples/java/DBTScanner10.java
@@ -525,29 +525,27 @@ public class DBTScanner10 {
return HCIStatusCode.SUCCESS == status;
}
- public void runTest(final BluetoothManager manager) {
- final BluetoothAdapter adapter;
- {
- final List<BluetoothAdapter> adapters = manager.getAdapters();
- for(int i=0; i < adapters.size(); i++) {
- println("Adapter["+i+"]: "+adapters.get(i));
- }
- if( adapters.size() <= dev_id ) {
- println("No adapter dev_id "+dev_id+" available, adapter count "+adapters.size());
- System.exit(-1);
- }
- if( 0 > dev_id ) {
- adapter = manager.getDefaultAdapter();
- } else {
- adapter = adapters.get(dev_id);
- }
- if( !adapter.isEnabled() ) {
- println("Adapter not enabled: device "+adapter.getName()+", address "+adapter.getAddress()+": "+adapter.toString());
- System.exit(-1);
+ private BluetoothAdapter createAdapter(final BluetoothManager mngr, final int dev_id0) {
+ BluetoothAdapter adapter;
+ if( 0 > dev_id0 ) {
+ adapter = mngr.getDefaultAdapter();
+ } else {
+ adapter = mngr.getAdapter(dev_id0);
+ if( !adapter.isPowered() ) {
+ adapter = mngr.getDefaultAdapter();
}
}
+ final int dev_id = null != adapter ? adapter.getDevID() : -1;
+ if( 0 > dev_id ) {
+ println("Adapter not available (1): Request "+dev_id0+", deduced "+dev_id);
+ return null;
+ }
- timestamp_t0 = BluetoothUtils.currentTimeMillis();
+ if( !adapter.isPowered() ) { // should have been covered above
+ println("Adapter not powered (2): "+adapter.toString());
+ return null;
+ }
+ println("Using adapter: "+adapter.toString());
adapter.addStatusListener(statusListener, null);
adapter.enableDiscoverableNotifications(new BooleanNotification("Discoverable", timestamp_t0));
@@ -558,8 +556,6 @@ public class DBTScanner10 {
adapter.enablePoweredNotifications(new BooleanNotification("Powered", timestamp_t0));
- boolean done = false;
-
if( USE_WHITELIST ) {
for(final Iterator<String> wliter = whitelist.iterator(); wliter.hasNext(); ) {
final String addr = wliter.next();
@@ -568,9 +564,17 @@ public class DBTScanner10 {
}
} else {
if( !startDiscovery(adapter, "kick-off") ) {
- done = true;
}
}
+ return adapter;
+ }
+
+ public void runTest(final BluetoothManager manager) {
+ BluetoothAdapter adapter = createAdapter(manager, dev_id);
+
+ timestamp_t0 = BluetoothUtils.currentTimeMillis();
+
+ boolean done = false;
while( !done ) {
if( 0 == MULTI_MEASUREMENTS.get() ||
@@ -583,8 +587,21 @@ public class DBTScanner10 {
println("****** DevicesProcessed "+Arrays.toString(devicesProcessed.toArray()));
done = true;
} else {
+ // validate existing adapter
+ if( null != adapter ) {
+ if( !adapter.isValid() /* || !adapter.isPowered() */ ) {
+ // In case of removed adapter, not just powered-off (soft-reset)
+ // We could also close adapter on !isPowered() here, but its not required - adapter operational.
+ adapter.close();
+ adapter = null; // purge
+ }
+ }
+ // re-create adapter if required
+ if( null == adapter ) {
+ adapter = createAdapter(manager, dev_id);
+ }
try {
- Thread.sleep(3000);
+ Thread.sleep(2000);
} catch (final InterruptedException e) {
e.printStackTrace();
}