Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[iOS] Fix detection of devices via Service UUID (CircuitCubes, WeDo2) #138

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
using Foundation;
using BrickController2.PlatformServices.BluetoothLE;

using static BrickController2.Protocols.BluetoothLowEnergy;

namespace BrickController2.iOS.PlatformServices.BluetoothLE
{
public class BluetoothLEService : CBCentralManagerDelegate, IBluetoothLEService
Expand Down Expand Up @@ -112,13 +114,19 @@ private IDictionary<byte, byte[]> ProcessAdvertisementData(NSDictionary advertis
var manufacturerData = GetDataForKey(advertisementData, CBAdvertisement.DataManufacturerDataKey);
if (manufacturerData is not null)
{
result[0xFF] = manufacturerData;
result[ADTYPE_MANUFACTURER_SPECIFIC] = manufacturerData;
}

var completeDeviceName = GetDataForKey(advertisementData, CBAdvertisement.DataLocalNameKey);
if (completeDeviceName is not null)
{
result[0x09] = completeDeviceName;
result[ADTYPE_LOCAL_NAME_COMPLETE] = completeDeviceName;
}

var serviceUuid = GetServiceUuidForKey(advertisementData, CBAdvertisement.DataServiceUUIDsKey);
if (serviceUuid is not null)
{
result[ADTYPE_SERVICE_128BIT] = serviceUuid;
}

// TODO: add the rest of the advertisementdata...
Expand All @@ -145,5 +153,27 @@ private IDictionary<byte, byte[]> ProcessAdvertisementData(NSDictionary advertis

return null;
}

private static byte[]? GetServiceUuidForKey(NSDictionary advertisementData, NSString key)
{
if (advertisementData != null &&
advertisementData.TryGetValue(key, out var rawObject) &&
rawObject is NSArray arrayObject)
{
// find first available 128-bit UUID
for (nuint i = 0; i < arrayObject.Count; i++)
{
var cbuuid = arrayObject.GetItem<CBUUID>(i);
if (cbuuid.Data.Length == 16)
{
// Service UUID's are read backwards (little endian) according to specs
var serviceUUid = cbuuid.Data.ToArray();
Array.Reverse(serviceUUid);
return serviceUUid;
}
}
}
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
using BrickController2.Helpers;
using BrickController2.PlatformServices.BluetoothLE;

using static BrickController2.Protocols.BluetoothLowEnergy;

namespace BrickController2.DeviceManagement
{
internal class BluetoothDeviceManager : IBluetoothDeviceManager
Expand Down Expand Up @@ -61,7 +63,7 @@ public async Task<bool> ScanAsync(Func<DeviceType, string, string, byte[]?, Task
return (DeviceType.Unknown, null);
}

if (!advertismentData.TryGetValue(0xFF, out var manufacturerData) || manufacturerData.Length < 2)
if (!advertismentData.TryGetValue(ADTYPE_MANUFACTURER_SPECIFIC, out var manufacturerData) || manufacturerData.Length < 2)
{
return GetDeviceInfoByService(advertismentData);
}
Expand All @@ -74,7 +76,7 @@ public async Task<bool> ScanAsync(Func<DeviceType, string, string, byte[]?, Task
case "98-01": return (DeviceType.SBrick, manufacturerData);
case "48-4d": return (DeviceType.BuWizz, manufacturerData);
case "4e-05":
if (advertismentData.TryGetValue(0x09, out byte[]? completeLocalName))
if (advertismentData.TryGetValue(ADTYPE_LOCAL_NAME_COMPLETE, out byte[]? completeLocalName))
{
var completeLocalNameString = BitConverter.ToString(completeLocalName).ToLower();
if (completeLocalNameString == "42-75-57-69-7a-7a") // BuWizz
Expand Down Expand Up @@ -108,7 +110,7 @@ public async Task<bool> ScanAsync(Func<DeviceType, string, string, byte[]?, Task
private (DeviceType DeviceType, byte[]? ManufacturerData) GetDeviceInfoByService(IDictionary<byte, byte[]> advertismentData)
{
// 0x06: 128 bits Service UUID type
if (!advertismentData.TryGetValue(0x06, out byte[]? serviceData) || serviceData.Length < 16)
if (!advertismentData.TryGetValue(ADTYPE_SERVICE_128BIT, out byte[]? serviceData) || serviceData.Length < 16)
{
return (DeviceType.Unknown, null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ private async Task<bool> SendDriveCommandAsync(int[] values, CancellationToken t
commendBytes.CopyTo(_driveMotorsBuffer, idx);
idx += 5;
}
return await _bleDevice!.WriteAsync(_writeCharacteristic!, _driveMotorsBuffer, token);
return await _bleDevice!.WriteNoResponseAsync(_writeCharacteristic!, _driveMotorsBuffer, token);
}
catch (Exception)
{
Expand All @@ -199,7 +199,7 @@ private async Task<bool> SendStopCommandAsync(CancellationToken token)
{
try
{
return await _bleDevice!.WriteAsync(_writeCharacteristic!, TURN_OFF_ALL_COMMAND, token);
return await _bleDevice!.WriteNoResponseAsync(_writeCharacteristic!, TURN_OFF_ALL_COMMAND, token);
}
catch (Exception)
{
Expand All @@ -223,7 +223,7 @@ private async Task ReadDeviceInfo(CancellationToken token)
HardwareVersion = hardwareRevision;
}

await _bleDevice!.WriteAsync(_writeCharacteristic!, BATTERY_STATUS_COMMAND, token);
await _bleDevice!.WriteNoResponseAsync(_writeCharacteristic!, BATTERY_STATUS_COMMAND, token);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace BrickController2.Protocols;

public static class BluetoothLowEnergy
{
// advertisment data types
public const byte ADTYPE_SERVICE_128BIT = 0x06; // Service: Additional 128-bit UUIDs
public const byte ADTYPE_LOCAL_NAME_COMPLETE = 0x09; // Complete local name
public const byte ADTYPE_MANUFACTURER_SPECIFIC = 0xFF; // Manufacturer specific data
}