|
@@ -0,0 +1,165 @@
|
|
|
+using InABox.Core;
|
|
|
+using Plugin.BLE;
|
|
|
+using Plugin.BLE.Abstractions;
|
|
|
+using Plugin.BLE.Abstractions.Contracts;
|
|
|
+using Plugin.BLE.Abstractions.EventArgs;
|
|
|
+using System;
|
|
|
+using System.Linq;
|
|
|
+using System.Threading.Tasks;
|
|
|
+
|
|
|
+namespace InABox.Avalonia.Platform.iOS;
|
|
|
+
|
|
|
+
|
|
|
+public class iOS_Bluetooth : IBluetooth
|
|
|
+{
|
|
|
+ public Logger? Logger { get; set; }
|
|
|
+
|
|
|
+ public event EventHandler? Changed;
|
|
|
+ public CoreObservableCollection<IBluetoothDevice> Devices { get; } = new ();
|
|
|
+
|
|
|
+ private IBluetoothLE _ble;
|
|
|
+ private IAdapter _adapter;
|
|
|
+ private ScanFilterOptions _scanoptions = new ScanFilterOptions();
|
|
|
+ private StaleItemMonitor<IBluetoothDevice> _staleItemMonitor;
|
|
|
+ public iOS_Bluetooth()
|
|
|
+ {
|
|
|
+
|
|
|
+ _staleItemMonitor = new StaleItemMonitor<IBluetoothDevice>(
|
|
|
+ Devices,
|
|
|
+ x=>x.LastSeen,
|
|
|
+ x =>x.ID,
|
|
|
+ TimeSpan.FromSeconds(10),
|
|
|
+ TimeSpan.FromMilliseconds(500)
|
|
|
+ );
|
|
|
+
|
|
|
+ _ble = CrossBluetoothLE.Current;
|
|
|
+ _adapter = CrossBluetoothLE.Current.Adapter;
|
|
|
+ _adapter.ScanTimeout = 5000;
|
|
|
+ _adapter.ScanTimeoutElapsed += async (sender, args) => { await _adapter.StartScanningForDevicesAsync(_scanoptions); };
|
|
|
+ _adapter.DeviceDiscovered += AdapterOnDeviceDiscovered;
|
|
|
+ //_adapter.ScanMatchMode = ScanMatchMode.AGRESSIVE;
|
|
|
+ //_adapter.ScanMode = ScanMode.LowLatency;
|
|
|
+
|
|
|
+ // Task.Run(() =>
|
|
|
+ // {
|
|
|
+ // while (true)
|
|
|
+ // {
|
|
|
+ // var stale = Devices.ToArray().Where(x => (x == null) || (x.LastSeen < DateTime.Now.Subtract(new TimeSpan(0, 0, 10))))
|
|
|
+ // .ToArray();
|
|
|
+ // if (stale.Any())
|
|
|
+ // {
|
|
|
+ // Devices.RemoveRange(stale);
|
|
|
+ // Changed?.Invoke(this, EventArgs.Empty);
|
|
|
+ // }
|
|
|
+ //
|
|
|
+ // Task.Delay(500);
|
|
|
+ // }
|
|
|
+ // });
|
|
|
+ }
|
|
|
+
|
|
|
+ // public static async Task<bool> IsPermitted<TPermission>() where TPermission : Permissions.BasePermission, new()
|
|
|
+ // {
|
|
|
+ // try
|
|
|
+ // {
|
|
|
+ // PermissionStatus status = await Permissions.CheckStatusAsync<TPermission>();
|
|
|
+ // if (status == PermissionStatus.Granted)
|
|
|
+ // return true;
|
|
|
+ // var request = await Permissions.RequestAsync<TPermission>();
|
|
|
+ // return request == PermissionStatus.Granted;
|
|
|
+ //
|
|
|
+ // }
|
|
|
+ // catch (TaskCanceledException ex)
|
|
|
+ // {
|
|
|
+ // return false;
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+
|
|
|
+ public async Task<bool> IsAvailable()
|
|
|
+ {
|
|
|
+ //if (await IsPermitted<Permissions.Bluetooth>())
|
|
|
+ //{
|
|
|
+
|
|
|
+ //}
|
|
|
+ return _adapter != null;
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task<bool> StartScanningAsync(Guid configServiceId)
|
|
|
+ {
|
|
|
+
|
|
|
+ _scanoptions.ServiceUuids = [configServiceId];
|
|
|
+ return await StartScanningAsync();
|
|
|
+ }
|
|
|
+
|
|
|
+ private async Task<bool> StartScanningAsync()
|
|
|
+ {
|
|
|
+ System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Starting Bluetooth Scanning...");
|
|
|
+ await _staleItemMonitor.StartAsync();
|
|
|
+ await _adapter.StartScanningForDevicesAsync(_scanoptions);
|
|
|
+ System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Bluetooth Scanning Started.");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void AdapterOnDeviceDiscovered(object? sender, DeviceEventArgs e)
|
|
|
+ {
|
|
|
+ System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Found device {e.Device.Name}...");
|
|
|
+ var device = Devices.FirstOrDefault(x => string.Equals(x.ID, e.Device.Id.ToString()));
|
|
|
+ if (device == null)
|
|
|
+ {
|
|
|
+ System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Adding device {e.Device.Id}...");
|
|
|
+ device = new iOS_BluetoothDevice(e.Device);
|
|
|
+ Devices.Add(device);
|
|
|
+ System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Added device {device.ID}.");
|
|
|
+ }
|
|
|
+
|
|
|
+ device.LastSeen = DateTime.Now;
|
|
|
+ device.ManufacturerData = e.Device.AdvertisementRecords
|
|
|
+ .FirstOrDefault(x => x.Type == AdvertisementRecordType.ManufacturerSpecificData)?.Data ?? [];
|
|
|
+
|
|
|
+ System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Notifying Changes...");
|
|
|
+ Changed?.Invoke(this, EventArgs.Empty);
|
|
|
+ System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Changes Notified.");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public async Task<bool> StopScanningAsync()
|
|
|
+ {
|
|
|
+ System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Stopping Bluetooth Scanning...");
|
|
|
+ await _staleItemMonitor.StopAsync();
|
|
|
+ await _adapter.StopScanningForDevicesAsync();
|
|
|
+ System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Bluetooth Scanning Stopped.");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task<IConnectedBluetoothDevice?> Connect(IBluetoothDevice device)
|
|
|
+ {
|
|
|
+ if (Guid.TryParse(device.ID, out var deviceid))
|
|
|
+ {
|
|
|
+ System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Connecting Bluetooth Device {device.ID}...");
|
|
|
+ await StopScanningAsync();
|
|
|
+ var connected = await _adapter.ConnectToKnownDeviceAsync(deviceid);
|
|
|
+ if (connected != null)
|
|
|
+ {
|
|
|
+ var result = new iOS_ConnectedBluetoothDevice(device);
|
|
|
+ System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Bluetooth Device {device.ID} connected.");
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ await StartScanningAsync();
|
|
|
+ System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Connection to {device.ID} failed.");
|
|
|
+ }
|
|
|
+ System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Device has invalid ID.");
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task<bool> Disconnect(IConnectedBluetoothDevice device)
|
|
|
+ {
|
|
|
+ if (device is iOS_ConnectedBluetoothDevice connected)
|
|
|
+ {
|
|
|
+ System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Disconnecting Bluetooth Device {device.ID}...");
|
|
|
+ await _adapter.DisconnectDeviceAsync(connected.Device.Native);
|
|
|
+ await StartScanningAsync();
|
|
|
+ System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Bluetooth Device {device.ID} disconnected.");
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|