Statistiques
| Branche: | Révision:

teotestbluetooth / TestTeoBluetooth / TestTeoBluetooth.Android / Services / BluetoothService.cs @ 4ca686e8

Historique | Voir | Annoter | Télécharger (8,48 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 TeoTestBluetooth.Droid.Receivers;
18
using TeoTestBluetooth.Droid.Utils;
19
using TeoTestBluetooth.Models;
20
using TeoTestBluetooth.Services;
21

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

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

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

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

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

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

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

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

    
78
                    CancellationTokenSource cts = new CancellationTokenSource();
79

    
80
                    cts.CancelAfter(50000);
81
                    await socket.ConnectAsync().WithCancellation(cts.Token);
82

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

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

    
95
            return false;
96
        }
97

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

    
126
        public EventHandler<string> DataReceivedEvent { get; set; }
127
        private string _bufferedData;
128

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

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

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

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

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

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

    
196
            // Lancement du scan
197
            bluetoothAdapter.StartDiscovery();
198

    
199
            return scanCompletionSource.Task;
200
        }
201

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

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

    
213
        public Task<bool> SendHexValues(byte[] hexValues)
214
        {
215
            if (socket.IsConnected == false)
216
            {
217
                return Task.FromResult(false);
218
            } else
219
            {
220
                // Envoi de la commande
221
                socket.OutputStream.Write(hexValues, 0, hexValues.Length);
222
                socket.OutputStream.Flush();
223
            }
224

    
225
            return Task.FromResult(true);
226
        }
227

    
228
        public ICollection<BTDevice> GetBondedDevices()
229
        {
230
            ICollection<BTDevice> ret = new ObservableCollection<BTDevice>();
231
            foreach (BluetoothDevice bondedDevice in bluetoothAdapter.BondedDevices)
232
            {
233
                BTDevice toAddItem = new BTDevice
234
                {
235
                    MACAddress = bondedDevice.Address,
236
                    Name = bondedDevice.Name
237
                };
238
                ret.Add(toAddItem);
239
            }
240
            return ret;
241
        }
242
    }
243
}