import Foundation /* final class TemperatureDataTransfer { private let startDateOfCurrentTransfer: Date private var interval: TimeInterval { TimeInterval(info.measurementInterval) * dilation } private var dataBuffer: Data = Data() private(set) var currentByteIndex = 0 private var info: DeviceInfo private let dilation: Double var size: Int { info.numberOfRecordedBytes } var blockSize: Int { min(50, info.transferBlockSize) } private var numberOfRecordingsInCurrentTransfer: Int { measurements.count } var time: DeviceTime { info.time } var measurements: [TemperatureMeasurement] = [] /// The last temperatures to calculate relative values private var lastRecording: TemperatureMeasurement = .init(sensor0: .notFound, sensor1: .notFound, date: .now) private var dateOfNextRecording: Date { startDateOfCurrentTransfer.addingTimeInterval(TimeInterval(numberOfRecordingsInCurrentTransfer) * interval) } var unprocessedByteCount: Int { dataBuffer.count } var remainingBytesToTransfer: Int { size - currentByteIndex } init(info: DeviceInfo, previous: DeviceTime?) { let (estimatedStart, dilation) = info.estimatedTimeDilation(to: previous) log.info("Starting transfer") log.info("Estimated start of recording: \(estimatedStart)") log.info("Estimated time dilation: \(dilation)") self.info = info self.dilation = dilation self.startDateOfCurrentTransfer = estimatedStart log.info("True measurement interval: \(interval)") } func update(info: DeviceInfo) { self.info = info // Possible bug: Device time updated, but new measurement not transferred // Future transfer will calculate wrong time } func nextRequest() -> BluetoothRequest { guard remainingBytesToTransfer > 0 else { return .clearRecordingBuffer(byteCount: currentByteIndex) } let chunkSize = min(remainingBytesToTransfer, blockSize) return .getRecordingData(offset: currentByteIndex, count: chunkSize) } func add(data: Data, offset: Int, count: Int) -> Bool { guard currentByteIndex == offset else { log.warning("Transfer: Discarding \(data.count) bytes at offset \(offset), expected \(currentByteIndex)") return false } guard data.count == count else { log.warning("Transfer: Expected \(count) bytes, received only \(data.count)") return false } dataBuffer.append(data) currentByteIndex += data.count log.info("Transfer: \(currentByteIndex) bytes (added \(data.count))") return true } private func processBytes() { while !dataBuffer.isEmpty { let byte = dataBuffer.removeFirst() guard (byte == 0xFF) else { addRelative(byte: byte) continue } guard dataBuffer.count >= 2 else { // Missing data return } let temp0 = TemperatureValue(byte: dataBuffer.removeFirst()) let temp1 = TemperatureValue(byte: dataBuffer.removeFirst()) add(sensor0: temp0, sensor1: temp1) } } func completeTransfer() -> Bool { let emptyIndices = dataBuffer.enumerated().filter { $0.element == 0 }.map { $0.offset } processBytes() guard dataBuffer.isEmpty else { log.warning("\(dataBuffer.count) bytes remaining in transfer buffer") return false } log.info("Transfer complete: \(currentByteIndex) bytes, \(measurements.count) points") log.info("Empty bytes: \(emptyIndices)") if measurements.count != info.numberOfStoredMeasurements { log.warning("Decoded \(measurements.count) points, but only \(info.numberOfStoredMeasurements) recorded") } return true } private func addRelative(byte: UInt8) { add(sensor0: convertTemp(value: (byte >> 4) & 0x0F, relativeTo: lastRecording.sensor0), sensor1: convertTemp(value: byte & 0x0F, relativeTo: lastRecording.sensor1)) } private func add(sensor0: TemperatureValue, sensor1: TemperatureValue) { let measurement = TemperatureMeasurement( sensor0: sensor0, sensor1: sensor1, date: dateOfNextRecording) if measurement.sensor0.isValid { lastRecording.sensor0 = measurement.sensor0 } if measurement.sensor1.isValid { lastRecording.sensor1 = measurement.sensor1 } lastRecording.id = measurement.id measurements.append(measurement) } private func convertTemp(value: UInt8, relativeTo previous: TemperatureValue) -> TemperatureValue { if value == 0 { return .notFound } let newValue = previous.relativeValue - (Double(value) - 8) * 0.5 return .value(newValue) } } private extension TemperatureValue { var relativeValue: Double { if case .value(let double) = self { return double } return 0 } } */