import Foundation final class TransferHandler: ObservableObject { @Published var bytesTransferred: Double = 0.0 @Published var totalBytes: Double = 0.0 @Published var measurements: [TemperatureMeasurement] = [] @Published var transferIsRunning = false func startTransfer(from device: BluetoothDevice, with info: DeviceInfo, storage: PersistentStorage) { #warning("Update device info during transfer") discardTransfer() transferIsRunning = true let total = info.numberOfRecordedBytes let chunkSize = info.transferBlockSize totalBytes = Double(total) Task { defer { DispatchQueue.main.async { self.transferIsRunning = false } } var data = Data(capacity: total) while data.count < total { let remainingBytes = total - data.count let currentChunkSize = min(remainingBytes, chunkSize) guard let chunk = await device.getDeviceData(offset: data.count, count: currentChunkSize) else { log.warning("Failed to finish transfer") return } guard !chunk.isEmpty else { break } data.append(chunk) let count = Double(data.count) DispatchQueue.main.async { self.bytesTransferred = count } } if data.count != info.numberOfRecordedBytes { log.warning("Expected \(info.numberOfRecordedBytes) in transfer, got only \(data.count)") } let sum = data.reduce(0) { $0 &+ UInt16($1) } if sum != info.dataChecksum { log.warning("Checksum does not match") } if data.count != 4 * info.numberOfStoredMeasurements { log.warning("expected \(4 * info.numberOfStoredMeasurements) bytes for \(info.numberOfStoredMeasurements) measurements, got \(data.count)") } storage.saveTransferData(data: data, date: info.time.date) DispatchQueue.main.async { self.bytesTransferred = self.totalBytes } let recordingStart = info.currentMeasurementStartTime while !data.isEmpty { guard data.count >= 4 else { log.error("Expected four bytes at index \(total - data.count - 1)") break } let intervalCount = try! data.decodeUInt16() let temp0 = TemperatureValue(byte: data.removeFirst()) let temp1 = TemperatureValue(byte: data.removeFirst()) let date = recordingStart .addingTimeInterval(TimeInterval(intervalCount) * TimeInterval(info.measurementInterval)) let measurement = TemperatureMeasurement( sensor0: temp0, sensor1: temp1, date: date) DispatchQueue.main.async { self.measurements.append(measurement) } } } } func saveTransfer(in storage: PersistentStorage) { storage.add(measurements) discardTransfer() } func discardTransfer() { self.measurements = [] self.bytesTransferred = 0 self.totalBytes = 0 } }