Fix macOS Bluetooth state and add RTK debug console
This commit is contained in:
@@ -10,6 +10,7 @@ public sealed record DiscoveredDevice(Guid Id, string Name, int Rssi);
|
||||
/// <summary>Thin scan wrapper over Plugin.BLE with per-platform permission handling.</summary>
|
||||
public sealed class BleScanner
|
||||
{
|
||||
private readonly IBluetoothLE _bluetooth = CrossBluetoothLE.Current;
|
||||
private readonly IAdapter _adapter = CrossBluetoothLE.Current.Adapter;
|
||||
|
||||
public event EventHandler<DiscoveredDevice>? DeviceDiscovered;
|
||||
@@ -23,9 +24,7 @@ public sealed class BleScanner
|
||||
public async Task ScanAsync(TimeSpan duration, CancellationToken cancellationToken = default)
|
||||
{
|
||||
await EnsurePermissionsAsync();
|
||||
|
||||
if (!CrossBluetoothLE.Current.IsOn)
|
||||
throw new InvalidOperationException("Bluetooth is turned off.");
|
||||
await EnsureBluetoothReadyAsync(cancellationToken);
|
||||
|
||||
void OnDiscovered(object? sender, DeviceEventArgs e)
|
||||
{
|
||||
@@ -58,6 +57,65 @@ public sealed class BleScanner
|
||||
}
|
||||
}
|
||||
|
||||
private async Task EnsureBluetoothReadyAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
// CoreBluetooth commonly starts in Unknown while CBCentralManager is being
|
||||
// initialized. IsOn is false for every state except On, so checking it
|
||||
// immediately incorrectly reports that Bluetooth is switched off on macOS.
|
||||
if (_bluetooth.State is BluetoothState.Unknown or BluetoothState.TurningOn)
|
||||
{
|
||||
var stateChanged = new TaskCompletionSource<BluetoothState>(
|
||||
TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
|
||||
void OnStateChanged(object? sender, BluetoothStateChangedArgs args)
|
||||
{
|
||||
if (args.NewState is not (BluetoothState.Unknown or BluetoothState.TurningOn))
|
||||
stateChanged.TrySetResult(args.NewState);
|
||||
}
|
||||
|
||||
_bluetooth.StateChanged += OnStateChanged;
|
||||
try
|
||||
{
|
||||
// Recheck after subscribing so a transition cannot be missed.
|
||||
var currentState = _bluetooth.State;
|
||||
if (currentState is BluetoothState.Unknown or BluetoothState.TurningOn)
|
||||
{
|
||||
using var initializationTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(5));
|
||||
using var linkedCancellation = CancellationTokenSource.CreateLinkedTokenSource(
|
||||
cancellationToken, initializationTimeout.Token);
|
||||
try
|
||||
{
|
||||
await stateChanged.Task.WaitAsync(linkedCancellation.Token);
|
||||
}
|
||||
catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Bluetooth did not finish initializing. Try scanning again.");
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_bluetooth.StateChanged -= OnStateChanged;
|
||||
}
|
||||
}
|
||||
|
||||
if (_bluetooth.State == BluetoothState.On)
|
||||
return;
|
||||
|
||||
throw _bluetooth.State switch
|
||||
{
|
||||
BluetoothState.Off or BluetoothState.TurningOff =>
|
||||
new InvalidOperationException("Bluetooth is turned off."),
|
||||
BluetoothState.Unauthorized =>
|
||||
new PermissionException(
|
||||
"Bluetooth access is denied. Enable Field Logger in System Settings > Privacy & Security > Bluetooth."),
|
||||
BluetoothState.Unavailable =>
|
||||
new InvalidOperationException("Bluetooth is not available on this Mac."),
|
||||
_ => new InvalidOperationException($"Bluetooth is not ready (state: {_bluetooth.State}).")
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>Requests the runtime permissions BLE scanning needs (Android only; no-op elsewhere).</summary>
|
||||
public static async Task EnsurePermissionsAsync()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user