// // ConfigureAlertsCommand.swift // OmniKit // // Created by Pete Schwamb on 2/22/18. // Copyright © 2018 Pete Schwamb. All rights reserved. // import Foundation public struct ConfigureAlertsCommand : NonceResyncableMessageBlock { public let blockType: MessageBlockType = .configureAlerts public var nonce: UInt32 let configurations: [AlertConfiguration] public var data: Data { var data = Data([ blockType.rawValue, UInt8(4 + configurations.count * AlertConfiguration.length), ]) data.appendBigEndian(nonce) for config in configurations { data.append(contentsOf: config.data) } return data } public init(encodedData: Data) throws { if encodedData.count < 10 { throw MessageBlockError.notEnoughData } self.nonce = encodedData[2...].toBigEndian(UInt32.self) let length = Int(encodedData[1]) let numConfigs = (length - 4) / AlertConfiguration.length var configs = [AlertConfiguration]() for i in 0..> 4 guard let alertType = AlertSlot(rawValue: alertTypeBits) else { throw MessageError.unknownValue(value: alertTypeBits, typeDescription: "AlertType") } self.slot = alertType self.active = encodedData[0] & 0b1000 != 0 self.autoOffModifier = encodedData[0] & 0b10 != 0 self.duration = TimeInterval(minutes: Double((Int(encodedData[0] & 0b1) << 8) + Int(encodedData[1]))) let yyyy = (Int(encodedData[2]) << 8) + (Int(encodedData[3])) & 0x3fff if encodedData[0] & 0b100 != 0 { let volume = Double(yyyy * 2) * Pod.pulseSize self.trigger = .unitsRemaining(volume) } else { self.trigger = .timeUntilAlert(TimeInterval(minutes: Double(yyyy))) } let beepRepeatBits = encodedData[4] guard let beepRepeat = BeepRepeat(rawValue: beepRepeatBits) else { throw MessageError.unknownValue(value: beepRepeatBits, typeDescription: "BeepRepeat") } self.beepRepeat = beepRepeat let beepTypeBits = encodedData[5] guard let beepType = BeepType(rawValue: beepTypeBits) else { throw MessageError.unknownValue(value: beepTypeBits, typeDescription: "BeepType") } self.beepType = beepType } public var data: Data { var firstByte = slot.rawValue << 4 firstByte += active ? (1 << 3) : 0 if case .unitsRemaining = trigger { firstByte += 1 << 2 } if autoOffModifier { firstByte += 1 << 1 } // High bit of duration firstByte += UInt8((Int(duration.minutes) >> 8) & 0x1) var data = Data([ firstByte, UInt8(Int(duration.minutes) & 0xff) ]) switch trigger { case .unitsRemaining(let volume): let ticks = UInt16(volume / Pod.pulseSize / 2) data.appendBigEndian(ticks) case .timeUntilAlert(let secondsUntilAlert): // round the time to alert to the nearest minute let minutes = UInt16((secondsUntilAlert + 30).minutes) data.appendBigEndian(minutes) } data.append(beepRepeat.rawValue) data.append(beepType.rawValue) return data } } extension ConfigureAlertsCommand: CustomDebugStringConvertible { public var debugDescription: String { return "ConfigureAlertsCommand(nonce:\(Data(bigEndian: nonce).hexadecimalString), configurations:\(configurations))" } }