Fix error on Windows scan (#146)

* Error on windows scan

* Implement thread safe cache handling

* Fix start scan method

* Update windows/src/universal_ble_thread_safe.h

Co-authored-by: Foti Dim <foti@navideck.com>

---------

Co-authored-by: Rohit Sangwan <rohitsangwan647@gmail.com>
This commit is contained in:
Foti Dim
2025-03-18 11:11:28 +01:00
committed by GitHub
parent a9f396bb4a
commit 0b51a5bbbd
4 changed files with 76 additions and 22 deletions
+1
View File
@@ -44,6 +44,7 @@ list(APPEND PLUGIN_SOURCES
"src/pin_entry.h"
"src/universal_ble_filter_util.cpp"
"src/universal_ble_filter_util.h"
"src/universal_ble_thread_safe.h"
)
add_library(${PLUGIN_NAME} SHARED
+19 -20
View File
@@ -667,10 +667,10 @@ namespace universal_ble
// if device is already discovered in deviceWatcher then merge the scan result
void UniversalBlePlugin::pushUniversalScanResult(UniversalBleScanResult scanResult, bool isConnectable)
{
auto it = scanResults.find(scanResult.device_id());
if (it != scanResults.end())
std::optional<UniversalBleScanResult> it = scanResults.get(scanResult.device_id());
if (it.has_value())
{
UniversalBleScanResult &currentScanResult = it->second;
UniversalBleScanResult &currentScanResult = it.value();
bool shouldUpdate = false;
// Check if current scanResult name is longer than the received scanResult name
@@ -708,16 +708,13 @@ namespace universal_ble
// if nothing to update then return
if (!shouldUpdate)
{
return;
}
}
// update the current scan result
currentScanResult = scanResult;
}
else
{
// if not present, insert the new scan result
scanResults.insert(std::make_pair(scanResult.device_id(), scanResult));
}
// Update cache
scanResults.insert_or_assign(scanResult.device_id(), scanResult);
// Filter final result before sending to Flutter
if (isConnectable && filterDevice(scanResult))
@@ -757,11 +754,13 @@ namespace universal_ble
deviceWatcherUpdatedToken = deviceWatcher.Updated([this](DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate)
{
std::string deviceId = winrt::to_string(deviceInfoUpdate.Id());
auto it = deviceWatcherDevices.find(deviceId);
if (it != deviceWatcherDevices.end())
auto it = deviceWatcherDevices.get(deviceId);
if (it.has_value())
{
it->second.Update(deviceInfoUpdate);
onDeviceInfoReceived(it->second);
auto value = it.value();
value.Update(deviceInfoUpdate);
deviceWatcherDevices.insert_or_assign(deviceId, value);
onDeviceInfoReceived(value);
}
// On Device Updated
});
@@ -769,7 +768,7 @@ namespace universal_ble
deviceWatcherRemovedToken = deviceWatcher.Removed([this](DeviceWatcher sender, DeviceInformationUpdate args)
{
std::string deviceId = winrt::to_string(args.Id());
deviceWatcherDevices.erase(deviceId);
deviceWatcherDevices.remove(deviceId);
// On Device Removed
});
@@ -820,7 +819,7 @@ namespace universal_ble
std::string deviceAddress = winrt::to_string(bluetoothAddressPropertyValue.GetString());
// Update device info if already discovered in advertisementWatcher
if (scanResults.count(deviceAddress) > 0)
if (scanResults.get(deviceAddress).has_value())
{
bool isPaired = deviceInfo.Pairing().IsPaired();
if (properties.HasKey(isPairedKey))
@@ -900,10 +899,10 @@ namespace universal_ble
universalScanResult.set_services(services);
// check if this device already discovered in deviceWatcher
auto it = deviceWatcherDevices.find(deviceId);
if (it != deviceWatcherDevices.end())
auto it = deviceWatcherDevices.get(deviceId);
if (it.has_value())
{
auto &deviceInfo = it->second;
auto &deviceInfo = it.value();
auto properties = deviceInfo.Properties();
// Update Paired Status
+4 -2
View File
@@ -21,6 +21,7 @@
#include "helper/universal_ble_base.h"
#include "generated/universal_ble.g.h"
#include "ui_thread_handler.hpp"
#include "universal_ble_thread_safe.h"
namespace universal_ble
{
@@ -92,8 +93,10 @@ namespace universal_ble
RadioState oldRadioState = RadioState::Unknown;
BluetoothLEAdvertisementWatcher bluetoothLEWatcher{nullptr};
DeviceWatcher deviceWatcher{nullptr};
std::unordered_map<uint64_t, std::unique_ptr<BluetoothDeviceAgent>> connectedDevices{};
std::unordered_map<std::string, DeviceInformation> deviceWatcherDevices{};
ThreadSafeMap<std::string, DeviceInformation> deviceWatcherDevices{};
ThreadSafeMap<std::string, UniversalBleScanResult> scanResults{};
winrt::event_token bluetoothLEWatcherReceivedToken;
winrt::event_token deviceWatcherAddedToken;
@@ -112,7 +115,6 @@ namespace universal_ble
void onDeviceInfoReceived(DeviceInformation deviceInfo);
std::string GattCommunicationStatusToString(GattCommunicationStatus status);
std::unordered_map<std::string, UniversalBleScanResult> scanResults{};
winrt::event_revoker<IRadio> radioStateChangedRevoker;
winrt::fire_and_forget ConnectAsync(uint64_t bluetoothAddress);
void BluetoothLEDevice_ConnectionStatusChanged(BluetoothLEDevice sender, IInspectable args);
+52
View File
@@ -0,0 +1,52 @@
#include <iostream>
#include <list>
#include <map>
#include <mutex>
#include <shared_mutex>
#include <thread>
namespace universal_ble
{
// Thread Safe Map wrapper
// Use only if you don't care about value ownership and it's OK to work with copies of the data.
template <typename Key, typename Value>
class ThreadSafeMap
{
private:
std::unordered_map<Key, Value> data;
mutable std::shared_mutex mutex;
public:
void insert_or_assign(const Key &key, const Value &value)
{
std::unique_lock lock(mutex);
data.insert_or_assign(key, value);
}
bool remove(const Key &key)
{
std::unique_lock lock(mutex);
return data.erase(key) > 0;
}
std::optional<Value> get(const Key &key) const
{
std::shared_lock lock(mutex);
auto it = data.find(key);
return (it != data.end()) ? std::optional<Value>(it->second) : std::nullopt;
}
void clear()
{
std::unique_lock lock(mutex);
data.clear();
}
std::map<Key, Value> get_snapshot() const
{
std::shared_lock lock(mutex);
return data;
}
};
} // namespace universal_ble