137 lines
4.4 KiB
Swift
137 lines
4.4 KiB
Swift
import Foundation
|
|
|
|
final class TemperatureDataTransfer {
|
|
|
|
private let startDateOfCurrentTransfer: Date
|
|
|
|
private let interval: Int
|
|
|
|
private var dataBuffer: Data = Data()
|
|
|
|
private(set) var currentByteIndex = 0
|
|
|
|
private(set) var size: Int
|
|
|
|
private(set) var blockSize: Int
|
|
|
|
private var numberOfRecordingsInCurrentTransfer = 0
|
|
|
|
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) {
|
|
self.interval = info.measurementInterval
|
|
let recordingTime = info.numberOfStoredMeasurements * info.measurementInterval
|
|
self.startDateOfCurrentTransfer = info.nextMeasurement.addingTimeInterval(-TimeInterval(recordingTime))
|
|
self.size = info.numberOfRecordedBytes
|
|
self.blockSize = info.transferBlockSize
|
|
}
|
|
|
|
func update(info: DeviceInfo) {
|
|
self.size = info.numberOfRecordedBytes
|
|
self.blockSize = info.transferBlockSize
|
|
}
|
|
|
|
func nextRequest() -> BluetoothRequest {
|
|
guard remainingBytesToTransfer > 0 else {
|
|
return .clearRecordingBuffer(byteCount: size)
|
|
}
|
|
let chunkSize = min(remainingBytesToTransfer, blockSize)
|
|
return .getRecordingData(offset: currentByteIndex, count: chunkSize)
|
|
}
|
|
|
|
func add(data: Data, offset: Int, count: Int) {
|
|
guard currentByteIndex == offset else {
|
|
log.warning("Transfer: Discarding \(data.count) bytes at offset \(offset), expected \(currentByteIndex)")
|
|
return
|
|
}
|
|
if data.count != count {
|
|
log.warning("Transfer: Expected \(count) bytes, received only \(data.count)")
|
|
}
|
|
dataBuffer.append(data)
|
|
currentByteIndex += data.count
|
|
processBytes()
|
|
log.info("Transfer: \(currentByteIndex) bytes (added \(data.count)), \(measurements.count) points")
|
|
}
|
|
|
|
private func processBytes() {
|
|
while !dataBuffer.isEmpty {
|
|
let byte = dataBuffer.removeFirst()
|
|
guard (byte == 0xFF) else {
|
|
addRelative(byte: byte)
|
|
continue
|
|
}
|
|
guard dataBuffer.count >= 2 else {
|
|
// Wait for more data
|
|
return
|
|
}
|
|
let temp0 = TemperatureValue(byte: dataBuffer.removeFirst())
|
|
let temp1 = TemperatureValue(byte: dataBuffer.removeFirst())
|
|
add(sensor0: temp0, sensor1: temp1)
|
|
}
|
|
}
|
|
|
|
func completeTransfer() {
|
|
processBytes()
|
|
if !dataBuffer.isEmpty {
|
|
log.warning("\(dataBuffer.count) bytes remaining in transfer buffer")
|
|
}
|
|
log.info("Transfer: \(currentByteIndex) bytes, \(measurements.count) points")
|
|
}
|
|
|
|
private func addRelative(byte: UInt8) {
|
|
add(sensor0: convertTemp(value: byte >> 4, 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)
|
|
|
|
numberOfRecordingsInCurrentTransfer += 1
|
|
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
|
|
}
|
|
}
|