Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

te21blz

macrumors newbie
Original poster
Dec 12, 2020
4
0
Hi folks,

I want to connect a bluetooth device on macos 10.15 for development reasons. But any read/write operstion to the characteristics fails with this message:


Bluetooth powered on.

------------------------------------------------
Device Contour7802H6798544 found, try to connect...
Connected to Contour7802H6798544
*******************************************************
Service: <CBService: 0x10047a550, isPrimary = NO, UUID = Glucose>
<CBCharacteristic: 0x1005069c0, UUID = 2A18, properties = 0x10, value = (null), notifying = NO>
... has notify
<CBCharacteristic: 0x10047be80, UUID = 2A34, properties = 0x10, value = (null), notifying = NO>
... has notify
<CBCharacteristic: 0x10047a1e0, UUID = 2A51, properties = 0x2, value = (null), notifying = NO>
... has read
<CBCharacteristic: 0x10047c220, UUID = 2A52, properties = 0x28, value = (null), notifying = NO>
... has write
2020-12-12 23:35:05.701945+0100 bluetooth.test[1255:37185] [CoreBluetooth] WARNING: Unknown error: -536870212
Optional(Error Domain=CBErrorDomain Code=0 "Unknown error." UserInfo={NSLocalizedDescription=Unknown error.})
2020-12-12 23:35:05.758360+0100 bluetooth.test[1255:37186] [CoreBluetooth] WARNING: Unknown error: -536870212
*******************************************************
Error changing notification state:Optional("Unknown error.")
CBCharacteristicProperties(rawValue: 16)


The console app of macos show the following corresponding error:

standard 12:18:36.349729+0100 bluetoothd Read Device Name: c7532430
standard 12:18:36.393712+0100 bluetoothd ***** [handleATTErrorResponse].
fehler 12:18:36.393780+0100 bluetoothd ***** [handleATTErrorResponse] - Insufficient Encryption.
standard 12:18:36.393820+0100 bluetoothd ***** [handleATTErrorResponse] - Link is not encrypted, perform pairing with MITM disbled.
standard 12:18:36.393858+0100 bluetoothd ***** [startLESecurityManagerPairingSecureConnection] Start secure pairing with mitm: 0, bonding: 1, sc: 1, keypress: 0, ct2: 0
standard 12:18:36.394505+0100 bluetoothd ***** [startLESecurityManagerPairingSecureConnection] - Master: _localAuthReq: 0x9, localInitiatorKeyDistribution: 0x3, localResponderKeyDistribution: 0x3
standard 12:18:36.394572+0100 bluetoothd ***** [pairingRequest] Send Pairing Request: auth 0x9
standard 12:18:36.417047+0100 bluetoothd ***** [l2capChannelData] - Received Pairing Failed.
fehler 12:18:36.417088+0100 bluetoothd *****[handlePairingFailed] reason = 5.
fehler 12:18:36.418854+0100 bluetooth.test WARNING: Unknown error: -536870212

In the Bluetooth settings the Countour device is paired, but on the iMac without exchange the pairing code like in iOS.
What can I do? I mean it should be possible to handle BLE development in macOS with any BLE capable device, isn't it?

To be complete, here' the code:
//
// main.swift
// bluetooth.test
//
// Created by Christoph Bilz on 07.12.20.
//

import Foundation
import CoreBluetooth

let serviceGlucose = CBUUID(string: "1808");
let glucoseMeasurementCharacteristicCBUUID = CBUUID(string: "2A18");
let glucoseMeasurementContextCharacteristicCBUUID = CBUUID(string: "2A34");
let glucoseFeatureCharacteristicCBUUID = CBUUID(string: "2A51");
let readAccessControlPointCharacteristicCBUUID = CBUUID(string: "2A52");

// MARK: - BLE Class

class BLE : NSObject, CBCentralManagerDelegate, CBPeripheralDelegate {

var centralManager : CBCentralManager!
var characteristics: [CBUUID : CBCharacteristic] = [:]
var device: CBPeripheral?

override init() {

super.init();

centralManager = CBCentralManager(delegate: self, queue: DispatchQueue.global());
}

func hex(from string: String) -> Data? {
.init(stride(from: 0, to: string.count, by: 2).map {
string[string.index(string.startIndex, offsetBy: $0) ... string.index(string.startIndex, offsetBy: $0 + 1)]
}.map {
UInt8($0, radix: 16)!
})
}

// MARK: - didUpdateState

func centralManagerDidUpdateState(_ central: CBCentralManager) {

if(central.state == CBManagerState.poweredOn) {

print("Bluetooth powered on.");

central.scanForPeripherals(withServices: nil, options: nil);

} else {

print("Error: Bluetooth not powerd on.");
}
}

// func startScan() {
// print("Now Scanning...")
// self.timer.invalidate()
// cm?.scanForPeripherals(withServices: nil , options: [CBCentralManagerScanOptionAllowDuplicatesKey:false])
// Timer.scheduledTimer(timeInterval: 30, target: self, selector: #selector(self.cancelScan), userInfo: nil, repeats: false)
// }
//
// @objc func cancelScan() {
// self.cm?.stopScan()
// print("Scan Stopped")
// print("Number of Peripherals Found: \(peripherals.count)")
// }

// MARK: - didDiscover

func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral,advertisementData: [String : Any], rssi RSSI: NSNumber) {

guard let pname = peripheral.name else {
return;
}

if(pname.hasPrefix("Contour") || pname.hasPrefix("Christoph")) {
print("Device " + pname + " found, try to connect...");

device = peripheral as CBPeripheral

device?.delegate = self;

central.connect(device!, options: nil);

central.stopScan();



} else {

print("Unknown device \(pname)");
print(peripheral);
print("------------------------------------------------")
}
}

