diff options
author | Sven Gothel <[email protected]> | 2021-11-29 16:16:34 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2021-11-29 16:16:34 +0100 |
commit | e725e4f0b382d948cdfae5c5aaab8a5881e34034 (patch) | |
tree | 389e30eec30c7c2f5062fcf2d285b6da4a3f7175 | |
parent | 4a1456402ecbf07cf16e02aa31788f1f66567890 (diff) |
BTAdapter::pausing_discovery_devices: Use std::weak_ptr<BTDevice> list; Add BTAdapter::removeDevicePausingDiscovery() and getCurrentDiscoveryPolicy()
Using a weak_ptr<BTDevice> list avoid stopping BTDevice destruction.
BTAdapter::removeDevicePausingDiscovery() allows manual DiscoveryPolicy intervention point,
allowing user to remove the ready device from the queue of pausing-discovery devices.
Manual intervention might be desired, if using DiscoveryPolicy::PAUSE_CONNECTED_UNTIL_DISCONNECTED,
but allowing discovery at an earlier processing step from AdapterStatusListener::deviceReady().
+++
Further added removeDevicePausingDiscovery() call in BTAdapter::removeDevice() as a last resort.
-rw-r--r-- | api/direct_bt/BTAdapter.hpp | 30 | ||||
-rw-r--r-- | examples/dbt_scanner10.cpp | 17 | ||||
-rw-r--r-- | examples/java/DBTScanner10.java | 4 | ||||
-rw-r--r-- | java/jau/direct_bt/DBTAdapter.java | 9 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTAdapter.cxx | 25 | ||||
-rw-r--r-- | java/org/direct_bt/BTAdapter.java | 21 | ||||
-rw-r--r-- | src/direct_bt/BTAdapter.cpp | 72 |
7 files changed, 165 insertions, 13 deletions
diff --git a/api/direct_bt/BTAdapter.hpp b/api/direct_bt/BTAdapter.hpp index a8bb08c7..6c5d3a90 100644 --- a/api/direct_bt/BTAdapter.hpp +++ b/api/direct_bt/BTAdapter.hpp @@ -374,6 +374,8 @@ namespace direct_bt { std::condition_variable cv_single_conn_device; typedef jau::darray<BTDeviceRef> device_list_t; + typedef jau::darray<std::weak_ptr<BTDevice>> weak_device_list_t; + /** All discovered devices: Transient until removeDiscoveredDevices(), startDiscovery(). */ device_list_t discoveredDevices; /** All connected devices: Transient until disconnect or removal. */ @@ -381,7 +383,7 @@ namespace direct_bt { /** All active shared devices: Persistent until removal. Final holder of BTDevice lifecycle! */ device_list_t sharedDevices; /** All connected devices for which discovery has been paused. */ - device_list_t pausing_discovery_devices; + weak_device_list_t pausing_discovery_devices; typedef jau::cow_darray<impl::StatusListenerPair> statusListenerList_t; statusListenerList_t statusListenerList; @@ -409,7 +411,10 @@ namespace direct_bt { static BTDeviceRef findDevice(device_list_t & devices, const EUI48 & address, const BDAddressType addressType) noexcept; static BTDeviceRef findDevice(device_list_t & devices, BTDevice const & device) noexcept; + static BTDeviceRef findWeakDevice(weak_device_list_t & devices, const EUI48 & address, const BDAddressType addressType) noexcept; + static BTDeviceRef findWeakDevice(weak_device_list_t & devices, BTDevice const & device) noexcept; static void printDeviceList(const std::string& prefix, const BTAdapter::device_list_t& list) noexcept; + static void printWeakDeviceList(const std::string& prefix, BTAdapter::weak_device_list_t& list) noexcept; /** Private class only for private make_shared(). */ class ctor_cookie { friend BTAdapter; ctor_cookie(const uint16_t secret) { (void)secret; } }; @@ -998,6 +1003,29 @@ namespace direct_bt { HCIStatusCode stopDiscovery() noexcept; /** + * Return the current DiscoveryPolicy, set via startDiscovery(). + * @since 2.5.1 + */ + DiscoveryPolicy getCurrentDiscoveryPolicy() const noexcept { return discovery_policy; } + + /** + * Manual DiscoveryPolicy intervention point, allowing user to remove the ready device from + * the queue of pausing-discovery devices. + * + * Manual intervention might be desired, if using DiscoveryPolicy::PAUSE_CONNECTED_UNTIL_DISCONNECTED, + * but allowing discovery at an earlier processing step from AdapterStatusListener::deviceReady(). + * + * Re-enabling discovery is performed on the current thread. + * + * @param device the BTDevice to remove from the pausing-discovery queue + * @return true if this was the last BTDevice, re-enabling discovery. Otherwise false. + * @since 2.5.1 + */ + bool removeDevicePausingDiscovery(const BTDevice & device) noexcept { + return removeDevicePausingDiscovery(device, false /* off_thread_enable */); + } + + /** * Returns the current meta discovering ScanType. It can be modified through startDiscovery(..) and stopDiscovery(). * <p> * Note that if startDiscovery(..) has been issued with keepAlive==true, diff --git a/examples/dbt_scanner10.cpp b/examples/dbt_scanner10.cpp index 5ba2dc98..d49bf930 100644 --- a/examples/dbt_scanner10.cpp +++ b/examples/dbt_scanner10.cpp @@ -112,6 +112,13 @@ static uint64_t timestamp_t0; static EUI48 useAdapter = EUI48::ALL_DEVICE; static BTMode btMode = BTMode::DUAL; + +static DiscoveryPolicy discoveryPolicy = DiscoveryPolicy::PAUSE_CONNECTED_UNTIL_READY; // default value +static bool le_scan_active = true; // default value +static const uint16_t le_scan_interval = 24; // default value +static const uint16_t le_scan_window = 24; // default value +static const uint8_t filter_policy = 0; // default value + static std::shared_ptr<BTAdapter> chosenAdapter = nullptr; static int RESET_ADAPTER_EACH_CONN = 0; @@ -547,6 +554,10 @@ exit: BTDeviceRegistry::removeFromProcessingDevices(device->getAddressAndType()); + if( DiscoveryPolicy::PAUSE_CONNECTED_UNTIL_DISCONNECTED == discoveryPolicy ) { + device->getAdapter().removeDevicePausingDiscovery(*device); + } + if( KEEP_CONNECTED && GATT_PING_ENABLED && success ) { while( device->pingGATT() ) { fprintf_td(stderr, "****** Processing Ready Device: pingGATT OK: %s\n", device->getAddressAndType().toString().c_str()); @@ -597,12 +608,6 @@ static void resetAdapter(BTAdapter *a, int mode) { fprintf_td(stderr, "****** Reset Adapter: reset[%d] end: %s, %s\n", mode, to_string(res).c_str(), a->toString().c_str()); } -static DiscoveryPolicy discoveryPolicy = DiscoveryPolicy::PAUSE_CONNECTED_UNTIL_READY; // default value -static bool le_scan_active = true; // default value -static const uint16_t le_scan_interval = 24; // default value -static const uint16_t le_scan_window = 24; // default value -static const uint8_t filter_policy = 0; // default value - static bool startDiscovery(BTAdapter *a, std::string msg) { if( useAdapter != EUI48::ALL_DEVICE && useAdapter != a->getAddressAndType().address ) { fprintf_td(stderr, "****** Start discovery (%s): Adapter not selected: %s\n", msg.c_str(), a->toString().c_str()); diff --git a/examples/java/DBTScanner10.java b/examples/java/DBTScanner10.java index ea4c1f4a..fd297311 100644 --- a/examples/java/DBTScanner10.java +++ b/examples/java/DBTScanner10.java @@ -555,6 +555,10 @@ public class DBTScanner10 { BTDeviceRegistry.removeFromProcessingDevices( device.getAddressAndType() ); + if( DiscoveryPolicy.PAUSE_CONNECTED_UNTIL_DISCONNECTED == discoveryPolicy ) { + device.getAdapter().removeDevicePausingDiscovery(device); + } + if( KEEP_CONNECTED && GATT_PING_ENABLED && success ) { while( device.pingGATT() ) { BTUtils.println(System.err, "****** Processing Ready Device: pingGATT OK: "+device.getAddressAndType()); diff --git a/java/jau/direct_bt/DBTAdapter.java b/java/jau/direct_bt/DBTAdapter.java index 2a1d6e39..8a018526 100644 --- a/java/jau/direct_bt/DBTAdapter.java +++ b/java/jau/direct_bt/DBTAdapter.java @@ -389,6 +389,15 @@ public class DBTAdapter extends DBTObject implements BTAdapter } private native byte stopDiscoveryImpl() throws BTException; + @Override + public DiscoveryPolicy getCurrentDiscoveryPolicy() { + return DiscoveryPolicy.get( getCurrentDiscoveryPolicyImpl() ); + } + private native byte getCurrentDiscoveryPolicyImpl(); + + @Override + public native boolean removeDevicePausingDiscovery(final BTDevice device); + // std::vector<std::shared_ptr<direct_bt::HCIDevice>> discoveredDevices = adapter.getDiscoveredDevices(); private native List<BTDevice> getDiscoveredDevicesImpl(); diff --git a/java/jni/direct_bt/DBTAdapter.cxx b/java/jni/direct_bt/DBTAdapter.cxx index fc9c39c2..d675b4b4 100644 --- a/java/jni/direct_bt/DBTAdapter.cxx +++ b/java/jni/direct_bt/DBTAdapter.cxx @@ -710,6 +710,31 @@ jbyte Java_jau_direct_1bt_DBTAdapter_stopDiscoveryImpl(JNIEnv *env, jobject obj) return (jbyte) number(HCIStatusCode::INTERNAL_FAILURE); } +jbyte Java_jau_direct_1bt_DBTAdapter_getCurrentDiscoveryPolicyImpl(JNIEnv *env, jobject obj) { + DiscoveryPolicy current = DiscoveryPolicy::AUTO_OFF; + try { + BTAdapter *adapter = jau::getJavaUplinkObject<BTAdapter>(env, obj); + current = adapter->getCurrentDiscoveryPolicy(); + } catch(...) { + rethrow_and_raise_java_exception(env); + } + return (jbyte)number(current); +} + +jboolean Java_jau_direct_1bt_DBTAdapter_removeDevicePausingDiscovery(JNIEnv *env, jobject obj, jobject jdevice) { + try { + BTAdapter *adapter = jau::getJavaUplinkObject<BTAdapter>(env, obj); + + BTDevice *device = jau::getJavaUplinkObject<BTDevice>(env, jdevice); + jau::JavaGlobalObj::check(device->getJavaObject(), E_FILE_LINE); + + return adapter->removeDevicePausingDiscovery(*device) ? JNI_TRUE : JNI_FALSE; + } catch(...) { + rethrow_and_raise_java_exception(env); + } + return JNI_FALSE; +} + jbyte Java_jau_direct_1bt_DBTAdapter_getRoleImpl(JNIEnv *env, jobject obj) { try { diff --git a/java/org/direct_bt/BTAdapter.java b/java/org/direct_bt/BTAdapter.java index 3e9ad989..bef24ccd 100644 --- a/java/org/direct_bt/BTAdapter.java +++ b/java/org/direct_bt/BTAdapter.java @@ -243,6 +243,27 @@ public interface BTAdapter extends BTObject */ HCIStatusCode stopDiscovery() throws BTException; + /** + * Return the current {@link DiscoveryPolicy}, set via {@link #startDiscovery(DiscoveryPolicy, boolean, short, short, byte, boolean)}. + * @since 2.5.1 + */ + DiscoveryPolicy getCurrentDiscoveryPolicy(); + + /** + * Manual {@link DiscoveryPolicy} intervention point, allowing user to remove the ready device from + * the queue of pausing-discovery devices. + * + * Manual intervention might be desired, if using {@link DiscoveryPolicy#PAUSE_CONNECTED_UNTIL_DISCONNECTED}, + * but allowing discovery at an earlier processing step from {@link AdapterStatusListener#deviceReady(BTDevice, long)}. + * + * Re-enabling discovery is performed on the current thread. + * + * @param device the {@link BTDevice} to remove from the pausing-discovery queue + * @return true if this was the last {@link BTDevice}, re-enabling discovery. Otherwise false. + * @since 2.5.1 + */ + boolean removeDevicePausingDiscovery(final BTDevice device); + /** Returns a list of discovered BluetoothDevices from this adapter. * @return A list of discovered BluetoothDevices on this adapter, * NULL if an error occurred diff --git a/src/direct_bt/BTAdapter.cpp b/src/direct_bt/BTAdapter.cpp index b284cbdc..9776b13e 100644 --- a/src/direct_bt/BTAdapter.cpp +++ b/src/direct_bt/BTAdapter.cpp @@ -88,16 +88,51 @@ BTDeviceRef BTAdapter::findDevice(device_list_t & devices, BTDevice const & devi return nullptr; } +BTDeviceRef BTAdapter::findWeakDevice(weak_device_list_t & devices, const EUI48 & address, const BDAddressType addressType) noexcept { + auto end = devices.end(); + for (auto it = devices.begin(); it != end; ) { + std::weak_ptr<BTDevice> & w = *it; + BTDeviceRef e = w.lock(); + if( nullptr == e ) { + devices.erase(it); // erase and move it to next element + } else if ( address == e->getAddressAndType().address && + ( addressType == e->getAddressAndType().type || addressType == BDAddressType::BDADDR_UNDEFINED ) + ) + { + return e; + } else { + ++it; // move it to next element + } + } + return nullptr; +} + +BTDeviceRef BTAdapter::findWeakDevice(weak_device_list_t & devices, BTDevice const & device) noexcept { + auto end = devices.end(); + for (auto it = devices.begin(); it != end; ) { + std::weak_ptr<BTDevice> & w = *it; + BTDeviceRef e = w.lock(); + if( nullptr == e ) { + devices.erase(it); // erase and move it to next element + } else if ( device == *e ) { + return e; + } else { + ++it; // move it to next element + } + } + return nullptr; +} + BTDeviceRef BTAdapter::findDevicePausingDiscovery (const EUI48 & address, const BDAddressType & addressType) noexcept { const std::lock_guard<std::mutex> lock(mtx_pausingDiscoveryDevices); // RAII-style acquire and relinquish via destructor - return findDevice(pausing_discovery_devices, address, addressType); + return findWeakDevice(pausing_discovery_devices, address, addressType); } bool BTAdapter::addDevicePausingDiscovery(const BTDeviceRef & device) noexcept { bool added_first = false; { const std::lock_guard<std::mutex> lock(mtx_pausingDiscoveryDevices); // RAII-style acquire and relinquish via destructor - if( nullptr != findDevice(pausing_discovery_devices, *device) ) { + if( nullptr != findWeakDevice(pausing_discovery_devices, *device) ) { return false; } added_first = 0 == pausing_discovery_devices.size(); @@ -120,13 +155,18 @@ bool BTAdapter::removeDevicePausingDiscovery(const BTDevice & device, const bool bool removed_last = false; { const std::lock_guard<std::mutex> lock(mtx_pausingDiscoveryDevices); // RAII-style acquire and relinquish via destructor - bool done = false; auto end = pausing_discovery_devices.end(); - for (auto it = pausing_discovery_devices.begin(); it != end && !done; ++it) { - if ( nullptr != *it && device == **it ) { + for (auto it = pausing_discovery_devices.begin(); it != end; ) { + std::weak_ptr<BTDevice> & w = *it; + BTDeviceRef e = w.lock(); + if( nullptr == e ) { + pausing_discovery_devices.erase(it); // erase and move it to next element + } else if ( device == *e ) { pausing_discovery_devices.erase(it); removed_last = 0 == pausing_discovery_devices.size(); - done = true; + break; // done + } else { + ++it; // move it to next element } } } @@ -473,18 +513,37 @@ void BTAdapter::printDeviceList(const std::string& prefix, const BTAdapter::devi (*it)->getName().c_str() ); } } +void BTAdapter::printWeakDeviceList(const std::string& prefix, BTAdapter::weak_device_list_t& list) noexcept { + const size_t sz = list.size(); + jau::PLAIN_PRINT(true, "- BTAdapter::%s: %zu elements", prefix.c_str(), sz); + int idx = 0; + for (auto it = list.begin(); it != list.end(); ++idx, ++it) { + std::weak_ptr<BTDevice> & w = *it; + BTDeviceRef e = w.lock(); + if( nullptr == e ) { + jau::PLAIN_PRINT(true, " - %d / %zu: null", (idx+1), sz); + } else { + jau::PLAIN_PRINT(true, " - %d / %zu: %s, name '%s'", (idx+1), sz, + e->getAddressAndType().toString().c_str(), + e->getName().c_str() ); + } + } +} void BTAdapter::printDeviceLists() noexcept { device_list_t _sharedDevices, _discoveredDevices, _connectedDevices; + weak_device_list_t _pausingDiscoveryDevice; { jau::sc_atomic_critical sync(sync_data); // lock-free simple cache-load 'snapshot' // Using an expensive copy here: debug mode only _sharedDevices = sharedDevices; _discoveredDevices = discoveredDevices; _connectedDevices = connectedDevices; + _pausingDiscoveryDevice = pausing_discovery_devices; } printDeviceList("SharedDevices ", _sharedDevices); printDeviceList("ConnectedDevices ", _connectedDevices); printDeviceList("DiscoveredDevices ", _discoveredDevices); + printWeakDeviceList("PausingDiscoveryDevices ", _pausingDiscoveryDevice); printStatusListenerList(); } @@ -1230,6 +1289,7 @@ void BTAdapter::removeDevice(BTDevice & device) noexcept { unlockConnect(device); removeConnectedDevice(device); // usually done in BTAdapter::mgmtEvDeviceDisconnectedHCI removeDiscoveredDevice(device.addressAndType); // usually done in BTAdapter::mgmtEvDeviceDisconnectedHCI + removeDevicePausingDiscovery(device, true /* off_thread_enable */); removeSharedDevice(device); if( _print_device_lists || jau::environment::get().verbose ) { |