[Bluetooth][Non-ACR] Define Interop callback to global variable (#2005)
[platform/core/csapi/tizenfx.git] / src / Tizen.Network.Bluetooth / Tizen.Network.Bluetooth / BluetoothGattImpl.cs
index 39530db..4e8f288 100644 (file)
@@ -27,9 +27,15 @@ namespace Tizen.Network.Bluetooth
     {
         private BluetoothGattServerHandle _handle;
         internal event EventHandler<NotificationSentEventArg> _notificationSent;
+        int _requestId = 0;
+        Dictionary<int, TaskCompletionSource<bool>> _sendIndicationTaskSource = new Dictionary<int, TaskCompletionSource<bool>>();
+        private Interop.Bluetooth.BtGattServerNotificationSentCallback _sendIndicationCallback;
+        private Interop.Bluetooth.BtGattForeachCallback _serviceForeachCallback;
 
         internal BluetoothGattServerImpl()
         {
+            _sendIndicationCallback = SendIndicationCallback;
+
             int err = Interop.Bluetooth.BtGattServerInitialize();
             GattUtil.ThrowForError(err, "Failed to initialize server");
 
@@ -83,7 +89,7 @@ namespace Tizen.Network.Bluetooth
         internal IEnumerable<BluetoothGattService> GetServices(BluetoothGattServer server)
         {
             List<BluetoothGattService> attribututeList = new List<BluetoothGattService>();
-            Interop.Bluetooth.BtGattForeachCallback cb = (total, index, attributeHandle, userData) =>
+            _serviceForeachCallback = (total, index, attributeHandle, userData) =>
             {
                 BluetoothGattAttributeHandle handle = new BluetoothGattAttributeHandle(attributeHandle, false);
                 BluetoothGattService service = BluetoothGattServiceImpl.CreateBluetoothGattService(handle, ""); ;
@@ -95,7 +101,7 @@ namespace Tizen.Network.Bluetooth
                 return true;
             };
 
-            int err = Interop.Bluetooth.BtGattServerForeachServices(_handle, cb, IntPtr.Zero);
+            int err = Interop.Bluetooth.BtGattServerForeachServices(_handle, _serviceForeachCallback, IntPtr.Zero);
             GattUtil.Error(err, "Failed to get all services");
 
             return attribututeList;
@@ -107,28 +113,44 @@ namespace Tizen.Network.Bluetooth
             GattUtil.ThrowForError(err, string.Format("Failed to send response for request Id {0}", requestId));
         }
 
-        internal void SendNotification(BluetoothGattCharacteristic characteristic, string clientAddress)
-        {
-            int err = Interop.Bluetooth.BtGattServerNotify(characteristic.GetHandle(), null, clientAddress, IntPtr.Zero);
-            GattUtil.ThrowForError(err, string.Format("Failed to send value changed notification for characteristic uuid {0}", characteristic.Uuid));
-        }
-
-        internal Task<bool> SendIndicationAsync(BluetoothGattServer server, BluetoothGattCharacteristic characteristic, string clientAddress)
+        void SendIndicationCallback(int result, string clientAddress, IntPtr serverHandle, IntPtr characteristicHandle, bool completed, IntPtr userData)
         {
-            TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
-            Interop.Bluetooth.BtGattServerNotificationSentCallback cb = (result, address, serverHandle, characteristicHandle, completed, userData) =>
+            int requestId = (int)userData;
+            if (_sendIndicationTaskSource.ContainsKey(requestId))
             {
-                _notificationSent?.Invoke(characteristic, new NotificationSentEventArg(server, address, result, completed));
+                _notificationSent?.Invoke(this, new NotificationSentEventArg(null, clientAddress, result, completed));
                 if (completed)
                 {
-                    tcs.SetResult(true);
+                    _sendIndicationTaskSource[requestId].SetResult(true);
                 }
-            };
+                else
+                {
+                    _sendIndicationTaskSource[requestId].SetResult(false);
+                }
+                _sendIndicationTaskSource.Remove(requestId);
+            }
+        }
+
+        internal Task<bool> SendIndicationAsync(BluetoothGattServer server, BluetoothGattCharacteristic characteristic, string clientAddress)
+        {
+            TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
+            int requestId = 0;
 
-            int err = Interop.Bluetooth.BtGattServerNotify(characteristic.GetHandle(), cb, clientAddress, IntPtr.Zero);
-            GattUtil.ThrowForError(err, string.Format("Failed to send value changed indication for characteristic uuid {0}", characteristic.Uuid));
+            lock (this)
+            {
+                requestId = _requestId++;
+                _sendIndicationTaskSource[requestId] = task;
+            }
 
-            return tcs.Task;
+            int err = Interop.Bluetooth.BtGattServerNotify(characteristic.GetHandle(), _sendIndicationCallback, clientAddress, (IntPtr)requestId);
+            if (err.IsFailed())
+            {
+                GattUtil.Error(err, string.Format("Failed to send value changed indication for characteristic uuid {0}", characteristic.Uuid));
+                task.SetResult(false);
+                _sendIndicationTaskSource.Remove(requestId);
+                BluetoothErrorFactory.ThrowBluetoothException(err);
+            }
+            return task.Task;
         }
 
         internal BluetoothGattServerHandle GetHandle()
@@ -140,11 +162,39 @@ namespace Tizen.Network.Bluetooth
     internal class BluetoothGattClientImpl
     {
         private BluetoothGattClientHandle _handle;
+        int _requestId = 0;
+        Dictionary<int, TaskCompletionSource<bool>> _readValueTaskSource = new Dictionary<int, TaskCompletionSource<bool>>();
+        private Interop.Bluetooth.BtGattClientRequestCompletedCallback _readValueCallback;
+        Dictionary<int, TaskCompletionSource<bool>> _writeValueTaskSource = new Dictionary<int, TaskCompletionSource<bool>>();
+        private Interop.Bluetooth.BtGattClientRequestCompletedCallback _writeValueCallback;
+        private Interop.Bluetooth.BtGattForeachCallback _serviceForeachCallback;
 
         internal BluetoothGattClientImpl(string remoteAddress)
         {
-            int err = Interop.Bluetooth.BtGattClientCreate(remoteAddress, out _handle);
-            GattUtil.ThrowForError(err, "Failed to get native client handle");
+            _readValueCallback = ReadValueCallback;
+            _writeValueCallback = WriteValueCallback;
+
+            if (BluetoothAdapter.IsBluetoothEnabled)
+            {
+                int err = Interop.Bluetooth.BtGattClientCreate(remoteAddress, out _handle);
+                GattUtil.ThrowForError(err, "Failed to get native client handle");
+            }
+            else
+            {
+                BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
+            }
+        }
+
+        internal void Connect(string remoteAddress, bool autoConnect)
+        {
+            int err = Interop.Bluetooth.GattConnect(remoteAddress, autoConnect);
+            GattUtil.ThrowForError(err, "Failed to connect to remote address");
+        }
+
+        internal void Disconnect(string remoteAddress)
+        {
+            int err = Interop.Bluetooth.GattDisconnect(remoteAddress);
+            GattUtil.ThrowForError(err, "Failed to disconnect to remote address");
         }
 
         internal string GetRemoteAddress()
@@ -174,7 +224,7 @@ namespace Tizen.Network.Bluetooth
         internal IEnumerable<BluetoothGattService> GetServices(BluetoothGattClient client)
         {
             List<BluetoothGattService> attribututeList = new List<BluetoothGattService>();
-            Interop.Bluetooth.BtGattForeachCallback cb = (total, index, attributeHandle, userData) =>
+            _serviceForeachCallback = (total, index, attributeHandle, userData) =>
             {
                 BluetoothGattAttributeHandle handle = new BluetoothGattAttributeHandle(attributeHandle, false);
                 BluetoothGattService service = BluetoothGattServiceImpl.CreateBluetoothGattService(handle, "");
@@ -186,52 +236,88 @@ namespace Tizen.Network.Bluetooth
                 return true;
             };
 
-            int err = Interop.Bluetooth.BtGattClientForeachServices(_handle, cb, IntPtr.Zero);
+            int err = Interop.Bluetooth.BtGattClientForeachServices(_handle, _serviceForeachCallback, IntPtr.Zero);
             GattUtil.Error(err, "Failed to get all services");
 
             return attribututeList;
         }
 
-        internal Task<bool> ReadValueAsyncTask(BluetoothGattAttributeHandle handle)
+        void ReadValueCallback(int result, IntPtr requestHandle, IntPtr userData)
         {
-            TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
-            Interop.Bluetooth.BtGattClientRequestCompletedCallback cb = (result, requestHandle, userData) =>
+            int requestId = (int)userData;
+            if (_readValueTaskSource.ContainsKey(requestId))
             {
                 if (result == (int)BluetoothError.None)
-                    tcs.SetResult(true);
+                {
+                    _readValueTaskSource[requestId].SetResult(true);
+                }
                 else
-                    tcs.SetResult(false);
-            };
+                {
+                    _readValueTaskSource[requestId].SetResult(false);
+                }
+            }
+            _readValueTaskSource.Remove(requestId);
+        }
 
-            int err = Interop.Bluetooth.BtGattClientReadValue(handle, cb, IntPtr.Zero);
+        internal Task<bool> ReadValueAsyncTask(BluetoothGattAttributeHandle handle)
+        {
+            TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
+            int requestId = 0;
+
+            lock (this)
+            {
+                requestId = _requestId++;
+                _readValueTaskSource[requestId] = task;
+            }
+
+            int err = Interop.Bluetooth.BtGattClientReadValue(handle, _readValueCallback, (IntPtr)requestId);
             if (err.IsFailed())
             {
                 GattUtil.Error(err, "Failed to read value from remote device");
-                tcs.SetResult(false);
+                task.SetResult(false);
+                _readValueTaskSource.Remove(requestId);
                 BluetoothErrorFactory.ThrowBluetoothException(err);
             }
-            return tcs.Task;
+            return task.Task;
         }
 
-        internal Task<bool> WriteValueAsyncTask(BluetoothGattAttributeHandle handle)
+        void WriteValueCallback(int result, IntPtr requestHandle, IntPtr userData)
         {
-            TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
-            Interop.Bluetooth.BtGattClientRequestCompletedCallback cb = (result, requestHandle, userData) =>
+            int requestId = (int)userData;
+            if (_writeValueTaskSource.ContainsKey(requestId))
             {
                 if (result == (int)BluetoothError.None)
-                    tcs.SetResult(true);
+                {
+                    _writeValueTaskSource[requestId].SetResult(true);
+                }
                 else
-                    tcs.SetResult(false);
-            };
+                {
+                    _writeValueTaskSource[requestId].SetResult(false);
+                }
+            }
+            _writeValueTaskSource.Remove(requestId);
+        }
+
+        internal Task<bool> WriteValueAsyncTask(BluetoothGattAttributeHandle handle)
+        {
+            TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
+            int requestId = 0;
+
+            lock (this)
+            {
+                requestId = _requestId++;
+                _writeValueTaskSource[requestId] = task;
+            }
 
-            int err = Interop.Bluetooth.BtGattClientWriteValue(handle, cb, IntPtr.Zero);
+            int err = Interop.Bluetooth.BtGattClientWriteValue(handle, _writeValueCallback, (IntPtr)requestId);
             if (err.IsFailed())
             {
                 GattUtil.Error(err, "Failed to write value to remote device");
-                tcs.SetResult(false);
+                task.SetResult(false);
+                _writeValueTaskSource.Remove(requestId);
                 BluetoothErrorFactory.ThrowBluetoothException(err);
             }
-            return tcs.Task;
+            return task.Task;
         }
 
         internal BluetoothGattClientHandle GetHandle()
@@ -242,6 +328,9 @@ namespace Tizen.Network.Bluetooth
 
     internal class BluetoothGattServiceImpl : BluetoothGattAttributeImpl
     {
+        private Interop.Bluetooth.BtGattForeachCallback _characteristicForeachCallback;
+        private Interop.Bluetooth.BtGattForeachCallback _includedServiceForeachCallback;
+
         internal BluetoothGattServiceImpl(string uuid, BluetoothGattServiceType type)
         {
             int err = Interop.Bluetooth.BtGattServiceCreate(uuid, (int)type, out _handle);
@@ -289,7 +378,7 @@ namespace Tizen.Network.Bluetooth
         internal IEnumerable<BluetoothGattCharacteristic> GetCharacteristics(BluetoothGattService service)
         {
             List<BluetoothGattCharacteristic> attribututeList = new List<BluetoothGattCharacteristic>();
-            Interop.Bluetooth.BtGattForeachCallback cb = (total, index, attributeHandle, userData) =>
+            _characteristicForeachCallback = (total, index, attributeHandle, userData) =>
             {
                 BluetoothGattAttributeHandle handle = new BluetoothGattAttributeHandle(attributeHandle, false);
                 BluetoothGattCharacteristic Characteristic = BluetoothGattCharacteristicImpl.CreateBluetoothGattGattCharacteristic(handle, "");
@@ -301,7 +390,7 @@ namespace Tizen.Network.Bluetooth
                 return true;
             };
 
-            int err = Interop.Bluetooth.BtGattServiceForeachCharacteristics(service.GetHandle(), cb, IntPtr.Zero);
+            int err = Interop.Bluetooth.BtGattServiceForeachCharacteristics(service.GetHandle(), _characteristicForeachCallback, IntPtr.Zero);
             GattUtil.Error(err, "Failed to get all Characteristic");
 
             return attribututeList;
@@ -331,7 +420,7 @@ namespace Tizen.Network.Bluetooth
         internal IEnumerable<BluetoothGattService> GetIncludeServices(BluetoothGattService parentService)
         {
             List<BluetoothGattService> attribututeList = new List<BluetoothGattService>();
-            Interop.Bluetooth.BtGattForeachCallback cb = (total, index, attributeHandle, userData) =>
+            _includedServiceForeachCallback = (total, index, attributeHandle, userData) =>
             {
                 BluetoothGattAttributeHandle handle = new BluetoothGattAttributeHandle(attributeHandle, false);
                 BluetoothGattService service = BluetoothGattServiceImpl.CreateBluetoothGattService(handle, "");
@@ -343,7 +432,7 @@ namespace Tizen.Network.Bluetooth
                 return true;
             };
 
-            int err = Interop.Bluetooth.BtGattServiceForeachIncludedServices(parentService.GetHandle(), cb, IntPtr.Zero);
+            int err = Interop.Bluetooth.BtGattServiceForeachIncludedServices(parentService.GetHandle(), _includedServiceForeachCallback, IntPtr.Zero);
             GattUtil.Error(err, "Failed to get all services");
 
             return attribututeList;
@@ -352,6 +441,8 @@ namespace Tizen.Network.Bluetooth
 
     internal class BluetoothGattCharacteristicImpl : BluetoothGattAttributeImpl
     {
+        private Interop.Bluetooth.BtGattForeachCallback _descriptorForeachCallback;
+
         internal BluetoothGattCharacteristicImpl(string uuid, BluetoothGattPermission permission, BluetoothGattProperty property, byte[] value)
         {
             int err = Interop.Bluetooth.BtGattCharacteristicCreate(uuid, (int)permission, (int)property, value, value.Length, out _handle);
@@ -448,7 +539,7 @@ namespace Tizen.Network.Bluetooth
         internal IEnumerable<BluetoothGattDescriptor> GetDescriptors(BluetoothGattCharacteristic characteristic)
         {
             List<BluetoothGattDescriptor> attribututeList = new List<BluetoothGattDescriptor>();
-            Interop.Bluetooth.BtGattForeachCallback cb = (total, index, attributeHandle, userData) =>
+            _descriptorForeachCallback = (total, index, attributeHandle, userData) =>
             {
                 BluetoothGattAttributeHandle handle = new BluetoothGattAttributeHandle(attributeHandle, false);
                 BluetoothGattDescriptor descriptor = BluetoothGattDescriptorImpl.CreateBluetoothGattDescriptor(handle, "");
@@ -460,7 +551,7 @@ namespace Tizen.Network.Bluetooth
                 return true;
             };
 
-            int err = Interop.Bluetooth.BtGattCharacteristicForeachDescriptors(characteristic.GetHandle(), cb, IntPtr.Zero);
+            int err = Interop.Bluetooth.BtGattCharacteristicForeachDescriptors(characteristic.GetHandle(), _descriptorForeachCallback, IntPtr.Zero);
             GattUtil.Error(err, "Failed to get all descriptor");
 
             return attribututeList;
@@ -637,8 +728,22 @@ namespace Tizen.Network.Bluetooth
         {
             if (_hasOwnership == true)
             {
-                Interop.Bluetooth.BtGattServerDeinitialize();
-                Interop.Bluetooth.BtGattServerDestroy(handle);
+                int err;
+
+                err = Interop.Bluetooth.BtGattServerDestroy(handle);
+                if (err.IsFailed())
+                {
+                    Log.Error(Globals.LogTag, "Failed to destroy the server instance");
+                    return false;
+                }
+
+                err = Interop.Bluetooth.BtGattServerDeinitialize();
+                if (err.IsFailed())
+                {
+                    Log.Error(Globals.LogTag, "Failed to deinitialize");
+                    SetHandle(IntPtr.Zero);
+                    return false;
+                }
             }
             SetHandle(IntPtr.Zero);
             return true;