Statistiques
| Branche: | Révision:

teotestbluetooth / TestTeoBluetooth / TestTeoBluetooth.Android / Services / BluetoothService.cs @ 828228e7

Historique | Voir | Annoter | Télécharger (8,689 ko)

1
using Android.App;
2
using Android.Bluetooth;
3
using Android.Content;
4
using Android.OS;
5
using Android.Runtime;
6
using Android.Views;
7
using Android.Widget;
8
using Java.IO;
9
using Java.Util;
10
using System;
11
using System.Collections.Generic;
12
using System.Collections.ObjectModel;
13
using System.Linq;
14
using System.Text;
15
using System.Threading;
16
using System.Threading.Tasks;
17
using TestBLE.Droid.Receivers;
18
using TestBLE.Droid.Utils;
19
using TestBLE.Models;
20
using TestBLE.Services;
21

    
22
namespace TestBLE.Droid.Services
23
{
24
    public class BluetoothService : IBluetoothService
25
    {
26

    
27
        private List<BluetoothDevice> discoveredDevices = new List<BluetoothDevice>();
28
        private TaskCompletionSource<bool> scanCompletionSource;
29
        private BluetoothManager bluetoothManager;
30
        private BluetoothAdapter bluetoothAdapter;
31
        private BluetoothReceiver bluetoothReceiver;
32

    
33
        private Thread listeningThread;
34
        private BluetoothSocket socket;
35
        private readonly string sppUUID = "00001101-0000-1000-8000-00805f9b34fb";
36
        private string bufferedData;
37

    
38
        public ObservableCollection<BTDevice> FoundDevices = new ObservableCollection<BTDevice>();
39
        public BluetoothService()
40
        {
41
            FoundDevices = new ObservableCollection<BTDevice>();
42
            bluetoothAdapter = BluetoothAdapter.DefaultAdapter;
43
            bluetoothReceiver = new BluetoothReceiver();
44
            bluetoothReceiver.OnBluetoothDeviceDiscovered += DeviceDiscovered;
45
            bluetoothReceiver.OnScanFinished += ScanFinished;
46

    
47
            // abonnements du BluetoothReceiver au intent ActionFound Et ActionDiscoveryFinished
48
            IntentFilter intentFilter = new IntentFilter();
49
            intentFilter.AddAction(BluetoothDevice.ActionFound);
50
            intentFilter.AddAction(BluetoothAdapter.ActionDiscoveryFinished);
51
            intentFilter.AddAction(BluetoothDevice.ActionBondStateChanged);
52
            Application.Context.RegisterReceiver(bluetoothReceiver, intentFilter);
53
        }
54

    
55
        public async Task<bool> Connect(BTDevice btDevice)
56
        {
57
            try
58
            {
59
                // Si jamais on est en train de scanner
60
                // On annule le scan
61
                if (bluetoothAdapter.IsDiscovering)
62
                {
63
                    bluetoothAdapter.CancelDiscovery();
64
                }
65

    
66
                BluetoothDevice droidBtDevice = bluetoothAdapter.GetRemoteDevice(btDevice.MACAddress);
67
                //Android.Bluetooth.BluetoothDevice droidBtDevice = adapter.BondedDevices.FirstOrDefault(x => (x.Address == bluetoothDevice.Address));
68
                if (droidBtDevice != null)
69
                {
70
                    // Si le socket est occupé pour une autre connexion
71
                    // On ferme la connexion existante
72
                    if (socket != null)
73
                    {
74
                        await Disconnect(btDevice);
75
                    }
76

    
77
                    // Creation du canal RFCOMM (non sécurisé)
78
                    socket = droidBtDevice.CreateInsecureRfcommSocketToServiceRecord(UUID.FromString(sppUUID));
79

    
80
                    CancellationTokenSource cts = new CancellationTokenSource();
81

    
82
                    cts.CancelAfter(50000);
83
                    await socket.ConnectAsync().WithCancellation(cts.Token);
84

    
85
                    if (listeningThread != null) listeningThread.Abort();
86
                    listeningThread = new Thread(async delagate => await ListeningAsync(btDevice));
87
                    listeningThread.Start();
88

    
89
                    return true;
90
                }
91
            }
92
            catch (Exception ex)
93
            {
94
                System.Diagnostics.Debug.WriteLine(ex);
95
            }
96

    
97
            return false;
98
        }
99

    
100
        // Fonction d'écoute pour le Thread d'écoute
101
        private async Task ListeningAsync(BTDevice btDevice)
102
        {
103
            try
104
            {
105
                byte[] buffer = new byte[1024];
106
                while (socket.IsConnected)
107
                {
108
                    int byteAvailable = await socket.InputStream.ReadAsync(buffer, 0, buffer.Length);
109
                    // Resize the byte array 
110
                    byte[] filledBuffer = buffer.Take(byteAvailable).ToArray();
111
                    Application.SynchronizationContext.Post(_ => { OnDataReceived(filledBuffer); }, null);
112
                }
113
            }
114
            catch (IOException ex)
115
            {
116
                System.Diagnostics.Debug.WriteLine(ex);
117
            }
118
            catch (ThreadAbortException taEx)
119
            {
120
                System.Diagnostics.Debug.WriteLine(taEx);
121
            }
122
            catch (Exception ex)
123
            {
124
                System.Diagnostics.Debug.WriteLine(ex);
125
            }
126
        }
127

    
128
        public EventHandler<string> DataReceivedEvent { get; set; }
129
        private string _bufferedData;
130

    
131
        /* 
132
         * Fonction appelée à la reception de données
133
         * Trigger l'evenement DataReceivedEvent
134
         * 
135
         * IMPORTANT: Les trames peuvent arriver découpées,
136
         * Donc les données sont gardées dans un buffer d'envoi
137
         * nommé _bufferedData
138
         */
139
        private void OnDataReceived(byte[] buffer)
140
        {
141
            // Si le premier character est 2 (ASCII: STX)
142
            // Alors c'est le début de la trame.
143
            if (buffer[0] == 2)
144
            {
145
                _bufferedData = "";
146
                // Si character seul on quitte
147
                if (buffer.Length == 1)
148
                {
149
                    return;
150
                }
151
                // On enlève STX
152
                buffer = buffer.Skip(1).ToArray();
153
                // On mets le début de la trame dans buffer d'envoi
154
                _bufferedData += Encoding.ASCII.GetString(buffer);
155
            }
156
            
157
            // Si le dernier character est 13 (ASCII: CR)
158
            // Alors la trame est terminée
159
            if (buffer[^1] == 13)
160
            {
161
                // On enlève CR
162
                buffer = buffer.SkipLast(1).ToArray();
163
                // Conversion en chaîne de caractères
164
                // Et on complète le buffer d'envoi
165
                _bufferedData += Encoding.ASCII.GetString(buffer);
166
                // Trigger evènement
167
                DataReceivedEvent.Invoke(this, _bufferedData);
168
            }
169
        }
170

    
171
        private void ScanFinished(object sender, string e)
172
        {
173
            scanCompletionSource?.SetResult(true);
174
        }
175

    
176
        private void DeviceDiscovered(object sender, BluetoothDevice e)
177
        {
178
            if (discoveredDevices.FirstOrDefault(x => x.Address == e.Address) is null)
179
            {
180
                discoveredDevices.Add(e);
181
                FoundDevices.Add(new BTDevice() { Name = e.Name, MACAddress = e.Address });
182
            }
183
        }
184

    
185
        public ObservableCollection<BTDevice> DeviceList { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
186

    
187
        public Task StartScan()
188
        {
189
            if (bluetoothAdapter.IsDiscovering)
190
            {
191
                return scanCompletionSource.Task;
192
            }
193

    
194
            scanCompletionSource = new TaskCompletionSource<bool>();
195
            discoveredDevices.Clear();
196
            FoundDevices.Clear();
197

    
198
            // Lancement du scan
199
            bluetoothAdapter.StartDiscovery();
200

    
201
            return scanCompletionSource.Task;
202
        }
203

    
204
        public Task<bool> Pair(BTDevice bluetoothDevice)
205
        {
206
            throw new NotImplementedException();
207
        }
208

    
209
        public Task<bool> Disconnect(BTDevice bluetoothDevice)
210
        {
211
            while (socket.IsConnected) socket.Close();
212
            return Task.FromResult(true);
213
        }
214

    
215
        private byte[] hexValuesToByteArray(string[] hexValues)
216
        {
217
            byte[] ret = hexValues.Select(value => Convert.ToByte(value, 16)).ToArray();
218
            return ret;
219
        }
220

    
221
        public Task<bool> SendHexValues(byte[] hexValues)
222
        {
223
            if (socket.IsConnected == false)
224
            {
225
                return Task.FromResult(false);
226
            } else
227
            {
228
                // Envoi de la commande
229
                socket.OutputStream.Write(hexValues, 0, hexValues.Length);
230
                socket.OutputStream.Flush();
231
            }
232

    
233
            return Task.FromResult(true);
234
        }
235

    
236
        public ICollection<BTDevice> GetBondedDevices()
237
        {
238
            ICollection<BTDevice> ret = new ObservableCollection<BTDevice>();
239
            foreach (BluetoothDevice bondedDevice in bluetoothAdapter.BondedDevices)
240
            {
241
                BTDevice toAddItem = new BTDevice
242
                {
243
                    MACAddress = bondedDevice.Address,
244
                    Name = bondedDevice.Name
245
                };
246
                ret.Add(toAddItem);
247
            }
248
            return ret;
249
        }
250
    }
251
}