| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- //
- // 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..<numConfigs {
- let offset = 2 + 4 + i * AlertConfiguration.length
- configs.append(try AlertConfiguration(encodedData: encodedData.subdata(in: offset..<(offset+6))))
- }
- self.configurations = configs
- }
-
- public init(nonce: UInt32, configurations: [AlertConfiguration]) {
- self.nonce = nonce
- self.configurations = configurations
- }
- }
- // MARK: - AlertConfiguration encoding/decoding
- extension AlertConfiguration {
- public init(encodedData: Data) throws {
- if encodedData.count < 6 {
- throw MessageBlockError.notEnoughData
- }
- let alertTypeBits = encodedData[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))"
- }
- }
|