-
Notifications
You must be signed in to change notification settings - Fork 20
Expand file tree
/
Copy pathBlueZPoweredUpBluetoothAdapter.cs
More file actions
142 lines (112 loc) · 5.35 KB
/
Copy pathBlueZPoweredUpBluetoothAdapter.cs
File metadata and controls
142 lines (112 loc) · 5.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using SharpBrick.PoweredUp.Bluetooth;
using SharpBrick.PoweredUp.BlueZ.Utilities;
using Tmds.DBus;
namespace SharpBrick.PoweredUp.BlueZ
{
public class BlueZPoweredUpBluetoothAdapter : IPoweredUpBluetoothAdapter
{
private readonly ILogger<BlueZPoweredUpBluetoothAdapter> _logger;
private readonly string _adapterObjectPath;
private readonly Dictionary<ulong, IPoweredUpBluetoothDevice> _devices = new Dictionary<ulong, IPoweredUpBluetoothDevice>();
private IAdapter1 _adapter;
public bool Discovering { get; set; } = false;
public BlueZPoweredUpBluetoothAdapter(
ILogger<BlueZPoweredUpBluetoothAdapter> logger,
string adapterObjectPath = null) //"/org/bluez/hci0")
{
_logger = logger;
_adapterObjectPath = adapterObjectPath;
}
private async Task<IAdapter1> GetAdapterAsync()
{
var adapter = !string.IsNullOrEmpty(_adapterObjectPath) ? Connection.System.CreateProxy<IAdapter1>(BlueZConstants.BlueZDBusServiceName, _adapterObjectPath) : await FindFirstAdapter();
// validate the adapter
await adapter.GetAliasAsync();
// make sure it is powered on
if (!await adapter.GetPoweredAsync())
{
await adapter.SetPoweredAsync(true);
}
await adapter.WatchPropertiesAsync(AdapterPropertyChangedHandler);
return adapter;
}
private async Task<IAdapter1> FindFirstAdapter()
{
var adapters = await Connection.System.FindProxies<IAdapter1>();
return adapters.FirstOrDefault();
}
private void AdapterPropertyChangedHandler(PropertyChanges changes)
{
_logger.LogDebug("Property changed {ChangedProperties}", changes.Changed);
foreach (var propertyChanged in changes.Changed)
{
switch (propertyChanged.Key)
{
case "Discovering":
Discovering = (bool)propertyChanged.Value;
break;
}
}
}
private async Task<ICollection<IDevice1>> GetExistingDevicesAsync()
=> await Connection.System.FindProxies<IDevice1>();
private IDevice1 GetSpecificDeviceAsync(ObjectPath objectPath)
=> Connection.System.CreateProxy<IDevice1>(BlueZConstants.BlueZDBusServiceName, objectPath);
private async Task<bool> IsLegoWirelessProcotolDevice(IDevice1 device)
=> (await device.GetUUIDsAsync()).NullToEmpty().Any(x => x.ToUpperInvariant() == PoweredUpBluetoothConstants.LegoHubService);
public async void Discover(Func<PoweredUpBluetoothDeviceInfo, Task> discoveryHandler, CancellationToken cancellationToken = default)
{
_adapter ??= await GetAdapterAsync();
var existingDevices = await GetExistingDevicesAsync();
foreach (var device in existingDevices)
{
if (await IsLegoWirelessProcotolDevice(device))
{
var poweredUpDevice = new BlueZPoweredUpBluetoothDevice(device, discoveryHandler);
await poweredUpDevice.Initialize();
_devices.Add(poweredUpDevice.DeviceInfo.BluetoothAddress, poweredUpDevice);
await poweredUpDevice.TryGetManufacturerDataAsync();
}
}
await Connection.System.WatchInterfacesAdded(NewDeviceAddedHandler);
await _adapter.SetDiscoveryFilterAsync(new Dictionary<string,object>()
{
{ "UUIDs", new string[] { PoweredUpBluetoothConstants.LegoHubService } }
});
cancellationToken.Register(async () =>
{
if (Discovering)
{
await _adapter.StopDiscoveryAsync();
}
});
await _adapter.StartDiscoveryAsync();
async void NewDeviceAddedHandler((ObjectPath objectPath, IDictionary<string, IDictionary<string, object>> interfaces) args)
{
if (!args.interfaces.ContainsKey("org.bluez.Device1"))
{
return;
}
var device = GetSpecificDeviceAsync(args.objectPath);
var poweredUpDevice = new BlueZPoweredUpBluetoothDevice(device, discoveryHandler);
await poweredUpDevice.Initialize();
_devices.Add(poweredUpDevice.DeviceInfo.BluetoothAddress, poweredUpDevice);
await poweredUpDevice.TryGetManufacturerDataAsync();
}
}
public Task<IPoweredUpBluetoothDevice> GetDeviceAsync(ulong bluetoothAddress)
{
if (!_devices.ContainsKey(bluetoothAddress))
{
throw new ArgumentOutOfRangeException("Requested bluetooth device is not available from this adapter");
}
return Task.FromResult<IPoweredUpBluetoothDevice>(_devices[bluetoothAddress]);
}
}
}