diff options
author | Sven Gothel <[email protected]> | 2020-10-25 02:57:31 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2020-10-25 02:57:31 +0100 |
commit | e878104ae9950d7cbc44841e6c5c5f0b9c131304 (patch) | |
tree | 4113a6af50db87dcbc32a4e5dd58a5b5e1a253bd /examples | |
parent | 305a92e8f295298bc4dd3cb12f4b32b68d7bf0ae (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.cpp | 85 | ||||
-rw-r--r-- | examples/java/DBTScanner10.java | 65 |
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(); } |