I'm writing my code using Xamarin. I'm developing my IOS app which allows me to read the BLE devices, Services, characteristic value and activation of the notification.
My BLE beacon have one custom Services that contain two custom characteristics and both have the notification implemented using CCCD.
My ble devices work correctly I test it with BLE scanner app and it working well without any problem.
I can read value and I can active the notification for both characteristic. See picture here.
The app that I wrote using xamarin work correctly (reading services, characteristic value....) the only problem that didn't work is the activation of the notification. Here's a portion of the code :
public UUID Charac_UUID0 = UUID.FromString("0000beef-1212-efde-1523-785fef13d123");
public UUID Charac_UUID = UUID.FromString("0000b1e0-1212-efde-1523-785fef13d123") ;
public UUID Descr_UUID = UUID.FromString("00002902-1212-efde-1523-785fef13d123");
protected BluetoothGattCharacteristic _charac;
....
....
this._charac = App.Current.State.SelectedService.GetCharacteristic(Charac_UUID0);
BluetoothLEManager.Current.ConnectedDevices[App.Current.State.SelectedDevice].SetCharacteristicNotification(_charac, true);
BluetoothGattDescriptor descriptor = _charac.GetDescriptor(Descr_UUID0);
descriptor.SetValue(BluetoothGattDescriptor.EnableNotificationValue.ToArray());
BluetoothLEManager.Current.ConnectedDevices[App.Current.State.SelectedDevice].WriteDescriptor(descriptor);
The code always give me an error at descriptor.SetValue and it indicate me that the descriptor is NULL meaning that _charac.GetDescriptor didn't return any value.
I suspect the Descriptor UUID value (Descr_UUID) is not correct. I don't know excatly how can I determine the Descr_UUID but I saw many example in the internet of people replacing the custom UUID of the caracteristic by 2902 which give me in my case a 128 descriptor UUID equal to 00002902-1212-efde-1523-785fef13d123.
But there is a problem here. The descriptor UUID for both characteristic will be the same because the base UUID is the same for both characteristic?
Any solution?
3 years later im sure you figured it out but, 2902 is the 16 bit value for a Client Characteristic Configuration Descriptor, and I believe it should also be inflated using the "BASE UUID" not just whatever your characteristic descriptor uses. See this: answer
This will convert your 16 (or 32) bit uuids to full 128 bit uuids using the BASE UUID:
public static UUID ConvertUuid(uint uuid)
{
const long msbMask = 0x0000000000001000;
const ulong lsb = 0x800000805f9b34fb;
var msb = msbMask | ((ulong)(uuid & uint.MaxValue) << 32);
return new UUID((long)msb, unchecked((long)lsb));
}
Related
I'm currently building an app that turns my device into a Beacon while simultaneously scanning for other Beacons.
So I can keep track of beacons that I had come in contact with.
Problem
Current I've tested this code in the following Scenarios:
Android TO Android - Broadcasting & Scanning - Working well
Android To IOS - BroadCasting & Scanning Both ways - Working well
IOS to IOS - Not Working (When I broadcast UUID from IOS Device, I can see UUID in Android device but I can't see UUID in any IOS device.)
I installed this piece of code in 4 devices (2 Android & 2 IOS). Now all 4 devices are broadcasting different UUID's and at the same time listening.
In Android Devices, I see 1 UUID of another Android Device and 2 UUID's of IOS Devices
In IOS Devices, I see 2 Android UUID's but I cannot see another IOS Device UUID.
This is very strange, and I need help to solve this, please!
I've currently implemented 2 packages to achieve this functionality :
(1) For broadcast
beacon_broadcast: https://pub.dev/packages/beacon_broadcast
version : 0.2.1
(2) For scan other beacons
flutter_blue: https://pub.dev/packages/flutter_blue
version : 0.6.3+1
These are some glimpse of my code
(1) For Broadcasting
String UUID = 'DYNAMIC_UUID_FOR_EACH_DEVICE';
static const MAJOR_ID = 1;
static const MINOR_ID = 30;
static const TRANSMISSION_POWER = -59;
static const IDENTIFIER = 'com.example.myDeviceRegion';
static const LAYOUT = 'm:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24';
static const MANUFACTURER_ID = 0x004c;
BeaconBroadcast beaconBroadcast = BeaconBroadcast();
beaconBroadcast
.setUUID(UUID)
.setMajorId(MAJOR_ID)
.setMinorId(MINOR_ID)
.setTransmissionPower(TRANSMISSION_POWER)
.setIdentifier(IDENTIFIER)
.setLayout(LAYOUT)
.setManufacturerId(MANUFACTURER_ID);
.start();
(2) For Scanning
FlutterBlue flutterBlue = FlutterBlue.instance;
flutterBlue.startScan(timeout: Duration(seconds: 30));
flutterBlue.scanResults.listen((List<ScanResult> results) {
print('scanningListen...');
for (ScanResult result in results) {
result.advertisementData.manufacturerData.forEach((item, hexcodeAsArray) => {
print("calculated UUID String : " + calculateHexFromArray(v));
_addToScanResult(calculateHexFromArray(v));
});
}
}
String calculateHexFromArray(decimalArray) {
String uuid = '';
decimalArray.forEach((i) => {uuid += i.toRadixString(16).padLeft(2, '0')});
String uuid1 = uuid.substring(4, uuid.length - 12);
return uuid1.toUpperCase();
}
Unfortunately, you cannot use FlutterBlue to detect iBeacon packets on iOS.
Why? FlutterBlue uses raw bluetooth scanning to detect beacons, which under the hood means using the native CoreBluetooth scanning APIs on iOS. Apple blocks CoreBluetooth APIs from reading the raw bytes of any bluetooth advertisement decodable as an iBeacon advertisement. While this may sound crazy, it is likely motivated by misguided security concerns by Apple. Read more in my blog post here: CoreBluetooth Doesn't Let You See iBeacons
Two options to fix this:
Switch to using the AltBeacon format. Simply change LAYOUT = 'm:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25'; and MANUFACTURER_ID = 0x0118;
This will work, but has the disadvantage of the advertisement only being detectable on iOS in the foreground.
Switch to using a different detection library on iOS that uses CoreLocation (the only API allowed to detect iBeacon on iOS) instead of CoreBluetooth. That means giving up FlutterBlue in favor of FlutterBeacon or similar.
I want to check which Bluetooth Devices my iPhone is connected to. In order to do that, I use CBCentralManager.retrieveConnectedPeripherals() like this:
let connectedPerphs = centralManager.retrieveConnectedPeripherals(withServices: []);
My problem is that even if my iPhone is connected to a BluetoothDongle (it explicitly says "connected" in the settings), the list that is returned by retriveConnectedPeripherals() is always empty. Am I using the method in a wrong way or can it not be used to detect a bluetooth connection such as the connection to to my dongle? If the latter is the case, how can I detect that connection?
Let me clear, centralManager.retrieveConnectedPeripherals always return empty or nil value, If you are not passing any value into serviceUUIDs
retrieveConnectedPeripherals(withServices:)
Returns a list of the peripherals (containing any of the specified
services) currently connected to the system.
serviceUUIDs:
A list of service UUIDs (represented by CBUUID objects).
Update:
Unfortunately this the long way to do it. You can create Array of CBUUID statically then you can pass it to the method. Please refer below code.
let aryUUID = ["1800","18811"]
var aryCBUUIDS = [CBUUID]()
for uuid in aryUUID{
let uuid = CBUUID(string: "1800")
aryCBUUIDS.append(uuid)
}
let connectedPerphs = centralManager.retrieveConnectedPeripherals(withServices: aryCBUUIDS)
List of available services
First, this works only with BLE devices, thus if your dongle is using a common BT you will not get it from here, but probably using EAAccessoryManager var connectedAccessories: [EAAccessory] method, but as far as I know your app must comply to MFI.
That is why is asking which service your devices are exposing as a filter.
I'm writing a upper class filter for WPD device. I specified the callback functions for the Read/Write/Ioctl, from the callback declaration I could get the WDFQueue, WDFRequest.
VOID WdfFltrDeviceControl(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode)
But from the parameter Queue or Request, I could only get the information of device which is created by my driver. Is there any way to retrieve the informations of the attached devices which my driver is currently filtering?(e.g. From the kernel log I can see the ioctl request to my android device, but I don't know how to get the android device object to get the device name)
You are really should be able to get information about your WPD device request using parameters of this method. If you are not, probably your code or .inf filter setup is wrong.
You can use this code snippet to check what device you are filtering now:
WDFDEVICE device = WdfIoQueueGetDevice(Queue);
WCHAR id[255];
ULONG resultLength;
NTSTATUS status = WdfDeviceQueryProperty(device, DevicePropertyHardwareID, sizeof(id), id, &resultLength);
if(NT_SUCCESS(status))
{
//check the device id here
}
Or, if you prefer some another parameter, you could find the list here
so in this question I asked how would I identify a bluetooth device after doing an scan. It seems that only those devices I have connected to show their name, all other devices are shown as unnamed.
So my question is, how do I pair all the unnamed devices using the Ionic Native BLE library? It doesn't matter if I need to do a manual process for each one (since this will be done only once). Thanks in advance.
Using your example, when you scan you get objects like this:
{
id: "2BD5D5A7-EF50-B4F4-D4FD-9A8413006D4B",
rssi: -24,
advertising: {
kCBAdvDataIsConnectable: true
},
name: ""
}
where name is an empty string which is your term unnamed.
You can check if the name is an empty string, take the id value instead to establish BLE connection.
ble.connect("2BD5D5A7-EF50-B4F4-D4FD-9A8413006D4B", connectSuccess, connectFailure);
I want send large binary string to BLE device(peripheral) from my ios app(central device). Its working fine with small string, but when iam trying to send large string, It was not receiving and the connection was automatically disconnecting. I have read that we need to divide the large data into multiple chunks to send it. But i didn't find any working sample on that.
Please look at the code send the string
let stringToSend = "0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000#"
.
let data : NSData = stringToSend.dataUsingEncoding(NSUTF8StringEncoding)!
if positionCharacteristic != nil {
self.polarH7HRMPeripheral.writeValue(data, forCharacteristic: positionCharacteristic, type: .WithoutResponse)
self.polarH7HRMPeripheral.setNotifyValue(true, forCharacteristic: positionCharacteristic)
}
Thanks in advance
Some devices registers are limited in size. They can't contain more than X bytes for processing.
Let's assume said BLE device expects a long command in a format of a few short commands.
Let's also assume said device able to receive short commands as well.
How would the device know the difference between a short command and a partial long command? Using a command format which states command type.
For example:
A command will contain 1 header byte, 6 content bytes, 1 command type byte.
Partial long command will have 11111111 as its command type with the final part as 11111110.
Short command will have 00000000 as the its command type.
This is how I "defined" a simple protocol for difference commands for a device.
I would recommend you look for that protocol in the developer manual of that device
Some device accepts 20 bytes at most, so you have to spit your string.
for strMsgPart in stringToSend.split(by: 20) {
if positionCharacteristic != nil {
self.polarH7HRMPeripheral.writeValue(strMsgPart, forCharacteristic: positionCharacteristic, type: .WithoutResponse)
self.polarH7HRMPeripheral.setNotifyValue(true, forCharacteristic: positionCharacteristic)
}
}