890c80e3e4ac49517268805f3df88cd6ee18b5f5
[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 int _serviceListCount = 0;
38         private bool _scanStarted;
39
40         internal static BluetoothLeImplAdapter Instance
41         {
42             get
43             {
44                 return _instance;
45             }
46         }
47
48         private BluetoothLeImplAdapter()
49         {
50         }
51
52         ~BluetoothLeImplAdapter()
53         {
54             Dispose(false);
55         }
56
57         public void Dispose()
58         {
59             Dispose(true);
60             GC.SuppressFinalize(this);
61         }
62
63         private void Dispose(bool disposing)
64         {
65             if (disposed)
66                 return;
67
68             if (disposing)
69             {
70                 // Free managed objects.
71             }
72
73             //stop scan operation in progress
74             StopScan ();
75
76             disposed = true;
77         }
78
79         internal event EventHandler<AdapterLeScanResultChangedEventArgs> AdapterLeScanResultChanged
80         {
81             add
82             {
83                 _adapterLeScanResultChanged += value;
84             }
85             remove {
86                 _adapterLeScanResultChanged -= value;
87             }
88         }
89
90         internal event EventHandler<AdvertisingStateChangedEventArgs> AdapterLeAdvertisingStateChanged
91         {
92             add
93             {
94                 _advertisingStateChanged += value;
95             }
96             remove
97             {
98                 _advertisingStateChanged -= value;
99             }
100         }
101
102         internal int StartScan()
103         {
104             _adapterLeScanResultChangedCallback = (int result, ref BluetoothLeScanDataStruct scanData, IntPtr userData) =>
105             {
106                 Log.Info(Globals.LogTag, "Inside Le scan callback " );
107                 BluetoothLeScanData scanDataInfo = BluetoothUtils.ConvertStructToLeScanData(scanData);
108
109                 BluetoothLeDevice device = new BluetoothLeDevice(scanDataInfo);
110                 BluetoothError res = (BluetoothError)result;
111
112                 AdapterLeScanResultChangedEventArgs e = new AdapterLeScanResultChangedEventArgs (res,
113                                                                     device);
114                 _adapterLeScanResultChanged?.Invoke(null, e);
115             };
116
117             IntPtr data = IntPtr.Zero;
118             int ret = Interop.Bluetooth.StartScan(_adapterLeScanResultChangedCallback, data);
119             if (ret != (int)BluetoothError.None)
120             {
121                 Log.Error(Globals.LogTag, "Failed to start BLE scan - " + (BluetoothError)ret);
122                 BluetoothErrorFactory.ThrowBluetoothException(ret);
123             }
124             _scanStarted = true;
125             return ret;
126         }
127
128         internal int StopScan()
129         {
130             int ret = (int)BluetoothError.None;
131
132             if (_scanStarted)
133             {
134                 ret = Interop.Bluetooth.StopScan ();
135                 if (ret != (int)BluetoothError.None) {
136                     Log.Error (Globals.LogTag, "Failed to stop BLE scan - " + (BluetoothError)ret);
137                     BluetoothErrorFactory.ThrowBluetoothException (ret);
138                 }
139             }
140             return ret;
141         }
142
143         internal int SetScanMode(BluetoothLeScanMode mode)
144         {
145             int ret = (int)BluetoothError.None;
146
147             ret = Interop.Bluetooth.SetLeScanMode(mode);
148             if (ret != (int)BluetoothError.None) {
149                 Log.Error (Globals.LogTag, "Failed to set LE scan mode - " + (BluetoothError)ret);
150                 BluetoothErrorFactory.ThrowBluetoothException (ret);
151             }
152             return ret;
153         }
154
155         internal IList<string> GetLeScanResultServiceUuids(BluetoothLeScanData scanData, BluetoothLePacketType packetType)
156         {
157             if (!BluetoothAdapter.IsBluetoothEnabled || !Globals.IsInitialize)
158             {
159                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
160             }
161
162             IntPtr uuidListArray = IntPtr.Zero;
163             int count = -1;
164             BluetoothLeScanDataStruct scanDataStruct = BluetoothUtils.ConvertLeScanDataToStruct(scanData);
165
166             int ret = Interop.Bluetooth.GetScanResultServiceUuid(ref scanDataStruct, packetType, ref uuidListArray, ref count);
167             if (ret == (int)BluetoothError.NoData)
168             {
169                 Log.Info(Globals.LogTag, "No ServiceUuids in " + packetType);
170                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
171                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
172                 return null;
173             }
174             else if (ret != (int)BluetoothError.None)
175             {
176                 Log.Info(Globals.LogTag, "Failed to service uuids list- " + (BluetoothError)ret);
177                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
178                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
179                 BluetoothErrorFactory.ThrowBluetoothException(ret);
180             }
181
182             Log.Info(Globals.LogTag, "Count of ServiceUuids: " + count);
183
184             IList<string> list = new List<string>();
185             IntPtr[] uuidList = new IntPtr[count];
186             Marshal.Copy(uuidListArray, uuidList, 0, count);
187             foreach (IntPtr uuids in uuidList)
188             {
189                 list.Add(Marshal.PtrToStringAnsi(uuids));
190                 Interop.Libc.Free(uuids);
191             }
192
193             Interop.Libc.Free(uuidListArray);
194             Marshal.FreeHGlobal(scanDataStruct.AdvData);
195             Marshal.FreeHGlobal(scanDataStruct.ScanData);
196             return list;
197         }
198
199         internal string GetLeScanResultDeviceName(BluetoothLeScanData scanData, BluetoothLePacketType packetType)
200         {
201             if (!BluetoothAdapter.IsBluetoothEnabled || !Globals.IsInitialize)
202             {
203                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
204             }
205
206             string deviceName;
207             BluetoothLeScanDataStruct scanDataStruct = BluetoothUtils.ConvertLeScanDataToStruct(scanData);
208
209             int ret = Interop.Bluetooth.GetLeScanResultDeviceName(ref scanDataStruct, packetType, out deviceName);
210             if (ret == (int)BluetoothError.NoData)
211             {
212                 Log.Info(Globals.LogTag, "No DeviceName in " + packetType);
213                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
214                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
215                 return null;
216             }
217             else if (ret != (int)BluetoothError.None)
218             {
219                 Log.Error(Globals.LogTag, "Failed to get Device name- " + (BluetoothError)ret);
220                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
221                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
222                 BluetoothErrorFactory.ThrowBluetoothException(ret);
223             }
224
225             Log.Info(Globals.LogTag, "DeviceName: " + deviceName);
226             Marshal.FreeHGlobal(scanDataStruct.AdvData);
227             Marshal.FreeHGlobal(scanDataStruct.ScanData);
228             return deviceName;
229         }
230
231         internal int GetScanResultTxPowerLevel(BluetoothLeScanData scanData, BluetoothLePacketType packetType)
232         {
233             if (!BluetoothAdapter.IsBluetoothEnabled || !Globals.IsInitialize)
234             {
235                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
236             }
237
238             int powerLevel = -1;
239             BluetoothLeScanDataStruct scanDataStruct = BluetoothUtils.ConvertLeScanDataToStruct(scanData);
240
241             int ret = Interop.Bluetooth.GetScanResultTxPowerLevel(ref scanDataStruct, packetType, out powerLevel);
242             if (ret == (int)BluetoothError.NoData)
243             {
244                 Log.Info(Globals.LogTag, "No TxPowerLevel data in " + packetType);
245                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
246                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
247                 return -1;
248             }
249             else if (ret != (int)BluetoothError.None)
250             {
251                 Log.Error(Globals.LogTag, "Failed to get tx power level- " + (BluetoothError)ret);
252                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
253                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
254                 BluetoothErrorFactory.ThrowBluetoothException(ret);
255             }
256
257             Log.Info (Globals.LogTag, "TxPowerLevel: " + powerLevel);
258             Marshal.FreeHGlobal(scanDataStruct.AdvData);
259             Marshal.FreeHGlobal(scanDataStruct.ScanData);
260             return powerLevel;
261         }
262
263         internal IList<string> GetScanResultSvcSolicitationUuids(BluetoothLeScanData scanData, BluetoothLePacketType packetType)
264         {
265             if (!BluetoothAdapter.IsBluetoothEnabled || !Globals.IsInitialize)
266             {
267                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
268             }
269
270             IntPtr uuidListArray;
271             int count;
272             BluetoothLeScanDataStruct scanDataStruct = BluetoothUtils.ConvertLeScanDataToStruct(scanData);
273
274             int ret = Interop.Bluetooth.GetScanResultSvcSolicitationUuids(ref scanDataStruct, packetType, out uuidListArray, out count);
275             if (ret == (int)BluetoothError.NoData)
276             {
277                 Log.Info(Globals.LogTag, "No ServiceSolicitationUuids in " + packetType);
278                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
279                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
280                 return null;
281             }
282             else if (ret != (int)BluetoothError.None)
283             {
284                 Log.Error(Globals.LogTag, "Failed to get service solicitation uuids " + (BluetoothError)ret);
285                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
286                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
287                 BluetoothErrorFactory.ThrowBluetoothException(ret);
288             }
289
290             Log.Info(Globals.LogTag, "Count of ServiceSolicitationUuids: " + count);
291
292             IList<string> list = new List<string>();
293             IntPtr[] uuidList = new IntPtr[count];
294             Marshal.Copy(uuidListArray, uuidList, 0, count);
295             foreach (IntPtr uuids in uuidList)
296             {
297                 list.Add(Marshal.PtrToStringAnsi(uuids));
298                 Interop.Libc.Free(uuids);
299             }
300
301             Interop.Libc.Free(uuidListArray);
302             Marshal.FreeHGlobal(scanDataStruct.AdvData);
303             Marshal.FreeHGlobal(scanDataStruct.ScanData);
304             return list;
305         }
306
307         internal IList<BluetoothLeServiceData> GetScanResultServiceDataList(BluetoothLeScanData scanData, BluetoothLePacketType packetType)
308         {
309             if (!BluetoothAdapter.IsBluetoothEnabled || !Globals.IsInitialize)
310             {
311                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
312             }
313
314             IntPtr serviceListArray;
315             _serviceListCount = 0;
316             BluetoothLeScanDataStruct scanDataStruct = BluetoothUtils.ConvertLeScanDataToStruct(scanData);
317
318             int ret = Interop.Bluetooth.GetScanResultServiceDataList(ref scanDataStruct, packetType, out serviceListArray, out _serviceListCount);
319             if (ret == (int)BluetoothError.NoData)
320             {
321                 Log.Info(Globals.LogTag, "No ServiceDataList in " + packetType);
322                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
323                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
324                 return null;
325             }
326             else if (ret != (int)BluetoothError.None)
327             {
328                 Log.Info(Globals.LogTag, "Failed to get Service Data List, Error - " + (BluetoothError)ret);
329                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
330                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
331                 BluetoothErrorFactory.ThrowBluetoothException(ret);
332             }
333
334             Log.Info(Globals.LogTag, "Count of ServiceDataList: " + _serviceListCount);
335
336             IList<BluetoothLeServiceData> list = new List<BluetoothLeServiceData>();
337             int sizePointerToABC = Marshal.SizeOf(new BluetoothLeServiceDataStruct());
338             for (int i = 0; i < _serviceListCount; i++)
339             {
340                 var svc = (BluetoothLeServiceDataStruct)Marshal.PtrToStructure(IntPtr.Add(serviceListArray, (i * sizePointerToABC)), typeof(BluetoothLeServiceDataStruct));
341                 list.Add(BluetoothUtils.ConvertStructToLeServiceData(svc));
342             }
343
344             Interop.Bluetooth.FreeServiceDataList(serviceListArray, _serviceListCount);
345             Marshal.FreeHGlobal(scanDataStruct.AdvData);
346             Marshal.FreeHGlobal(scanDataStruct.ScanData);
347             return list;
348         }
349
350         internal int GetScanResultAppearance(BluetoothLeScanData scanData, BluetoothLePacketType packetType)
351         {
352             if (!BluetoothAdapter.IsBluetoothEnabled || !Globals.IsInitialize)
353             {
354                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
355             }
356
357             int appearance = -1;
358             BluetoothLeScanDataStruct scanDataStruct = BluetoothUtils.ConvertLeScanDataToStruct(scanData);
359
360             int ret = Interop.Bluetooth.GetScanResultAppearance(ref scanDataStruct, packetType, out appearance);
361             if (ret == (int)BluetoothError.NoData)
362             {
363                 Log.Info(Globals.LogTag, "No Appearance in " + packetType);
364                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
365                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
366                 return -1;
367             }
368             else if (ret != (int)BluetoothError.None)
369             {
370                 Log.Error(Globals.LogTag, "Failed to get Appearance value- " + (BluetoothError)ret);
371                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
372                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
373                 BluetoothErrorFactory.ThrowBluetoothException(ret);
374             }
375
376             Marshal.FreeHGlobal(scanDataStruct.AdvData);
377             Marshal.FreeHGlobal(scanDataStruct.ScanData);
378             return appearance;
379         }
380
381         internal ManufacturerData GetScanResultManufacturerData(BluetoothLeScanData scanData, BluetoothLePacketType packetType)
382         {
383             if (!BluetoothAdapter.IsBluetoothEnabled || !Globals.IsInitialize)
384             {
385                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
386             }
387
388             int dataId = 0;
389             int dataLength = 0;
390             IntPtr manufData;
391             BluetoothLeScanDataStruct scanDataStruct = BluetoothUtils.ConvertLeScanDataToStruct(scanData);
392
393             int ret = Interop.Bluetooth.GetScanResultManufacturerData(ref scanDataStruct, packetType, out dataId, out manufData, out dataLength);
394             if (ret == (int)BluetoothError.NoData)
395             {
396                 Log.Info(Globals.LogTag, "No ManufacturerData in " + packetType);
397                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
398                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
399                 return null;
400             }
401             else if (ret != (int)BluetoothError.None)
402             {
403                 Log.Error(Globals.LogTag, "Failed to get Manufacturer data - " + (BluetoothError)ret);
404                 Marshal.FreeHGlobal(scanDataStruct.AdvData);
405                 Marshal.FreeHGlobal(scanDataStruct.ScanData);
406                 BluetoothErrorFactory.ThrowBluetoothException(ret);
407             }
408
409             Log.Info(Globals.LogTag, "Count of ManufacturerData: " + dataLength);
410
411             ManufacturerData data = new ManufacturerData();
412             data.Id = dataId;
413             data.DataLength = dataLength;
414             if (data.DataLength > 0)
415             {
416                 data.Data = new byte[data.DataLength];
417                 Marshal.Copy(manufData, data.Data, 0, data.DataLength);
418             }
419
420             Interop.Libc.Free(manufData);
421             Marshal.FreeHGlobal(scanDataStruct.AdvData);
422             Marshal.FreeHGlobal(scanDataStruct.ScanData);
423             return data;
424         }
425
426         internal int GattConnect(string remoteAddress, bool autoConnect)
427         {
428             int ret = Interop.Bluetooth.GattConnect (remoteAddress, autoConnect);
429             if (ret != (int)BluetoothError.None)
430             {
431                 Log.Error(Globals.LogTag, "Failed to establish GATT connection - " + (BluetoothError)ret);
432                 BluetoothErrorFactory.ThrowBluetoothException(ret);
433             }
434             return ret;
435         }
436
437         internal int GattDisconnect(string remoteAddress)
438         {
439             int ret = Interop.Bluetooth.GattDisconnect (remoteAddress);
440             if (ret != (int)BluetoothError.None)
441             {
442                 Log.Error(Globals.LogTag, "Failed to disconnect GATT connection - " + (BluetoothError)ret);
443                 BluetoothErrorFactory.ThrowBluetoothException(ret);
444             }
445             return ret;
446         }
447
448         internal int CreateAdvertiser(out IntPtr advertiserHandle)
449         {
450             return Interop.Bluetooth.CreateAdvertiser (out advertiserHandle);
451         }
452
453         internal int DestroyAdvertiser(IntPtr advertiserHandle)
454         {
455             int ret =  Interop.Bluetooth.DestroyAdvertiser (advertiserHandle);
456             if (ret != (int)BluetoothError.None) {
457                 Log.Error(Globals.LogTag, "Failed to destroy the Advertiser- " + (BluetoothError)ret);
458                 BluetoothErrorFactory.ThrowBluetoothException(ret);
459             }
460             return ret;
461         }
462
463         internal int StartAdvertising(IntPtr advertisingHandle)
464         {
465             _advertisingStateChangedCallback = (int result, IntPtr advertiserHandle,
466                             BluetoothLeAdvertisingState state, IntPtr userData) =>
467             {
468                 Log.Info(Globals.LogTag, "Setting advertising state changed callback !! " );
469                 AdvertisingStateChangedEventArgs e = new AdvertisingStateChangedEventArgs(result, advertiserHandle, state);
470                 _advertisingStateChanged?.Invoke(null, e);
471             };
472
473             IntPtr uData = IntPtr.Zero;
474             int ret = Interop.Bluetooth.BluetoothLeStartAdvertising (advertisingHandle,
475                                    _advertisingStateChangedCallback, uData );
476             if (ret != (int)BluetoothError.None)
477             {
478                 Log.Error(Globals.LogTag, "Failed to start BLE advertising - " + (BluetoothError)ret);
479                 BluetoothErrorFactory.ThrowBluetoothException(ret);
480             }
481             return ret;
482         }
483
484
485         internal int StopAdvertising(IntPtr advertisingHandle)
486         {
487             return Interop.Bluetooth.BluetoothLeStopAdvertising (advertisingHandle);
488         }
489     }
490 }