/* * 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.Threading.Tasks; using System.Collections.Generic; using System.Collections.Specialized; using System.Runtime.InteropServices; namespace Tizen.Network.Bluetooth { /// /// This is the BluetoothLeAdvertiser class. It handles the LE advertising operation amd callback. /// public class BluetoothLeAdvertiser { private static readonly BluetoothLeAdvertiser _instance = new BluetoothLeAdvertiser(); internal static BluetoothLeAdvertiser Instance { get { return _instance; } } private BluetoothLeAdvertiser() { } /// /// This event is called when the LE advertising state changes. /// public event EventHandler AdvertisingStateChanged { add { BluetoothLeImplAdapter.Instance.AdapterLeAdvertisingStateChanged += value; } remove { BluetoothLeImplAdapter.Instance.AdapterLeAdvertisingStateChanged -= value; } } /// /// Starts advertising using the advertise data object. /// /// /// The Bluetooth must be enabled. /// /// The advertiser object carrying information of the advertising. /// Thrown when the Bluetooth LE is not supported. /// Thrown when the Bluetooth LE is not enabled. public void StartAdvertising(BluetoothLeAdvertiseData advertiseData) { if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { int ret = BluetoothLeImplAdapter.Instance.StartAdvertising (advertiseData.GetHandle ()); if (ret != (int)BluetoothError.None) { Log.Error (Globals.LogTag, "Failed to start advertising- " + (BluetoothError)ret); BluetoothErrorFactory.ThrowBluetoothException(ret); } } else { BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled); } } /// /// Stops the advertising. /// /// /// The Bluetooth must be enabled. /// /// The advertiser object carrying information of the advertising. /// Thrown when the Bluetooth LE is not supported. /// Thrown when the Bluetooth LE is not enabled. public void StopAdvertising(BluetoothLeAdvertiseData advertiseData) { if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { int ret = BluetoothLeImplAdapter.Instance.StopAdvertising (advertiseData.GetHandle ()); if (ret != (int)BluetoothError.None) { Log.Error (Globals.LogTag, "Failed to stop advertising operation- " + (BluetoothError)ret); BluetoothErrorFactory.ThrowBluetoothException(ret); } } else { BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled); } } } /// /// This is the BluetoothLeDevice class. /// It handles the LE device operations like getting data from the scan result information. /// public class BluetoothLeDevice { //properties of Bluetoothlesacandata private string _remoteAddress; private BluetoothLeDeviceAddressType _addressType; private int _rssi; private byte[] _advDataValue; private byte[] _scanDataValue; private BluetoothLePacketType _packetType; private BluetoothLeScanData _scanData; /// /// This event is called when the GATT client connects/disconnects with the server. /// public event EventHandler GattConnectionStateChanged { add { BluetoothLeImplAdapter.Instance.LeGattConnectionStateChanged += value; } remove { BluetoothLeImplAdapter.Instance.LeGattConnectionStateChanged -= value; } } internal BluetoothLeDevice(BluetoothLeScanData scanData) { _scanData = new BluetoothLeScanData (); _scanData = scanData; Log.Info (Globals.LogTag, "Rssi" + _scanData.Rssi); _rssi = scanData.Rssi; Log.Info (Globals.LogTag, "RemoteAddress" + _scanData.RemoteAddress); if (scanData.RemoteAddress != null) _remoteAddress = scanData.RemoteAddress; Log.Info (Globals.LogTag, "AddressType" + _scanData.AddressType); _addressType = scanData.AddressType; Log.Info (Globals.LogTag, "AdvDataLength" + _scanData.AdvDataLength); if (_scanData.AdvDataLength > 0) { _advDataValue = new byte[_scanData.AdvDataLength]; scanData.AdvData.CopyTo(_advDataValue, 0); } Log.Info(Globals.LogTag, "ScanDataLength" + _scanData.ScanDataLength); // Check length before copying if (_scanData.ScanDataLength > 0) { _scanDataValue = new byte[_scanData.ScanDataLength]; scanData.ScanData.CopyTo(_scanDataValue, 0); } } /// /// BluetoothLeDevice destructor. /// ~BluetoothLeDevice() { if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { BluetoothLeImplAdapter.Instance.FreeServiceDataList(); } } /// /// The remote address. /// public string RemoteAddress { get { return _remoteAddress; } } /// /// The type of the address. /// public BluetoothLeDeviceAddressType AddressType { get { return _addressType; } } /// /// The rssi value. /// public int Rssi { get { return _rssi; } } /// /// The advertsing data information. /// public byte[] AdvertsingDataInformation { get { return _advDataValue; } } /// /// The scan data information. /// public byte[] ScanDataInformation { get { return _scanDataValue; } } /// /// The type of the packet. /// public BluetoothLePacketType PacketType { get { return _packetType; } set { _packetType = value; } } /// /// Gets the service UUIDs list from the LE scan result information. /// /// Gets the list of the string service UUIDs. /// /// The Bluetooth must be enabled. /// /// Thrown when the Bluetooth LE is not supported. /// Thrown when the Bluetooth LE is not enabled. public IEnumerable ServiceUuid { get { if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { Log.Info(Globals.LogTag, "Retrieving Service uuid- "); return BluetoothLeImplAdapter.Instance.GetLeScanResultServiceUuids(_scanData, _packetType); } return null; } } /// /// Gets the device name from the LE scan result information. /// /// Gets the device name. /// /// The Bluetooth must be enabled. /// /// Thrown when the Bluetooth LE is not supported. /// Thrown when the Bluetooth LE is not enabled. public string DeviceName { get { Log.Info(Globals.LogTag, "Retrieving device name- "); if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { return BluetoothLeImplAdapter.Instance.GetLeScanResultDeviceName(_scanData, _packetType); } return null; } } /// /// Gets the transmission power level from the LE scan result information. /// /// Gets the transmission power level in dB. /// /// The Bluetooth must be enabled. /// /// Thrown when the Bluetooth LE is not supported. /// Thrown when the Bluetooth LE is not enabled. public int TxPowerLevel { get { if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { return BluetoothLeImplAdapter.Instance.GetScanResultTxPowerLevel(_scanData, _packetType); } return -1; } } /// /// Gets the service solicitation UUID list from the scan result information. /// /// Gets the list of the service solicitation UUIDs. /// /// The Bluetooth must be enabled. /// /// Thrown when the Bluetooth LE is not supported. /// Thrown when the Bluetooth LE is not enabled. public IEnumerable ServiceSolictationUuid { get { if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { return BluetoothLeImplAdapter.Instance.GetScanResultSvcSolicitationUuids(_scanData, _packetType); } return null; } } /// /// Gets the manufacturer data from the scan result information. /// /// Gets the appearance value. /// /// The Bluetooth must be enabled. /// /// Thrown when the Bluetooth LE is not supported. /// Thrown when the Bluetooth LE is not enabled. public int Appearance { get { if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { return BluetoothLeImplAdapter.Instance.GetScanResultAppearance(_scanData, _packetType); } return -1; } } /// /// Gets the manufacturer data from the scan result information. /// /// Gets the manufacturer data containing the manucturer data and ID information. /// /// The Bluetooth must be enabled. /// /// Thrown when the Bluetooth LE is not supported. /// Thrown when the Bluetooth LE is not enabled./// public ManufacturerData ManufacturerData { get { if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { return BluetoothLeImplAdapter.Instance.GetScanResultManufacturerData(_scanData, _packetType); } return null; } } /// /// Gets the service data list from the scan result information. /// /// /// The Bluetooth must be enabled. /// /// Returns the service data list. /// Thrown when the Bluetooth LE is not supported. /// Thrown when the Bluetooth LE is not enabled. public IEnumerable GetServiceDataList() { int serviceCount = 0; if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { return BluetoothLeImplAdapter.Instance.GetScanResultServiceDataList(_scanData, _packetType, out serviceCount); } return null; } /// /// Creates a GATT connection with the remote device. /// /// /// The Bluetooth must be enabled. /// /// The auto connect flag. /// client instance /// Thrown when the Bluetooth LE is not supported. /// Thrown when the Bluetooth LE is not enabled /// or when the gatt connection attempt to remote device fails. public BluetoothGattClient GattConnect(bool autoConnect) { BluetoothGattClient client = null; if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { int ret = BluetoothLeImplAdapter.Instance.GattConnect (_remoteAddress, autoConnect); if (ret != (int)BluetoothError.None) { Log.Error (Globals.LogTag, "Failed to create GATT Connection with remote device- " + (BluetoothError)ret); } else { client = BluetoothGattClient.CreateClient(_remoteAddress); } } else { BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled); } return client; } /// /// Disconnects a GATT connection with the remote device. /// /// /// The Bluetooth must be enabled. /// /// Thrown when the Bluetooth LE is not supported. /// Thrown when the Bluetooth LE is not enabled /// or when the GATT disconnection attempt to remote device fails. public void GattDisconnect() { if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { int ret = BluetoothLeImplAdapter.Instance.GattDisconnect (_remoteAddress); if (ret != (int)BluetoothError.None) { Log.Error (Globals.LogTag, "Failed to disconnect GATT connection with remote device- " + (BluetoothError)ret); } } else { BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled); } } } /// /// Bluetooth LE advertise data. Handles the data advertising. /// public class BluetoothLeAdvertiseData:IDisposable { private IntPtr _handle = IntPtr.Zero; private BluetoothLeAdvertisingMode _mode; private bool _advertisingConnectable; private BluetoothLePacketType _packetType; private int _appearance; private bool _includePowerLevel; private bool _includeDeviceName; /// /// The default constructor initializes an object of the BluetoothLeAdvertiseData. /// /// Thrown when the Bluetooth LE is not supported. /// Thrown when the Bluetooth LE is not enabled /// or when create advertiser fails. public BluetoothLeAdvertiseData() { if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { Log.Debug(Globals.LogTag, " Creating LeAdvertiser()"); int ret = Interop.Bluetooth.CreateAdvertiser(out _handle); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to create advertiser object- " + (BluetoothError)ret); BluetoothErrorFactory.ThrowBluetoothException(ret); } } else { BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled); } } /// /// BluetoothLeAdvertiseData destructor. /// ~BluetoothLeAdvertiseData() { if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { //clean-up ClearAdvertisingData (BluetoothLePacketType.BluetoothLeAdvertisingPacket); ClearAdvertisingData (BluetoothLePacketType.BluetoothLeScanResponsePacket); BluetoothLeImplAdapter.Instance.DestroyAdvertiser (_handle); } Dispose(false); } internal IntPtr GetHandle() { return _handle; } /// /// The advertising mode to control the advertising power and latency. /// /// /// The Bluetooth must be enabled. /// /// Thrown when the Bluetooth LE is not supported. /// Thrown when the Bluetooth LE is not enabled /// or when the set advertising mode fails. public BluetoothLeAdvertisingMode AdvertisingMode { get { return _mode; } set { if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { _mode = value; int ret = Interop.Bluetooth.SetAdvertisingMode (GetHandle (), _mode); if (ret != (int)BluetoothError.None) { Log.Error (Globals.LogTag, "Failed to set advertising mode- " + (BluetoothError)ret); BluetoothErrorFactory.ThrowBluetoothException (ret); } } } } /// /// The advertising connectable type. /// /// /// The Bluetooth must be enabled. /// /// Thrown when the Bluetooth LE is not supported. /// Thrown when the Bluetooth LE is not enabled /// or when the set advertising connectable mode fails. public bool AdvertisingConnectable { get { return _advertisingConnectable; } set { if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { _advertisingConnectable = value; int ret = Interop.Bluetooth.SetAdvertisingConnectable (GetHandle (), _advertisingConnectable); if (ret != (int)BluetoothError.None) { Log.Error (Globals.LogTag, "Failed to set advertising connectable value- " + (BluetoothError)ret); BluetoothErrorFactory.ThrowBluetoothException (ret); } } } } /// /// Dispose /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool disposing) { //todo... } /// /// The type of the packet. /// public BluetoothLePacketType PacketType { get { return _packetType; } set { _packetType = value; } } /// /// Sets the external appearance of this device to the advertise or the scan response data. /// Please refer to the adopted Bluetooth specification for the appearance. /// /// /// The Bluetooth must be enabled. /// /// Thrown when the Bluetooth LE is not supported. /// Thrown when the Bluetooth LE is not enabled /// or when the set appearance fails. public int Appearance { get { return _appearance; } set { _appearance = value; if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { int ret = Interop.Bluetooth.SetAdvertisingAppearance (GetHandle (), _packetType, _appearance); if (ret != (int)BluetoothError.None) { Log.Error (Globals.LogTag, "Failed to add appearance value to advertising data- " + (BluetoothError)ret); BluetoothErrorFactory.ThrowBluetoothException(ret); } } } } /// /// Sets whether the device name has to be included in the advertise or the scan response data. /// The maximum advertised or responded data size is 31 bytes including the data type and the system wide data. /// /// /// The Bluetooth must be enabled. /// /// Thrown when the Bluetooth LE is not supported. /// Thrown when the Bluetooth LE is not enabled /// or when the set advertising device name fails. public bool IncludeDeviceName { get { return _includeDeviceName; } set { _includeDeviceName = value; if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { int ret = Interop.Bluetooth.SetAdvertisingDeviceName(GetHandle(), _packetType, _includeDeviceName); if (ret != (int)BluetoothError.None) { Log.Error (Globals.LogTag, "Failed to add device name to advertising data- " + (BluetoothError)ret); BluetoothErrorFactory.ThrowBluetoothException(ret); } } } } /// /// Sets whether the transmission power level should be included in the advertise or the scan response data. /// The maximum advertised or responded data size is 31 bytes including the data type and the system wide data. /// /// /// The Bluetooth must be enabled. /// /// Thrown when the Bluetooth LE is not supported. /// Thrown when the Bluetooth LE is not enabled /// or when the set advertising TC power level fails. public bool IncludeTxPowerLevel { get { return _includePowerLevel; } set { _includePowerLevel = value; if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { int ret = Interop.Bluetooth.SetAdvertisingTxPowerLevel(GetHandle(), _packetType, _includePowerLevel); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to add advertising service solicitation uuid- " + (BluetoothError)ret); } } } } /// /// Adds a service UUID to the advertise or the scan response data. /// The maximum advertised or responded data size is 31 bytes /// including the data type and the system wide data. /// /// /// The Bluetooth must be enabled. /// /// The packet type. /// The service UUID to add to advertise data. /// Thrown when the Bluetooth LE is not supported. /// Thrown when the Bluetooth LE is not enabled /// or when the add advertising service UUID procedure fails. public void AddAdvertisingServiceUuid(BluetoothLePacketType packetType, string serviceUuid) { if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { int ret = Interop.Bluetooth.AddAdvertisingServiceUuid (GetHandle (), packetType, serviceUuid); if (ret != (int)BluetoothError.None) { Log.Error (Globals.LogTag, "Failed to add service uuid to advertising data- " + (BluetoothError)ret); BluetoothErrorFactory.ThrowBluetoothException (ret); } } else { BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled); } } /// /// Adds a service solicitation UUID to advertise or scan the response data. /// The maximum advertised or responded data size is 31 bytes /// including the data type and the system wide data. /// /// /// The Bluetooth must be enabled. /// /// The packet type. /// The service solicitation UUID to add to advertise data. /// Thrown when the Bluetooth LE is not supported. /// Thrown when the Bluetooth LE is not enabled /// or when the add advertising service solicitation UUID procedure fails. public void AddAdvertisingServiceSolicitationUuid(BluetoothLePacketType packetType, string serviceSolicitationUuid) { if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { int ret = Interop.Bluetooth.AddAdvertisingServiceSolicitationUuid(GetHandle(), packetType, serviceSolicitationUuid); if (ret != (int)BluetoothError.None) { Log.Error (Globals.LogTag, "Failed to add service solicitation uuid to advertising data- " + (BluetoothError)ret); BluetoothErrorFactory.ThrowBluetoothException(ret); } } else { BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled); } } /// /// Adds a service data to the advertise or the scan response data. /// The maximum advertised or responded data size is 31 bytes /// including data type and system wide data. /// /// /// The Bluetooth must be enabled. /// /// The packet type. /// The service data to be added to advertising. /// Thrown when the Bluetooth LE is not supported. /// Thrown when the Bluetooth LE is not enabled /// or when the add advertising data procedure fails. public void AddAdvertisingServiceData(BluetoothLePacketType packetType, BluetoothServiceData data) { if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { IntPtr serviceDataPtr; serviceDataPtr = Marshal.AllocHGlobal(data.DataLength); Marshal.Copy(data.Data, 0, serviceDataPtr, data.DataLength); for (int i = 0; i < 3; i++) Log.Error (Globals.LogTag, " service data is " + data.Data [i]); int ret = Interop.Bluetooth.AddAdvertisingServiceData(GetHandle(), packetType, data.Uuid, serviceDataPtr, data.DataLength); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to add service data to advertising data- " + (BluetoothError)ret); BluetoothErrorFactory.ThrowBluetoothException(ret); } } else { BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled); } } /// /// Adds the manufacturer specific data to the advertise or the scan response data. /// Please refer to the adopted Bluetooth specification for the the appearance. /// /// /// The Bluetooth must be enabled. /// /// The packet type. /// The manufacturer specific data. /// Thrown when the Bluetooth LE is not supported. /// Thrown when the Bluetooth LE is not enabled /// or when the add advertising manufacturer data procedure fails. public void AddAdvertisingManufacturerData(BluetoothLePacketType packetType, ManufacturerData manufacturerData) { if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { IntPtr manufDataPtr; manufDataPtr = Marshal.AllocHGlobal(manufacturerData.DataLength); Marshal.Copy(manufacturerData.Data, 0, manufDataPtr, manufacturerData.DataLength); int ret = Interop.Bluetooth.AddAdvertisingManufData(GetHandle(), packetType, manufacturerData.Id, manufDataPtr, manufacturerData.DataLength); if (ret != (int)BluetoothError.None) { Log.Error(Globals.LogTag, "Failed to add service solicitation uuid to advertising data- " + (BluetoothError)ret); BluetoothErrorFactory.ThrowBluetoothException(ret); } } else { BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled); } } /// /// Clears all data to be advertised or responded to the scan request from the LE scanning device. /// /// /// The Bluetooth must be enabled. /// /// The packet type to be cleared. /// Thrown when the Bluetooth LE is not supported. /// Thrown when the Bluetooth LE is not enabled /// or when the clear advertising data procedure fails. internal void ClearAdvertisingData(BluetoothLePacketType packetType) { if (BluetoothAdapter.IsBluetoothEnabled && Globals.IsInitialize) { int ret = Interop.Bluetooth.ClearAdvertisingData (GetHandle (), packetType); if (ret != (int)BluetoothError.None) { Log.Error (Globals.LogTag, "Failed to Clear Advertising Data- " + (BluetoothError)ret); } } else { BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled); } } } }