1
1
namespace Unosquare . RaspberryIO . Computer
2
2
{
3
+ using Swan . Abstractions ;
4
+ using Swan . Components ;
3
5
using System ;
4
6
using System . Collections . Generic ;
5
7
using System . Linq ;
6
8
using System . Threading ;
7
9
using System . Threading . Tasks ;
8
- using Unosquare . RaspberryIO . Abstractions ;
9
- using Unosquare . Swan . Abstractions ;
10
- using Unosquare . Swan . Components ;
11
10
12
11
/// <summary>
13
- /// Represents the bluetooth information.
12
+ /// Represents the Bluetooth information.
14
13
/// </summary>
15
14
public class Bluetooth : SingletonBase < Bluetooth >
16
15
{
17
-
18
- private const string BC = "bluetoothctl" ;
16
+ private const string BcCommand = "bluetoothctl" ;
19
17
20
18
/// <summary>
21
- /// Turns on the bluetooth adapter.
19
+ /// Turns on the Bluetooth adapter.
22
20
/// </summary>
23
- /// <returns>Returns true or false depending if the controller was turned on.</returns>
24
- public async Task < bool > PowerOn ( )
21
+ /// <param name="cancellationToken">The cancellation token.</param>
22
+ /// <returns>
23
+ /// Returns true or false depending if the controller was turned on.
24
+ /// </returns>
25
+ /// <exception cref="BluetoothErrorException">Failed to power on:.</exception>
26
+ public async Task < bool > PowerOn ( CancellationToken cancellationToken = default )
25
27
{
26
28
try
27
29
{
28
- var output = await ProcessRunner . GetProcessOutputAsync ( BC , "power on" ) . ConfigureAwait ( false ) ;
30
+ var output = await ProcessRunner . GetProcessOutputAsync ( BcCommand , "power on" , cancellationToken ) . ConfigureAwait ( false ) ;
29
31
return output . Contains ( "succeeded" ) ;
30
32
}
31
33
catch ( Exception ex )
@@ -37,12 +39,16 @@ public async Task<bool> PowerOn()
37
39
/// <summary>
38
40
/// Turns off the bluetooth adapter.
39
41
/// </summary>
40
- /// <returns>Returns true or false depending if the controller was turned off.</returns>
41
- public async Task < bool > PowerOff ( )
42
+ /// <param name="cancellationToken">The cancellation token.</param>
43
+ /// <returns>
44
+ /// Returns true or false depending if the controller was turned off.
45
+ /// </returns>
46
+ /// <exception cref="BluetoothErrorException">Failed to power off:.</exception>
47
+ public async Task < bool > PowerOff ( CancellationToken cancellationToken = default )
42
48
{
43
49
try
44
50
{
45
- var output = await ProcessRunner . GetProcessOutputAsync ( BC , "power off" ) . ConfigureAwait ( false ) ;
51
+ var output = await ProcessRunner . GetProcessOutputAsync ( BcCommand , "power off" , cancellationToken ) . ConfigureAwait ( false ) ;
46
52
return output . Contains ( "succeeded" ) ;
47
53
}
48
54
catch ( Exception ex )
@@ -54,16 +60,20 @@ public async Task<bool> PowerOff()
54
60
/// <summary>
55
61
/// Gets the list of detected devices.
56
62
/// </summary>
57
- /// <returns> Returns the list of detected devices. </returns>
58
- public async Task < IEnumerable < string > > ListDevices ( )
63
+ /// <param name="cancellationToken">The cancellation token.</param>
64
+ /// <returns>
65
+ /// Returns the list of detected devices.
66
+ /// </returns>
67
+ /// <exception cref="BluetoothErrorException">Failed to retrieve devices:.</exception>
68
+ public async Task < IEnumerable < string > > ListDevices ( CancellationToken cancellationToken = default )
59
69
{
60
70
try
61
71
{
62
72
using ( var cancellationTokenSource = new CancellationTokenSource ( 3000 ) )
63
73
{
64
- ProcessRunner . GetProcessOutputAsync ( BC , "scan on" , cancellationTokenSource . Token ) ;
65
- await ProcessRunner . GetProcessOutputAsync ( BC , "scan off" ) . ConfigureAwait ( false ) ;
66
- var devices = await ProcessRunner . GetProcessOutputAsync ( BC , "devices" ) . ConfigureAwait ( false ) ;
74
+ await ProcessRunner . GetProcessOutputAsync ( BcCommand , "scan on" , cancellationTokenSource . Token ) . ConfigureAwait ( false ) ;
75
+ await ProcessRunner . GetProcessOutputAsync ( BcCommand , "scan off" , cancellationToken ) . ConfigureAwait ( false ) ;
76
+ var devices = await ProcessRunner . GetProcessOutputAsync ( BcCommand , "devices" , cancellationToken ) . ConfigureAwait ( false ) ;
67
77
return devices . Trim ( ) . Split ( '\n ' ) . Select ( x => x . Trim ( ) ) ;
68
78
}
69
79
}
@@ -76,12 +86,16 @@ public async Task<IEnumerable<string>> ListDevices()
76
86
/// <summary>
77
87
/// Gets the list of bluetooth controllers.
78
88
/// </summary>
79
- /// <returns> Returns the list of bluetooth controllers. </returns>
80
- public async Task < IEnumerable < string > > ListControllers ( )
89
+ /// <param name="cancellationToken">The cancellation token.</param>
90
+ /// <returns>
91
+ /// Returns the list of bluetooth controllers.
92
+ /// </returns>
93
+ /// <exception cref="BluetoothErrorException">Failed to retrieve controllers:.</exception>
94
+ public async Task < IEnumerable < string > > ListControllers ( CancellationToken cancellationToken = default )
81
95
{
82
96
try
83
97
{
84
- var controllers = await ProcessRunner . GetProcessOutputAsync ( BC , "list" ) . ConfigureAwait ( false ) ;
98
+ var controllers = await ProcessRunner . GetProcessOutputAsync ( BcCommand , "list" , cancellationToken ) . ConfigureAwait ( false ) ;
85
99
return controllers . Trim ( ) . Split ( '\n ' ) . Select ( x => x . Trim ( ) ) ;
86
100
}
87
101
catch ( Exception ex )
@@ -95,17 +109,30 @@ public async Task<IEnumerable<string>> ListControllers()
95
109
/// </summary>
96
110
/// <param name="controllerAddress">The mac address of the controller that will be used to pair.</param>
97
111
/// <param name="deviceAddress">The mac address of the device that will be paired.</param>
98
- /// <returns> Returns true or false if the pair was succesfully.</returns>
99
- public async Task < bool > Pair ( string controllerAddress , string deviceAddress )
112
+ /// <param name="cancellationToken">The cancellation token.</param>
113
+ /// <returns>
114
+ /// Returns true or false if the pair was successfully.
115
+ /// </returns>
116
+ /// <exception cref="BluetoothErrorException">Failed to Pair:.</exception>
117
+ public async Task < bool > Pair ( string controllerAddress , string deviceAddress , CancellationToken cancellationToken = default )
100
118
{
101
119
try
102
120
{
103
- await ProcessRunner . GetProcessOutputAsync ( BC , $ "select { controllerAddress } ") . ConfigureAwait ( false ) ; // Selects the controller to pair. Once you select the controller, all controller-related commands will apply to it for three minutes.
104
- await ProcessRunner . GetProcessOutputAsync ( BC , "discoverable on" ) . ConfigureAwait ( false ) ; // Makes the controller visible to other devices.
105
- await ProcessRunner . GetProcessOutputAsync ( BC , "pairable on" ) . ConfigureAwait ( false ) ; // Readies the controller for pairing. Remember that you have three minutes after running this command to pair.
121
+ // Selects the controller to pair. Once you select the controller, all controller-related commands will apply to it for three minutes.
122
+ await ProcessRunner . GetProcessOutputAsync ( BcCommand , $ "select { controllerAddress } ", cancellationToken )
123
+ . ConfigureAwait ( false ) ;
124
+
125
+ // Makes the controller visible to other devices.
126
+ await ProcessRunner . GetProcessOutputAsync ( BcCommand , "discoverable on" , cancellationToken ) . ConfigureAwait ( false ) ;
127
+
128
+ // Readies the controller for pairing. Remember that you have three minutes after running this command to pair.
129
+ await ProcessRunner . GetProcessOutputAsync ( BcCommand , "pairable on" , cancellationToken ) . ConfigureAwait ( false ) ;
130
+
131
+ // Pairs the device with the controller.
132
+ var result = await ProcessRunner . GetProcessOutputAsync ( BcCommand , $ "pair { deviceAddress } ", cancellationToken ) . ConfigureAwait ( false ) ;
106
133
107
- var result = await ProcessRunner . GetProcessOutputAsync ( BC , $ "pair { deviceAddress } " ) . ConfigureAwait ( false ) ; // Pairs the device with the controller .
108
- await ProcessRunner . GetProcessOutputAsync ( BC , "discoverable off" ) . ConfigureAwait ( false ) ; // Hides the controller from other Bluetooth devices. Otherwise, any device that can detect it has access to it, leaving a major security hole.
134
+ // Hides the controller from other Bluetooth devices. Otherwise, any device that can detect it has access to it, leaving a major security hole .
135
+ await ProcessRunner . GetProcessOutputAsync ( BcCommand , "discoverable off" , cancellationToken ) . ConfigureAwait ( false ) ;
109
136
110
137
return result . Contains ( "Paired: yes" ) ;
111
138
}
@@ -118,20 +145,31 @@ public async Task<bool> Pair(string controllerAddress, string deviceAddress)
118
145
/// <summary>
119
146
/// Performs a connection of a given controller with a given device.
120
147
/// </summary>
121
- /// <param name="controllerAddress">The mac address of the controller that will be used to make the connection. </param>
122
- /// <param name="deviceAddress">The mac address of the device that will be connected. </param>
123
- /// <returns> Returns true or false if the connection was successfully. </returns>
124
- public async Task < bool > Connect ( string controllerAddress , string deviceAddress )
148
+ /// <param name="controllerAddress">The mac address of the controller that will be used to make the connection.</param>
149
+ /// <param name="deviceAddress">The mac address of the device that will be connected.</param>
150
+ /// <param name="cancellationToken">The cancellation token.</param>
151
+ /// <returns>
152
+ /// Returns true or false if the connection was successfully.
153
+ /// </returns>
154
+ /// <exception cref="BluetoothErrorException">Failed to connect:.</exception>
155
+ public async Task < bool > Connect ( string controllerAddress , string deviceAddress , CancellationToken cancellationToken = default )
125
156
{
126
157
try
127
158
{
128
- await ProcessRunner . GetProcessOutputAsync ( BC , $ "select { controllerAddress } ") . ConfigureAwait ( false ) ; // Selects the controller to pair. Once you select the controller, all controller-related commands will apply to it for three minutes.
129
- await ProcessRunner . GetProcessOutputAsync ( BC , "discoverable on" ) . ConfigureAwait ( false ) ; // Makes the controller visible to other devices.
130
- await ProcessRunner . GetProcessOutputAsync ( BC , "pairable on" ) . ConfigureAwait ( false ) ; // Readies the controller for pairing. Remember that you have three minutes after running this command to pair.
159
+ // Selects the controller to pair. Once you select the controller, all controller-related commands will apply to it for three minutes.
160
+ await ProcessRunner . GetProcessOutputAsync ( BcCommand , $ "select { controllerAddress } ", cancellationToken ) . ConfigureAwait ( false ) ;
131
161
132
- var result = await ProcessRunner . GetProcessOutputAsync ( BC , $ "connect { deviceAddress } ") . ConfigureAwait ( false ) ; // Readies the device for pairing.
162
+ // Makes the controller visible to other devices.
163
+ await ProcessRunner . GetProcessOutputAsync ( BcCommand , "discoverable on" , cancellationToken ) . ConfigureAwait ( false ) ;
133
164
134
- await ProcessRunner . GetProcessOutputAsync ( BC , "discoverable off" ) . ConfigureAwait ( false ) ; // Hides the controller from other Bluetooth devices. Otherwise, any device that can detect it has access to it, leaving a major security hole.
165
+ // Readies the controller for pairing. Remember that you have three minutes after running this command to pair.
166
+ await ProcessRunner . GetProcessOutputAsync ( BcCommand , "pairable on" , cancellationToken ) . ConfigureAwait ( false ) ;
167
+
168
+ // Readies the device for pairing.
169
+ var result = await ProcessRunner . GetProcessOutputAsync ( BcCommand , $ "connect { deviceAddress } ", cancellationToken ) . ConfigureAwait ( false ) ;
170
+
171
+ // Hides the controller from other Bluetooth devices. Otherwise, any device that can detect it has access to it, leaving a major security hole.
172
+ await ProcessRunner . GetProcessOutputAsync ( BcCommand , "discoverable off" , cancellationToken ) . ConfigureAwait ( false ) ;
135
173
136
174
return result . Contains ( "Connected: yes" ) ;
137
175
}
@@ -146,19 +184,29 @@ public async Task<bool> Connect(string controllerAddress, string deviceAddress)
146
184
/// </summary>
147
185
/// <param name="controllerAddress">The mac address of the controller will be used.</param>
148
186
/// <param name="deviceAddress">The mac address of the device will be added to the trust list devices.</param>
149
- /// <returns>Returns true or false if the operation was successful.</returns>
150
- public async Task < bool > Trust ( string controllerAddress , string deviceAddress )
187
+ /// <param name="cancellationToken">The cancellation token.</param>
188
+ /// <returns>
189
+ /// Returns true or false if the operation was successful.
190
+ /// </returns>
191
+ /// <exception cref="BluetoothErrorException">Failed to add to trust devices list:.</exception>
192
+ public async Task < bool > Trust ( string controllerAddress , string deviceAddress , CancellationToken cancellationToken = default )
151
193
{
152
194
try
153
195
{
196
+ // Selects the controller to pair. Once you select the controller, all controller-related commands will apply to it for three minutes.
197
+ await ProcessRunner . GetProcessOutputAsync ( BcCommand , $ "select { controllerAddress } ", cancellationToken ) . ConfigureAwait ( false ) ;
154
198
155
- await ProcessRunner . GetProcessOutputAsync ( BC , $ "select { controllerAddress } ") . ConfigureAwait ( false ) ; // Selects the controller to pair. Once you select the controller, all controller-related commands will apply to it for three minutes.
156
- await ProcessRunner . GetProcessOutputAsync ( BC , "discoverable on" ) . ConfigureAwait ( false ) ; // Makes the controller visible to other devices.
157
- await ProcessRunner . GetProcessOutputAsync ( BC , "pairable on" ) . ConfigureAwait ( false ) ; // Readies the controller for pairing. Remember that you have three minutes after running this command to pair.
199
+ // Makes the controller visible to other devices.
200
+ await ProcessRunner . GetProcessOutputAsync ( BcCommand , "discoverable on" , cancellationToken ) . ConfigureAwait ( false ) ;
158
201
159
- var result = await ProcessRunner . GetProcessOutputAsync ( BC , $ "trust { deviceAddress } ") . ConfigureAwait ( false ) ; // Sets the device to re-pair automatically when it is turned on, which eliminates the need to pair all over again.
202
+ // Readies the controller for pairing. Remember that you have three minutes after running this command to pair.
203
+ await ProcessRunner . GetProcessOutputAsync ( BcCommand , "pairable on" , cancellationToken ) . ConfigureAwait ( false ) ;
160
204
161
- await ProcessRunner . GetProcessOutputAsync ( BC , "discoverable off" ) . ConfigureAwait ( false ) ; // Hides the controller from other Bluetooth devices. Otherwise, any device that can detect it has access to it, leaving a major security hole.
205
+ // Sets the device to re-pair automatically when it is turned on, which eliminates the need to pair all over again.
206
+ var result = await ProcessRunner . GetProcessOutputAsync ( BcCommand , $ "trust { deviceAddress } ", cancellationToken ) . ConfigureAwait ( false ) ;
207
+
208
+ // Hides the controller from other Bluetooth devices. Otherwise, any device that can detect it has access to it, leaving a major security hole.
209
+ await ProcessRunner . GetProcessOutputAsync ( BcCommand , "discoverable off" , cancellationToken ) . ConfigureAwait ( false ) ;
162
210
163
211
return result . Contains ( "Trusted: yes" ) ;
164
212
}
@@ -172,11 +220,19 @@ public async Task<bool> Trust(string controllerAddress, string deviceAddress)
172
220
/// Displays information about a particular device.
173
221
/// </summary>
174
222
/// <param name="deviceAddress">The mac address of the device which info will be retrieved.</param>
175
- /// <returns> Returns the device info.</returns>
176
- public async Task < string > DeviceInfo ( string deviceAddress )
223
+ /// <param name="cancellationToken">The cancellation token.</param>
224
+ /// <returns>
225
+ /// Returns the device info.
226
+ /// </returns>
227
+ /// <exception cref="BluetoothErrorException">Failed to retrieve info for {deviceAddress}.</exception>
228
+ public async Task < string > DeviceInfo ( string deviceAddress , CancellationToken cancellationToken = default )
177
229
{
178
- var info = await ProcessRunner . GetProcessOutputAsync ( BC , $ "info { deviceAddress } ") . ConfigureAwait ( false ) ;
179
- return ! string . IsNullOrEmpty ( info ) ? info : throw new BluetoothErrorException ( $ "Failed to retrieve info for { deviceAddress } ") ;
230
+ var info = await ProcessRunner . GetProcessOutputAsync ( BcCommand , $ "info { deviceAddress } ", cancellationToken )
231
+ . ConfigureAwait ( false ) ;
232
+
233
+ return ! string . IsNullOrEmpty ( info )
234
+ ? info
235
+ : throw new BluetoothErrorException ( $ "Failed to retrieve info for { deviceAddress } ") ;
180
236
}
181
237
}
182
- }
238
+ }
0 commit comments