2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 using System.Collections.Generic;
19 using System.Collections.Specialized;
20 using System.Threading.Tasks;
21 using System.Runtime.InteropServices;
23 namespace Tizen.Network.Bluetooth
25 internal class BluetoothLeImplAdapter : IDisposable
27 private static readonly BluetoothLeImplAdapter _instance = new BluetoothLeImplAdapter();
29 private bool disposed = false;
31 private event EventHandler<AdapterLeScanResultChangedEventArgs> _adapterLeScanResultChanged = null;
32 private Interop.Bluetooth.AdapterLeScanResultChangedCallBack _adapterLeScanResultChangedCallback;
34 private event EventHandler<AdvertisingStateChangedEventArgs> _advertisingStateChanged = null;
35 private Interop.Bluetooth.AdvertisingStateChangedCallBack _advertisingStateChangedCallback;
37 private event EventHandler<GattConnectionStateChangedEventArgs> _gattConnectionStateChanged = null;
38 private Interop.Bluetooth.GattConnectionStateChangedCallBack _gattConnectionStateChangedCallback;
40 private int _serviceListCount = 0;
41 private IList<BluetoothLeServiceData> _list = new List<BluetoothLeServiceData>();
42 private bool _scanStarted;
44 internal static BluetoothLeImplAdapter Instance
52 private BluetoothLeImplAdapter()
56 ~BluetoothLeImplAdapter()
64 GC.SuppressFinalize(this);
67 private void Dispose(bool disposing)
74 // Free managed objects.
76 //Free unmanaged objects
77 if (_gattConnectionStateChanged != null)
79 UnRegisterGattConnectionStateChangedEvent();
82 //stop scan operation in progress
88 internal event EventHandler<AdapterLeScanResultChangedEventArgs> AdapterLeScanResultChanged
92 _adapterLeScanResultChanged += value;
95 _adapterLeScanResultChanged -= value;
99 internal event EventHandler<AdvertisingStateChangedEventArgs> AdapterLeAdvertisingStateChanged
103 _advertisingStateChanged += value;
107 _advertisingStateChanged -= value;
111 internal event EventHandler<GattConnectionStateChangedEventArgs> LeGattConnectionStateChanged
115 if (_gattConnectionStateChanged == null)
117 RegisterGattConnectionStateChangedEvent();
119 _gattConnectionStateChanged += value;
123 _gattConnectionStateChanged -= value;
124 if (_gattConnectionStateChanged == null)
126 UnRegisterGattConnectionStateChangedEvent();
131 internal void RegisterGattConnectionStateChangedEvent()
133 _gattConnectionStateChangedCallback = (int result, bool connected,
134 string remoteDeviceAddress, IntPtr userData) =>
136 if (_gattConnectionStateChanged != null)
138 Log.Info(Globals.LogTag, "Setting gatt connection state changed callback" );
139 GattConnectionStateChangedEventArgs e = new GattConnectionStateChangedEventArgs (result,
140 connected, remoteDeviceAddress);
142 _gattConnectionStateChanged(null, e);
146 int ret = Interop.Bluetooth.SetGattConnectionStateChangedCallback(
147 _gattConnectionStateChangedCallback, IntPtr.Zero);
148 if (ret != (int)BluetoothError.None)
150 Log.Error(Globals.LogTag, "Failed to set gatt connection state changed callback, Error - " + (BluetoothError)ret);
154 internal void UnRegisterGattConnectionStateChangedEvent()
156 int ret = Interop.Bluetooth.UnsetGattConnectionStateChangedCallback();
157 if (ret != (int)BluetoothError.None)
159 Log.Error(Globals.LogTag, "Failed to unset gatt connection state changed callback, Error - " + (BluetoothError)ret);
163 internal int StartScan()
165 _adapterLeScanResultChangedCallback = (int result, ref BluetoothLeScanDataStruct scanData, IntPtr userData) =>
167 Log.Info(Globals.LogTag, "Inside Le scan callback " );
168 BluetoothLeScanData scanDataInfo = BluetoothUtils.ConvertStructToLeScanData(scanData);
170 BluetoothLeDevice device = new BluetoothLeDevice(scanDataInfo);
171 BluetoothError res = (BluetoothError)result;
173 AdapterLeScanResultChangedEventArgs e = new AdapterLeScanResultChangedEventArgs (res,
175 _adapterLeScanResultChanged (null, e);
178 IntPtr data = IntPtr.Zero;
179 int ret = Interop.Bluetooth.StartScan(_adapterLeScanResultChangedCallback, data);
180 if (ret != (int)BluetoothError.None)
182 Log.Error(Globals.LogTag, "Failed to start BLE scan - " + (BluetoothError)ret);
183 BluetoothErrorFactory.ThrowBluetoothException(ret);
189 internal int StopScan()
191 int ret = (int)BluetoothError.None;
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);
204 internal int SetScanMode(BluetoothLeScanMode mode)
206 int ret = (int)BluetoothError.None;
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);
216 internal IList<string> GetLeScanResultServiceUuids(BluetoothLeScanData scanData, BluetoothLePacketType packetType)
218 if (!BluetoothAdapter.IsBluetoothEnabled || !Globals.IsInitialize)
220 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
223 IntPtr uuidListArray = IntPtr.Zero;
225 BluetoothLeScanDataStruct scanDataStruct = BluetoothUtils.ConvertLeScanDataToStruct(scanData);
227 int ret = Interop.Bluetooth.GetScanResultServiceUuid(ref scanDataStruct, packetType, ref uuidListArray, ref count);
228 if (ret == (int)BluetoothError.NoData)
230 Log.Info(Globals.LogTag, "No ServiceUuids in " + packetType);
231 Marshal.FreeHGlobal(scanDataStruct.AdvData);
232 Marshal.FreeHGlobal(scanDataStruct.ScanData);
235 else if (ret != (int)BluetoothError.None)
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);
243 Log.Info(Globals.LogTag, "Count of ServiceUuids: " + count);
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)
250 list.Add(Marshal.PtrToStringAnsi(uuids));
251 Interop.Libc.Free(uuids);
254 Interop.Libc.Free(uuidListArray);
255 Marshal.FreeHGlobal(scanDataStruct.AdvData);
256 Marshal.FreeHGlobal(scanDataStruct.ScanData);
260 internal string GetLeScanResultDeviceName(BluetoothLeScanData scanData, BluetoothLePacketType packetType)
262 if (!BluetoothAdapter.IsBluetoothEnabled || !Globals.IsInitialize)
264 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
268 BluetoothLeScanDataStruct scanDataStruct = BluetoothUtils.ConvertLeScanDataToStruct(scanData);
270 int ret = Interop.Bluetooth.GetLeScanResultDeviceName(ref scanDataStruct, packetType, out deviceName);
271 if (ret == (int)BluetoothError.NoData)
273 Log.Info(Globals.LogTag, "No DeviceName in " + packetType);
274 Marshal.FreeHGlobal(scanDataStruct.AdvData);
275 Marshal.FreeHGlobal(scanDataStruct.ScanData);
278 else if (ret != (int)BluetoothError.None)
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);
286 Log.Info(Globals.LogTag, "DeviceName: " + deviceName);
287 Marshal.FreeHGlobal(scanDataStruct.AdvData);
288 Marshal.FreeHGlobal(scanDataStruct.ScanData);
292 internal int GetScanResultTxPowerLevel(BluetoothLeScanData scanData, BluetoothLePacketType packetType)
294 if (!BluetoothAdapter.IsBluetoothEnabled || !Globals.IsInitialize)
296 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
300 BluetoothLeScanDataStruct scanDataStruct = BluetoothUtils.ConvertLeScanDataToStruct(scanData);
302 int ret = Interop.Bluetooth.GetScanResultTxPowerLevel(ref scanDataStruct, packetType, out powerLevel);
303 if (ret == (int)BluetoothError.NoData)
305 Log.Info(Globals.LogTag, "No TxPowerLevel data in " + packetType);
306 Marshal.FreeHGlobal(scanDataStruct.AdvData);
307 Marshal.FreeHGlobal(scanDataStruct.ScanData);
310 else if (ret != (int)BluetoothError.None)
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);
318 Log.Info (Globals.LogTag, "TxPowerLevel: " + powerLevel);
319 Marshal.FreeHGlobal(scanDataStruct.AdvData);
320 Marshal.FreeHGlobal(scanDataStruct.ScanData);
324 internal IList<string> GetScanResultSvcSolicitationUuids(BluetoothLeScanData scanData, BluetoothLePacketType packetType)
326 if (!BluetoothAdapter.IsBluetoothEnabled || !Globals.IsInitialize)
328 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
331 IntPtr uuidListArray;
333 BluetoothLeScanDataStruct scanDataStruct = BluetoothUtils.ConvertLeScanDataToStruct(scanData);
335 int ret = Interop.Bluetooth.GetScanResultSvcSolicitationUuids(ref scanDataStruct, packetType, out uuidListArray, out count);
336 if (ret == (int)BluetoothError.NoData)
338 Log.Info(Globals.LogTag, "No ServiceSolicitationUuids in " + packetType);
339 Marshal.FreeHGlobal(scanDataStruct.AdvData);
340 Marshal.FreeHGlobal(scanDataStruct.ScanData);
343 else if (ret != (int)BluetoothError.None)
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);
351 Log.Info(Globals.LogTag, "Count of ServiceSolicitationUuids: " + count);
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)
358 list.Add(Marshal.PtrToStringAnsi(uuids));
359 Interop.Libc.Free(uuids);
362 Interop.Libc.Free(uuidListArray);
363 Marshal.FreeHGlobal(scanDataStruct.AdvData);
364 Marshal.FreeHGlobal(scanDataStruct.ScanData);
368 internal IList<BluetoothLeServiceData> GetScanResultServiceDataList(BluetoothLeScanData scanData, BluetoothLePacketType packetType)
370 if (!BluetoothAdapter.IsBluetoothEnabled || !Globals.IsInitialize)
372 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
375 IntPtr serviceListArray;
376 _serviceListCount = 0;
377 BluetoothLeScanDataStruct scanDataStruct = BluetoothUtils.ConvertLeScanDataToStruct(scanData);
379 int ret = Interop.Bluetooth.GetScanResultServiceDataList(ref scanDataStruct, packetType, out serviceListArray, out _serviceListCount);
380 if (ret == (int)BluetoothError.NoData)
382 Log.Info(Globals.LogTag, "No ServiceDataList in " + packetType);
383 Marshal.FreeHGlobal(scanDataStruct.AdvData);
384 Marshal.FreeHGlobal(scanDataStruct.ScanData);
387 else if (ret != (int)BluetoothError.None)
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);
395 Log.Info(Globals.LogTag, "Count of ServiceDataList: " + _serviceListCount);
397 int sizePointerToABC = Marshal.SizeOf(new BluetoothLeServiceDataStruct());
398 for (int i = 0; i < _serviceListCount; i++)
400 var svc = (BluetoothLeServiceDataStruct)Marshal.PtrToStructure(new IntPtr(serviceListArray.ToInt32() + (i * sizePointerToABC)), typeof(BluetoothLeServiceDataStruct));
401 _list.Add(BluetoothUtils.ConvertStructToLeServiceData(svc));
404 Interop.Bluetooth.FreeServiceDataList(serviceListArray, _serviceListCount);
405 Marshal.FreeHGlobal(scanDataStruct.AdvData);
406 Marshal.FreeHGlobal(scanDataStruct.ScanData);
410 internal int GetScanResultAppearance(BluetoothLeScanData scanData, BluetoothLePacketType packetType)
412 if (!BluetoothAdapter.IsBluetoothEnabled || !Globals.IsInitialize)
414 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
418 BluetoothLeScanDataStruct scanDataStruct = BluetoothUtils.ConvertLeScanDataToStruct(scanData);
420 int ret = Interop.Bluetooth.GetScanResultAppearance(ref scanDataStruct, packetType, out appearance);
421 if (ret == (int)BluetoothError.NoData)
423 Log.Info(Globals.LogTag, "No Appearance in " + packetType);
424 Marshal.FreeHGlobal(scanDataStruct.AdvData);
425 Marshal.FreeHGlobal(scanDataStruct.ScanData);
428 else if (ret != (int)BluetoothError.None)
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);
436 Marshal.FreeHGlobal(scanDataStruct.AdvData);
437 Marshal.FreeHGlobal(scanDataStruct.ScanData);
441 internal ManufacturerData GetScanResultManufacturerData(BluetoothLeScanData scanData, BluetoothLePacketType packetType)
443 if (!BluetoothAdapter.IsBluetoothEnabled || !Globals.IsInitialize)
445 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
451 BluetoothLeScanDataStruct scanDataStruct = BluetoothUtils.ConvertLeScanDataToStruct(scanData);
453 int ret = Interop.Bluetooth.GetScanResultManufacturerData(ref scanDataStruct, packetType, out dataId, out manufData, out dataLength);
454 if (ret == (int)BluetoothError.NoData)
456 Log.Info(Globals.LogTag, "No ManufacturerData in " + packetType);
457 Marshal.FreeHGlobal(scanDataStruct.AdvData);
458 Marshal.FreeHGlobal(scanDataStruct.ScanData);
461 else if (ret != (int)BluetoothError.None)
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);
469 Log.Info(Globals.LogTag, "Count of ManufacturerData: " + dataLength);
471 ManufacturerData data = new ManufacturerData();
473 data.DataLength = dataLength;
474 if (data.DataLength > 0)
476 data.Data = new byte[data.DataLength];
477 Marshal.Copy(manufData, data.Data, 0, data.DataLength);
480 Interop.Libc.Free(manufData);
481 Marshal.FreeHGlobal(scanDataStruct.AdvData);
482 Marshal.FreeHGlobal(scanDataStruct.ScanData);
486 internal int GattConnect(string remoteAddress, bool autoConnect)
488 int ret = Interop.Bluetooth.GattConnect (remoteAddress, autoConnect);
489 if (ret != (int)BluetoothError.None)
491 Log.Error(Globals.LogTag, "Failed to establish GATT connection - " + (BluetoothError)ret);
492 BluetoothErrorFactory.ThrowBluetoothException(ret);
497 internal int GattDisconnect(string remoteAddress)
499 int ret = Interop.Bluetooth.GattDisconnect (remoteAddress);
500 if (ret != (int)BluetoothError.None)
502 Log.Error(Globals.LogTag, "Failed to disconnect GATT connection - " + (BluetoothError)ret);
503 BluetoothErrorFactory.ThrowBluetoothException(ret);
508 internal int CreateAdvertiser(out IntPtr advertiserHandle)
510 return Interop.Bluetooth.CreateAdvertiser (out advertiserHandle);
513 internal int DestroyAdvertiser(IntPtr advertiserHandle)
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);
523 internal int StartAdvertising(IntPtr advertisingHandle)
525 _advertisingStateChangedCallback = (int result, IntPtr advertiserHandle,
526 BluetoothLeAdvertisingState state, IntPtr userData) =>
528 Log.Info(Globals.LogTag, "Setting advertising state changed callback !! " );
529 AdvertisingStateChangedEventArgs e = new AdvertisingStateChangedEventArgs(result, advertiserHandle, state);
530 _advertisingStateChanged(null, e);
533 IntPtr uData = IntPtr.Zero;
534 int ret = Interop.Bluetooth.BluetoothLeStartAdvertising (advertisingHandle,
535 _advertisingStateChangedCallback, uData );
536 if (ret != (int)BluetoothError.None)
538 Log.Error(Globals.LogTag, "Failed to start BLE advertising - " + (BluetoothError)ret);
539 BluetoothErrorFactory.ThrowBluetoothException(ret);
545 internal int StopAdvertising(IntPtr advertisingHandle)
547 return Interop.Bluetooth.BluetoothLeStopAdvertising (advertisingHandle);