Skip to content
Open
Changes from 1 commit
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 @@ -16,19 +16,25 @@ class BleIoStream: NSObject, CBPeripheralDelegate {

private static let preferredServiceUUIDs: Set<CBUUID> = [
CBUUID(string: "CB3C4555-D670-4670-BC20-B61DBC851E9A"),
CBUUID(string: "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"),
]

private static let preferredWriteUUIDs: Set<CBUUID> = [
CBUUID(string: "6606AB42-89D5-4A00-A8CE-4EB5E1414EE0"),
CBUUID(string: "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"),
]
Comment thread
ericgriffin marked this conversation as resolved.

private static let preferredNotifyUUIDs: Set<CBUUID> = [
CBUUID(string: "A60B8E5C-B267-44D7-9764-837CAF96489E"),
CBUUID(string: "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"),
]

private static let pelagicGen1TxCharacteristic = CBUUID(
string: "6606AB42-89D5-4A00-A8CE-4EB5E1414EE0"
)
private static let crestCr5lTxCharacteristic = CBUUID(
string: "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
)
Comment thread
ericgriffin marked this conversation as resolved.
Outdated
private static let notifySettleDelaySeconds: TimeInterval = 0.3
private static let bleIoctlType: UInt32 = UInt32(Character("b").asciiValue!)
private static let bleIoctlGetNameNumber: UInt32 = 0
Expand All @@ -45,12 +51,14 @@ class BleIoStream: NSObject, CBPeripheralDelegate {

private var writeCharacteristic: CBCharacteristic?
private var notifyCharacteristic: CBCharacteristic?
private var subscribedCharacteristics: [CBCharacteristic] = []
Comment thread
ericgriffin marked this conversation as resolved.
private var bestCandidate: CharacteristicCandidate?
private var remainingServiceDiscoveries = 0
private var discoverySignaled = false

private let readLock = NSLock()
private var readBuffer = Data()
private var readPackets: [Data] = []
private var partialReadBuffer = Data()
private let readSemaphore = DispatchSemaphore(value: 0)
private let writeSemaphore = DispatchSemaphore(value: 0)
private let writeReadySemaphore = DispatchSemaphore(value: 0)
Expand Down Expand Up @@ -138,6 +146,7 @@ class BleIoStream: NSObject, CBPeripheralDelegate {
bestCandidate = nil
writeCharacteristic = nil
notifyCharacteristic = nil
subscribedCharacteristics = []
hasSeenNotify = false
writeWithoutResponsePreferred = false
consecutiveReadTimeouts = 0
Expand Down Expand Up @@ -261,9 +270,9 @@ class BleIoStream: NSObject, CBPeripheralDelegate {
private static let cPoll: libdc_io_poll_fn = { userdata, timeout in
let stream = Unmanaged<BleIoStream>.fromOpaque(userdata!).takeUnretainedValue()
stream.readLock.lock()
let available = stream.readBuffer.count
let available = !stream.partialReadBuffer.isEmpty || !stream.readPackets.isEmpty
stream.readLock.unlock()
if available > 0 { return Int32(LIBDC_STATUS_SUCCESS) }
if available { return Int32(LIBDC_STATUS_SUCCESS) }

if timeout == 0 { return Int32(LIBDC_STATUS_TIMEOUT) }

Expand All @@ -286,13 +295,15 @@ class BleIoStream: NSObject, CBPeripheralDelegate {

while true {
readLock.lock()
let available = readBuffer.count
if available > 0 {
let bytesToRead = min(size, readBuffer.count)
_ = readBuffer.withUnsafeBytes { ptr in
if partialReadBuffer.isEmpty, !readPackets.isEmpty {
partialReadBuffer = readPackets.removeFirst()
}
Comment thread
ericgriffin marked this conversation as resolved.
if !partialReadBuffer.isEmpty {
let bytesToRead = min(size, partialReadBuffer.count)
_ = partialReadBuffer.withUnsafeBytes { ptr in
memcpy(data, ptr.baseAddress!, bytesToRead)
}
readBuffer.removeFirst(bytesToRead)
partialReadBuffer.removeFirst(bytesToRead)
Comment thread
ericgriffin marked this conversation as resolved.
readLock.unlock()
actual.pointee = bytesToRead
return Int32(LIBDC_STATUS_SUCCESS)
Comment thread
ericgriffin marked this conversation as resolved.
Expand Down Expand Up @@ -392,7 +403,8 @@ class BleIoStream: NSObject, CBPeripheralDelegate {
}

readLock.lock()
readBuffer.removeAll(keepingCapacity: true)
readPackets.removeAll(keepingCapacity: true)
partialReadBuffer.removeAll(keepingCapacity: true)
readLock.unlock()
drainSemaphore(readSemaphore)
return Int32(LIBDC_STATUS_SUCCESS)
Expand Down Expand Up @@ -431,6 +443,9 @@ class BleIoStream: NSObject, CBPeripheralDelegate {

private func initialWriteWithoutResponsePreference(for characteristic: CBCharacteristic) -> Bool {
let properties = characteristic.properties
if characteristic.uuid == Self.crestCr5lTxCharacteristic {
return false
}
if characteristic.uuid == Self.pelagicGen1TxCharacteristic {
return true
}
Expand Down Expand Up @@ -626,7 +641,7 @@ class BleIoStream: NSObject, CBPeripheralDelegate {
+ " \(error.localizedDescription)")
return
}
if let notify = notifyCharacteristic, characteristic.uuid != notify.uuid {
guard subscribedCharacteristics.contains(where: { $0.uuid == characteristic.uuid }) else {
Comment thread
ericgriffin marked this conversation as resolved.
return
}
guard let value = characteristic.value else { return }
Expand All @@ -637,7 +652,7 @@ class BleIoStream: NSObject, CBPeripheralDelegate {
+ " bytes=\(value.count)"
+ " data=\(Self.hexString(value, maxBytes: Self.maxLogBytes))")
readLock.lock()
readBuffer.append(value)
readPackets.append(value)
Comment thread
ericgriffin marked this conversation as resolved.
readLock.unlock()
readSemaphore.signal()
}
Expand All @@ -660,11 +675,10 @@ class BleIoStream: NSObject, CBPeripheralDelegate {
func peripheral(_ peripheral: CBPeripheral,
didUpdateNotificationStateFor characteristic: CBCharacteristic,
error: Error?) {
guard let notify = notifyCharacteristic, characteristic.uuid == notify.uuid else {
guard subscribedCharacteristics.contains(where: { $0.uuid == characteristic.uuid }) else {
return
}
guard waitingForNotifyEnable else { return }
waitingForNotifyEnable = false

if let error {
NativeLogger.e("BleIoStream", category: "BLE",
Expand All @@ -681,8 +695,11 @@ class BleIoStream: NSObject, CBPeripheralDelegate {
}
NativeLogger.d("BleIoStream", category: "BLE",
"Notify enabled for \(characteristic.uuid.uuidString)")
isReady = true
signalDiscoveryReady()
if subscribedCharacteristics.allSatisfy(\.isNotifying) {
waitingForNotifyEnable = false
isReady = true
signalDiscoveryReady()
}
Comment thread
ericgriffin marked this conversation as resolved.
}

private func signalDiscoveryReady() {
Expand Down Expand Up @@ -749,23 +766,39 @@ class BleIoStream: NSObject, CBPeripheralDelegate {

writeCharacteristic = candidate.write
notifyCharacteristic = candidate.notify
let serviceCharacteristics = candidate.write.service?.characteristics ?? []
if candidate.write.uuid == Self.crestCr5lTxCharacteristic {
subscribedCharacteristics = serviceCharacteristics.filter {
$0.properties.contains(.notify) || $0.properties.contains(.indicate)
}
if subscribedCharacteristics.isEmpty {
subscribedCharacteristics = [candidate.notify]
}
} else {
subscribedCharacteristics = [candidate.notify]
}
Comment thread
ericgriffin marked this conversation as resolved.
writeWithoutResponsePreferred = initialWriteWithoutResponsePreference(for: candidate.write)
NativeLogger.d("BleIoStream", category: "BLE",
"Selected write=\(candidate.write.uuid.uuidString)"
+ " (\(Self.propertySummary(candidate.write.properties)))"
+ " notify=\(candidate.notify.uuid.uuidString)"
+ " (\(Self.propertySummary(candidate.notify.properties)))"
+ " (score=\(candidate.score))")
NativeLogger.d("BleIoStream", category: "BLE",
"Subscribed characteristics:"
+ " \(subscribedCharacteristics.map { $0.uuid.uuidString }.joined(separator: ","))")
NativeLogger.d("BleIoStream", category: "BLE",
"Initial write mode preference:"
+ " \(writeWithoutResponsePreferred ? "withoutResponse" : "withResponse")")
if candidate.notify.isNotifying {
if !subscribedCharacteristics.isEmpty && subscribedCharacteristics.allSatisfy(\.isNotifying) {
isReady = true
signalDiscoveryReady()
return
}
waitingForNotifyEnable = true
peripheral.setNotifyValue(true, for: candidate.notify)
for characteristic in subscribedCharacteristics where !characteristic.isNotifying {
peripheral.setNotifyValue(true, for: characteristic)
}
}
}

Expand Down
Loading