private bool UpdateConnectionIntervalNative(ConnectionInterval interval) { if (_gatt == null || _gattCallback == null) { Trace.Message("You can't update a connection interval for disconnected devices. Device is {0}", State); return(false); } if (Build.VERSION.SdkInt < BuildVersionCodes.Lollipop) { Trace.Message($"Update connection interval paramter in this Android API level"); return(false); } try { // map to android gattConnectionPriorities // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#CONNECTION_PRIORITY_BALANCED return(_gatt.RequestConnectionPriority((GattConnectionPriority)(int)interval)); } catch (Exception ex) { throw new Exception($"Update Connection Interval fails with error. {ex.Message}"); } }
private async Task <bool> UpdateRssiNativeAsync() { if (_gatt == null || _gattCallback == null) { Trace.Message("You can't read the RSSI value for disconnected devices except on discovery on Android. Device is {0}", State); return(false); } return(await TaskBuilder.FromEvent <bool, EventHandler <RssiReadCallbackEventArgs>, EventHandler>( execute : () => _gatt.ReadRemoteRssi(), getCompleteHandler : (complete, reject) => ((sender, args) => { if (args.Error == null) { Trace.Message("Read RSSI for {0} {1}: {2}", Id, Name, args.Rssi); Rssi = args.Rssi; complete(true); } else { Trace.Message($"Failed to read RSSI for device {Id}-{Name}. {args.Error.Message}"); complete(false); } }), subscribeComplete : handler => _gattCallback.RemoteRssiRead += handler, unsubscribeComplete : handler => _gattCallback.RemoteRssiRead -= handler, getRejectHandler : reject => ((sender, args) => { reject(new Exception($"Device {Name} disconnected while updating rssi.")); }), subscribeReject : handler => _gattCallback.ConnectionInterrupted += handler, unsubscribeReject : handler => _gattCallback.ConnectionInterrupted -= handler)); }
private void StartScanningOld(Guid[] serviceUuids) { var hasFilter = serviceUuids?.Any() ?? false; UUID[] uuids = null; if (hasFilter) { uuids = serviceUuids.Select(u => UUID.FromString(u.ToString())).ToArray(); } Trace.Message("Adapter < 21: Starting a scan for devices."); #pragma warning disable 618 _bluetoothAdapter.StartLeScan(uuids, _api18ScanCallback); #pragma warning restore 618 }
public IReadOnlyList <Device> GetSystemConnectedOrPairedDevices(Guid[] services = null) { if (services != null) { Trace.Message("Caution: GetSystemConnectedDevices does not take into account the 'services' parameter on Android."); } //add dualMode type too as they are BLE too ;) var connectedDevices = _bluetoothManager.GetConnectedDevices(ProfileType.Gatt).Where(d => d.Type == BluetoothDeviceType.Le || d.Type == BluetoothDeviceType.Dual); var bondedDevices = _bluetoothAdapter.BondedDevices.Where(d => d.Type == BluetoothDeviceType.Le || d.Type == BluetoothDeviceType.Dual); return(connectedDevices.Union(bondedDevices, new DeviceComparer()).Select(d => new Device(this, d, null, 0)).Cast <Device>().ToList()); }
protected void StopScanNative() { if (Build.VERSION.SdkInt < BuildVersionCodes.Lollipop) { Trace.Message("Adapter < 21: Stopping the scan for devices."); #pragma warning disable 618 _bluetoothAdapter.StopLeScan(_api18ScanCallback); #pragma warning restore 618 } else { Trace.Message("Adapter >= 21: Stopping the scan for devices."); _bluetoothAdapter.BluetoothLeScanner?.StopScan(_api21ScanCallback); } }
/// <summary> /// This method is only called by a user triggered disconnect. /// A user will first trigger _gatt.disconnect -> which in turn will trigger _gatt.Close() via the gattCallback /// </summary> internal void Disconnect() { if (_gatt != null) { IsOperationRequested = true; ClearServices(); _gatt.Disconnect(); } else { Trace.Message("[Warning]: Can't disconnect {0}. Gatt is null.", Name); } }
private void StartScanningNew(Guid[] serviceUuids) { var hasFilter = serviceUuids?.Any() ?? false; List <ScanFilter> scanFilters = null; if (hasFilter) { scanFilters = new List <ScanFilter>(); foreach (var serviceUuid in serviceUuids) { var sfb = new ScanFilter.Builder(); sfb.SetServiceUuid(ParcelUuid.FromString(serviceUuid.ToString())); scanFilters.Add(sfb.Build()); } } var ssb = new ScanSettings.Builder(); ssb.SetScanMode(ScanMode.ToNative()); if (Build.VERSION.SdkInt >= BuildVersionCodes.O) { // enable Bluetooth 5 Advertisement Extensions on Android 8.0 and above ssb.SetLegacy(false); } //ssb.SetCallbackType(ScanCallbackType.AllMatches); if (_bluetoothAdapter.BluetoothLeScanner != null) { Trace.Message($"Adapter >=21: Starting a scan for devices. ScanMode: {ScanMode}"); if (hasFilter) { Trace.Message($"ScanFilters: {string.Join(", ", serviceUuids)}"); } _bluetoothAdapter.BluetoothLeScanner.StartScan(scanFilters, ssb.Build(), _api21ScanCallback); } else { Trace.Message("Adapter >= 21: Scan failed. Bluetooth is probably off"); } }
private async Task <int> RequestMtuNativeAsync(int requestValue) { if (_gatt == null || _gattCallback == null) { Trace.Message("You can't request a MTU for disconnected devices. Device is {0}", State); return(-1); } if (Build.VERSION.SdkInt < BuildVersionCodes.Lollipop) { Trace.Message($"Request MTU not supported in this Android API level"); return(-1); } return(await TaskBuilder.FromEvent <int, EventHandler <MtuRequestCallbackEventArgs>, EventHandler>( execute : () => { _gatt.RequestMtu(requestValue); }, getCompleteHandler : (complete, reject) => ((sender, args) => { if (args.Error != null) { Trace.Message($"Failed to request MTU ({requestValue}) for device {Id}-{Name}. {args.Error.Message}"); reject(new Exception($"Request MTU error: {args.Error.Message}")); } else { complete(args.Mtu); } }), subscribeComplete : handler => _gattCallback.MtuRequested += handler, unsubscribeComplete : handler => _gattCallback.MtuRequested -= handler, getRejectHandler : reject => ((sender, args) => { reject(new Exception($"Device {Name} disconnected while requesting MTU.")); }), subscribeReject : handler => _gattCallback.ConnectionInterrupted += handler, unsubscribeReject : handler => _gattCallback.ConnectionInterrupted -= handler )); }
public override void OnScanFailed(ScanFailure errorCode) { Trace.Message("Adapter: Scan failed with code {0}", errorCode); base.OnScanFailed(errorCode); }
public void OnLeScan(BluetoothDevice bleDevice, int rssi, byte[] scanRecord) { Trace.Message("Adapter.LeScanCallback: " + bleDevice.Name); _adapter.HandleDiscoveredDevice(new Device(_adapter, bleDevice, null, rssi, scanRecord)); }
private static List <AdvertisementRecord> ParseScanRecord(byte[] scanRecord) { var records = new List <AdvertisementRecord>(); if (scanRecord == null) { return(records); } int index = 0; while (index < scanRecord.Length) { byte length = scanRecord[index++]; //Done once we run out of records // 1 byte for type and length-1 bytes for data if (length == 0) { break; } int type = scanRecord[index]; //Done if our record isn't a valid type if (type == 0) { break; } if (!Enum.IsDefined(typeof(AdvertisementRecordType), type)) { Trace.Message("Advertisment record type not defined: {0}", type); break; } //data length is length -1 because type takes the first byte byte[] data = new byte[length - 1]; Array.Copy(scanRecord, index + 1, data, 0, length - 1); // don't forget that data is little endian so reverse // Supplement to Bluetooth Core Specification 1 // NOTE: all relevant devices are already little endian, so this is not necessary for any type except UUIDs //var record = new AdvertisementRecord((AdvertisementRecordType)type, data.Reverse().ToArray()); switch ((AdvertisementRecordType)type) { case AdvertisementRecordType.ServiceDataUuid32Bit: case AdvertisementRecordType.SsUuids128Bit: case AdvertisementRecordType.SsUuids16Bit: case AdvertisementRecordType.SsUuids32Bit: case AdvertisementRecordType.UuidCom32Bit: case AdvertisementRecordType.UuidsComplete128Bit: case AdvertisementRecordType.UuidsComplete16Bit: case AdvertisementRecordType.UuidsIncomple16Bit: case AdvertisementRecordType.UuidsIncomplete128Bit: Array.Reverse(data); break; } var record = new AdvertisementRecord((AdvertisementRecordType)type, data); Trace.Message(record.ToString()); records.Add(record); //Advance index += length; } return(records); }