sicpaconnexions / SICPA_Connexions / Model / GestionnaireBLE.cs @ 35f65dee
Historique | Voir | Annoter | Télécharger (10,976 ko)
1 |
using Plugin.BLE; |
---|---|
2 |
using Plugin.BLE.Abstractions; |
3 |
using Plugin.BLE.Abstractions.Contracts; |
4 |
using Plugin.BLE.Abstractions.EventArgs; |
5 |
using System; |
6 |
using System.Collections.Generic; |
7 |
using System.Linq; |
8 |
using System.Text; |
9 |
using System.Threading.Tasks; |
10 |
|
11 |
namespace SICPA_Connexions.Model |
12 |
{ |
13 |
public class GestionnaireBLE |
14 |
{ |
15 |
// Class for the Bluetooth adapter |
16 |
private readonly IAdapter bluetoothAdapter; |
17 |
// Empty list to store BLE devices that can be detected by the Bluetooth adapter |
18 |
private List<IDevice> gattDevices; |
19 |
private List<IService> servicesList; |
20 |
private List<ICharacteristic> charList; |
21 |
private ICharacteristic characRead; |
22 |
private ICharacteristic characWrite; |
23 |
private String tempoLecture; |
24 |
private String retourBLE; |
25 |
public event EventHandler RetourBlEMofifiee; |
26 |
public IDevice DeviceConnected { get; set; } |
27 |
public IService SelectedService { get; set; } |
28 |
public String RetourBLE |
29 |
{ |
30 |
get |
31 |
{ |
32 |
return retourBLE; |
33 |
} |
34 |
set |
35 |
{ |
36 |
if (retourBLE != value) |
37 |
{ |
38 |
retourBLE = value; |
39 |
OnRetourBLEMofifiee(EventArgs.Empty); |
40 |
} |
41 |
} |
42 |
} |
43 |
|
44 |
public void OnRetourBLEMofifiee(EventArgs e) |
45 |
{ |
46 |
RetourBlEMofifiee?.Invoke(this, e); |
47 |
} |
48 |
|
49 |
public GestionnaireBLE() |
50 |
{ |
51 |
gattDevices = new List<IDevice>(); |
52 |
servicesList = new List<IService>(); |
53 |
charList = new List<ICharacteristic>(); // List for the available Characteristics on the BLE Device |
54 |
bluetoothAdapter = CrossBluetoothLE.Current.Adapter; // Point bluetoothAdapter to the current adapter on the phone |
55 |
bluetoothAdapter.DeviceDiscovered += (sender, foundBleDevice) => // When a BLE Device is found, run the small function below to add it to our list |
56 |
{ |
57 |
if (foundBleDevice.Device != null && !string.IsNullOrEmpty(foundBleDevice.Device.Name)) |
58 |
gattDevices.Add(foundBleDevice.Device); |
59 |
}; |
60 |
} |
61 |
|
62 |
|
63 |
public async Task ScanBLE() |
64 |
{ |
65 |
|
66 |
if (!await PermissionsGrantedAsync()) // Make sure there is permission to use Bluetooth |
67 |
{ |
68 |
await Application.Current.MainPage.DisplayAlert("Persmission requise", "L'application a besoin des permissions locales", "OK"); |
69 |
return; |
70 |
} |
71 |
|
72 |
gattDevices.Clear(); // Also clear the _gattDevices list |
73 |
|
74 |
if (!bluetoothAdapter.IsScanning) // Make sure that the Bluetooth adapter is scanning for devices |
75 |
{ |
76 |
await bluetoothAdapter.StartScanningForDevicesAsync(); |
77 |
} |
78 |
|
79 |
foreach (var device in bluetoothAdapter.ConnectedDevices) // Make sure BLE devices are added to the _gattDevices list |
80 |
gattDevices.Add(device); |
81 |
|
82 |
foreach (var device in bluetoothAdapter.BondedDevices) |
83 |
gattDevices.Add(device); |
84 |
|
85 |
foreach (IDevice item in gattDevices) |
86 |
{ |
87 |
if (item.Name.Contains("SICPA")) |
88 |
{ |
89 |
if (item.State == DeviceState.Connected) // Check first if we are already connected to the BLE Device |
90 |
{ |
91 |
await RecuperationServices(item); |
92 |
} |
93 |
else |
94 |
{ |
95 |
try |
96 |
{ |
97 |
var connectParameters = new ConnectParameters(false, true); |
98 |
await bluetoothAdapter.ConnectToDeviceAsync(item, connectParameters); // if we are not connected, then try to connect to the BLE Device selected |
99 |
await RecuperationServices(item); |
100 |
} |
101 |
catch |
102 |
{ |
103 |
await Application.Current.MainPage.DisplayAlert("Erreur de connexion", "Erreur de connexion au BLE " + item.Name, "OK"); |
104 |
} |
105 |
} |
106 |
} |
107 |
} |
108 |
} |
109 |
|
110 |
private async Task<bool> PermissionsGrantedAsync() // Function to make sure that all the appropriate approvals are in place |
111 |
{ |
112 |
var status = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>(); |
113 |
|
114 |
if (status != PermissionStatus.Granted) |
115 |
{ |
116 |
status = await Permissions.RequestAsync<Permissions.LocationWhenInUse>(); |
117 |
} |
118 |
|
119 |
return status == PermissionStatus.Granted; |
120 |
} |
121 |
|
122 |
private async Task RecuperationServices(IDevice device) |
123 |
{ |
124 |
try |
125 |
{ |
126 |
var servicesListReadOnly = await device.GetServicesAsync(); // Read in the Services available |
127 |
|
128 |
servicesList.Clear(); |
129 |
for (int i = 0; i < servicesListReadOnly.Count; i++) // Cycle through the found interfaces |
130 |
{ |
131 |
servicesList.Add(servicesListReadOnly[i]); // Write to a list of service interfaces |
132 |
if (servicesListReadOnly[i].Id.ToString().Substring(0, 8) == "6e400001") |
133 |
{ |
134 |
SelectedService = servicesListReadOnly[i]; |
135 |
} |
136 |
} |
137 |
if (SelectedService != null) |
138 |
{ |
139 |
var charListReadOnly = await SelectedService.GetCharacteristicsAsync(); // Read in available Characteristics |
140 |
|
141 |
charList.Clear(); |
142 |
for (int i = 0; i < charListReadOnly.Count; i++) // Cycle through available interfaces |
143 |
{ |
144 |
charList.Add(charListReadOnly[i]); // Write to a list of Chars |
145 |
// IMPORTANT: listview cannot cope with entries that have the exact same name. That is why I added "i" to the beginning of the name. If you add the UUID you can delete "i" again. |
146 |
if (charListReadOnly[i].CanRead || charListReadOnly[i].CanUpdate) |
147 |
{ |
148 |
characRead = charListReadOnly[i]; |
149 |
characRead.ValueUpdated += CharacRead_ValueUpdated; |
150 |
} |
151 |
if (charListReadOnly[i].CanWrite) characWrite = charListReadOnly[i]; |
152 |
} |
153 |
DeviceConnected = device; |
154 |
} |
155 |
else |
156 |
{ |
157 |
await Application.Current.MainPage.DisplayAlert("Erreur récupération Characteristics", "Erreur récupération Characteristics", "OK"); |
158 |
} |
159 |
} |
160 |
catch |
161 |
{ |
162 |
await Application.Current.MainPage.DisplayAlert("Erreur d'initialisation", "Erreur d'initialisation aux services", "OK"); |
163 |
} |
164 |
} |
165 |
|
166 |
private void CharacRead_ValueUpdated(object sender, CharacteristicUpdatedEventArgs args) |
167 |
{ |
168 |
var receivedBytes = args.Characteristic.Value; // read in received bytes |
169 |
Console.WriteLine("byte array: " + BitConverter.ToString(receivedBytes)); // write to the console for debugging |
170 |
|
171 |
|
172 |
string charStrBytes = ""; // in the following section the received bytes will be displayed in different ways (you can select the method you need) |
173 |
string charStrUTF8 = ""; |
174 |
if (receivedBytes != null) |
175 |
{ |
176 |
charStrBytes = "Bytes : " + BitConverter.ToString(receivedBytes); // by directly converting the bytes to strings we see the bytes themselves as they are received |
177 |
charStrUTF8 = Encoding.UTF8.GetString(receivedBytes, 0, receivedBytes.Length); // This code interprets the bytes received as ASCII characters |
178 |
} |
179 |
|
180 |
if (receivedBytes.Length <= 4) |
181 |
{ // If only 4 or less bytes were received than it could be that an INT was sent. The code here combines the 4 bytes back to an INT |
182 |
int char_val = 0; |
183 |
for (int i = 0; i < receivedBytes.Length; i++) |
184 |
{ |
185 |
char_val |= (receivedBytes[i] << i * 8); |
186 |
} |
187 |
charStrBytes += " | int: " + char_val.ToString(); |
188 |
} |
189 |
tempoLecture = tempoLecture + charStrUTF8; |
190 |
if (args.Characteristic.StringValue.EndsWith("\r\n")) |
191 |
{ |
192 |
RetourBLE = tempoLecture; |
193 |
tempoLecture = ""; |
194 |
} |
195 |
//_charStr += Environment.NewLine; // the NewLine command is added to go to the next line |
196 |
|
197 |
//MainThread.BeginInvokeOnMainThread(() => // as this is a callback function, the "MainThread" needs to be invoked to update the GUI |
198 |
//{ |
199 |
// Output.Text += _charStr; |
200 |
//}); |
201 |
} |
202 |
|
203 |
public async Task LectureTag(IDevice deviceConnected) |
204 |
{ |
205 |
try |
206 |
{ |
207 |
String cmd = "READ"; |
208 |
|
209 |
List<byte> local_frame = new List<byte>(); |
210 |
CRC crcProcess = new CRC(); |
211 |
byte local_crc; |
212 |
|
213 |
local_frame.Add(BytesPrtc.STX); //add STX byte |
214 |
local_frame.Add(BytesPrtc.DST_TX); //add DST byte |
215 |
local_frame.Add(BytesPrtc.SRC_TX); //add SRC byte |
216 |
for (int i = 0; i < cmd.Length; i++) |
217 |
{ |
218 |
local_frame.Add((byte)cmd[i]); //add cmd string |
219 |
} |
220 |
crcProcess.putBytes(local_frame.ToArray()); //send that buffer (without "the CRC" and ETX bytes !) |
221 |
local_crc = crcProcess.getCRC(); //calculate CRC with that buffer |
222 |
|
223 |
local_frame.Add(local_crc); //add CRC byte |
224 |
local_frame.Add(BytesPrtc.ETX); //add ETX byte |
225 |
|
226 |
///////////////////////////////////////////// |
227 |
//And now send buffer ! |
228 |
await characWrite.WriteAsync(local_frame.ToArray()); |
229 |
await characRead.StartUpdatesAsync(); |
230 |
} |
231 |
catch |
232 |
{ |
233 |
await Application.Current.MainPage.DisplayAlert("Erreur de lecture", "Erreur de lecture du Tag", "OK"); |
234 |
} |
235 |
} |
236 |
|
237 |
} |
238 |
} |