Add log view, manual transfer
This commit is contained in:
@@ -10,6 +10,17 @@ final class BluetoothClient: ObservableObject {
|
||||
private let connection = DeviceManager()
|
||||
|
||||
private let storage: TemperatureStorage
|
||||
|
||||
var hasInfo: Bool {
|
||||
deviceInfo != nil
|
||||
}
|
||||
|
||||
var isConnected: Bool {
|
||||
if case .configured = deviceState {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
init(storage: TemperatureStorage, deviceInfo: DeviceInfo? = nil) {
|
||||
self.storage = storage
|
||||
@@ -24,7 +35,7 @@ final class BluetoothClient: ObservableObject {
|
||||
@Published
|
||||
private(set) var deviceState: DeviceState = .disconnected {
|
||||
didSet {
|
||||
print("State: \(deviceState)")
|
||||
log.info("State: \(deviceState)")
|
||||
if case .configured = deviceState {
|
||||
startRegularUpdates()
|
||||
} else {
|
||||
@@ -37,7 +48,7 @@ final class BluetoothClient: ObservableObject {
|
||||
private(set) var deviceInfo: DeviceInfo? {
|
||||
didSet {
|
||||
updateDeviceTimeIfNeeded()
|
||||
collectRecordedData()
|
||||
// collectRecordedData()
|
||||
if let deviceInfo, let runningTransfer {
|
||||
runningTransfer.update(info: deviceInfo)
|
||||
let next = runningTransfer.nextRequest()
|
||||
@@ -68,7 +79,7 @@ final class BluetoothClient: ObservableObject {
|
||||
guard dataUpdateTimer == nil else {
|
||||
return
|
||||
}
|
||||
print("Starting updates")
|
||||
log.info("Starting updates")
|
||||
dataUpdateTimer = Timer.scheduledTimer(withTimeInterval: updateInterval, repeats: true) { [weak self] timer in
|
||||
guard let self = self else {
|
||||
timer.invalidate()
|
||||
@@ -87,7 +98,7 @@ final class BluetoothClient: ObservableObject {
|
||||
dataUpdateTimer.invalidate()
|
||||
runningRequest = nil
|
||||
self.dataUpdateTimer = nil
|
||||
print("Ending updates")
|
||||
log.info("Ending updates")
|
||||
}
|
||||
|
||||
// MARK: Requests
|
||||
@@ -102,7 +113,7 @@ final class BluetoothClient: ObservableObject {
|
||||
let next = openRequests.removeFirst()
|
||||
|
||||
guard connection.send(next.serialized) else {
|
||||
print("Failed to start request \(next)")
|
||||
log.warning("Failed to start request \(next)")
|
||||
performNextRequest()
|
||||
return
|
||||
}
|
||||
@@ -115,11 +126,11 @@ final class BluetoothClient: ObservableObject {
|
||||
}
|
||||
let type = request.byte
|
||||
if let runningRequest, runningRequest.byte == type {
|
||||
print("Skipping duplicate request \(request)")
|
||||
log.info("Skipping duplicate request \(request)")
|
||||
return
|
||||
}
|
||||
guard !openRequests.contains(where: { $0.byte == type }) else {
|
||||
print("Skipping duplicate request \(request)")
|
||||
log.info("Skipping duplicate request \(request)")
|
||||
return
|
||||
}
|
||||
openRequests.append(request)
|
||||
@@ -140,7 +151,7 @@ final class BluetoothClient: ObservableObject {
|
||||
}
|
||||
let time = deviceInfo.deviceStartTime.seconds
|
||||
addRequest(.setDeviceStartTime(deviceStartTimeSeconds: time))
|
||||
print("Setting device start time to \(time) s (\(Date().seconds) current)")
|
||||
log.info("Setting device start time to \(time) s (\(Date().seconds) current)")
|
||||
}
|
||||
|
||||
// MARK: Data transfer
|
||||
@@ -148,15 +159,15 @@ final class BluetoothClient: ObservableObject {
|
||||
@discardableResult
|
||||
func collectRecordedData() -> Bool {
|
||||
guard runningTransfer == nil else {
|
||||
print("Transfer already running")
|
||||
log.info("Transfer already running")
|
||||
return false
|
||||
}
|
||||
guard !openRequests.contains(where: { if case .getRecordingData = $0 { return true }; return false }) else {
|
||||
print("Transfer already in scheduled")
|
||||
log.info("Transfer already scheduled")
|
||||
return false
|
||||
}
|
||||
guard let info = deviceInfo else {
|
||||
print("No device info to start transfer")
|
||||
log.warning("No device info to start transfer")
|
||||
return false
|
||||
}
|
||||
guard info.numberOfStoredMeasurements > 0 else {
|
||||
@@ -166,14 +177,14 @@ final class BluetoothClient: ObservableObject {
|
||||
let transfer = TemperatureDataTransfer(info: info)
|
||||
runningTransfer = transfer
|
||||
let next = transfer.nextRequest()
|
||||
print("Starting transfer")
|
||||
log.info("Starting transfer")
|
||||
addRequest(next)
|
||||
return true
|
||||
}
|
||||
|
||||
private func didReceive(data: Data, offset: Int, count: Int) {
|
||||
guard let runningTransfer else {
|
||||
print("No running transfer to process device data")
|
||||
log.warning("No running transfer to process device data")
|
||||
return // TODO: Start new transfer?
|
||||
}
|
||||
runningTransfer.add(data: data, offset: offset, count: count)
|
||||
@@ -183,7 +194,7 @@ final class BluetoothClient: ObservableObject {
|
||||
|
||||
private func decode(info: Data) {
|
||||
guard let newInfo = try? DeviceInfo(info: info) else {
|
||||
print("Failed to decode device info")
|
||||
log.error("Failed to decode device info")
|
||||
return
|
||||
}
|
||||
self.deviceInfo = newInfo
|
||||
@@ -197,25 +208,25 @@ extension BluetoothClient: DeviceManagerDelegate {
|
||||
performNextRequest()
|
||||
}
|
||||
guard let runningRequest else {
|
||||
print("No request active, but \(data) received")
|
||||
log.warning("No request active, but \(data) received")
|
||||
return
|
||||
}
|
||||
self.runningRequest = nil
|
||||
|
||||
guard data.count > 0 else {
|
||||
print("No response data for request \(runningRequest)")
|
||||
log.error("No response data for request \(runningRequest)")
|
||||
return
|
||||
}
|
||||
|
||||
guard let type = BluetoothResponseType(rawValue: data[0]) else {
|
||||
print("Unknown response \(data[0]) for request \(runningRequest)")
|
||||
log.error("Unknown response \(data[0]) for request \(runningRequest)")
|
||||
return
|
||||
}
|
||||
switch type {
|
||||
case .success:
|
||||
break
|
||||
case .responseInProgress:
|
||||
print("Device is busy for \(runningRequest)")
|
||||
log.info("Device is busy for \(runningRequest)")
|
||||
// Retry the request
|
||||
addRequest(runningRequest)
|
||||
return
|
||||
@@ -226,7 +237,7 @@ extension BluetoothClient: DeviceManagerDelegate {
|
||||
addRequest(.getInfo)
|
||||
return
|
||||
}
|
||||
print("Request \(runningRequest) received non-matching responde about number of bytes to delete")
|
||||
log.error("Request \(runningRequest) received non-matching responde about number of bytes to delete")
|
||||
case .responseTooLarge:
|
||||
guard case .getRecordingData = runningRequest else {
|
||||
// If requesting bytes fails due to the response size,
|
||||
@@ -234,9 +245,9 @@ extension BluetoothClient: DeviceManagerDelegate {
|
||||
addRequest(.getInfo)
|
||||
return
|
||||
}
|
||||
print("Unexpectedly exceeded payload size for request \(runningRequest)")
|
||||
log.error("Unexpectedly exceeded payload size for request \(runningRequest)")
|
||||
default:
|
||||
print("Unknown response \(data[0]) for request \(runningRequest)")
|
||||
log.error("Unknown response \(data[0]) for request \(runningRequest)")
|
||||
// If clearing the recording buffer fails due to byte mismatch,
|
||||
// then requesting new info will resolve the mismatch, and the transfer will be resumed
|
||||
|
||||
@@ -255,14 +266,14 @@ extension BluetoothClient: DeviceManagerDelegate {
|
||||
didClearDeviceStorage()
|
||||
|
||||
case .setDeviceStartTime:
|
||||
print("Device time set")
|
||||
log.info("Device time set")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private func didClearDeviceStorage() {
|
||||
guard let runningTransfer else {
|
||||
print("No running transfer after clearing device storage")
|
||||
log.warning("No running transfer after clearing device storage")
|
||||
return
|
||||
}
|
||||
runningTransfer.completeTransfer()
|
||||
|
@@ -31,7 +31,7 @@ final class DeviceManager: NSObject, CBCentralManagerDelegate {
|
||||
func connect() -> Bool {
|
||||
switch state {
|
||||
case .bluetoothDisabled:
|
||||
print("Can't connect, bluetooth disabled")
|
||||
log.info("Can't connect, bluetooth disabled")
|
||||
return false
|
||||
case .disconnected, .bluetoothEnabled:
|
||||
break
|
||||
@@ -91,7 +91,6 @@ final class DeviceManager: NSObject, CBCentralManagerDelegate {
|
||||
}
|
||||
|
||||
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
|
||||
//print("Found device '\(peripheral.name ?? "NO_NAME")'")
|
||||
peripheral.delegate = self
|
||||
manager.connect(peripheral)
|
||||
manager.stopScan()
|
||||
@@ -107,30 +106,30 @@ final class DeviceManager: NSObject, CBCentralManagerDelegate {
|
||||
connect()
|
||||
case .unsupported:
|
||||
state = .bluetoothDisabled
|
||||
print("Bluetooth is not supported")
|
||||
log.info("Bluetooth is not supported")
|
||||
case .unknown:
|
||||
state = .bluetoothDisabled
|
||||
print("Bluetooth state is unknown")
|
||||
log.info("Bluetooth state is unknown")
|
||||
case .resetting:
|
||||
state = .bluetoothDisabled
|
||||
print("Bluetooth is resetting")
|
||||
log.info("Bluetooth is resetting")
|
||||
case .unauthorized:
|
||||
state = .bluetoothDisabled
|
||||
print("Bluetooth is not authorized")
|
||||
log.info("Bluetooth is not authorized")
|
||||
@unknown default:
|
||||
state = .bluetoothDisabled
|
||||
print("Unknown state \(central.state)")
|
||||
log.warning("Unknown state \(central.state)")
|
||||
}
|
||||
}
|
||||
|
||||
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
|
||||
//print("Connected to " + peripheral.name!)
|
||||
log.info("Connected to " + peripheral.name!)
|
||||
peripheral.discoverServices([DeviceManager.serviceUUID])
|
||||
state = .discoveringServices(device: peripheral)
|
||||
}
|
||||
|
||||
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
|
||||
print("Disconnected from " + peripheral.name!)
|
||||
log.info("Disconnected from " + peripheral.name!)
|
||||
state = .disconnected
|
||||
// Attempt to reconnect
|
||||
if shouldConnectIfPossible {
|
||||
@@ -139,9 +138,9 @@ final class DeviceManager: NSObject, CBCentralManagerDelegate {
|
||||
}
|
||||
|
||||
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
|
||||
print("Failed to connect device '\(peripheral.name ?? "NO_NAME")'")
|
||||
log.warning("Failed to connect device '\(peripheral.name ?? "NO_NAME")'")
|
||||
if let error = error {
|
||||
print(error)
|
||||
log.warning(error.localizedDescription)
|
||||
}
|
||||
state = manager.isScanning ? .scanning : .disconnected
|
||||
// Attempt to reconnect
|
||||
@@ -155,12 +154,12 @@ extension DeviceManager: CBPeripheralDelegate {
|
||||
|
||||
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
|
||||
guard let services = peripheral.services, !services.isEmpty else {
|
||||
print("No services found for device '\(peripheral.name ?? "NO_NAME")'")
|
||||
log.error("No services found for device '\(peripheral.name ?? "NO_NAME")'")
|
||||
manager.cancelPeripheralConnection(peripheral)
|
||||
return
|
||||
}
|
||||
guard let service = services.first(where: { $0.uuid.uuidString == DeviceManager.serviceUUID.uuidString }) else {
|
||||
print("Required service not found for '\(peripheral.name ?? "NO_NAME")': \(services.map { $0.uuid.uuidString})")
|
||||
log.error("Required service not found for '\(peripheral.name ?? "NO_NAME")': \(services.map { $0.uuid.uuidString})")
|
||||
manager.cancelPeripheralConnection(peripheral)
|
||||
return
|
||||
}
|
||||
@@ -170,18 +169,18 @@ extension DeviceManager: CBPeripheralDelegate {
|
||||
|
||||
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
|
||||
if let error = error {
|
||||
print("Failed to discover characteristics: \(error)")
|
||||
log.error("Failed to discover characteristics: \(error)")
|
||||
manager.cancelPeripheralConnection(peripheral)
|
||||
return
|
||||
}
|
||||
guard let characteristics = service.characteristics, !characteristics.isEmpty else {
|
||||
print("No characteristics found for device")
|
||||
log.error("No characteristics found for device")
|
||||
manager.cancelPeripheralConnection(peripheral)
|
||||
return
|
||||
}
|
||||
for characteristic in characteristics {
|
||||
guard characteristic.uuid == DeviceManager.characteristicUUID else {
|
||||
print("Unused characteristic \(characteristic.uuid.uuidString)")
|
||||
log.warning("Unused characteristic \(characteristic.uuid.uuidString)")
|
||||
continue
|
||||
}
|
||||
state = .configured(device: peripheral, characteristic: characteristic)
|
||||
@@ -191,35 +190,34 @@ extension DeviceManager: CBPeripheralDelegate {
|
||||
|
||||
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
|
||||
if let error = error {
|
||||
print("Peripheral failed to write value for \(characteristic.uuid.uuidString): \(error)")
|
||||
log.error("Peripheral failed to write value for \(characteristic.uuid.uuidString): \(error)")
|
||||
}
|
||||
//print("Peripheral did write value for \(characteristic.uuid.uuidString)")
|
||||
}
|
||||
|
||||
func peripheral(_ peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: Error?) {
|
||||
if let error = error {
|
||||
print("Failed to get RSSI: \(error)")
|
||||
log.warning("Failed to get RSSI: \(error)")
|
||||
return
|
||||
}
|
||||
lastRSSI = RSSI.intValue
|
||||
print("RSSI: \(lastRSSI)")
|
||||
log.info("RSSI: \(lastRSSI)")
|
||||
}
|
||||
|
||||
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
|
||||
if let error = error {
|
||||
print("Failed to read value update: \(error)")
|
||||
log.error("Failed to read value update: \(error)")
|
||||
return
|
||||
}
|
||||
guard case .configured(device: _, characteristic: let storedCharacteristic) = state else {
|
||||
print("Received data while not properly configured")
|
||||
log.warning("Received data while not properly configured")
|
||||
return
|
||||
}
|
||||
guard characteristic.uuid == storedCharacteristic.uuid else {
|
||||
print("Read unknown characteristic \(characteristic.uuid.uuidString)")
|
||||
log.warning("Read unknown characteristic \(characteristic.uuid.uuidString)")
|
||||
return
|
||||
}
|
||||
guard let data = characteristic.value else {
|
||||
print("No data")
|
||||
log.warning("No data")
|
||||
return
|
||||
}
|
||||
delegate?.deviceManager(didReceive: data)
|
||||
|
Reference in New Issue
Block a user