|
|
|
@@ -8,15 +8,19 @@
|
|
|
|
#include "Modules/ModuleManager.h"
|
|
|
|
#include "Modules/ModuleManager.h"
|
|
|
|
|
|
|
|
|
|
|
|
// ─── WinRT includes (Windows only) ───────────────────────────────────────────
|
|
|
|
// ─── WinRT includes (Windows only) ───────────────────────────────────────────
|
|
|
|
|
|
|
|
// NOTE: AllowWindowsPlatformTypes must wrap the WinRT headers.
|
|
|
|
|
|
|
|
// We do NOT place any "using namespace" at file scope because Unreal also
|
|
|
|
|
|
|
|
// defines a ::Windows namespace (via AllowWindowsPlatformTypes) and that would
|
|
|
|
|
|
|
|
// cause "ambiguous symbol" errors. All WinRT types are fully qualified with
|
|
|
|
|
|
|
|
// winrt:: inside each function body.
|
|
|
|
|
|
|
|
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
|
|
|
|
|
|
|
|
// Unreal defines WIN32_LEAN_AND_MEAN which can strip some COM headers — we
|
|
|
|
|
|
|
|
// add the specific ones we need without touching the Unreal macros.
|
|
|
|
|
|
|
|
#include "Windows/AllowWindowsPlatformTypes.h"
|
|
|
|
#include "Windows/AllowWindowsPlatformTypes.h"
|
|
|
|
#include "Windows/AllowWindowsPlatformAtomics.h"
|
|
|
|
#include "Windows/AllowWindowsPlatformAtomics.h"
|
|
|
|
|
|
|
|
|
|
|
|
#pragma warning(push)
|
|
|
|
#pragma warning(push)
|
|
|
|
#pragma warning(disable: 4668 4946 5204 5220)
|
|
|
|
#pragma warning(disable: 4265 4668 4946 5204 5220) // 4265: WinRT internal non-virtual dtor (harmless)
|
|
|
|
|
|
|
|
|
|
|
|
#include <winrt/Windows.Foundation.h>
|
|
|
|
#include <winrt/Windows.Foundation.h>
|
|
|
|
#include <winrt/Windows.Foundation.Collections.h>
|
|
|
|
#include <winrt/Windows.Foundation.Collections.h>
|
|
|
|
@@ -30,22 +34,38 @@
|
|
|
|
#include "Windows/HideWindowsPlatformAtomics.h"
|
|
|
|
#include "Windows/HideWindowsPlatformAtomics.h"
|
|
|
|
#include "Windows/HideWindowsPlatformTypes.h"
|
|
|
|
#include "Windows/HideWindowsPlatformTypes.h"
|
|
|
|
|
|
|
|
|
|
|
|
using namespace winrt;
|
|
|
|
// ─── Convenient namespace aliases used ONLY inside function bodies ────────────
|
|
|
|
using namespace Windows::Devices::Bluetooth;
|
|
|
|
// (Defined as macros so we can paste them at the top of each #if PLATFORM_WINDOWS block)
|
|
|
|
using namespace Windows::Devices::Bluetooth::Advertisement;
|
|
|
|
#define PS_BLE_WINRT_NS \
|
|
|
|
using namespace Windows::Devices::Bluetooth::GenericAttributeProfile;
|
|
|
|
namespace WinBT = winrt::Windows::Devices::Bluetooth; \
|
|
|
|
using namespace Windows::Foundation;
|
|
|
|
namespace WinAdv = winrt::Windows::Devices::Bluetooth::Advertisement; \
|
|
|
|
using namespace Windows::Foundation::Collections;
|
|
|
|
namespace WinGAP = winrt::Windows::Devices::Bluetooth::GenericAttributeProfile; \
|
|
|
|
using namespace Windows::Storage::Streams;
|
|
|
|
namespace WinFnd = winrt::Windows::Foundation; \
|
|
|
|
|
|
|
|
namespace WinStr = winrt::Windows::Storage::Streams;
|
|
|
|
|
|
|
|
|
|
|
|
// ─── Scanner state (allocated on heap so WinRT types don't leak into header) ─
|
|
|
|
// ─── Scanner state (heap-allocated so WinRT types don't appear in the header) ─
|
|
|
|
struct FPS_ScannerState
|
|
|
|
struct FPS_ScannerState
|
|
|
|
{
|
|
|
|
{
|
|
|
|
BluetoothLEAdvertisementWatcher Watcher{ nullptr };
|
|
|
|
winrt::Windows::Devices::Bluetooth::Advertisement::BluetoothLEAdvertisementWatcher Watcher{ nullptr };
|
|
|
|
winrt::event_token ReceivedToken;
|
|
|
|
winrt::event_token ReceivedToken;
|
|
|
|
winrt::event_token StoppedToken;
|
|
|
|
winrt::event_token StoppedToken;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ─── WinRT object wrappers ────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
// WinRT types delete operator new — we wrap them in plain structs so they can
|
|
|
|
|
|
|
|
// live on the heap via regular new/delete (stored as void* in UObject headers).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct FPS_BLEDeviceHandle
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
winrt::Windows::Devices::Bluetooth::BluetoothLEDevice Device{ nullptr };
|
|
|
|
|
|
|
|
winrt::event_token ConnectionStatusToken;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct FPS_GattServiceHandle
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::GattDeviceService Service{ nullptr };
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#endif // PLATFORM_WINDOWS
|
|
|
|
#endif // PLATFORM_WINDOWS
|
|
|
|
|
|
|
|
|
|
|
|
#define LOCTEXT_NAMESPACE "PS_Win_BLE"
|
|
|
|
#define LOCTEXT_NAMESPACE "PS_Win_BLE"
|
|
|
|
@@ -112,12 +132,14 @@ UPS_BLE_Manager* UPS_BLE_Module::GetBLEManager(const UPS_BLE_Module* Mod)
|
|
|
|
void UPS_BLE_Module::ScannerCleanup()
|
|
|
|
void UPS_BLE_Module::ScannerCleanup()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
|
|
|
|
PS_BLE_WINRT_NS
|
|
|
|
if (ScannerHandle)
|
|
|
|
if (ScannerHandle)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
FPS_ScannerState* State = static_cast<FPS_ScannerState*>(ScannerHandle);
|
|
|
|
FPS_ScannerState* State = static_cast<FPS_ScannerState*>(ScannerHandle);
|
|
|
|
try
|
|
|
|
try
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (State->Watcher && State->Watcher.Status() == BluetoothLEAdvertisementWatcherStatus::Started)
|
|
|
|
if (State->Watcher &&
|
|
|
|
|
|
|
|
State->Watcher.Status() == WinAdv::BluetoothLEAdvertisementWatcherStatus::Started)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
State->Watcher.Stop();
|
|
|
|
State->Watcher.Stop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -132,24 +154,24 @@ void UPS_BLE_Module::ScannerCleanup()
|
|
|
|
bool UPS_BLE_Module::StartDiscoveryLive(UPS_BLE_Manager* Ref, int32 DurationMs, const FString& Filter)
|
|
|
|
bool UPS_BLE_Module::StartDiscoveryLive(UPS_BLE_Manager* Ref, int32 DurationMs, const FString& Filter)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
|
|
|
|
PS_BLE_WINRT_NS
|
|
|
|
if (!Ref) return false;
|
|
|
|
if (!Ref) return false;
|
|
|
|
ScannerCleanup();
|
|
|
|
ScannerCleanup();
|
|
|
|
|
|
|
|
|
|
|
|
FPS_ScannerState* State = new FPS_ScannerState();
|
|
|
|
FPS_ScannerState* State = new FPS_ScannerState();
|
|
|
|
State->Watcher = BluetoothLEAdvertisementWatcher();
|
|
|
|
State->Watcher = WinAdv::BluetoothLEAdvertisementWatcher();
|
|
|
|
State->Watcher.ScanningMode(BluetoothLEScanningMode::Active);
|
|
|
|
State->Watcher.ScanningMode(WinAdv::BluetoothLEScanningMode::Active);
|
|
|
|
ScannerHandle = State;
|
|
|
|
ScannerHandle = State;
|
|
|
|
|
|
|
|
|
|
|
|
// Capture filter and manager ref
|
|
|
|
|
|
|
|
FString FilterCopy = Filter;
|
|
|
|
FString FilterCopy = Filter;
|
|
|
|
UPS_BLE_Manager* MgrRef = Ref;
|
|
|
|
UPS_BLE_Manager* MgrRef = Ref;
|
|
|
|
|
|
|
|
|
|
|
|
State->ReceivedToken = State->Watcher.Received(
|
|
|
|
State->ReceivedToken = State->Watcher.Received(
|
|
|
|
[MgrRef, FilterCopy](BluetoothLEAdvertisementWatcher const&, BluetoothLEAdvertisementReceivedEventArgs const& Args)
|
|
|
|
[MgrRef, FilterCopy](WinAdv::BluetoothLEAdvertisementWatcher const&,
|
|
|
|
|
|
|
|
WinAdv::BluetoothLEAdvertisementReceivedEventArgs const& Args)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
FString Name = Args.Advertisement().LocalName().c_str();
|
|
|
|
FString Name = Args.Advertisement().LocalName().c_str();
|
|
|
|
|
|
|
|
|
|
|
|
// Apply name filter (comma-separated substrings)
|
|
|
|
|
|
|
|
if (!FilterCopy.IsEmpty())
|
|
|
|
if (!FilterCopy.IsEmpty())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
TArray<FString> Parts;
|
|
|
|
TArray<FString> Parts;
|
|
|
|
@@ -157,11 +179,7 @@ bool UPS_BLE_Module::StartDiscoveryLive(UPS_BLE_Manager* Ref, int32 DurationMs,
|
|
|
|
bool bMatch = false;
|
|
|
|
bool bMatch = false;
|
|
|
|
for (const FString& Part : Parts)
|
|
|
|
for (const FString& Part : Parts)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (Name.Contains(Part.TrimStartAndEnd()))
|
|
|
|
if (Name.Contains(Part.TrimStartAndEnd())) { bMatch = true; break; }
|
|
|
|
{
|
|
|
|
|
|
|
|
bMatch = true;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!bMatch) return;
|
|
|
|
if (!bMatch) return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -170,12 +188,12 @@ bool UPS_BLE_Module::StartDiscoveryLive(UPS_BLE_Manager* Ref, int32 DurationMs,
|
|
|
|
Rec.ID = Args.BluetoothAddress();
|
|
|
|
Rec.ID = Args.BluetoothAddress();
|
|
|
|
Rec.RSSI = Args.RawSignalStrengthInDBm();
|
|
|
|
Rec.RSSI = Args.RawSignalStrengthInDBm();
|
|
|
|
Rec.Name = Name;
|
|
|
|
Rec.Name = Name;
|
|
|
|
|
|
|
|
|
|
|
|
DispatchDeviceDiscovered(MgrRef, Rec);
|
|
|
|
DispatchDeviceDiscovered(MgrRef, Rec);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
State->StoppedToken = State->Watcher.Stopped(
|
|
|
|
State->StoppedToken = State->Watcher.Stopped(
|
|
|
|
[MgrRef](BluetoothLEAdvertisementWatcher const&, BluetoothLEAdvertisementWatcherStoppedEventArgs const&)
|
|
|
|
[MgrRef](WinAdv::BluetoothLEAdvertisementWatcher const&,
|
|
|
|
|
|
|
|
WinAdv::BluetoothLEAdvertisementWatcherStoppedEventArgs const&)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
TArray<FPS_DeviceRecord> Empty;
|
|
|
|
TArray<FPS_DeviceRecord> Empty;
|
|
|
|
DispatchDiscoveryEnd(MgrRef, Empty);
|
|
|
|
DispatchDiscoveryEnd(MgrRef, Empty);
|
|
|
|
@@ -183,7 +201,6 @@ bool UPS_BLE_Module::StartDiscoveryLive(UPS_BLE_Manager* Ref, int32 DurationMs,
|
|
|
|
|
|
|
|
|
|
|
|
State->Watcher.Start();
|
|
|
|
State->Watcher.Start();
|
|
|
|
|
|
|
|
|
|
|
|
// Auto-stop after DurationMs
|
|
|
|
|
|
|
|
if (DurationMs > 0)
|
|
|
|
if (DurationMs > 0)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
int32 Ms = DurationMs;
|
|
|
|
int32 Ms = DurationMs;
|
|
|
|
@@ -203,28 +220,28 @@ bool UPS_BLE_Module::StartDiscoveryLive(UPS_BLE_Manager* Ref, int32 DurationMs,
|
|
|
|
bool UPS_BLE_Module::StartDiscoveryInBackground(UPS_BLE_Manager* Ref, int32 DurationMs, const FString& Filter)
|
|
|
|
bool UPS_BLE_Module::StartDiscoveryInBackground(UPS_BLE_Manager* Ref, int32 DurationMs, const FString& Filter)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
|
|
|
|
PS_BLE_WINRT_NS
|
|
|
|
if (!Ref) return false;
|
|
|
|
if (!Ref) return false;
|
|
|
|
ScannerCleanup();
|
|
|
|
ScannerCleanup();
|
|
|
|
|
|
|
|
|
|
|
|
// Collect all devices during scan, fire DiscoveryEnd at the end
|
|
|
|
|
|
|
|
TSharedPtr<TArray<FPS_DeviceRecord>, ESPMode::ThreadSafe> Collected =
|
|
|
|
TSharedPtr<TArray<FPS_DeviceRecord>, ESPMode::ThreadSafe> Collected =
|
|
|
|
MakeShared<TArray<FPS_DeviceRecord>, ESPMode::ThreadSafe>();
|
|
|
|
MakeShared<TArray<FPS_DeviceRecord>, ESPMode::ThreadSafe>();
|
|
|
|
|
|
|
|
|
|
|
|
FPS_ScannerState* State = new FPS_ScannerState();
|
|
|
|
FPS_ScannerState* State = new FPS_ScannerState();
|
|
|
|
State->Watcher = BluetoothLEAdvertisementWatcher();
|
|
|
|
State->Watcher = WinAdv::BluetoothLEAdvertisementWatcher();
|
|
|
|
State->Watcher.ScanningMode(BluetoothLEScanningMode::Active);
|
|
|
|
State->Watcher.ScanningMode(WinAdv::BluetoothLEScanningMode::Active);
|
|
|
|
ScannerHandle = State;
|
|
|
|
ScannerHandle = State;
|
|
|
|
|
|
|
|
|
|
|
|
FString FilterCopy = Filter;
|
|
|
|
FString FilterCopy = Filter;
|
|
|
|
UPS_BLE_Manager* MgrRef = Ref;
|
|
|
|
UPS_BLE_Manager* MgrRef = Ref;
|
|
|
|
|
|
|
|
|
|
|
|
State->ReceivedToken = State->Watcher.Received(
|
|
|
|
State->ReceivedToken = State->Watcher.Received(
|
|
|
|
[MgrRef, FilterCopy, Collected](BluetoothLEAdvertisementWatcher const&, BluetoothLEAdvertisementReceivedEventArgs const& Args)
|
|
|
|
[MgrRef, FilterCopy, Collected](WinAdv::BluetoothLEAdvertisementWatcher const&,
|
|
|
|
|
|
|
|
WinAdv::BluetoothLEAdvertisementReceivedEventArgs const& Args)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
FString Name = Args.Advertisement().LocalName().c_str();
|
|
|
|
FString Name = Args.Advertisement().LocalName().c_str();
|
|
|
|
|
|
|
|
|
|
|
|
// Dedup by address
|
|
|
|
|
|
|
|
uint64 Addr = Args.BluetoothAddress();
|
|
|
|
uint64 Addr = Args.BluetoothAddress();
|
|
|
|
|
|
|
|
|
|
|
|
for (const FPS_DeviceRecord& R : *Collected)
|
|
|
|
for (const FPS_DeviceRecord& R : *Collected)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (R.ID == Addr) return;
|
|
|
|
if (R.ID == Addr) return;
|
|
|
|
@@ -250,7 +267,8 @@ bool UPS_BLE_Module::StartDiscoveryInBackground(UPS_BLE_Manager* Ref, int32 Dura
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
State->StoppedToken = State->Watcher.Stopped(
|
|
|
|
State->StoppedToken = State->Watcher.Stopped(
|
|
|
|
[MgrRef, Collected](BluetoothLEAdvertisementWatcher const&, BluetoothLEAdvertisementWatcherStoppedEventArgs const&)
|
|
|
|
[MgrRef, Collected](WinAdv::BluetoothLEAdvertisementWatcher const&,
|
|
|
|
|
|
|
|
WinAdv::BluetoothLEAdvertisementWatcherStoppedEventArgs const&)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
DispatchDiscoveryEnd(MgrRef, *Collected);
|
|
|
|
DispatchDiscoveryEnd(MgrRef, *Collected);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
@@ -276,12 +294,14 @@ bool UPS_BLE_Module::StartDiscoveryInBackground(UPS_BLE_Manager* Ref, int32 Dura
|
|
|
|
bool UPS_BLE_Module::StopDiscovery()
|
|
|
|
bool UPS_BLE_Module::StopDiscovery()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
|
|
|
|
PS_BLE_WINRT_NS
|
|
|
|
if (ScannerHandle)
|
|
|
|
if (ScannerHandle)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
FPS_ScannerState* State = static_cast<FPS_ScannerState*>(ScannerHandle);
|
|
|
|
FPS_ScannerState* State = static_cast<FPS_ScannerState*>(ScannerHandle);
|
|
|
|
try
|
|
|
|
try
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (State->Watcher && State->Watcher.Status() == BluetoothLEAdvertisementWatcherStatus::Started)
|
|
|
|
if (State->Watcher &&
|
|
|
|
|
|
|
|
State->Watcher.Status() == WinAdv::BluetoothLEAdvertisementWatcherStatus::Started)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
State->Watcher.Stop();
|
|
|
|
State->Watcher.Stop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -303,39 +323,33 @@ bool UPS_BLE_Module::ConnectDevice(UPS_BLE_Device* Device)
|
|
|
|
if (!Device) return false;
|
|
|
|
if (!Device) return false;
|
|
|
|
|
|
|
|
|
|
|
|
uint64 Addr = Device->DeviceID;
|
|
|
|
uint64 Addr = Device->DeviceID;
|
|
|
|
UPS_BLE_Module* ModRef = this;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// WinRT async connect + service discovery on background thread
|
|
|
|
AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, [Device, Addr]()
|
|
|
|
AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, [ModRef, Device, Addr]()
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
PS_BLE_WINRT_NS
|
|
|
|
try
|
|
|
|
try
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// FromBluetoothAddressAsync is the standard WinRT connect path
|
|
|
|
auto BLEDev = WinBT::BluetoothLEDevice::FromBluetoothAddressAsync(Addr).get();
|
|
|
|
auto Op = BluetoothLEDevice::FromBluetoothAddressAsync(Addr);
|
|
|
|
|
|
|
|
BluetoothLEDevice BLEDev = Op.get();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!BLEDev)
|
|
|
|
if (!BLEDev)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
DispatchDeviceDisconnected(Device);
|
|
|
|
DispatchDeviceDisconnected(Device);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Store native handle (AddRef via IUnknown kept alive by winrt wrapper)
|
|
|
|
FPS_BLEDeviceHandle* Handle = new FPS_BLEDeviceHandle();
|
|
|
|
Device->NativeDeviceHandle = new winrt::Windows::Devices::Bluetooth::BluetoothLEDevice(BLEDev);
|
|
|
|
Handle->Device = BLEDev;
|
|
|
|
|
|
|
|
Handle->ConnectionStatusToken = BLEDev.ConnectionStatusChanged(
|
|
|
|
// Subscribe to connection-status change
|
|
|
|
[Device](WinBT::BluetoothLEDevice const& Dev, winrt::Windows::Foundation::IInspectable const&)
|
|
|
|
BLEDev.ConnectionStatusChanged(
|
|
|
|
|
|
|
|
[Device](BluetoothLEDevice const& Dev, IInspectable const&)
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (Dev.ConnectionStatus() == BluetoothConnectionStatus::Disconnected)
|
|
|
|
if (Dev.ConnectionStatus() == WinBT::BluetoothConnectionStatus::Disconnected)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
DispatchDeviceDisconnected(Device);
|
|
|
|
DispatchDeviceDisconnected(Device);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
Device->NativeDeviceHandle = Handle;
|
|
|
|
|
|
|
|
|
|
|
|
// Discover GATT services
|
|
|
|
auto SvcResult = BLEDev.GetGattServicesAsync(WinBT::BluetoothCacheMode::Uncached).get();
|
|
|
|
auto SvcResult = BLEDev.GetGattServicesAsync(BluetoothCacheMode::Uncached).get();
|
|
|
|
if (SvcResult.Status() != WinGAP::GattCommunicationStatus::Success)
|
|
|
|
if (SvcResult.Status() != GattCommunicationStatus::Success)
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
DispatchDeviceDisconnected(Device);
|
|
|
|
DispatchDeviceDisconnected(Device);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
@@ -348,16 +362,17 @@ bool UPS_BLE_Module::ConnectDevice(UPS_BLE_Device* Device)
|
|
|
|
for (uint32_t si = 0; si < Services.Size(); si++)
|
|
|
|
for (uint32_t si = 0; si < Services.Size(); si++)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
auto Svc = Services.GetAt(si);
|
|
|
|
auto Svc = Services.GetAt(si);
|
|
|
|
Device->NativeGattServices.Add(new GattDeviceService(Svc));
|
|
|
|
FPS_GattServiceHandle* SvcHandle = new FPS_GattServiceHandle();
|
|
|
|
|
|
|
|
SvcHandle->Service = Svc;
|
|
|
|
|
|
|
|
Device->NativeGattServices.Add(SvcHandle);
|
|
|
|
|
|
|
|
|
|
|
|
FPS_ServiceItem SvcItem;
|
|
|
|
FPS_ServiceItem SvcItem;
|
|
|
|
GUID g = Svc.Uuid();
|
|
|
|
GUID g = Svc.Uuid();
|
|
|
|
SvcItem.ServiceUUID = UPS_BLE_Device::GUIDToString(&g);
|
|
|
|
SvcItem.ServiceUUID = UPS_BLE_Device::GUIDToString(&g);
|
|
|
|
SvcItem.ServiceName = SvcItem.ServiceUUID; // WinRT doesn't give a friendly name
|
|
|
|
SvcItem.ServiceName = SvcItem.ServiceUUID;
|
|
|
|
|
|
|
|
|
|
|
|
// Discover characteristics
|
|
|
|
auto CharResult = SvcHandle->Service.GetCharacteristicsAsync(WinBT::BluetoothCacheMode::Uncached).get();
|
|
|
|
auto CharResult = Svc.GetCharacteristicsAsync(BluetoothCacheMode::Uncached).get();
|
|
|
|
if (CharResult.Status() == WinGAP::GattCommunicationStatus::Success)
|
|
|
|
if (CharResult.Status() == GattCommunicationStatus::Success)
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
auto Chars = CharResult.Characteristics();
|
|
|
|
auto Chars = CharResult.Characteristics();
|
|
|
|
for (uint32_t ci = 0; ci < Chars.Size(); ci++)
|
|
|
|
for (uint32_t ci = 0; ci < Chars.Size(); ci++)
|
|
|
|
@@ -368,17 +383,17 @@ bool UPS_BLE_Module::ConnectDevice(UPS_BLE_Device* Device)
|
|
|
|
ChItem.CharacteristicUUID = UPS_BLE_Device::GUIDToString(&cg);
|
|
|
|
ChItem.CharacteristicUUID = UPS_BLE_Device::GUIDToString(&cg);
|
|
|
|
ChItem.CharacteristicName = ChItem.CharacteristicUUID;
|
|
|
|
ChItem.CharacteristicName = ChItem.CharacteristicUUID;
|
|
|
|
|
|
|
|
|
|
|
|
// Map WinRT properties to our descriptor bits
|
|
|
|
|
|
|
|
auto Props = Ch.CharacteristicProperties();
|
|
|
|
auto Props = Ch.CharacteristicProperties();
|
|
|
|
uint8 Desc = 0;
|
|
|
|
uint8 Desc = 0;
|
|
|
|
if ((Props & GattCharacteristicProperties::Broadcast) != GattCharacteristicProperties::None) Desc |= 0x01;
|
|
|
|
using GP = WinGAP::GattCharacteristicProperties;
|
|
|
|
if ((Props & GattCharacteristicProperties::ExtendedProperties) != GattCharacteristicProperties::None) Desc |= 0x02;
|
|
|
|
if ((Props & GP::Broadcast) != GP::None) Desc |= 0x01;
|
|
|
|
if ((Props & GattCharacteristicProperties::Notify) != GattCharacteristicProperties::None) Desc |= 0x04;
|
|
|
|
if ((Props & GP::ExtendedProperties) != GP::None) Desc |= 0x02;
|
|
|
|
if ((Props & GattCharacteristicProperties::Indicate) != GattCharacteristicProperties::None) Desc |= 0x08;
|
|
|
|
if ((Props & GP::Notify) != GP::None) Desc |= 0x04;
|
|
|
|
if ((Props & GattCharacteristicProperties::Read) != GattCharacteristicProperties::None) Desc |= 0x10;
|
|
|
|
if ((Props & GP::Indicate) != GP::None) Desc |= 0x08;
|
|
|
|
if ((Props & GattCharacteristicProperties::Write) != GattCharacteristicProperties::None) Desc |= 0x20;
|
|
|
|
if ((Props & GP::Read) != GP::None) Desc |= 0x10;
|
|
|
|
if ((Props & GattCharacteristicProperties::WriteWithoutResponse)!= GattCharacteristicProperties::None) Desc |= 0x40;
|
|
|
|
if ((Props & GP::Write) != GP::None) Desc |= 0x20;
|
|
|
|
if ((Props & GattCharacteristicProperties::AuthenticatedSignedWrites)!= GattCharacteristicProperties::None) Desc |= 0x80;
|
|
|
|
if ((Props & GP::WriteWithoutResponse) != GP::None) Desc |= 0x40;
|
|
|
|
|
|
|
|
if ((Props & GP::AuthenticatedSignedWrites) != GP::None) Desc |= 0x80;
|
|
|
|
ChItem.Descriptor = Desc;
|
|
|
|
ChItem.Descriptor = Desc;
|
|
|
|
|
|
|
|
|
|
|
|
SvcItem.Characteristics.Add(ChItem);
|
|
|
|
SvcItem.Characteristics.Add(ChItem);
|
|
|
|
@@ -405,22 +420,18 @@ bool UPS_BLE_Module::ConnectDevice(UPS_BLE_Device* Device)
|
|
|
|
bool UPS_BLE_Module::DisconnectDevice(UPS_BLE_Device* Device)
|
|
|
|
bool UPS_BLE_Module::DisconnectDevice(UPS_BLE_Device* Device)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
|
|
|
|
PS_BLE_WINRT_NS
|
|
|
|
if (!Device) return false;
|
|
|
|
if (!Device) return false;
|
|
|
|
|
|
|
|
|
|
|
|
// Close native GATT service handles
|
|
|
|
|
|
|
|
for (void* SvcPtr : Device->NativeGattServices)
|
|
|
|
for (void* SvcPtr : Device->NativeGattServices)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (SvcPtr)
|
|
|
|
if (SvcPtr) delete static_cast<FPS_GattServiceHandle*>(SvcPtr);
|
|
|
|
{
|
|
|
|
|
|
|
|
delete static_cast<GattDeviceService*>(SvcPtr);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Device->NativeGattServices.Empty();
|
|
|
|
Device->NativeGattServices.Empty();
|
|
|
|
|
|
|
|
|
|
|
|
// Close device handle
|
|
|
|
|
|
|
|
if (Device->NativeDeviceHandle)
|
|
|
|
if (Device->NativeDeviceHandle)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
delete static_cast<BluetoothLEDevice*>(Device->NativeDeviceHandle);
|
|
|
|
delete static_cast<FPS_BLEDeviceHandle*>(Device->NativeDeviceHandle);
|
|
|
|
Device->NativeDeviceHandle = nullptr;
|
|
|
|
Device->NativeDeviceHandle = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
@@ -432,11 +443,12 @@ bool UPS_BLE_Module::DisconnectDevice(UPS_BLE_Device* Device)
|
|
|
|
bool UPS_BLE_Module::IsDeviceConnected(UPS_BLE_Device* Device)
|
|
|
|
bool UPS_BLE_Module::IsDeviceConnected(UPS_BLE_Device* Device)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
|
|
|
|
PS_BLE_WINRT_NS
|
|
|
|
if (!Device || !Device->NativeDeviceHandle) return false;
|
|
|
|
if (!Device || !Device->NativeDeviceHandle) return false;
|
|
|
|
try
|
|
|
|
try
|
|
|
|
{
|
|
|
|
{
|
|
|
|
BluetoothLEDevice* BLEDev = static_cast<BluetoothLEDevice*>(Device->NativeDeviceHandle);
|
|
|
|
auto* Handle = static_cast<FPS_BLEDeviceHandle*>(Device->NativeDeviceHandle);
|
|
|
|
return BLEDev->ConnectionStatus() == BluetoothConnectionStatus::Connected;
|
|
|
|
return Handle->Device.ConnectionStatus() == WinBT::BluetoothConnectionStatus::Connected;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (...) {}
|
|
|
|
catch (...) {}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
@@ -450,26 +462,27 @@ bool UPS_BLE_Module::IsDeviceConnected(UPS_BLE_Device* Device)
|
|
|
|
bool UPS_BLE_Module::ReadCharacteristic(UPS_BLE_Device* Device, uint8 SI, uint8 CI)
|
|
|
|
bool UPS_BLE_Module::ReadCharacteristic(UPS_BLE_Device* Device, uint8 SI, uint8 CI)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
if (!Device || SI >= Device->NativeGattServices.Num()) return false;
|
|
|
|
if (!Device || SI >= (uint8)Device->NativeGattServices.Num()) return false;
|
|
|
|
|
|
|
|
|
|
|
|
AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, [Device, SI, CI]()
|
|
|
|
AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, [Device, SI, CI]()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
PS_BLE_WINRT_NS
|
|
|
|
try
|
|
|
|
try
|
|
|
|
{
|
|
|
|
{
|
|
|
|
GattDeviceService* Svc = static_cast<GattDeviceService*>(Device->NativeGattServices[SI]);
|
|
|
|
auto* SvcH = static_cast<FPS_GattServiceHandle*>(Device->NativeGattServices[SI]);
|
|
|
|
auto Chars = Svc->GetCharacteristicsAsync(BluetoothCacheMode::Cached).get();
|
|
|
|
auto Chars = SvcH->Service.GetCharacteristicsAsync(WinBT::BluetoothCacheMode::Cached).get();
|
|
|
|
if (Chars.Status() != GattCommunicationStatus::Success) return;
|
|
|
|
if (Chars.Status() != WinGAP::GattCommunicationStatus::Success) return;
|
|
|
|
|
|
|
|
|
|
|
|
auto Ch = Chars.Characteristics().GetAt(CI);
|
|
|
|
auto Ch = Chars.Characteristics().GetAt(CI);
|
|
|
|
auto Result = Ch.ReadValueAsync(BluetoothCacheMode::Uncached).get();
|
|
|
|
auto Result = Ch.ReadValueAsync(WinBT::BluetoothCacheMode::Uncached).get();
|
|
|
|
|
|
|
|
|
|
|
|
EPS_GATTStatus Status = (Result.Status() == GattCommunicationStatus::Success)
|
|
|
|
EPS_GATTStatus Status = (Result.Status() == WinGAP::GattCommunicationStatus::Success)
|
|
|
|
? EPS_GATTStatus::Success : EPS_GATTStatus::Failure;
|
|
|
|
? EPS_GATTStatus::Success : EPS_GATTStatus::Failure;
|
|
|
|
|
|
|
|
|
|
|
|
TArray<uint8> Data;
|
|
|
|
TArray<uint8> Data;
|
|
|
|
if (Result.Status() == GattCommunicationStatus::Success)
|
|
|
|
if (Result.Status() == WinGAP::GattCommunicationStatus::Success)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
auto Reader = DataReader::FromBuffer(Result.Value());
|
|
|
|
auto Reader = WinStr::DataReader::FromBuffer(Result.Value());
|
|
|
|
Data.SetNumUninitialized(Reader.UnconsumedBufferLength());
|
|
|
|
Data.SetNumUninitialized(Reader.UnconsumedBufferLength());
|
|
|
|
for (uint8& B : Data) B = Reader.ReadByte();
|
|
|
|
for (uint8& B : Data) B = Reader.ReadByte();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -487,26 +500,26 @@ bool UPS_BLE_Module::ReadCharacteristic(UPS_BLE_Device* Device, uint8 SI, uint8
|
|
|
|
bool UPS_BLE_Module::WriteCharacteristic(UPS_BLE_Device* Device, uint8 SI, uint8 CI, const TArray<uint8>& Data)
|
|
|
|
bool UPS_BLE_Module::WriteCharacteristic(UPS_BLE_Device* Device, uint8 SI, uint8 CI, const TArray<uint8>& Data)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
if (!Device || SI >= Device->NativeGattServices.Num()) return false;
|
|
|
|
if (!Device || SI >= (uint8)Device->NativeGattServices.Num()) return false;
|
|
|
|
|
|
|
|
|
|
|
|
TArray<uint8> DataCopy = Data;
|
|
|
|
TArray<uint8> DataCopy = Data;
|
|
|
|
AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, [Device, SI, CI, DataCopy]()
|
|
|
|
AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, [Device, SI, CI, DataCopy]()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
PS_BLE_WINRT_NS
|
|
|
|
try
|
|
|
|
try
|
|
|
|
{
|
|
|
|
{
|
|
|
|
GattDeviceService* Svc = static_cast<GattDeviceService*>(Device->NativeGattServices[SI]);
|
|
|
|
auto* SvcH = static_cast<FPS_GattServiceHandle*>(Device->NativeGattServices[SI]);
|
|
|
|
auto Chars = Svc->GetCharacteristicsAsync(BluetoothCacheMode::Cached).get();
|
|
|
|
auto Chars = SvcH->Service.GetCharacteristicsAsync(WinBT::BluetoothCacheMode::Cached).get();
|
|
|
|
if (Chars.Status() != GattCommunicationStatus::Success) return;
|
|
|
|
if (Chars.Status() != WinGAP::GattCommunicationStatus::Success) return;
|
|
|
|
|
|
|
|
|
|
|
|
auto Ch = Chars.Characteristics().GetAt(CI);
|
|
|
|
auto Ch = Chars.Characteristics().GetAt(CI);
|
|
|
|
|
|
|
|
auto Writer = WinStr::DataWriter();
|
|
|
|
auto Writer = DataWriter();
|
|
|
|
|
|
|
|
for (uint8 B : DataCopy) Writer.WriteByte(B);
|
|
|
|
for (uint8 B : DataCopy) Writer.WriteByte(B);
|
|
|
|
|
|
|
|
|
|
|
|
auto Status = Ch.WriteValueAsync(Writer.DetachBuffer(),
|
|
|
|
auto WriteStatus = Ch.WriteValueAsync(Writer.DetachBuffer(),
|
|
|
|
GattWriteOption::WriteWithResponse).get();
|
|
|
|
WinGAP::GattWriteOption::WriteWithResponse).get();
|
|
|
|
|
|
|
|
|
|
|
|
EPS_GATTStatus GattStatus = (Status == GattCommunicationStatus::Success)
|
|
|
|
EPS_GATTStatus GattStatus = (WriteStatus == WinGAP::GattCommunicationStatus::Success)
|
|
|
|
? EPS_GATTStatus::Success : EPS_GATTStatus::Failure;
|
|
|
|
? EPS_GATTStatus::Success : EPS_GATTStatus::Failure;
|
|
|
|
|
|
|
|
|
|
|
|
DispatchWrite(Device, SI, CI, GattStatus);
|
|
|
|
DispatchWrite(Device, SI, CI, GattStatus);
|
|
|
|
@@ -522,39 +535,39 @@ bool UPS_BLE_Module::WriteCharacteristic(UPS_BLE_Device* Device, uint8 SI, uint8
|
|
|
|
bool UPS_BLE_Module::SubscribeCharacteristic(UPS_BLE_Device* Device, uint8 SI, uint8 CI)
|
|
|
|
bool UPS_BLE_Module::SubscribeCharacteristic(UPS_BLE_Device* Device, uint8 SI, uint8 CI)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
if (!Device || SI >= Device->NativeGattServices.Num()) return false;
|
|
|
|
if (!Device || SI >= (uint8)Device->NativeGattServices.Num()) return false;
|
|
|
|
|
|
|
|
|
|
|
|
AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, [Device, SI, CI]()
|
|
|
|
AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, [Device, SI, CI]()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
PS_BLE_WINRT_NS
|
|
|
|
try
|
|
|
|
try
|
|
|
|
{
|
|
|
|
{
|
|
|
|
GattDeviceService* Svc = static_cast<GattDeviceService*>(Device->NativeGattServices[SI]);
|
|
|
|
auto* SvcH = static_cast<FPS_GattServiceHandle*>(Device->NativeGattServices[SI]);
|
|
|
|
auto Chars = Svc->GetCharacteristicsAsync(BluetoothCacheMode::Cached).get();
|
|
|
|
auto Chars = SvcH->Service.GetCharacteristicsAsync(WinBT::BluetoothCacheMode::Cached).get();
|
|
|
|
if (Chars.Status() != GattCommunicationStatus::Success) return;
|
|
|
|
if (Chars.Status() != WinGAP::GattCommunicationStatus::Success) return;
|
|
|
|
|
|
|
|
|
|
|
|
auto Ch = Chars.Characteristics().GetAt(CI);
|
|
|
|
auto Ch = Chars.Characteristics().GetAt(CI);
|
|
|
|
|
|
|
|
|
|
|
|
// Write CCCD to enable notifications
|
|
|
|
|
|
|
|
auto WriteStatus = Ch.WriteClientCharacteristicConfigurationDescriptorAsync(
|
|
|
|
auto WriteStatus = Ch.WriteClientCharacteristicConfigurationDescriptorAsync(
|
|
|
|
GattClientCharacteristicConfigurationDescriptorValue::Notify).get();
|
|
|
|
WinGAP::GattClientCharacteristicConfigurationDescriptorValue::Notify).get();
|
|
|
|
|
|
|
|
|
|
|
|
EPS_GATTStatus GattStatus = (WriteStatus == GattCommunicationStatus::Success)
|
|
|
|
EPS_GATTStatus GattStatus = (WriteStatus == WinGAP::GattCommunicationStatus::Success)
|
|
|
|
? EPS_GATTStatus::Success : EPS_GATTStatus::Failure;
|
|
|
|
? EPS_GATTStatus::Success : EPS_GATTStatus::Failure;
|
|
|
|
|
|
|
|
|
|
|
|
if (WriteStatus == GattCommunicationStatus::Success)
|
|
|
|
if (WriteStatus == WinGAP::GattCommunicationStatus::Success)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// Register value-changed callback
|
|
|
|
|
|
|
|
auto Token = Ch.ValueChanged(
|
|
|
|
auto Token = Ch.ValueChanged(
|
|
|
|
[Device, SI, CI](GattCharacteristic const&, GattValueChangedEventArgs const& Args)
|
|
|
|
[Device, SI, CI](WinGAP::GattCharacteristic const&,
|
|
|
|
|
|
|
|
WinGAP::GattValueChangedEventArgs const& Args)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
auto Reader = DataReader::FromBuffer(Args.CharacteristicValue());
|
|
|
|
PS_BLE_WINRT_NS
|
|
|
|
|
|
|
|
auto Reader = WinStr::DataReader::FromBuffer(Args.CharacteristicValue());
|
|
|
|
TArray<uint8> Data;
|
|
|
|
TArray<uint8> Data;
|
|
|
|
Data.SetNumUninitialized(Reader.UnconsumedBufferLength());
|
|
|
|
Data.SetNumUninitialized(Reader.UnconsumedBufferLength());
|
|
|
|
for (uint8& B : Data) B = Reader.ReadByte();
|
|
|
|
for (uint8& B : Data) B = Reader.ReadByte();
|
|
|
|
DispatchNotify(Device, SI, CI, EPS_GATTStatus::Success, MoveTemp(Data));
|
|
|
|
DispatchNotify(Device, SI, CI, EPS_GATTStatus::Success, MoveTemp(Data));
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// Store token (key = packed SI<<8|CI)
|
|
|
|
|
|
|
|
uint64 Key = ((uint64)SI << 8) | CI;
|
|
|
|
uint64 Key = ((uint64)SI << 8) | CI;
|
|
|
|
Device->NotifyTokens.Add(Key, new winrt::event_token(Token));
|
|
|
|
Device->NotifyTokens.Add(Key, new winrt::event_token(Token));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -572,19 +585,19 @@ bool UPS_BLE_Module::SubscribeCharacteristic(UPS_BLE_Device* Device, uint8 SI, u
|
|
|
|
bool UPS_BLE_Module::UnsubscribeCharacteristic(UPS_BLE_Device* Device, uint8 SI, uint8 CI)
|
|
|
|
bool UPS_BLE_Module::UnsubscribeCharacteristic(UPS_BLE_Device* Device, uint8 SI, uint8 CI)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
#if PLATFORM_WINDOWS
|
|
|
|
if (!Device || SI >= Device->NativeGattServices.Num()) return false;
|
|
|
|
if (!Device || SI >= (uint8)Device->NativeGattServices.Num()) return false;
|
|
|
|
|
|
|
|
|
|
|
|
AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, [Device, SI, CI]()
|
|
|
|
AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, [Device, SI, CI]()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
PS_BLE_WINRT_NS
|
|
|
|
try
|
|
|
|
try
|
|
|
|
{
|
|
|
|
{
|
|
|
|
GattDeviceService* Svc = static_cast<GattDeviceService*>(Device->NativeGattServices[SI]);
|
|
|
|
auto* SvcH = static_cast<FPS_GattServiceHandle*>(Device->NativeGattServices[SI]);
|
|
|
|
auto Chars = Svc->GetCharacteristicsAsync(BluetoothCacheMode::Cached).get();
|
|
|
|
auto Chars = SvcH->Service.GetCharacteristicsAsync(WinBT::BluetoothCacheMode::Cached).get();
|
|
|
|
if (Chars.Status() != GattCommunicationStatus::Success) return;
|
|
|
|
if (Chars.Status() != WinGAP::GattCommunicationStatus::Success) return;
|
|
|
|
|
|
|
|
|
|
|
|
auto Ch = Chars.Characteristics().GetAt(CI);
|
|
|
|
auto Ch = Chars.Characteristics().GetAt(CI);
|
|
|
|
|
|
|
|
|
|
|
|
// Remove event token
|
|
|
|
|
|
|
|
uint64 Key = ((uint64)SI << 8) | CI;
|
|
|
|
uint64 Key = ((uint64)SI << 8) | CI;
|
|
|
|
if (winrt::event_token** TokenPtr = reinterpret_cast<winrt::event_token**>(Device->NotifyTokens.Find(Key)))
|
|
|
|
if (winrt::event_token** TokenPtr = reinterpret_cast<winrt::event_token**>(Device->NotifyTokens.Find(Key)))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@@ -593,11 +606,10 @@ bool UPS_BLE_Module::UnsubscribeCharacteristic(UPS_BLE_Device* Device, uint8 SI,
|
|
|
|
Device->NotifyTokens.Remove(Key);
|
|
|
|
Device->NotifyTokens.Remove(Key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Write CCCD to disable notifications
|
|
|
|
|
|
|
|
auto WriteStatus = Ch.WriteClientCharacteristicConfigurationDescriptorAsync(
|
|
|
|
auto WriteStatus = Ch.WriteClientCharacteristicConfigurationDescriptorAsync(
|
|
|
|
GattClientCharacteristicConfigurationDescriptorValue::None).get();
|
|
|
|
WinGAP::GattClientCharacteristicConfigurationDescriptorValue::None).get();
|
|
|
|
|
|
|
|
|
|
|
|
EPS_GATTStatus GattStatus = (WriteStatus == GattCommunicationStatus::Success)
|
|
|
|
EPS_GATTStatus GattStatus = (WriteStatus == WinGAP::GattCommunicationStatus::Success)
|
|
|
|
? EPS_GATTStatus::Success : EPS_GATTStatus::Failure;
|
|
|
|
? EPS_GATTStatus::Success : EPS_GATTStatus::Failure;
|
|
|
|
|
|
|
|
|
|
|
|
DispatchUnsubscribe(Device, SI, CI, GattStatus);
|
|
|
|
DispatchUnsubscribe(Device, SI, CI, GattStatus);
|
|
|
|
@@ -633,22 +645,55 @@ void UPS_BLE_Module::DispatchDiscoveryEnd(UPS_BLE_Manager* Mgr, const TArray<FPS
|
|
|
|
void UPS_BLE_Module::DispatchDeviceConnected(UPS_BLE_Device* Dev)
|
|
|
|
void UPS_BLE_Module::DispatchDeviceConnected(UPS_BLE_Device* Dev)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (!Dev) return;
|
|
|
|
if (!Dev) return;
|
|
|
|
if (IsInGameThread()) { Dev->RefToManager->JustConnectedDevice(Dev); Dev->OnConnect.Broadcast(Dev, Dev->ActiveServices); }
|
|
|
|
if (IsInGameThread())
|
|
|
|
else { AsyncTask(ENamedThreads::GameThread, [Dev]() { Dev->RefToManager->JustConnectedDevice(Dev); Dev->OnConnect.Broadcast(Dev, Dev->ActiveServices); }); }
|
|
|
|
{
|
|
|
|
|
|
|
|
Dev->RefToManager->JustConnectedDevice(Dev);
|
|
|
|
|
|
|
|
Dev->OnConnect.Broadcast(Dev, Dev->ActiveServices);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
AsyncTask(ENamedThreads::GameThread, [Dev]()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Dev->RefToManager->JustConnectedDevice(Dev);
|
|
|
|
|
|
|
|
Dev->OnConnect.Broadcast(Dev, Dev->ActiveServices);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UPS_BLE_Module::DispatchDeviceDisconnected(UPS_BLE_Device* Dev)
|
|
|
|
void UPS_BLE_Module::DispatchDeviceDisconnected(UPS_BLE_Device* Dev)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (!Dev) return;
|
|
|
|
if (!Dev) return;
|
|
|
|
if (IsInGameThread()) { Dev->RefToManager->JustDisconnectedDevice(Dev); Dev->OnDisconnect.Broadcast(Dev); }
|
|
|
|
if (IsInGameThread())
|
|
|
|
else { AsyncTask(ENamedThreads::GameThread, [Dev]() { Dev->RefToManager->JustDisconnectedDevice(Dev); Dev->OnDisconnect.Broadcast(Dev); }); }
|
|
|
|
{
|
|
|
|
|
|
|
|
Dev->RefToManager->JustDisconnectedDevice(Dev);
|
|
|
|
|
|
|
|
Dev->OnDisconnect.Broadcast(Dev);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
AsyncTask(ENamedThreads::GameThread, [Dev]()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Dev->RefToManager->JustDisconnectedDevice(Dev);
|
|
|
|
|
|
|
|
Dev->OnDisconnect.Broadcast(Dev);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UPS_BLE_Module::DispatchServicesDiscovered(UPS_BLE_Device* Dev)
|
|
|
|
void UPS_BLE_Module::DispatchServicesDiscovered(UPS_BLE_Device* Dev)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (!Dev) return;
|
|
|
|
if (!Dev) return;
|
|
|
|
if (IsInGameThread()) { Dev->RefToManager->JustDiscoveredServices(Dev); Dev->OnServicesDiscovered.Broadcast(Dev, Dev->ActiveServices); }
|
|
|
|
if (IsInGameThread())
|
|
|
|
else { AsyncTask(ENamedThreads::GameThread, [Dev]() { Dev->RefToManager->JustDiscoveredServices(Dev); Dev->OnServicesDiscovered.Broadcast(Dev, Dev->ActiveServices); }); }
|
|
|
|
{
|
|
|
|
|
|
|
|
Dev->RefToManager->JustDiscoveredServices(Dev);
|
|
|
|
|
|
|
|
Dev->OnServicesDiscovered.Broadcast(Dev, Dev->ActiveServices);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
AsyncTask(ENamedThreads::GameThread, [Dev]()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Dev->RefToManager->JustDiscoveredServices(Dev);
|
|
|
|
|
|
|
|
Dev->OnServicesDiscovered.Broadcast(Dev, Dev->ActiveServices);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UPS_BLE_Module::DispatchRead(UPS_BLE_Device* Dev, uint8 SI, uint8 CI, EPS_GATTStatus Status, TArray<uint8> Data)
|
|
|
|
void UPS_BLE_Module::DispatchRead(UPS_BLE_Device* Dev, uint8 SI, uint8 CI, EPS_GATTStatus Status, TArray<uint8> Data)
|
|
|
|
@@ -657,14 +702,16 @@ void UPS_BLE_Module::DispatchRead(UPS_BLE_Device* Dev, uint8 SI, uint8 CI, EPS_G
|
|
|
|
if (IsInGameThread())
|
|
|
|
if (IsInGameThread())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (SI < Dev->ActiveServices.Num() && CI < Dev->ActiveServices[SI].Characteristics.Num())
|
|
|
|
if (SI < Dev->ActiveServices.Num() && CI < Dev->ActiveServices[SI].Characteristics.Num())
|
|
|
|
Dev->OnRead.Broadcast(Status, Dev, Dev->ActiveServices[SI].ServiceUUID, Dev->ActiveServices[SI].Characteristics[CI].CharacteristicUUID, Data);
|
|
|
|
Dev->OnRead.Broadcast(Status, Dev, Dev->ActiveServices[SI].ServiceUUID,
|
|
|
|
|
|
|
|
Dev->ActiveServices[SI].Characteristics[CI].CharacteristicUUID, Data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
else
|
|
|
|
{
|
|
|
|
{
|
|
|
|
AsyncTask(ENamedThreads::GameThread, [Dev, SI, CI, Status, Data]()
|
|
|
|
AsyncTask(ENamedThreads::GameThread, [Dev, SI, CI, Status, Data]()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (SI < Dev->ActiveServices.Num() && CI < Dev->ActiveServices[SI].Characteristics.Num())
|
|
|
|
if (SI < Dev->ActiveServices.Num() && CI < Dev->ActiveServices[SI].Characteristics.Num())
|
|
|
|
Dev->OnRead.Broadcast(Status, Dev, Dev->ActiveServices[SI].ServiceUUID, Dev->ActiveServices[SI].Characteristics[CI].CharacteristicUUID, Data);
|
|
|
|
Dev->OnRead.Broadcast(Status, Dev, Dev->ActiveServices[SI].ServiceUUID,
|
|
|
|
|
|
|
|
Dev->ActiveServices[SI].Characteristics[CI].CharacteristicUUID, Data);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -675,14 +722,16 @@ void UPS_BLE_Module::DispatchNotify(UPS_BLE_Device* Dev, uint8 SI, uint8 CI, EPS
|
|
|
|
if (IsInGameThread())
|
|
|
|
if (IsInGameThread())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (SI < Dev->ActiveServices.Num() && CI < Dev->ActiveServices[SI].Characteristics.Num())
|
|
|
|
if (SI < Dev->ActiveServices.Num() && CI < Dev->ActiveServices[SI].Characteristics.Num())
|
|
|
|
Dev->OnNotify.Broadcast(Status, Dev, Dev->ActiveServices[SI].ServiceUUID, Dev->ActiveServices[SI].Characteristics[CI].CharacteristicUUID, Data);
|
|
|
|
Dev->OnNotify.Broadcast(Status, Dev, Dev->ActiveServices[SI].ServiceUUID,
|
|
|
|
|
|
|
|
Dev->ActiveServices[SI].Characteristics[CI].CharacteristicUUID, Data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
else
|
|
|
|
{
|
|
|
|
{
|
|
|
|
AsyncTask(ENamedThreads::GameThread, [Dev, SI, CI, Status, Data]()
|
|
|
|
AsyncTask(ENamedThreads::GameThread, [Dev, SI, CI, Status, Data]()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (SI < Dev->ActiveServices.Num() && CI < Dev->ActiveServices[SI].Characteristics.Num())
|
|
|
|
if (SI < Dev->ActiveServices.Num() && CI < Dev->ActiveServices[SI].Characteristics.Num())
|
|
|
|
Dev->OnNotify.Broadcast(Status, Dev, Dev->ActiveServices[SI].ServiceUUID, Dev->ActiveServices[SI].Characteristics[CI].CharacteristicUUID, Data);
|
|
|
|
Dev->OnNotify.Broadcast(Status, Dev, Dev->ActiveServices[SI].ServiceUUID,
|
|
|
|
|
|
|
|
Dev->ActiveServices[SI].Characteristics[CI].CharacteristicUUID, Data);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -693,7 +742,8 @@ void UPS_BLE_Module::DispatchWrite(UPS_BLE_Device* Dev, uint8 SI, uint8 CI, EPS_
|
|
|
|
auto Fire = [Dev, SI, CI, Status]()
|
|
|
|
auto Fire = [Dev, SI, CI, Status]()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (SI < Dev->ActiveServices.Num() && CI < Dev->ActiveServices[SI].Characteristics.Num())
|
|
|
|
if (SI < Dev->ActiveServices.Num() && CI < Dev->ActiveServices[SI].Characteristics.Num())
|
|
|
|
Dev->OnWrite.Broadcast(Status, Dev, Dev->ActiveServices[SI].ServiceUUID, Dev->ActiveServices[SI].Characteristics[CI].CharacteristicUUID);
|
|
|
|
Dev->OnWrite.Broadcast(Status, Dev, Dev->ActiveServices[SI].ServiceUUID,
|
|
|
|
|
|
|
|
Dev->ActiveServices[SI].Characteristics[CI].CharacteristicUUID);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
if (IsInGameThread()) Fire();
|
|
|
|
if (IsInGameThread()) Fire();
|
|
|
|
else AsyncTask(ENamedThreads::GameThread, Fire);
|
|
|
|
else AsyncTask(ENamedThreads::GameThread, Fire);
|
|
|
|
@@ -707,7 +757,8 @@ void UPS_BLE_Module::DispatchSubscribe(UPS_BLE_Device* Dev, uint8 SI, uint8 CI,
|
|
|
|
if (SI < Dev->ActiveServices.Num() && CI < Dev->ActiveServices[SI].Characteristics.Num())
|
|
|
|
if (SI < Dev->ActiveServices.Num() && CI < Dev->ActiveServices[SI].Characteristics.Num())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Dev->ActiveServices[SI].Characteristics[CI].subscribed = true;
|
|
|
|
Dev->ActiveServices[SI].Characteristics[CI].subscribed = true;
|
|
|
|
Dev->OnSubscribe.Broadcast(Status, Dev, Dev->ActiveServices[SI].ServiceUUID, Dev->ActiveServices[SI].Characteristics[CI].CharacteristicUUID);
|
|
|
|
Dev->OnSubscribe.Broadcast(Status, Dev, Dev->ActiveServices[SI].ServiceUUID,
|
|
|
|
|
|
|
|
Dev->ActiveServices[SI].Characteristics[CI].CharacteristicUUID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
if (IsInGameThread()) Fire();
|
|
|
|
if (IsInGameThread()) Fire();
|
|
|
|
@@ -722,7 +773,8 @@ void UPS_BLE_Module::DispatchUnsubscribe(UPS_BLE_Device* Dev, uint8 SI, uint8 CI
|
|
|
|
if (SI < Dev->ActiveServices.Num() && CI < Dev->ActiveServices[SI].Characteristics.Num())
|
|
|
|
if (SI < Dev->ActiveServices.Num() && CI < Dev->ActiveServices[SI].Characteristics.Num())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Dev->ActiveServices[SI].Characteristics[CI].subscribed = false;
|
|
|
|
Dev->ActiveServices[SI].Characteristics[CI].subscribed = false;
|
|
|
|
Dev->OnUnsubscribe.Broadcast(Status, Dev, Dev->ActiveServices[SI].ServiceUUID, Dev->ActiveServices[SI].Characteristics[CI].CharacteristicUUID);
|
|
|
|
Dev->OnUnsubscribe.Broadcast(Status, Dev, Dev->ActiveServices[SI].ServiceUUID,
|
|
|
|
|
|
|
|
Dev->ActiveServices[SI].Characteristics[CI].CharacteristicUUID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
if (IsInGameThread()) Fire();
|
|
|
|
if (IsInGameThread()) Fire();
|
|
|
|
|