Skip to content

Commit

Permalink
Merge branch 'develop' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
jmaha committed Oct 19, 2022
2 parents 6c90092 + 255ae78 commit e738847
Show file tree
Hide file tree
Showing 25 changed files with 694 additions and 245 deletions.
78 changes: 32 additions & 46 deletions Sources/CombustionBLE/BleData/AdvertisingData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,47 +28,43 @@ import Foundation

/// Enumeration of Combustion, Inc. product types.
public enum CombustionProductType: UInt8 {
case UNKNOWN = 0x00
case PROBE = 0x01
case NODE = 0x02
case unknown = 0x00
case probe = 0x01
case node = 0x02
}

/// Struct containing advertising data received from device.
public struct AdvertisingData {
struct AdvertisingData {
/// Type of Combustion product
public let type: CombustionProductType
let type: CombustionProductType
/// Product serial number
public let serialNumber: UInt32
let serialNumber: UInt32
/// Latest temperatures read by device
public let temperatures: ProbeTemperatures
/// Prode ID
public let id: ProbeID
/// Probe Color
public let color: ProbeColor
/// Probe mode
public let mode: ProbeMode
/// Battery Status
public let batteryStatus: BatteryStatus
let temperatures: ProbeTemperatures
// ModeId (Probe color, ID, and mode)
let modeId: ModeId
/// Battery Status and Virtual Sensors
let batteryStatusVirtualSensors: BatteryStatusVirtualSensors
}

extension AdvertisingData {
private enum Constants {
// Locations of data in advertising packets
static let PRODUCT_TYPE_RANGE = 2..<3
static let SERIAL_RANGE = 3..<7
static let TEMPERATURE_RANGE = 7..<20
static let MODE_COLOR_ID_RANGE = 20..<21
static let BATTERY_STATUS_RANGE = 21..<22
static let DEVICE_STATUS_RANGE = 21..<22
}
}

extension AdvertisingData {

init?(fromData : Data?) {
guard let data = fromData else { return nil }
guard data.count >= 20 else { return nil }

// Product type (1 byte)
let rawType = data.subdata(in: Constants.PRODUCT_TYPE_RANGE)
let typeByte = [UInt8](rawType)
type = CombustionProductType(rawValue: typeByte[0]) ?? .UNKNOWN
type = CombustionProductType(rawValue: typeByte[0]) ?? .unknown

// Device Serial number (4 bytes)
// Reverse the byte order (this is a little-endian packed bitfield)
Expand All @@ -91,26 +87,20 @@ extension AdvertisingData {
let tempData = data.subdata(in: Constants.TEMPERATURE_RANGE)
temperatures = ProbeTemperatures.fromRawData(data: tempData)

// Decode Probe ID and Color if its present in the advertising packet
// Decode ModeId byte if present in the advertising packet
if(data.count >= 21) {
let modeIdColorData = data.subdata(in: Constants.MODE_COLOR_ID_RANGE)
id = ProbeID.fromRawData(data: modeIdColorData)
color = ProbeColor.fromRawData(data: modeIdColorData)
mode = ProbeMode.fromRawData(data: modeIdColorData)
}
else {
id = .ID1
color = .COLOR1
mode = .Normal
let byte = data.subdata(in: Constants.MODE_COLOR_ID_RANGE)[0]
modeId = ModeId.fromByte(byte)
} else {
modeId = ModeId.defaultValues()
}

// Decode battery status if its present in the advertising packet
// Decode battery status & virutal sensors if present in the advertising packet
if(data.count >= 22) {
let statusData = data.subdata(in: Constants.BATTERY_STATUS_RANGE)
batteryStatus = BatteryStatus.fromRawData(data: statusData)
}
else {
batteryStatus = .OK
let byte = data.subdata(in: Constants.DEVICE_STATUS_RANGE)[0]
batteryStatusVirtualSensors = BatteryStatusVirtualSensors.fromByte(byte)
} else {
batteryStatusVirtualSensors = BatteryStatusVirtualSensors.defaultValues()
}
}
}
Expand All @@ -119,23 +109,19 @@ extension AdvertisingData {
extension AdvertisingData {
// Fake data initializer for previews
public init(fakeSerial: UInt32) {
type = .PROBE
type = .probe
temperatures = ProbeTemperatures.withFakeData()
serialNumber = fakeSerial
id = .ID1
color = .COLOR1
mode = .Normal
batteryStatus = .OK
modeId = ModeId.defaultValues()
batteryStatusVirtualSensors = BatteryStatusVirtualSensors.defaultValues()
}

// Fake data initializer for Simulated Probe
public init(fakeSerial: UInt32, fakeTemperatures: ProbeTemperatures) {
type = .PROBE
type = .probe
temperatures = fakeTemperatures
serialNumber = fakeSerial
id = .ID1
color = .COLOR1
mode = .Normal
batteryStatus = .OK
modeId = ModeId.defaultValues()
batteryStatusVirtualSensors = BatteryStatusVirtualSensors.defaultValues()
}
}
59 changes: 59 additions & 0 deletions Sources/CombustionBLE/BleData/BatteryStatusVirtualSensors.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// BatteryStatusVirtualSensors.swift

/*--
MIT License

Copyright (c) 2021 Combustion Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--*/
import Foundation

/// Enumeration of Battery status
public enum BatteryStatus: UInt8 {
case ok = 0x00
case low = 0x01

static let MASK: UInt8 = 0x3
}

struct BatteryStatusVirtualSensors {
let batteryStatus: BatteryStatus
let virtualSensors: VirtualSensors
}

extension BatteryStatusVirtualSensors {

private enum Constants {
static let VIRTUAL_SENSORS_SHIFT: UInt8 = 1
}

static func fromByte(_ byte: UInt8) -> BatteryStatusVirtualSensors {
let rawStatus = (byte & (BatteryStatus.MASK))
let battery = BatteryStatus(rawValue: rawStatus) ?? .ok
let virtualSensors = VirtualSensors.fromByte(byte >> Constants.VIRTUAL_SENSORS_SHIFT)

return BatteryStatusVirtualSensors(batteryStatus: battery, virtualSensors: virtualSensors)
}

static func defaultValues() -> BatteryStatusVirtualSensors {
return BatteryStatusVirtualSensors(batteryStatus: .ok,
virtualSensors: VirtualSensors(virtualCore: .T1, virtualSurface: .T4, virtualAmbient: .T5))
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// ProbeID.swift
// HopCount.swift

/*--
MIT License

Copyright (c) 2021 Combustion Inc.
Copyright (c) 2022 Combustion Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand All @@ -26,25 +26,21 @@ SOFTWARE.

import Foundation

public enum ProbeID: UInt8, CaseIterable {
case ID1 = 0x00
case ID2 = 0x01
case ID3 = 0x02
case ID4 = 0x03
case ID5 = 0x04
case ID6 = 0x05
case ID7 = 0x06
case ID8 = 0x07

public enum HopCount: UInt8, CaseIterable {
case hop1 = 0x00
case hop2 = 0x01
case hop3 = 0x02
case hop4 = 0x03
}

extension HopCount {
private enum Constants {
static let PRODE_ID_MASK: UInt8 = 0x7
static let PRODE_ID_SHIFT: UInt8 = 5
static let HOP_COUNT_MASK: UInt8 = 0x3
static let HOP_COUNT_SHIFT: UInt8 = 6
}

static func fromRawData(data: Data) -> ProbeID {
let modeIdColorBytes = [UInt8](data)

let rawProbeID = (modeIdColorBytes[0] & (Constants.PRODE_ID_MASK << Constants.PRODE_ID_SHIFT)) >> Constants.PRODE_ID_SHIFT
return ProbeID(rawValue: rawProbeID) ?? .ID1
static func from(deviceStatusByte: UInt8) -> HopCount {
let rawHopCount = (deviceStatusByte >> Constants.HOP_COUNT_SHIFT) & Constants.HOP_COUNT_MASK
return HopCount(rawValue: rawHopCount) ?? .hop1
}
}
89 changes: 89 additions & 0 deletions Sources/CombustionBLE/BleData/ModeId.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// ModeId.swift

/*--
MIT License

Copyright (c) 2022 Combustion Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--*/

import Foundation

public enum ProbeID: UInt8, CaseIterable {
case ID1 = 0x00
case ID2 = 0x01
case ID3 = 0x02
case ID4 = 0x03
case ID5 = 0x04
case ID6 = 0x05
case ID7 = 0x06
case ID8 = 0x07
}

public enum ProbeColor: UInt8, CaseIterable {
case color1 = 0x00
case color2 = 0x01
case color3 = 0x02
case color4 = 0x03
case color5 = 0x04
case color6 = 0x05
case color7 = 0x06
case color8 = 0x07
}

public enum ProbeMode: UInt8, CaseIterable {
case normal = 0x00
case instantRead = 0x01
case reserved = 0x02
case error = 0x03
}

struct ModeId {
let id: ProbeID
let color: ProbeColor
let mode: ProbeMode
}

extension ModeId {
private enum Constants {
static let PRODE_ID_MASK: UInt8 = 0x7
static let PRODE_ID_SHIFT: UInt8 = 5
static let PRODE_COLOR_MASK: UInt8 = 0x7
static let PRODE_COLOR_SHIFT: UInt8 = 2
static let PRODE_MODE_MASK: UInt8 = 0x3
}

static func fromByte(_ byte: UInt8) -> ModeId {
let rawProbeID = (byte >> Constants.PRODE_ID_SHIFT ) & Constants.PRODE_ID_MASK
let id = ProbeID(rawValue: rawProbeID) ?? .ID1

let rawProbeColor = (byte >> Constants.PRODE_COLOR_SHIFT) & Constants.PRODE_COLOR_MASK
let color = ProbeColor(rawValue: rawProbeColor) ?? .color1

let rawMode = byte & (Constants.PRODE_MODE_MASK)
let mode = ProbeMode(rawValue: rawMode) ?? .normal

return ModeId(id: id, color: color, mode: mode)
}

static func defaultValues() -> ModeId {
return ModeId(id: .ID1, color: .color1, mode: .normal)
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// BatteryStatus.swift
// PredictionMode.swift

/*--
MIT License
Expand All @@ -23,21 +23,14 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--*/

import Foundation

/// Enumeration of Battery status
public enum BatteryStatus: UInt8 {
case OK = 0x00
case LOW = 0x01

private enum Constants {
static let BATTERY_MASK: UInt8 = 0x3
}
public enum PredictionMode: UInt8, CaseIterable {
case none = 0x00
case timeToRemoval = 0x01
case removalAndResting = 0x02
case reserved = 0x03

static func fromRawData(data: Data) -> BatteryStatus {
let statusBytes = [UInt8](data)

let rawStatus = (statusBytes[0] & (Constants.BATTERY_MASK))
return BatteryStatus(rawValue: rawStatus) ?? .OK
}
static let MASK: UInt8 = 0x3
}
Loading

0 comments on commit e738847

Please sign in to comment.