Bluetooth.iOS.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. using InABox.Core;
  2. using Plugin.BLE;
  3. using Plugin.BLE.Abstractions;
  4. using Plugin.BLE.Abstractions.Contracts;
  5. using Plugin.BLE.Abstractions.EventArgs;
  6. using System;
  7. using System.Linq;
  8. using System.Threading.Tasks;
  9. namespace InABox.Avalonia.Platform.iOS;
  10. public class iOS_Bluetooth : IBluetooth
  11. {
  12. public Logger? Logger { get; set; }
  13. public event EventHandler? Changed;
  14. public CoreObservableCollection<IBluetoothDevice> Devices { get; } = new ();
  15. private IBluetoothLE _ble;
  16. private IAdapter _adapter;
  17. private ScanFilterOptions _scanoptions = new ScanFilterOptions();
  18. private StaleItemMonitor<IBluetoothDevice> _staleItemMonitor;
  19. public iOS_Bluetooth()
  20. {
  21. _staleItemMonitor = new StaleItemMonitor<IBluetoothDevice>(
  22. Devices,
  23. x=>x.LastSeen,
  24. x =>x.ID,
  25. TimeSpan.FromSeconds(10),
  26. TimeSpan.FromMilliseconds(500)
  27. );
  28. _ble = CrossBluetoothLE.Current;
  29. _adapter = CrossBluetoothLE.Current.Adapter;
  30. _adapter.ScanTimeout = 5000;
  31. _adapter.ScanTimeoutElapsed += async (sender, args) => { await _adapter.StartScanningForDevicesAsync(_scanoptions); };
  32. _adapter.DeviceDiscovered += AdapterOnDeviceDiscovered;
  33. //_adapter.ScanMatchMode = ScanMatchMode.AGRESSIVE;
  34. //_adapter.ScanMode = ScanMode.LowLatency;
  35. // Task.Run(() =>
  36. // {
  37. // while (true)
  38. // {
  39. // var stale = Devices.ToArray().Where(x => (x == null) || (x.LastSeen < DateTime.Now.Subtract(new TimeSpan(0, 0, 10))))
  40. // .ToArray();
  41. // if (stale.Any())
  42. // {
  43. // Devices.RemoveRange(stale);
  44. // Changed?.Invoke(this, EventArgs.Empty);
  45. // }
  46. //
  47. // Task.Delay(500);
  48. // }
  49. // });
  50. }
  51. // public static async Task<bool> IsPermitted<TPermission>() where TPermission : Permissions.BasePermission, new()
  52. // {
  53. // try
  54. // {
  55. // PermissionStatus status = await Permissions.CheckStatusAsync<TPermission>();
  56. // if (status == PermissionStatus.Granted)
  57. // return true;
  58. // var request = await Permissions.RequestAsync<TPermission>();
  59. // return request == PermissionStatus.Granted;
  60. //
  61. // }
  62. // catch (TaskCanceledException ex)
  63. // {
  64. // return false;
  65. // }
  66. // }
  67. public async Task<bool> IsAvailable()
  68. {
  69. //if (await IsPermitted<Permissions.Bluetooth>())
  70. //{
  71. //}
  72. return _adapter != null;
  73. }
  74. public async Task<bool> StartScanningAsync(Guid configServiceId)
  75. {
  76. _scanoptions.ServiceUuids = [configServiceId];
  77. return await StartScanningAsync();
  78. }
  79. private async Task<bool> StartScanningAsync()
  80. {
  81. System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Starting Bluetooth Scanning...");
  82. await _staleItemMonitor.StartAsync();
  83. await _adapter.StartScanningForDevicesAsync(_scanoptions);
  84. System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Bluetooth Scanning Started.");
  85. return true;
  86. }
  87. private void AdapterOnDeviceDiscovered(object? sender, DeviceEventArgs e)
  88. {
  89. System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Found device {e.Device.Name}...");
  90. var device = Devices.FirstOrDefault(x => string.Equals(x.ID, e.Device.Id.ToString()));
  91. if (device == null)
  92. {
  93. System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Adding device {e.Device.Id}...");
  94. device = new iOS_BluetoothDevice(e.Device);
  95. Devices.Add(device);
  96. System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Added device {device.ID}.");
  97. }
  98. device.LastSeen = DateTime.Now;
  99. device.ManufacturerData = e.Device.AdvertisementRecords
  100. .FirstOrDefault(x => x.Type == AdvertisementRecordType.ManufacturerSpecificData)?.Data ?? [];
  101. System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Notifying Changes...");
  102. Changed?.Invoke(this, EventArgs.Empty);
  103. System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Changes Notified.");
  104. }
  105. public async Task<bool> StopScanningAsync()
  106. {
  107. System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Stopping Bluetooth Scanning...");
  108. await _staleItemMonitor.StopAsync();
  109. await _adapter.StopScanningForDevicesAsync();
  110. System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Bluetooth Scanning Stopped.");
  111. return true;
  112. }
  113. public async Task<IConnectedBluetoothDevice?> Connect(IBluetoothDevice device)
  114. {
  115. if (Guid.TryParse(device.ID, out var deviceid))
  116. {
  117. System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Connecting Bluetooth Device {device.ID}...");
  118. await StopScanningAsync();
  119. var connected = await _adapter.ConnectToKnownDeviceAsync(deviceid);
  120. if (connected != null)
  121. {
  122. var result = new iOS_ConnectedBluetoothDevice(device);
  123. System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Bluetooth Device {device.ID} connected.");
  124. return result;
  125. }
  126. await StartScanningAsync();
  127. System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Connection to {device.ID} failed.");
  128. }
  129. System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Device has invalid ID.");
  130. return null;
  131. }
  132. public async Task<bool> Disconnect(IConnectedBluetoothDevice device)
  133. {
  134. if (device is iOS_ConnectedBluetoothDevice connected)
  135. {
  136. System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Disconnecting Bluetooth Device {device.ID}...");
  137. await _adapter.DisconnectDeviceAsync(connected.Device.Native);
  138. await StartScanningAsync();
  139. System.Diagnostics.Debug.WriteLine($"{DateTime.Now:O} Bluetooth Device {device.ID} disconnected.");
  140. }
  141. return true;
  142. }
  143. }