/* * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace Tizen.Network.Bluetooth { /// /// The Bluetooth GATT server. /// /// 3 public class BluetoothGattServer : IDisposable { private static BluetoothGattServer _instance; private BluetoothGattServerImpl _impl; private BluetoothGattServer() { _impl = new BluetoothGattServerImpl(); } /// /// (event) This event is called when the indication acknowledgement is received for each notified client. /// /// 3 public event EventHandler NotificationSent { add { _impl._notificationSent += value; } remove { _impl._notificationSent -= value; } } /// /// Creates the Bluetooth GATT server. /// /// The BluetoothGattServer instance. /// http://tizen.org/feature/network.bluetooth.le.gatt.server /// Thrown when the BT/BTLE is not supported. /// Thrown when the create GATT server fails. /// 3 public static BluetoothGattServer CreateServer() { if (_instance == null) { BluetoothGattServer server = new BluetoothGattServer(); if (server.IsValid()) { _instance = server; } } return _instance; } /// /// Registers the server along with the GATT services of the application it is hosting. /// /// http://tizen.org/feature/network.bluetooth.le.gatt.server /// Thrown when the BT/BTLE is not supported. /// Thrown when the register server application fails. /// 3 public void Start() { _impl.Start(); } /// /// Registers a specified service to this server. /// /// The service, which needs to be registered with this server. /// http://tizen.org/feature/network.bluetooth.le.gatt.server /// Thrown when the BT/BTLE is not supported. /// Thrown when the register service fails. /// 3 public void RegisterGattService(BluetoothGattService service) { if (service.IsRegistered()) { BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.InvalidParameter); } _impl.RegisterGattService(this, service); } /// /// Unregisters a specified service from this server. /// /// The service, which needs to be unregistered from this server. /// /// Once unregistered, the service object will become invalid and should not be used to access sevices or any children attribute's methods/members. /// /// http://tizen.org/feature/network.bluetooth.le.gatt.server /// Thrown when the BT/BTLE is not supported. /// Thrown when the unregister service fails. /// 3 public void UnregisterGattService(BluetoothGattService service) { if (service.GetGattServer() != this) { BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.InvalidParameter); } _impl.UnregisterGattService(service); } /// /// Unregisters all services from this server. /// /// /// Once unregistered, servicees will become invalid and should not be used to access sevices or any children attribute's methods/members. /// /// http://tizen.org/feature/network.bluetooth.le.gatt.server /// Thrown when the BT/BTLE is not supported. /// Thrown when the unregister all services fail. /// 3 public void UnregisterGattServices() { _impl.UnregisterAllGattServices(this); } /// /// Gets service with given UUID that belongs to this server. /// /// The UUID for the service to get. /// The Service with the given UUID if it exists, null otherwise. /// http://tizen.org/feature/network.bluetooth.le.gatt.server /// Thrown when the BT/BTLE is not supported. /// Thrown when the service is not registered. /// 3 public BluetoothGattService GetService(string uuid) { return _impl.GetService(this, uuid); } /// /// Gets the list of services that belongs to this server. /// /// The list of services that belongs to this server. /// http://tizen.org/feature/network.bluetooth.le.gatt.server /// Thrown when the BT/BTLE is not supported. /// Thrown when the service is not registered. /// 3 public IEnumerable GetServices() { return _impl.GetServices(this); } /// /// Sends indication for the value change of the characteristic to the remote devices. /// /// The characteristic whose the value is changed. /// The remote device address to send, notify, or indicate and if set to NULL, then notify/indicate all is enabled. /// true on success, false otherwise. /// http://tizen.org/feature/network.bluetooth.le.gatt.server /// Thrown when the BT/BTLE is not supported. /// Thrown when the BT/BTLE is not enabled /// or when the remote device is disconnected, or when service is not registered, or when the CCCD is not enabled. /// 3 public async Task SendIndicationAsync(BluetoothGattCharacteristic characteristic, string clientAddress) { return await _impl.SendIndicationAsync(this, characteristic, clientAddress); } /// /// Sends the notification for the value change of the characteristic to the remote devices. /// /// The characteristic, which has a changed value. /// The remote device address to send, notify, or indicate and if set to NULL, then notify/indicate all is enabled. /// http://tizen.org/feature/network.bluetooth.le.gatt.server /// Thrown when the BT/BTLE is not supported. /// Thrown when the BT/BTLE is not enabled /// or when the remote device is disconnected, or when service is not registered, or when the CCCD is not enabled. /// 3 public void SendNotification(BluetoothGattCharacteristic characteristic, string clientAddress) { _impl.SendNotification(characteristic, clientAddress); } /// /// Sends a response to the remote device as a result of a read/write request. /// /// The identification of a read/write request. /// The request type for read/write. /// The error value in case of failure, 0 for success. /// The value to be sent. /// The offset from where the value is read. /// http://tizen.org/feature/network.bluetooth.le.gatt.server /// Thrown when the BT/BTLE is not supported. /// Thrown when the BT/BTLE is not enabled /// or when the remote device is disconnected, or the send response procedure fails. /// 3 public void SendResponse(int requestId, BluetoothGattRequestType type, int status, byte[] value, int offset) { _impl.SendResponse(requestId, (int)type, status, value, offset); } internal bool IsValid() { return _impl.GetHandle().IsInvalid == false; } /// /// Destroys the current object. /// ~BluetoothGattServer() { Dispose(false); } /// /// Destroys the current object. /// /// http://tizen.org/feature/network.bluetooth.le.gatt.server /// 6 public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// Releases all the resources currently used by this instance. /// /// true if the managed resources should be disposed, otherwise false. /// 6 protected virtual void Dispose(bool disposing) { if (disposing) { _impl?.GetHandle()?.Dispose(); _instance = null; } } } /// /// The Bluetooth GATT client. /// /// 3 public class BluetoothGattClient : IDisposable { private BluetoothGattClientImpl _impl; private string _remoteAddress = string.Empty; private TaskCompletionSource _taskForConnection; private TaskCompletionSource _taskForDisconnection; private static event EventHandler s_connectionStateChanged; private static Interop.Bluetooth.GattConnectionStateChangedCallBack s_connectionStateChangeCallback; internal BluetoothGattClient(string remoteAddress) { _impl = new BluetoothGattClientImpl(remoteAddress); _remoteAddress = remoteAddress; StaticConnectionStateChanged += OnConnectionStateChanged; } /// /// Creates the Bluetooth GATT client. /// /// The BluetoothGattClient instance. /// http://tizen.org/feature/network.bluetooth.le.gatt.client /// Thrown when the BT/BTLE is not supported. /// Thrown when the create GATT client fails. /// 6 public static BluetoothGattClient CreateClient(string remoteAddress) { BluetoothGattClient client = new BluetoothGattClient(remoteAddress); return client.Isvalid() ? client : null; } /// /// The ConnectionStateChanged event is raised when the gatt connection state is changed. /// /// 6 public event EventHandler ConnectionStateChanged; private void OnConnectionStateChanged(Object s, GattConnectionStateChangedEventArgs e) { if (e.RemoteAddress == _remoteAddress) { if (_taskForConnection != null && !_taskForConnection.Task.IsCompleted) { if (e.Result == (int)BluetoothError.None) { _taskForConnection.SetResult(true); } else { _taskForConnection.SetException(BluetoothErrorFactory.CreateBluetoothException((int)e.Result)); } _taskForConnection = null; } if (_taskForDisconnection != null && !_taskForDisconnection.Task.IsCompleted) { if (e.Result == (int)BluetoothError.None) { _taskForDisconnection.SetResult(true); } else { _taskForDisconnection.SetException(BluetoothErrorFactory.CreateBluetoothException(e.Result)); } _taskForDisconnection = null; } if (e.Result == (int)BluetoothError.None) { ConnectionStateChanged?.Invoke(this, e); } } } private static event EventHandler StaticConnectionStateChanged { add { if (s_connectionStateChanged == null) { RegisterConnectionStateChangedEvent(); } s_connectionStateChanged += value; } remove { s_connectionStateChanged -= value; if (s_connectionStateChanged == null) { UnregisterConnectionStateChangedEvent(); } } } private static void RegisterConnectionStateChangedEvent() { s_connectionStateChangeCallback = (int result, bool connected, string remoteDeviceAddress, IntPtr userData) => { Log.Info(Globals.LogTag, "Setting gatt connection state changed callback"); GattConnectionStateChangedEventArgs e = new GattConnectionStateChangedEventArgs(result, connected, remoteDeviceAddress); s_connectionStateChanged?.Invoke(null, e); }; int ret = Interop.Bluetooth.SetGattConnectionStateChangedCallback(s_connectionStateChangeCallback, IntPtr.Zero); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to set gatt connection state changed callback, Error - " + (BluetoothError)ret); BluetoothErrorFactory.ThrowBluetoothException(ret); } } private static void UnregisterConnectionStateChangedEvent() { int ret = Interop.Bluetooth.UnsetGattConnectionStateChangedCallback(); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to unset gatt connection state changed callback, Error - " + (BluetoothError)ret); BluetoothErrorFactory.ThrowBluetoothException(ret); } } /// /// Connects to the remote GATT server asynchronously. /// /// The flag for reconnecting when the connection is disconnceted. /// A task indicating whether the method is done or not. /// http://tizen.org/feature/network.bluetooth.le.gatt.client /// http://tizen.org/privilege/bluetooth /// Thrown when the BT/BTLE is not supported. /// Thrown when the create GATT client fails. /// 6 public Task ConnectAsync(bool autoConnect) { if (_taskForConnection != null && !_taskForConnection.Task.IsCompleted) { BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NowInProgress); } _taskForConnection = new TaskCompletionSource(); _impl.Connect(_remoteAddress, autoConnect); return _taskForConnection.Task; } /// /// Disconnects to the remote GATT server asynchronously. /// /// A task indicating whether the method is done or not. /// http://tizen.org/feature/network.bluetooth.le.gatt.client /// http://tizen.org/privilege/bluetooth /// Thrown when the BT/BTLE is not supported. /// Thrown when the create GATT client fails. /// 6 public Task DisconnectAsync() { if (_taskForDisconnection != null && !_taskForDisconnection.Task.IsCompleted) { BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NowInProgress); } _taskForDisconnection = new TaskCompletionSource(); _impl.Disconnect(_remoteAddress); return _taskForDisconnection.Task; } /// /// Destroy Bluetooth GATT client /// /// 3 public void DestroyClient() { _impl.GetHandle().Dispose(); } /// /// The address of the remote device. /// /// Thrown when the BT/BTLE is not enabled /// or when the remote device is disconnected. /// 3 public string RemoteAddress { get { if (string.IsNullOrEmpty(_remoteAddress)) { _remoteAddress = _impl.GetRemoteAddress(); } return _remoteAddress; } } /// /// Gets the service with the given UUID that belongs to the remote device. /// /// The UUID for the service to get. /// The service with the given UUID if it exists, null otherwise. /// Thrown when the BT/BTLE is not enabled /// or when the remote device is disconnected, or when the get service fails. /// 3 public BluetoothGattService GetService(string uuid) { return _impl.GetService(this, uuid); } /// /// Gets list of services that belongs to the remote device. /// /// The list of services that belongs to the remote device. /// Thrown when the BT/BTLE is not enabled /// or when the remote device is disconnected, or when the get service fails. /// 3 public IEnumerable GetServices() { return _impl.GetServices(this); } /// /// Reads the value of a given characteristic from the remote device asynchronously. /// /// The characteristic to be read. /// true on success, false otherwise. /// Thrown when the BT/BTLE is not enabled /// or when the remote device is disconnected, or when the read attribute value fails. /// 3 public async Task ReadValueAsync(BluetoothGattCharacteristic characteristic) { return await _impl.ReadValueAsyncTask(characteristic.GetHandle()); } /// /// Reads the value of the given descriptor from the remote device asynchronously. /// /// The descriptor to be read. /// true on success, false otherwise. /// Thrown when the BT/BTLE is not enabled /// or when the remote device is disconnected, or when the read attribute value fails. /// 3 public async Task ReadValueAsync(BluetoothGattDescriptor descriptor) { return await _impl.ReadValueAsyncTask(descriptor.GetHandle()); } /// /// Writes the value of a given characteristic to the remote device asynchronously. /// /// The characteristic to be written. /// true on success, false otherwise. /// Thrown when the BT/BTLE is not enabled /// or when the remote device is disconnected or when the write attribute value fails. /// 3 public async Task WriteValueAsync(BluetoothGattCharacteristic characteristic) { return await _impl.WriteValueAsyncTask(characteristic.GetHandle()); } /// /// Writes the value of the given descriptor to the remote device asynchronously. /// /// The descriptor to be written. /// true on success, false otherwise. /// Thrown when the BT/BTLE is not enabled /// or when the remote device is disconnected, or when the write attribute value fails. /// 3 public async Task WriteValueAsync(BluetoothGattDescriptor descriptor) { return await _impl.WriteValueAsyncTask(descriptor.GetHandle()); } internal bool Isvalid() { return _impl.GetHandle().IsInvalid == false; } /// /// Destroys the current object. /// ~BluetoothGattClient() { Dispose(false); } /// /// Destroys the current object. /// /// http://tizen.org/feature/network.bluetooth.le.gatt.client /// 6 public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// Releases all the resources currently used by this instance. /// /// true if the managed resources should be disposed, otherwise false. /// 6 protected virtual void Dispose(bool disposing) { if (disposing) { _impl?.GetHandle()?.Dispose(); _impl = null; StaticConnectionStateChanged -= OnConnectionStateChanged; } } } /// /// The Bluetooth GATT service. /// /// 3 public class BluetoothGattService { private BluetoothGattServiceImpl _impl; private BluetoothGattClient _parentClient = null; private BluetoothGattServer _parentServer = null; private BluetoothGattService _parentService = null; /// /// The constructor. /// /// The UUID of the service. /// The type of service. /// Thrown when the create GATT service procedure fails. /// 3 public BluetoothGattService(string uuid, BluetoothGattServiceType type) { Uuid = uuid; _impl = new BluetoothGattServiceImpl(uuid, type); } internal BluetoothGattService(BluetoothGattServiceImpl impl, string uuid) { Uuid = uuid; _impl = impl; } /// /// Specification name from the UUID. /// /// 3 public string Uuid { get; } /// /// Adds a characteristic to this service. /// /// The characteristic to be added. /// true on success, false otherwise. /// Thrown when the add GATT characteristic procedure fails. /// 3 public void AddCharacteristic(BluetoothGattCharacteristic characteristic) { if (GetGattClient() != null) { BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotSupported); } if (characteristic.GetService() != null) { BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.InvalidParameter); } _impl.AddCharacteristic(characteristic); characteristic.SetParent(this); } /// /// Gets the characteristic with the given UUID that belongs to this service. /// /// The UUID for the characteristic to get. /// The characteristic with a given UUID if it exists, null otherwise. /// 3 public BluetoothGattCharacteristic GetCharacteristic(string uuid) { return _impl.GetCharacteristic(this, uuid); } /// /// Gets list of the characteristic that belongs to this service. /// /// The list of the characteristic that belongs to this service. /// 3 public IEnumerable GetCharacteristics() { return _impl.GetCharacteristics(this); } /// /// Includes a service to this service. /// /// The service to be included. /// true on success, false otherwise /// Thrown when the add GATT service procedure fails./// /// 3 public void AddService(BluetoothGattService service) { if (GetGattClient() != null) { BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotSupported); } if (service.IsRegistered()) { BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.InvalidParameter); } _impl.AddIncludeService(service); service.SetParent(this); } /// /// Gets the included service. /// /// The UUID for the service to get. /// The service with a given UUID if it exists, null otherwise. /// 3 public BluetoothGattService GetIncludeService(string uuid) { return _impl.GetIncludeService(this, uuid); } /// /// Gets the included service list of this service. /// /// The included service list of this service. /// 3 public IEnumerable GetIncludeServices() { return _impl.GetIncludeServices(this); } /// /// Gets the server instance which the specified service belongs to. /// /// The server instance which the specified service belongs to. /// 3 public BluetoothGattServer GetGattServer() { return _parentServer; } /// /// Gets the client instance which the specified service belongs to. /// /// The client instance which the specified service belongs to. /// 3 public BluetoothGattClient GetGattClient() { return _parentClient; } internal BluetoothGattAttributeHandle GetHandle() { return _impl.GetHandle(); } internal void SetParent(BluetoothGattService parent) { if (!IsRegistered()) { _parentService = parent; _impl.ReleaseHandleOwnership(); } } internal void SetParent(BluetoothGattClient parent) { if (!IsRegistered()) { _parentClient = parent; _impl.ReleaseHandleOwnership(); } } internal void SetParent(BluetoothGattServer parent) { if (!IsRegistered()) { _parentServer = parent; _impl.ReleaseHandleOwnership(); } } internal void UnregisterService() { _parentServer = null; _parentClient = null; _parentService = null; } internal bool IsRegistered() { return _parentClient != null || _parentServer != null || _parentService != null; } } /// /// The Bluetooth GATT characteristic. /// /// 3 public class BluetoothGattCharacteristic : BluetoothGattAttribute { private BluetoothGattCharacteristicImpl _impl; private BluetoothGattService _parent = null; private Interop.Bluetooth.BtClientCharacteristicValueChangedCallback _characteristicValueChangedCallback; private Interop.Bluetooth.BtGattServerNotificationStateChangeCallback _notificationStateChangedCallback; private EventHandler _characteristicValueChanged; internal EventHandler _notificationStateChanged; /// /// The constructor. /// /// The UUID of the characterstic. /// Permissions for the characterstic. /// Properties set for the characterstic. /// The value associated with the characterstic. /// throws in case of internal error. /// Thrown when the create GATT characteristics procedure fails. /// 3 public BluetoothGattCharacteristic(string uuid, BluetoothGattPermission permissions, BluetoothGattProperty properties, byte[] value) : base(uuid, permissions) { _impl = new BluetoothGattCharacteristicImpl(uuid, permissions, properties, value); } internal BluetoothGattCharacteristic(BluetoothGattCharacteristicImpl impl, string uuid, BluetoothGattPermission permission) : base(uuid, permission) { _impl = impl; } /// /// The CharacteristicValueChanged event is raised when the server notifies for change in this characteristic value. /// /// /// Adding the event handle on characteristic on the server side will not have any effect. /// /// 3 public event EventHandler ValueChanged { add { if (Client != null) { if (_characteristicValueChanged == null) { _characteristicValueChangedCallback = (gattHandle, characteristicValue, len, userData) => { _characteristicValueChanged?.Invoke(this, new ValueChangedEventArgs(characteristicValue, len)); }; _impl.SetCharacteristicValueChangedEvent(_characteristicValueChangedCallback); } _characteristicValueChanged = value; } } remove { if (Client != null) { _characteristicValueChanged = null; if (_characteristicValueChanged == null) { _impl.UnsetCharacteristicValueChangedEvent(); } } } } /// /// The NotificationStateChanged event is called when the client enables or disables the Notification/Indication for particular characteristics. /// /// /// Adding event handle on the characteristic on the client side will not have any effect. /// /// 3 public event EventHandler NotificationStateChanged { add { if (Server != null) { if (_notificationStateChangedCallback == null) { _notificationStateChangedCallback = (notify, serverHandle, characteristicHandle, userData) => { _notificationStateChanged?.Invoke(this, new NotificationStateChangedEventArg(Server, notify)); }; _impl.SetNotificationStateChangedEvent(_notificationStateChangedCallback); } _notificationStateChanged = value; } } remove { if (Server != null) { _notificationStateChanged = null; // CAPI does not allow unsetting ReadValueRequestedEventCallback. } } } /// /// The property for this characteristic. /// /// 3 public BluetoothGattProperty Properties { get { return _impl.GetProperties(); } set { if (Server != null) { _impl.SetProperties(value); } } } /// /// The write type to be used for write operations. /// /// 3 public BluetoothGattWriteType WriteType { get { return _impl.GetWriteType(); } set { _impl.SetWriteType(value); } } internal override BluetoothGattClient Client { get { return _parent?.GetGattClient(); } } internal override BluetoothGattServer Server { get { return _parent?.GetGattServer(); } } internal override BluetoothGattAttributeImpl Impl { get { return _impl; } } /// /// Adds a descriptor to this characteristic. /// /// The descriptor to be added. /// true on success, false otherwise. /// Thrown when the add GATT descriptor procedure fails. /// 3 public void AddDescriptor(BluetoothGattDescriptor descriptor) { if (Client != null) { BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotSupported); } if (descriptor.GetCharacteristic() != null) { BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.InvalidParameter); } _impl.AddDescriptor(descriptor); descriptor.SetParent(this); } /// /// Gets the descriptor with the given UUID that belongs to this characteristic. /// /// The UUID for the descriptor to get. /// The descriptor with a given UUID if it exists, null otherwise. /// 3 public BluetoothGattDescriptor GetDescriptor(string uuid) { return _impl.GetDescriptor(this, uuid); } /// /// Gets the list of descriptors that belongs to this characteristic. /// /// The list of descriptors that belongs to this characteristic. /// 3 public IEnumerable GetDescriptors() { return _impl.GetDescriptors(this); } /// /// Gets the service instance, which the specified characterstic belongs to. /// /// The characteristic instance, the specified characterstic belongs to. /// 3 public BluetoothGattService GetService() { return _parent; } internal void SetParent(BluetoothGattService parent) { if (_parent == null) { _parent = parent; ReleaseHandleOwnership(); } } } /// /// The Bluetooth GATT descriptor. /// /// 3 public class BluetoothGattDescriptor : BluetoothGattAttribute { private BluetoothGattCharacteristic _parent = null; private BluetoothGattDescriptorImpl _impl; /// /// The constructor. /// /// The UUID of the descriptor. /// Permissions for the descriptor. /// The value associated with the descriptor. /// throws in case of internal error. /// Thrown when the create GATT descriptor procedure fails. /// 3 public BluetoothGattDescriptor(string uuid, BluetoothGattPermission permisions, byte[] value) : base (uuid, permisions) { _impl = new BluetoothGattDescriptorImpl(uuid, permisions, value); } internal BluetoothGattDescriptor(BluetoothGattDescriptorImpl impl, string uuid, BluetoothGattPermission permission) : base(uuid, permission) { _impl = impl; } internal override BluetoothGattClient Client { get { return _parent?.Client; } } internal override BluetoothGattServer Server { get { return _parent?.Server; } } internal override BluetoothGattAttributeImpl Impl { get { return _impl; } } /// /// Gets the characteristic instance, which the specified descriptor belongs to. /// /// The characteristic instance, the specified descriptor belongs to. /// 3 public BluetoothGattCharacteristic GetCharacteristic() { return _parent; } internal void SetParent(BluetoothGattCharacteristic parent) { if (_parent == null) { _parent = parent; ReleaseHandleOwnership(); } } } /// /// The Bluetooth GATT attribute. /// /// 3 public abstract class BluetoothGattAttribute { private Interop.Bluetooth.BtGattServerReadValueRequestedCallback _readValueRequestedCallback; private Interop.Bluetooth.BtGattServerWriteValueRequestedCallback _writeValueRequestedCallback; private EventHandler _readValueRequested; private EventHandler _writeValueRequested; /// /// The constructor. /// /// The UUID of the GATT attribute. /// Permission for the GATT attribute. /// 3 public BluetoothGattAttribute(string uuid, BluetoothGattPermission permission) { Uuid = uuid; Permissions = permission; } // Events /// /// This event is called when the client request to read the value of a characteristic or a descriptor. /// /// Thrown when the set read value requested callback procedure fails. /// 3 public event EventHandler ReadRequested { add { if (Server == null) return; if (_readValueRequestedCallback == null) { _readValueRequestedCallback = (clientAddress, requestId, serverHandle, gattHandle, offset, userData) => { _readValueRequested?.Invoke(this, new ReadRequestedEventArgs(Server, clientAddress, requestId, offset)); }; Impl.SetReadValueRequestedEventCallback(_readValueRequestedCallback); } _readValueRequested = value; } remove { if (Server == null) return; _readValueRequested = null; // CAPI does not allow unsetting ReadValueRequestedEventCallback. } } /// /// This event is called when a value of a characteristic or a descriptor has been changed by a client. /// /// Thrown when the set write value requested callback procedure fails. /// 3 public event EventHandler WriteRequested { add { if (Server == null) return; if (_writeValueRequested == null) { _writeValueRequestedCallback = (clientAddress, requestId, serverHandle, gattHandle, response_needed, offset, valueToWrite, len, userData) => { _writeValueRequested?.Invoke(this, new WriteRequestedEventArgs(Server, clientAddress, requestId, valueToWrite, offset, response_needed)); }; Impl.SetWriteValueRequestedEventCallback(_writeValueRequestedCallback); } _writeValueRequested = value; } remove { if (Server == null) return; _writeValueRequested = null; // CAPI does not allow unsetting ReadValueRequestedEventCallback. } } /// /// The attribute's UUID. /// /// 3 public string Uuid { get; } /// /// Permissions for this attribute. /// /// 3 public BluetoothGattPermission Permissions { get; } /// /// The value of this descriptor. /// /// 3 public byte[] Value { get { return Impl.GetValue(); } set { Impl.SetValue(value); } } internal abstract BluetoothGattClient Client { get; } internal abstract BluetoothGattServer Server { get; } internal abstract BluetoothGattAttributeImpl Impl { get; } /// /// Returns a string value at the specified offset. /// /// An offset in the attribute value buffer. /// The string value at specified offset. /// 3 public string GetValue(int offset) { return Impl.GetValue(offset); } /// /// Sets the string value as a specified offset. /// /// value to set /// Throws exception if the value is null. /// 3 public void SetValue(string value) { if (string.IsNullOrEmpty(value)) GattUtil.ThrowForError((int)BluetoothError.InvalidParameter, "value should not be null"); byte[] val = Encoding.UTF8.GetBytes(value); Impl.SetValue(val); } /// /// Returns a value at specified offset as the int value of the specified type. /// /// The type of the int value. /// An offset in the attribute value buffer. /// The int value at given offset. /// Throws exception if (offset + size of int value) is greater than the length of the value buffer. /// 3 public int GetValue(IntDataType type, int offset) { return Impl.GetValue(type, offset); } /// /// Updates a value at the specified offset by the int value of the specified type. /// /// The type of the int value. /// The value to set. /// An offset in the attribute value buffer. /// Throws exception if (offset + size of int value) is greater than the length of the value buffer. /// 3 public void SetValue(IntDataType type, int value, int offset) { Impl.SetValue(type, value, offset); } /// /// Returns a value at the specified offset as the float value of the specified type. /// /// The type of the float value. /// An offset in the attribute value buffer. /// The float value at given offset. /// Throws exception if (offset + size of float value) is greater than the length of the value buffer. /// 3 public float GetValue(FloatDataType type, int offset) { return Impl.GetValue(type, offset); } /// /// Updates the value at the specified offset by the float value of the specified type. /// /// The type of the float value. /// The mantissa of the float value. /// An exponent of the float value. /// An offset in the attribute value buffer. /// Throws exception if (offset + size of float value) is greater than the length of the value buffer. /// 3 public void SetValue(FloatDataType type, int mantissa, int exponent, int offset) { Impl.SetValue(type, mantissa, exponent, offset); } internal void ReleaseHandleOwnership() { Impl.ReleaseHandleOwnership(); } internal BluetoothGattAttributeHandle GetHandle() { return Impl.GetHandle(); } } }