// MARK: - didConnect

func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {

print("Connected to " + (peripheral.name ?? "unknown"));
peripheral.discoverServices(nil);
}

// MARK: - didDiscoverServices

func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
print("*******************************************************")

if ((error) != nil) {
print("Error discovering services: \(error!.localizedDescription)")
return
}

guard let services = peripheral.services else {
return
}

for service in services {

if(service.uuid == serviceGlucose) {

print("Service: " + service.description)
peripheral.discoverCharacteristics(nil, for: service)
}
}
}

// MARK: - didDiscoverCharacteristics

func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {

if ((error) != nil) {
print("Error discovering services: \(error!.localizedDescription)")
return
}

guard let _characteristics = service.characteristics else {
return
}

var cpMember = Dictionary<String,CBCharacteristicProperties>();

cpMember = ["read":.read,"write":.write,"notify":.notify];


for _characteristic in _characteristics {

characteristics[_characteristic.uuid] = _characteristic;

print(_characteristic);

for (md,m) in cpMember {

if(_characteristic.properties.contains(m)) {
print("... has \(md)");
}
}

switch(_characteristic.uuid) {

case CBUUID(string: "2A18"):
peripheral.setNotifyValue(true, for: _characteristic);

case CBUUID(string: "2A52"):
// guard let data = hex(from: "0101") else {
// print("error operator set");
// return;
// }
let data = Data([0x01,0x01,0x00]);
peripheral.writeValue(data , for: _characteristic, type: .withResponse);

default:
();
}

//peripheral.discoverDescriptors(for: characteristic)
}
}

func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {

print(error);

}
// MARK: - didUpdateValueFor

func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {

print("------------------------------------------");
print(characteristic.uuid);
print(characteristic.value ?? "no value")

}

// MARK: - didDiscoverDescriptors

// func peripheral(_ peripheral: CBPeripheral, didDiscoverDescriptorsFor characteristic: CBCharacteristic, error: Error?) {
// print("*******************************************************")
//
// if error != nil {
// print("\(error.debugDescription)")
// return
// }
// guard let descriptors = characteristic.descriptors else { return }
//
// descriptors.forEach { descript in
// print("function name: DidDiscoverDescriptorForChar \(String(describing: descript.description))")
// print("Rx Value \(String(describing: rxCharacteristic?.value))")
// print("Tx Value \(String(describing: txCharacteristic?.value))")
//
// }
// }
//
// MARK: - didUpdateNotificationStateFor

func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
print("*******************************************************")

if (error != nil) {
print("Error changing notification state:\(String(describing: error?.localizedDescription))")
print(characteristic.properties)

} else {
print("Characteristic's value subscribed")
}

if (characteristic.isNotifying) {
print ("Subscribed. Notification has begun for: \(characteristic.uuid)")
}
}
}



// MARK: - Main Loop

BLE();

RunLoop.current.run();
 
I don't think this is about it being from a Mac - you could try and run the same code on an iOS device connected to the Bluetooth device to see if it fails there too, just to rule out macOS -> device setup and configuration.

I've not had to deal with the CoreBluetooth framework myself, but have you followed the developer docs for using it? Could be something still needs setting
Also dunno if it was MacRumors' codebox to blame here, but the indentation is whack, haha
 
Had the same idea this morning. Will give a try on a physical iOS device today. I have still another older model iMac with Mojave and Xcode 10, I will try too.
This test was made with an iMac 18.1 and Catalina 10.15.5.
If I google the error number an some of the message keywords, very, very sparse hits found about the topic around the world.

However it seems there are not so much BLE experts in the world...
 
Compiled directly for iOS running on physicak device brings the same error with the difference that core.bluetooth raises the error directly:


Device Contour7802H6798544 found, try to connect...
Connected to Contour7802H6798544
*******************************************************
Service: <CBService: 0x28387dc40, isPrimary = YES, UUID = Glucose>
<CBCharacteristic: 0x2809f40c0, UUID = 2A18, properties = 0x10, value = (null), notifying = NO>
... has notify
<CBCharacteristic: 0x2809f5c20, UUID = 2A34, properties = 0x10, value = (null), notifying = NO>
... has notify
<CBCharacteristic: 0x2809f5da0, UUID = 2A51, properties = 0x2, value = (null), notifying = NO>
... has read
<CBCharacteristic: 0x2809f5e00, UUID = 2A52, properties = 0x28, value = (null), notifying = NO>
... has write
*******************************************************
Error changing notification state:Optional("Encryption is insufficient.")
CBCharacteristicProperties(rawValue: 16)

I've test the device with a diabetes app and its works. So it seems it's my fault. But I have no idea what's missing in my code. There a several examples out there showing the basics how access an device via BLE should happen. And my code follows these (simple) examples.

Apple itself provides the BLE programming guide which offers a base line with topics you get along for the most common use:

  • Start up a central manager object
  • Discover and connect to peripheral devices that are advertising
  • Explore the data on a peripheral device after you’ve connected to it
  • Send read and write requests to a characteristic value of a peripheral’s service
  • Subscribe to a characteristic’s value to be notified when it is updated

I couldn't find any advicde regarding encryption processing or any special procedures regarding pairing (which obviously happens automatically in BLE when read/write to a characteristic.

I'm very appreciating for any advice for a better understanding and how I could get it work.
 
Wish I had more experience with this stuff to help out further. - The error doesn't indicate it as the issue, but could this be a permissions problem? You may need to update a plist file and ask for permission to use Bluetooth on devices
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.