8b57289fda4e17521fba93ef0a0262bc51b4fa96
[platform/core/csapi/tizenfx.git] / src / Tizen.Network.Bluetooth / Tizen.Network.Bluetooth / BluetoothLeAdapterImpl.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 using System;
18 using System.Collections.Generic;
19 using System.Collections.Specialized;
20 using System.Threading.Tasks;
21 using System.Runtime.InteropServices;
22
23 namespace Tizen.Network.Bluetooth
24 {
25     internal class BluetoothLeImplAdapter : IDisposable
26     {
27         private static readonly BluetoothLeImplAdapter _instance = new BluetoothLeImplAdapter();
28
29         private bool disposed = false;
30
31         private event EventHandler<AdapterLeScanResultChangedEventArgs> _adapterLeScanResultChanged = null;
32         private Interop.Bluetooth.AdapterLeScanResultChangedCallBack _adapterLeScanResultChangedCallback;
33
34         private event EventHandler<AdvertisingStateChangedEventArgs> _advertisingStateChanged = null;
35         private Interop.Bluetooth.AdvertisingStateChangedCallBack _advertisingStateChangedCallback;
36
37         private event EventHandler<GattConnectionStateChangedEventArgs> _gattConnectionStateChanged = null;
38         private Interop.Bluetooth.GattConnectionStateChangedCallBack _gattConnectionStateChangedCallback;
39
40         private int _serviceListCount = 0;
41         private IList<BluetoothLeServiceData> _list = new List<BluetoothLeServiceData>();
42         private bool _scanStarted;
43
44         internal static BluetoothLeImplAdapter Instance
45         {
46             get
47             {
48                 return _instance;
49             }
50         }
51
52         private BluetoothLeImplAdapter()
53         {
54         }
55
56         ~BluetoothLeImplAdapter()
57         {
58             Dispose(false);
59         }
60
61         public void Dispose()
62         {
63             Dispose(true);
64             GC.SuppressFinalize(this);
65         }
66
67         private void Dispose(bool disposing)
68         {
69             if (disposed)
70                 return;
71
72             if (disposing)
73             {
74                 // Free managed objects.
75             }
76             //Free unmanaged objects
77             if (_gattConnectionStateChanged != null)
78             {
79                 UnRegisterGattConnectionStateChangedEvent();
80             }
81
82             //stop scan operation in progress
83             StopScan ();
84
85             disposed = true;
86         }
87
88         internal event EventHandler<AdapterLeScanResultChangedEventArgs> AdapterLeScanResultChanged
89         {
90             add
91             {
92                 _adapterLeScanResultChanged += value;
93             }
94             remove {
95                 _adapterLeScanResultChanged -= value;
96             }
97         }
98
99         internal event EventHandler<AdvertisingStateChangedEventArgs> AdapterLeAdvertisingStateChanged
100         {
101             add
102             {
103                 _advertisingStateChanged += value;
104             }
105             remove
106             {
107                 _advertisingStateChanged -= value;
108             }
109         }
110
111         internal event EventHandler<GattConnectionStateChangedEventArgs> LeGattConnectionStateChanged
112         {
113             add
114             {
115                 if (_gattConnectionStateChanged == null)
116                 {
117                     RegisterGattConnectionStateChangedEvent();
118                 }
119                 _gattConnectionStateChanged += value;
120             }
121             remove
122             {
123                 _gattConnectionStateChanged -= value;
124                 if (_gattConnectionStateChanged == null)
125                 {
126                     UnRegisterGattConnectionStateChangedEvent();
127                 }
128             }
129         }
130
131         internal void RegisterGattConnectionStateChangedEvent()
132         {
133             _gattConnectionStateChangedCallback = (int result, bool connected,
134                                     string remoteDeviceAddress, IntPtr userData) =>
135             {
136                 if (_gattConnectionStateChanged != null)
137                 {
138                     Log.Info(Globals.LogTag, "Setting gatt connection state changed callback" );
139                     GattConnectionStateChangedEventArgs e = new GattConnectionStateChangedEventArgs (result,
140                         connected, remoteDeviceAddress);
141
142                     _gattConnectionStateChanged(null, e);
143                 }
144             };
145
146             int ret = Interop.Bluetooth.SetGattConnectionStateChangedCallback(
147                                     _gattConnectionStateChangedCallback, IntPtr.Zero);
148             if (ret != (int)BluetoothError.None)
149             {
150                 Log.Error(Globals.LogTag, "Failed to set gatt connection state changed callback, Error - " + (BluetoothError)ret);
151             }
152         }
153
154         internal void UnRegisterGattConnectionStateChangedEvent()
155         {
156             int ret = Interop.Bluetooth.UnsetGattConnectionStateChangedCallback();
157             if (ret != (int)BluetoothError.None)
158             {
159                 Log.Error(Globals.LogTag, "Failed to unset gatt connection state changed callback, Error - " + (BluetoothError)ret);
160             }
161         }
162
163         internal int StartScan()
164         {
165             _adapterLeScanResultChangedCallback = (int result, ref BluetoothLeScanDataStruct scanData, IntPtr userData) =>
166             {
167                 Log.Info(Globals.LogTag, "Inside Le scan callback " );
168                 BluetoothLeScanData scanDataInfo = BluetoothUtils.ConvertStructToLeScanData(scanData);
169
170                 BluetoothLeDevice device = new BluetoothLeDevice(scanDataInfo);
171                 BluetoothError res = (BluetoothError)result;
172
173                 AdapterLeScanResultChangedEventArgs e = new AdapterLeScanResultChangedEventArgs (res,
174                                                                     device);
175                 _adapterLeScanResultChanged (null, e);
176             };
177
178             IntPtr data = IntPtr.Zero;
179             int ret = Interop.Bluetooth.StartScan(_adapterLeScanResultChangedCallback, data);
180             if (ret != (int)BluetoothError.None)
181             {
182                 Log.Error(Globals.LogTag, "Failed to start BLE scan - " + (BluetoothError)ret);
183                 BluetoothErrorFactory.ThrowBluetoothException(ret);
184             }
185             _scanStarted = true;
186             return ret;
187         }
188
189         internal int StopScan()
190         {
191             int ret = (int)BluetoothError.None;
192
193             if (_scanStarted)
194             {
195                 ret = Interop.Bluetooth.StopScan ();
196                 if (ret != (int)BluetoothError.None) {
197                     Log.Error (Globals.LogTag, "Failed to stop BLE scan - " + (BluetoothError)ret);
198                     BluetoothErrorFactory.ThrowBluetoothException (ret);
199                 }
200             }
201             return ret;
202         }
203
204         internal int SetScanMode(BluetoothLeScanMode mode)
205         {
206             int ret = (int)BluetoothError.None;
207
208             ret = Interop.Bluetooth.SetLeScanMode(mode);
209             if (ret != (int)BluetoothError.None) {
210                 Log.Error (Globals.LogTag, "Failed to set LE scan mode - " + (BluetoothError)ret);
211                 BluetoothErrorFactory.ThrowBluetoothException (ret);
212             }
213             return ret;
214         }
215
216         internal IList<string> GetLeScanResultServiceUuids(BluetoothLeScanData scanData, BluetoothLePacketType packetType)
217         {
218             if (!BluetoothAdapter.IsBluetoothEnabled || !Globals.IsInitialize)
219             {
220                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
221             }
222
223             IntPtr uuidListArray = IntPtr.Zero;
224             int count = -1;
225             BluetoothLeScanDataStruct scanDataStruct = BluetoothUtils.ConvertLeScanDataToStruct(scanData);
226
227             int ret = Interop.Bluetooth.GetScanResultServiceUuid(ref scanDataStruct, packetType, ref uuidListArray, ref count);
228             if (ret == (int)BluetoothError.NoData)
229             {
230                 Log.Info(Globals.LogTag, "No ServiceUuids in " + packetType);
231                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
232                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
233                 return null;
234             }
235             else if (ret != (int)BluetoothError.None)
236             {
237                 Log.Info(Globals.LogTag, "Failed to service uuids list- " + (BluetoothError)ret);
238                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
239                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
240                 BluetoothErrorFactory.ThrowBluetoothException(ret);
241             }
242
243             Log.Info(Globals.LogTag, "Count of ServiceUuids: " + count);
244
245             IList<string> list = new List<string>();
246             IntPtr[] uuidList = new IntPtr[count];
247             Marshal.Copy(uuidListArray, uuidList, 0, count);
248             foreach (IntPtr uuids in uuidList)
249             {
250                 list.Add(Marshal.PtrToStringAnsi(uuids));
251                 Interop.Libc.Free(uuids);
252             }
253
254             Interop.Libc.Free(uuidListArray);
255             Marshal.FreeHGlobal(scanDataStruct.AdvData);
256             Marshal.FreeHGlobal(scanDataStruct.ScanData);
257             return list;
258         }
259
260         internal string GetLeScanResultDeviceName(BluetoothLeScanData scanData, BluetoothLePacketType packetType)
261         {
262             if (!BluetoothAdapter.IsBluetoothEnabled || !Globals.IsInitialize)
263             {
264                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
265             }
266
267             string deviceName;
268             BluetoothLeScanDataStruct scanDataStruct = BluetoothUtils.ConvertLeScanDataToStruct(scanData);
269
270             int ret = Interop.Bluetooth.GetLeScanResultDeviceName(ref scanDataStruct, packetType, out deviceName);
271             if (ret == (int)BluetoothError.NoData)
272             {
273                 Log.Info(Globals.LogTag, "No DeviceName in " + packetType);
274                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
275                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
276                 return null;
277             }
278             else if (ret != (int)BluetoothError.None)
279             {
280                 Log.Error(Globals.LogTag, "Failed to get Device name- " + (BluetoothError)ret);
281                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
282                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
283                 BluetoothErrorFactory.ThrowBluetoothException(ret);
284             }
285
286             Log.Info(Globals.LogTag, "DeviceName: " + deviceName);
287             Marshal.FreeHGlobal(scanDataStruct.AdvData);
288             Marshal.FreeHGlobal(scanDataStruct.ScanData);
289             return deviceName;
290         }
291
292         internal int GetScanResultTxPowerLevel(BluetoothLeScanData scanData, BluetoothLePacketType packetType)
293         {
294             if (!BluetoothAdapter.IsBluetoothEnabled || !Globals.IsInitialize)
295             {
296                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
297             }
298
299             int powerLevel = -1;
300             BluetoothLeScanDataStruct scanDataStruct = BluetoothUtils.ConvertLeScanDataToStruct(scanData);
301
302             int ret = Interop.Bluetooth.GetScanResultTxPowerLevel(ref scanDataStruct, packetType, out powerLevel);
303             if (ret == (int)BluetoothError.NoData)
304             {
305                 Log.Info(Globals.LogTag, "No TxPowerLevel data in " + packetType);
306                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
307                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
308                 return -1;
309             }
310             else if (ret != (int)BluetoothError.None)
311             {
312                 Log.Error(Globals.LogTag, "Failed to get tx power level- " + (BluetoothError)ret);
313                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
314                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
315                 BluetoothErrorFactory.ThrowBluetoothException(ret);
316             }
317
318             Log.Info (Globals.LogTag, "TxPowerLevel: " + powerLevel);
319             Marshal.FreeHGlobal(scanDataStruct.AdvData);
320             Marshal.FreeHGlobal(scanDataStruct.ScanData);
321             return powerLevel;
322         }
323
324         internal IList<string> GetScanResultSvcSolicitationUuids(BluetoothLeScanData scanData, BluetoothLePacketType packetType)
325         {
326             if (!BluetoothAdapter.IsBluetoothEnabled || !Globals.IsInitialize)
327             {
328                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
329             }
330
331             IntPtr uuidListArray;
332             int count;
333             BluetoothLeScanDataStruct scanDataStruct = BluetoothUtils.ConvertLeScanDataToStruct(scanData);
334
335             int ret = Interop.Bluetooth.GetScanResultSvcSolicitationUuids(ref scanDataStruct, packetType, out uuidListArray, out count);
336             if (ret == (int)BluetoothError.NoData)
337             {
338                 Log.Info(Globals.LogTag, "No ServiceSolicitationUuids in " + packetType);
339                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
340                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
341                 return null;
342             }
343             else if (ret != (int)BluetoothError.None)
344             {
345                 Log.Error(Globals.LogTag, "Failed to get service solicitation uuids " + (BluetoothError)ret);
346                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
347                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
348                 BluetoothErrorFactory.ThrowBluetoothException(ret);
349             }
350
351             Log.Info(Globals.LogTag, "Count of ServiceSolicitationUuids: " + count);
352
353             IList<string> list = new List<string>();
354             IntPtr[] uuidList = new IntPtr[count];
355             Marshal.Copy(uuidListArray, uuidList, 0, count);
356             foreach (IntPtr uuids in uuidList)
357             {
358                 list.Add(Marshal.PtrToStringAnsi(uuids));
359                 Interop.Libc.Free(uuids);
360             }
361
362             Interop.Libc.Free(uuidListArray);
363             Marshal.FreeHGlobal(scanDataStruct.AdvData);
364             Marshal.FreeHGlobal(scanDataStruct.ScanData);
365             return list;
366         }
367
368         internal IList<BluetoothLeServiceData> GetScanResultServiceDataList(BluetoothLeScanData scanData, BluetoothLePacketType packetType)
369         {
370             if (!BluetoothAdapter.IsBluetoothEnabled || !Globals.IsInitialize)
371             {
372                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
373             }
374
375             IntPtr serviceListArray;
376             _serviceListCount = 0;
377             BluetoothLeScanDataStruct scanDataStruct = BluetoothUtils.ConvertLeScanDataToStruct(scanData);
378
379             int ret = Interop.Bluetooth.GetScanResultServiceDataList(ref scanDataStruct, packetType, out serviceListArray, out _serviceListCount);
380             if (ret == (int)BluetoothError.NoData)
381             {
382                 Log.Info(Globals.LogTag, "No ServiceDataList in " + packetType);
383                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
384                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
385                 return null;
386             }
387             else if (ret != (int)BluetoothError.None)
388             {
389                 Log.Info(Globals.LogTag, "Failed to get Service Data List, Error - " + (BluetoothError)ret);
390                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
391                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
392                 BluetoothErrorFactory.ThrowBluetoothException(ret);
393             }
394
395             Log.Info(Globals.LogTag, "Count of ServiceDataList: " + _serviceListCount);
396
397             int sizePointerToABC = Marshal.SizeOf(new BluetoothLeServiceDataStruct());
398             for (int i = 0; i < _serviceListCount; i++)
399             {
400                 var svc = (BluetoothLeServiceDataStruct)Marshal.PtrToStructure(new IntPtr(serviceListArray.ToInt32() + (i * sizePointerToABC)), typeof(BluetoothLeServiceDataStruct));
401                 _list.Add(BluetoothUtils.ConvertStructToLeServiceData(svc));
402             }
403
404             Interop.Bluetooth.FreeServiceDataList(serviceListArray, _serviceListCount);
405             Marshal.FreeHGlobal(scanDataStruct.AdvData);
406             Marshal.FreeHGlobal(scanDataStruct.ScanData);
407             return _list;
408         }
409
410         internal int GetScanResultAppearance(BluetoothLeScanData scanData, BluetoothLePacketType packetType)
411         {
412             if (!BluetoothAdapter.IsBluetoothEnabled || !Globals.IsInitialize)
413             {
414                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
415             }
416
417             int appearance = -1;
418             BluetoothLeScanDataStruct scanDataStruct = BluetoothUtils.ConvertLeScanDataToStruct(scanData);
419
420             int ret = Interop.Bluetooth.GetScanResultAppearance(ref scanDataStruct, packetType, out appearance);
421             if (ret == (int)BluetoothError.NoData)
422             {
423                 Log.Info(Globals.LogTag, "No Appearance in " + packetType);
424                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
425                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
426                 return -1;
427             }
428             else if (ret != (int)BluetoothError.None)
429             {
430                 Log.Error(Globals.LogTag, "Failed to get Appearance value- " + (BluetoothError)ret);
431                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
432                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
433                 BluetoothErrorFactory.ThrowBluetoothException(ret);
434             }
435
436             Marshal.FreeHGlobal(scanDataStruct.AdvData);
437             Marshal.FreeHGlobal(scanDataStruct.ScanData);
438             return appearance;
439         }
440
441         internal ManufacturerData GetScanResultManufacturerData(BluetoothLeScanData scanData, BluetoothLePacketType packetType)
442         {
443             if (!BluetoothAdapter.IsBluetoothEnabled || !Globals.IsInitialize)
444             {
445                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
446             }
447
448             int dataId = 0;
449             int dataLength = 0;
450             IntPtr manufData;
451             BluetoothLeScanDataStruct scanDataStruct = BluetoothUtils.ConvertLeScanDataToStruct(scanData);
452
453             int ret = Interop.Bluetooth.GetScanResultManufacturerData(ref scanDataStruct, packetType, out dataId, out manufData, out dataLength);
454             if (ret == (int)BluetoothError.NoData)
455             {
456                 Log.Info(Globals.LogTag, "No ManufacturerData in " + packetType);
457                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
458                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
459                 return null;
460             }
461             else if (ret != (int)BluetoothError.None)
462             {
463                 Log.Error(Globals.LogTag, "Failed to get Manufacturer data - " + (BluetoothError)ret);
464                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
465                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
466                 BluetoothErrorFactory.ThrowBluetoothException(ret);
467             }
468
469             Log.Info(Globals.LogTag, "Count of ManufacturerData: " + dataLength);
470
471             ManufacturerData data = new ManufacturerData();
472             data.Id = dataId;
473             data.DataLength = dataLength;
474             if (data.DataLength > 0)
475             {
476                 data.Data = new byte[data.DataLength];
477                 Marshal.Copy(manufData, data.Data, 0, data.DataLength);
478             }
479
480             Interop.Libc.Free(manufData);
481             Marshal.FreeHGlobal(scanDataStruct.AdvData);
482             Marshal.FreeHGlobal(scanDataStruct.ScanData);
483             return data;
484         }
485
486         internal int GattConnect(string remoteAddress, bool autoConnect)
487         {
488             int ret = Interop.Bluetooth.GattConnect (remoteAddress, autoConnect);
489             if (ret != (int)BluetoothError.None)
490             {
491                 Log.Error(Globals.LogTag, "Failed to establish GATT connection - " + (BluetoothError)ret);
492                 BluetoothErrorFactory.ThrowBluetoothException(ret);
493             }
494             return ret;
495         }
496
497         internal int GattDisconnect(string remoteAddress)
498         {
499             int ret = Interop.Bluetooth.GattDisconnect (remoteAddress);
500             if (ret != (int)BluetoothError.None)
501             {
502                 Log.Error(Globals.LogTag, "Failed to disconnect GATT connection - " + (BluetoothError)ret);
503                 BluetoothErrorFactory.ThrowBluetoothException(ret);
504             }
505             return ret;
506         }
507
508         internal int CreateAdvertiser(out IntPtr advertiserHandle)
509         {
510             return Interop.Bluetooth.CreateAdvertiser (out advertiserHandle);
511         }
512
513         internal int DestroyAdvertiser(IntPtr advertiserHandle)
514         {
515             int ret =  Interop.Bluetooth.DestroyAdvertiser (advertiserHandle);
516             if (ret != (int)BluetoothError.None) {
517                 Log.Error(Globals.LogTag, "Failed to destroy the Advertiser- " + (BluetoothError)ret);
518                 BluetoothErrorFactory.ThrowBluetoothException(ret);
519             }
520             return ret;
521         }
522
523         internal int StartAdvertising(IntPtr advertisingHandle)
524         {
525             _advertisingStateChangedCallback = (int result, IntPtr advertiserHandle,
526                             BluetoothLeAdvertisingState state, IntPtr userData) =>
527             {
528                 Log.Info(Globals.LogTag, "Setting advertising state changed callback !! " );
529                 AdvertisingStateChangedEventArgs e = new AdvertisingStateChangedEventArgs(result, advertiserHandle, state);
530                 _advertisingStateChanged(null, e);
531             };
532
533             IntPtr uData = IntPtr.Zero;
534             int ret = Interop.Bluetooth.BluetoothLeStartAdvertising (advertisingHandle,
535                                    _advertisingStateChangedCallback, uData );
536             if (ret != (int)BluetoothError.None)
537             {
538                 Log.Error(Globals.LogTag, "Failed to start BLE advertising - " + (BluetoothError)ret);
539                 BluetoothErrorFactory.ThrowBluetoothException(ret);
540             }
541             return ret;
542         }
543
544
545         internal int StopAdvertising(IntPtr advertisingHandle)
546         {
547             return Interop.Bluetooth.BluetoothLeStopAdvertising (advertisingHandle);
548         }
549     }
550 }