PS_Win_BLE : fix erreurs de compilation WinRT
- Suppression des 'using namespace Windows::*' au scope global (conflit avec le namespace Windows d'Unreal via AllowWindowsPlatformTypes) - Remplacement par un macro PS_BLE_WINRT_NS avec aliases locaux (WinBT, WinAdv, WinGAP, WinStr) utilisés dans chaque fonction - Ajout de FPS_BLEDeviceHandle et FPS_GattServiceHandle : wrappers heap-alloués pour les types WinRT qui suppriment operator new - Suppression warning C4265 (dtor non-virtual interne aux headers WinRT) - Plugin charge sans erreur dans UE 5.5 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d593bbd9fd
commit
113eddef46
@ -17,6 +17,10 @@
|
|||||||
"TargetAllowList": [
|
"TargetAllowList": [
|
||||||
"Editor"
|
"Editor"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "PS_Win_BLE",
|
||||||
|
"Enabled": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -49,6 +49,13 @@ public class PS_Win_BLE : ModuleRules
|
|||||||
"runtimeobject.lib" // RoInitialize / WinRT activation
|
"runtimeobject.lib" // RoInitialize / WinRT activation
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// C++/WinRT headers (winrt/Windows.Devices.Bluetooth.h, etc.)
|
||||||
|
// Located in the Windows SDK — we pick the version used by UE5.5
|
||||||
|
string WinSDKDir = "C:/Program Files (x86)/Windows Kits/10";
|
||||||
|
string WinSDKVersion = "10.0.22621.0";
|
||||||
|
PrivateIncludePaths.Add(Path.Combine(WinSDKDir, "Include", WinSDKVersion, "cppwinrt"));
|
||||||
|
PrivateIncludePaths.Add(Path.Combine(WinSDKDir, "Include", WinSDKVersion, "winrt"));
|
||||||
|
|
||||||
// Allow WinRT headers in C++ code
|
// Allow WinRT headers in C++ code
|
||||||
bEnableExceptions = true;
|
bEnableExceptions = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,18 +4,6 @@
|
|||||||
#include "PS_BLEModule.h"
|
#include "PS_BLEModule.h"
|
||||||
#include "PS_BLEManager.h"
|
#include "PS_BLEManager.h"
|
||||||
|
|
||||||
#if PLATFORM_WINDOWS
|
|
||||||
#include "Windows/AllowWindowsPlatformTypes.h"
|
|
||||||
#include "Windows/AllowWindowsPlatformAtomics.h"
|
|
||||||
#pragma warning(push)
|
|
||||||
#pragma warning(disable: 4668 4946 5204 5220)
|
|
||||||
#include <winrt/Windows.Foundation.h>
|
|
||||||
#pragma warning(pop)
|
|
||||||
#include "Windows/HideWindowsPlatformAtomics.h"
|
|
||||||
#include "Windows/HideWindowsPlatformTypes.h"
|
|
||||||
using namespace winrt;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
UPS_BLE_Device::UPS_BLE_Device()
|
UPS_BLE_Device::UPS_BLE_Device()
|
||||||
|
|||||||
@ -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,20 +34,36 @@
|
|||||||
#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
|
||||||
@ -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();
|
||||||
|
uint64 Addr = Args.BluetoothAddress();
|
||||||
|
|
||||||
// Dedup by address
|
|
||||||
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();
|
||||||
|
|||||||
@ -9,15 +9,6 @@
|
|||||||
class UPS_BLE_Device;
|
class UPS_BLE_Device;
|
||||||
class UPS_BLE_Manager;
|
class UPS_BLE_Manager;
|
||||||
|
|
||||||
// ─── Internal device record (equivalent to TUE_dev_rec from old plugin) ──────
|
|
||||||
struct FPS_DeviceRecord
|
|
||||||
{
|
|
||||||
uint64 ID = 0;
|
|
||||||
int64 RSSI = 0;
|
|
||||||
FString Name;
|
|
||||||
void* NativeDeviceRef = nullptr; // WinRT IBluetoothLEDevice* (opaque ptr for forward compat)
|
|
||||||
};
|
|
||||||
|
|
||||||
// ─── Module ───────────────────────────────────────────────────────────────────
|
// ─── Module ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
class UPS_BLE_Module : public IModuleInterface
|
class UPS_BLE_Module : public IModuleInterface
|
||||||
@ -48,9 +39,9 @@ public:
|
|||||||
bool UnsubscribeCharacteristic(UPS_BLE_Device* Device, uint8 ServiceIndex, uint8 CharIndex);
|
bool UnsubscribeCharacteristic(UPS_BLE_Device* Device, uint8 ServiceIndex, uint8 CharIndex);
|
||||||
|
|
||||||
UPS_BLE_Manager* LocalBLEManager = nullptr;
|
UPS_BLE_Manager* LocalBLEManager = nullptr;
|
||||||
|
bool bInitialized = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool bInitialized = false;
|
|
||||||
|
|
||||||
// WinRT scanner (opaque handle — implementation in .cpp using WinRT types)
|
// WinRT scanner (opaque handle — implementation in .cpp using WinRT types)
|
||||||
void* ScannerHandle = nullptr;
|
void* ScannerHandle = nullptr;
|
||||||
|
|||||||
@ -97,6 +97,18 @@ public:
|
|||||||
UPROPERTY(BlueprintReadOnly, Category = "PS BLE") TArray<FPS_CharacteristicItem> Characteristics;
|
UPROPERTY(BlueprintReadOnly, Category = "PS BLE") TArray<FPS_CharacteristicItem> Characteristics;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ─── INTERNAL DEVICE RECORD (forward-declared here so Manager can use it) ────
|
||||||
|
// This is a plain C++ struct (no UCLASS/USTRUCT) used internally between
|
||||||
|
// the module and the manager — not exposed to Blueprint.
|
||||||
|
|
||||||
|
struct FPS_DeviceRecord
|
||||||
|
{
|
||||||
|
uint64 ID = 0;
|
||||||
|
int64 RSSI = 0;
|
||||||
|
FString Name;
|
||||||
|
void* NativeDeviceRef = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
// ─── FORWARD DECLARATIONS ────────────────────────────────────────────────────
|
// ─── FORWARD DECLARATIONS ────────────────────────────────────────────────────
|
||||||
|
|
||||||
class UPS_BLE_Device;
|
class UPS_BLE_Device;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user