aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2021-11-29 16:16:34 +0100
committerSven Gothel <[email protected]>2021-11-29 16:16:34 +0100
commite725e4f0b382d948cdfae5c5aaab8a5881e34034 (patch)
tree389e30eec30c7c2f5062fcf2d285b6da4a3f7175
parent4a1456402ecbf07cf16e02aa31788f1f66567890 (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.hpp30
-rw-r--r--examples/dbt_scanner10.cpp17
-rw-r--r--examples/java/DBTScanner10.java4
-rw-r--r--java/jau/direct_bt/DBTAdapter.java9
-rw-r--r--java/jni/direct_bt/DBTAdapter.cxx25
-rw-r--r--java/org/direct_bt/BTAdapter.java21
-rw-r--r--src/direct_bt/BTAdapter.cpp72
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 ) {