forked from nanoframework/Samples
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Program.cs
297 lines (243 loc) · 12.1 KB
/
Program.cs
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//
using System;
using System.Threading;
using nanoFramework.Device.Bluetooth;
using nanoFramework.Device.Bluetooth.Advertisement;
using nanoFramework.Device.Bluetooth.GenericAttributeProfile;
namespace Central3
{
/// <summary>
/// Sample to show how to Watch for advertisements and connect to a device which requires
/// pairing and authentication to access the Characteristics value.
/// Pairing can be done before or ad hoc when the accessing the Characteristic.
/// If Characteristic requires security or Authentication when accessed the system will automatically start a pairing operation.
/// </summary>
public static class Program
{
public static bool s_deviceFound = false;
public static BluetoothLEDevice s_device;
public const int PASSKEY = 654321;
public static void Main()
{
Console.WriteLine("Central: Simple Bluetooth LE watcher");
// Create a BluetoothLEAdvertisementWatcher to look for Bluetooth adverts.
BluetoothLEAdvertisementWatcher watcher = new();
// Get Scan response for Advertisement
watcher.ScanningMode = BluetoothLEScanningMode.Active;
// Set up event to monitor received adverts
watcher.Received += Watcher_Received;
while (true)
{
Console.WriteLine();
Console.WriteLine("=== Starting Bluetooth advert watcher ====");
MemoryCheck("before");
watcher.Start();
MemoryCheck("start");
// Wait for device to be found
while (s_deviceFound == false)
{
Thread.Sleep(100);
}
Console.WriteLine();
Console.WriteLine("=== Stopping Bluetooth advert watcher ====");
watcher.Stop();
MemoryCheck("stop");
// Now Connect to device
TestConnectAndPair(s_device);
s_device.Dispose();
s_device = null;
MemoryCheck("connect");
Thread.Sleep(4000);
s_deviceFound = false;
}
}
/// <summary>
/// With low memory devices, no spiram you can have problems with low native memory
/// </summary>
/// <param name="info"></param>
static void MemoryCheck(string info)
{
uint manMem = nanoFramework.Runtime.Native.GC.Run(true);
uint total;
uint free;
uint largest;
nanoFramework.Hardware.Esp32.NativeMemory.GetMemoryInfo( nanoFramework.Hardware.Esp32.NativeMemory.MemoryType.All, out total, out free, out largest);
Console.WriteLine($"Memory All ({info}) Managed:{manMem} Native:{total}/{free}/{largest}");
nanoFramework.Hardware.Esp32.NativeMemory.GetMemoryInfo(nanoFramework.Hardware.Esp32.NativeMemory.MemoryType.Internal, out total, out free, out largest);
Console.WriteLine($"Memory Internal ({info}) Managed:{manMem} Native:{total}/{free}/{largest}");
}
/// <summary>
/// Check for device for correct Service UUID in Advertisement
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
private static bool IsValidDevice(BluetoothLEAdvertisementReceivedEventArgs args)
{
if (args.Advertisement.ServiceUuids.Length > 0 &&
args.Advertisement.ServiceUuids[0].Equals(new Guid("A7EEDF2C-DA8C-4CB5-A9C5-5151C78B0057")))
{
return true;
}
return false;
}
private static void Watcher_Received(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
{
// Ignore any further events while found device queried
// Sometimes you will get a previously queued event after Watcher has been stopped
if (Program.s_deviceFound == true)
{
return;
}
DisplayAdvert(args);
// Look for advert with our primary service UUID from Bluetooth Sample 3
if (IsValidDevice(args) && Program.s_deviceFound == false)
{
Console.WriteLine($"Found device with service :{args.BluetoothAddress:X}");
Program.s_device = BluetoothLEDevice.FromBluetoothAddress(args.BluetoothAddress, args.BluetoothAddressType);
Program.s_deviceFound = true;
}
}
static void DisplayAdvert(BluetoothLEAdvertisementReceivedEventArgs args)
{
BluetoothLEAdvertisement adv = args.Advertisement;
Console.WriteLine();
Console.WriteLine($"=== Advert received - type {args.AdvertisementType} ====");
Console.WriteLine($"Address:{args.BluetoothAddress:X}");
Console.WriteLine($"Local name:{adv.LocalName}");
Console.WriteLine($"Manufacturers Data:{adv.ManufacturerData.Count}");
//Manufacturer Data
foreach (BluetoothLEManufacturerData md in adv.ManufacturerData)
{
Console.WriteLine($"-- Company:{md.CompanyId} Length:{md.Data.Length}");
DataReader dr = DataReader.FromBuffer(md.Data);
byte[] bytes = new byte[md.Data.Length];
dr.ReadBytes(bytes);
foreach (byte b in bytes)
{
Console.Write($"{b:X}");
}
Console.WriteLine();
}
Console.WriteLine($"Service UUIDS:{adv.ServiceUuids.Length}");
// Any Service Uuids
foreach (Guid uuid in adv.ServiceUuids)
{
Console.WriteLine($" - Advertised service:{uuid}");
}
}
/// <summary>
/// Method to connect to device
/// - (Optional pair) commented out as it will automatically pair on Read value
/// - Connect
/// - Get services & Characteristics
/// - Find Characteristic which authentication and read value
/// </summary>
/// <param name="device"></param>
static void TestConnectAndPair(BluetoothLEDevice device)
{
// Set up some events to handle
// - PairingRequested : Event for providing/Displaying Passkey
// - PairingComple : Pairing operation has completed (with or without error)
device.Pairing.PairingRequested += Pairing_PairingRequested;
device.Pairing.PairingComplete += Pairing_PairingComplete;
// Set IOCapabilities and ProtectionLevel for device
device.Pairing.IOCapabilities = DevicePairingIOCapabilities.KeyboardOnly;
device.Pairing.ProtectionLevel = DevicePairingProtectionLevel.EncryptionAndAuthentication;
// Pair with found device
Console.WriteLine($"=== Pair & Connect to {device.BluetoothAddress:X} ====");
DevicePairingResult pairResult = device.Pairing.Pair();
// Display result of pairing, if successful then IsPaired and optionally IsAuthenticated will be true
Console.WriteLine($"Pairing result:{pairResult.Status}");
Console.WriteLine($" -IsAuthenticated:{device.Pairing.IsAuthenticated}");
Console.WriteLine($" -IsPaired:{device.Pairing.IsPaired}");
Console.WriteLine($" -IoCaps:{device.Pairing.IOCapabilities}");
if (pairResult.Status == DevicePairingResultStatus.Paired)
{
Console.WriteLine($"Connection status {device.ConnectionStatus}");
Console.WriteLine($"From Generic Access service for connect device");
Console.WriteLine($"- Device name {device.Name}");
Console.WriteLine($"- Appearance {device.Appearance:X}");
GattDeviceServicesResult srvsResult = device.GetGattServices();
if (srvsResult.Status == GattCommunicationStatus.Success)
{
GattDeviceService[] Services = srvsResult.Services;
// List available services
Console.WriteLine($"=== Device available services ====");
foreach (GattDeviceService srv in Services)
{
Console.WriteLine($" Service:{srv.Uuid}");
// For each service get available Characteristics
GattCharacteristicsResult cr = srv.GetCharacteristics();
if (cr.Status == GattCommunicationStatus.Success)
{
foreach(GattCharacteristic characteristic in cr.Characteristics)
{
Console.WriteLine($"Characteristic -> {characteristic.Uuid}");
// If Characteristic has this UUID (from sample 2) then try to access data
if (characteristic.Uuid.Equals(new Guid("A7EEDF2C-DA8F-4CB5-A9C5-5151C78B0057")))
{
Console.WriteLine($"Characteristic found access, read value");
// Reading a value that requires Authentication will start a pairing
// PairingRequested event handler supplies Authentication pin.
var res = characteristic.ReadValue();
if (res.Status == GattCommunicationStatus.Success)
{
DataReader dr = DataReader.FromBuffer(res.Value);
int value = dr.ReadInt32();
Console.WriteLine($"Chr value = {value}");
}
else
{
Console.WriteLine($"Error access chr !!! {res.Status}");
}
}
}
}
}
}
}
// Close connection to free up resources
device.Close();
}
/// <summary>
/// Event called when a pairing operation has completed
/// </summary>
/// <param name="sender">DevicePairing object</param>
/// <param name="args">DevicePairingEventArgs args</param>
private static void Pairing_PairingComplete(object sender, DevicePairingEventArgs args)
{
// Pick up DevicePairing from sender or just use it directly
DevicePairing pairing = (DevicePairing)sender;
if (args.Status == DevicePairingResultStatus.Paired)
{
Console.WriteLine($"PairingComplete:{args.Status} IOCaps:{pairing.IOCapabilities} IsPaired:{pairing.IsPaired} IsAuthenticated:{pairing.IsAuthenticated}");
}
else
{
Console.WriteLine($"PairingComplete failed - status = {args.Status}");
}
}
/// <summary>
/// Event called when passkey is required, check args.PairingKind for type of request.
/// </summary>
/// <param name="sender">DevicePairing object</param>
/// <param name="args">DevicePairingRequestedEventArgs object</param>
private static void Pairing_PairingRequested(object sender, DevicePairingRequestedEventArgs args)
{
Console.WriteLine($"Pairing_PairingRequested:{args.PairingKind}");
switch (args.PairingKind)
{
case DevicePairingKinds.ProvidePin:
// Provide valid passcode
args.Accept(PASSKEY);
break;
default:
Console.WriteLine($"Unhandled Pairing request");
break;
}
}
}
}