{
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");
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, ""); ;
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;
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()
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()
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, "");
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()
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);
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, "");
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;
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, "");
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;
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);
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, "");
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;
{
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;