This project separates platform-specific BLE transport code from the protocol logic.
The PolarH10.Transport.Abstractions library defines interfaces; platform-specific
projects implement them.
Available Transports
| Transport | Platform | BLE Stack |
|---|---|---|
PolarH10.Transport.Windows |
Windows 10+ | WinRT (Windows.Devices.Bluetooth) |
Writing a New Transport
To add support for a new platform (e.g., Linux/BlueZ, macOS/CoreBluetooth, Android):
- Create a new project targeting the appropriate TFM.
- Reference
PolarH10.Transport.Abstractions. - Implement the following interfaces:
IBleScanner— discover devices via advertisementsIBleConnection— connect, negotiate MTU, discover servicesIGattServiceHandle— enumerate characteristics within a serviceIGattCharacteristicHandle— read, write, and subscribe to notificationsIBleAdapterFactory— factory to create scanner and connection instances
IBleScanner
- Raise
DeviceFoundevent withBleDeviceFoundrecords (address, name, RSSI). - Implement
StartScanAsyncandStopScan.
IBleConnection
- Implement
IAsyncDisposable. ConnectAsyncshould establish the connection and discover primary services.RequestMtuAsyncshould negotiate the ATT MTU size.- Raise
StateChangedevents on connect/disconnect.
IGattCharacteristicHandle
EnableNotificationsAsyncmust write the CCCD descriptor (0x2902) with value0x01 0x00(notifications) or0x02 0x00(indications).WriteAsyncsends commands (e.g., PMD start/stop).- The
ValueChangedevent delivers incoming notification payloads.
Windows Transport Details
The Windows transport uses:
BluetoothLEAdvertisementWatcherfor scanning (active mode)BluetoothLEDevice.FromBluetoothAddressAsyncfor connectingGattSessionfor MTU negotiation (MaxPduSize)GattCharacteristic.WriteValueWithResultAsyncfor reliable writesDataReaderfor reading notification payloads
Windows BLE Notes
- On this Windows 11 machine, direct WinRT characteristic discovery can return
AccessDeniedeven when the service lookup succeeds. - The durable fix in the Windows transport is to call
GattDeviceService.RequestAccessAsync()before characteristic discovery and retry short-livedAccessDeniedorUnreachableresults. - In this repo, that access-request and retry pattern lives in
src/PolarH10.Transport.Windows/WindowsGattServiceHandle.cs.
Windows Application-Control Note
- Local
dotnet testand normal multi-file local .NET runs can still be blocked by Windows application-control policy on this machine. - The canonical repo-local operator build is:
powershell -ExecutionPolicy Bypass -File .\tools\app\Build-Workspace-App.ps1
.\out\workspace-app\PolarH10.App.exe
- For manual operator validation, a practical workaround is a single-file publish if Windows still blocks that multi-file workspace build:
dotnet publish src/PolarH10.App/PolarH10.App.csproj `
-c Release `
-r win-x64 `
-p:PublishSingleFile=true `
-p:SelfContained=false `
-o out/app-single