2023-06-03 08:15:00 +02:00
|
|
|
import Foundation
|
|
|
|
|
|
|
|
struct DeviceInfo {
|
2023-07-02 17:29:39 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
The maximum factor by which the device clock can run
|
|
|
|
*/
|
|
|
|
private let maximumTimeDilationFactor: Double = 0.01
|
|
|
|
|
|
|
|
|
2023-06-03 08:15:00 +02:00
|
|
|
/// The number of bytes recorded by the tracker
|
|
|
|
let numberOfRecordedBytes: Int
|
|
|
|
|
|
|
|
/// The number of measurements already performed
|
2023-06-08 14:57:40 +02:00
|
|
|
let numberOfStoredMeasurements: Int
|
|
|
|
|
2023-06-03 08:15:00 +02:00
|
|
|
/// The interval between measurements (in seconds)
|
|
|
|
let measurementInterval: Int
|
|
|
|
|
|
|
|
let sensor0: TemperatureSensor?
|
|
|
|
|
|
|
|
let sensor1: TemperatureSensor?
|
|
|
|
|
2023-06-08 09:52:20 +02:00
|
|
|
// MARK: Device time
|
2023-06-03 08:15:00 +02:00
|
|
|
|
2023-06-13 17:14:57 +02:00
|
|
|
let wakeupReason: DeviceWakeCause
|
2023-07-02 17:29:39 +02:00
|
|
|
|
|
|
|
let time: DeviceTime
|
2023-06-13 17:14:57 +02:00
|
|
|
|
2023-06-08 09:52:20 +02:00
|
|
|
// MARK: Storage
|
|
|
|
|
|
|
|
let storageSize: Int
|
|
|
|
|
|
|
|
/// The maximum number of bytes which can be requested
|
|
|
|
let transferBlockSize: Int
|
2023-06-03 08:15:00 +02:00
|
|
|
|
|
|
|
var storageFillRatio: Double {
|
|
|
|
Double(numberOfRecordedBytes) / Double(storageSize)
|
|
|
|
}
|
|
|
|
|
|
|
|
var storageFillPercentage: Int {
|
|
|
|
Int((storageFillRatio * 100).rounded())
|
|
|
|
}
|
2023-07-02 17:29:39 +02:00
|
|
|
|
|
|
|
var currentMeasurementStartTime: Date {
|
|
|
|
time.nextMeasurement.addingTimeInterval(-Double(numberOfStoredMeasurements * measurementInterval))
|
2023-06-08 14:57:40 +02:00
|
|
|
}
|
2023-06-14 17:52:43 +02:00
|
|
|
|
2023-07-02 17:29:39 +02:00
|
|
|
func estimatedTimeDilation(to previous: DeviceTime?) -> (start: Date, dilation: Double) {
|
|
|
|
let trivialResult = (start: currentMeasurementStartTime, dilation: 1.0)
|
|
|
|
guard let previous else {
|
|
|
|
log.info("No previous device time to compare")
|
|
|
|
return trivialResult
|
|
|
|
}
|
|
|
|
// Check if device was restarted in between
|
|
|
|
guard time.secondsSincePowerOn >= previous.secondsSincePowerOn else {
|
|
|
|
log.info("Device restarted (runtime decreased from \(previous.secondsSincePowerOn) to \(time.secondsSincePowerOn))")
|
|
|
|
return trivialResult
|
|
|
|
}
|
|
|
|
let newMeasurementCount = time.totalNumberOfMeasurements - previous.totalNumberOfMeasurements
|
|
|
|
guard newMeasurementCount >= 0 else {
|
|
|
|
log.info("Device restarted (measurements decreased from \(previous.totalNumberOfMeasurements) to \(time.totalNumberOfMeasurements))")
|
|
|
|
return trivialResult
|
|
|
|
}
|
|
|
|
guard newMeasurementCount > 0 else {
|
|
|
|
log.warning("No new measurements to calculate time difference")
|
|
|
|
return trivialResult
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that no measurements are missing
|
|
|
|
|
|
|
|
// Calculate the difference between the expected time for the next measurement and the device time
|
|
|
|
let deviceTimeDifference = Double(newMeasurementCount * measurementInterval)
|
|
|
|
let expectedNextMeasurement = previous.nextMeasurement.addingTimeInterval(deviceTimeDifference)
|
|
|
|
let timeDifference = time.nextMeasurement.timeIntervalSince(expectedNextMeasurement)
|
|
|
|
|
|
|
|
let realTimeDifference = time.nextMeasurement.timeIntervalSince(previous.nextMeasurement)
|
|
|
|
let timeDilation = realTimeDifference / deviceTimeDifference
|
|
|
|
|
|
|
|
log.info("Device time dilation \(timeDilation) (difference \(timeDifference))")
|
|
|
|
|
|
|
|
guard abs(timeDilation - 1.0) < maximumTimeDilationFactor else {
|
|
|
|
log.warning("Device time too different from expected value (difference \(timeDifference) s)")
|
|
|
|
return (currentMeasurementStartTime, 1.0)
|
|
|
|
}
|
|
|
|
return (previous.nextMeasurement, timeDilation)
|
2023-06-14 17:52:43 +02:00
|
|
|
}
|
2023-06-03 08:15:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
extension DeviceInfo {
|
|
|
|
|
2023-06-08 14:57:40 +02:00
|
|
|
init(info: Data) throws {
|
2023-07-02 17:29:39 +02:00
|
|
|
let date = Date()
|
|
|
|
|
2023-06-08 14:57:40 +02:00
|
|
|
var data = info
|
|
|
|
|
|
|
|
self.numberOfRecordedBytes = try data.decodeTwoByteInteger()
|
2023-07-02 17:29:39 +02:00
|
|
|
let secondsUntilNextMeasurement = try data.decodeTwoByteInteger()
|
2023-06-08 14:57:40 +02:00
|
|
|
self.measurementInterval = try data.decodeTwoByteInteger()
|
|
|
|
self.numberOfStoredMeasurements = try data.decodeTwoByteInteger()
|
2023-07-02 17:29:39 +02:00
|
|
|
let totalNumberOfMeasurements = try data.decodeFourByteInteger()
|
2023-06-08 14:57:40 +02:00
|
|
|
self.transferBlockSize = try data.decodeTwoByteInteger()
|
|
|
|
self.storageSize = try data.decodeTwoByteInteger()
|
|
|
|
let secondsSincePowerOn = try data.decodeFourByteInteger()
|
2023-07-02 17:29:39 +02:00
|
|
|
|
|
|
|
self.time = .init(
|
|
|
|
date: date,
|
|
|
|
secondsSincePowerOn: secondsSincePowerOn,
|
|
|
|
totalNumberOfMeasurements: totalNumberOfMeasurements,
|
|
|
|
secondsUntilNextMeasurement: secondsUntilNextMeasurement)
|
|
|
|
let _ = try data.decodeFourByteInteger()
|
2023-06-08 14:57:40 +02:00
|
|
|
self.sensor0 = try data.decodeSensor()
|
|
|
|
self.sensor1 = try data.decodeSensor()
|
2023-06-13 17:14:57 +02:00
|
|
|
self.wakeupReason = .init(rawValue: try data.getByte()) ?? .WAKEUP_UNDEFINED
|
2023-06-03 08:15:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extension DeviceInfo {
|
|
|
|
|
|
|
|
static var mock: DeviceInfo {
|
|
|
|
.init(
|
|
|
|
numberOfRecordedBytes: 123,
|
2023-06-08 14:57:40 +02:00
|
|
|
numberOfStoredMeasurements: 234,
|
2023-06-03 08:15:00 +02:00
|
|
|
measurementInterval: 60,
|
|
|
|
sensor0: .init(address: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08], value: .value(21.0), date: .now.addingTimeInterval(-2)),
|
|
|
|
sensor1: .init(address: [0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09], value: .value(19.0), date: .now.addingTimeInterval(-4)),
|
2023-06-13 17:14:57 +02:00
|
|
|
wakeupReason: .WAKEUP_EXT0,
|
2023-07-02 17:29:39 +02:00
|
|
|
time: .mock,
|
2023-06-08 09:52:20 +02:00
|
|
|
storageSize: 10000,
|
|
|
|
transferBlockSize: 180)
|
2023-06-03 08:15:00 +02:00
|
|
|
}
|
|
|
|
}
|