Skip to content

Commit

Permalink
Merge pull request #22 from combustion-inc/develop
Browse files Browse the repository at this point in the history
Release v0.10.0
  • Loading branch information
jjohnstz authored Jun 17, 2022
2 parents 81c14c0 + 7157178 commit ff3978f
Show file tree
Hide file tree
Showing 17 changed files with 516 additions and 72 deletions.
15 changes: 14 additions & 1 deletion Sources/CombustionBLE/BleData/AdvertisingData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ public enum CombustionProductType: UInt8 {
case NODE = 0x02
}


/// Struct containing advertising data received from device.
public struct AdvertisingData {
/// Type of Combustion product
Expand All @@ -48,13 +47,16 @@ public struct AdvertisingData {
public let color: ProbeColor
/// Probe mode
public let mode: ProbeMode
/// Battery Status
public let batteryStatus: BatteryStatus

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
}
}

Expand Down Expand Up @@ -101,6 +103,15 @@ extension AdvertisingData {
color = .COLOR1
mode = .Normal
}

// Decode battery status if its 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
}
}
}

Expand All @@ -114,6 +125,7 @@ extension AdvertisingData {
id = .ID1
color = .COLOR1
mode = .Normal
batteryStatus = .OK
}

// Fake data initializer for Simulated Probe
Expand All @@ -124,5 +136,6 @@ extension AdvertisingData {
id = .ID1
color = .COLOR1
mode = .Normal
batteryStatus = .OK
}
}
43 changes: 43 additions & 0 deletions Sources/CombustionBLE/BleData/BatteryStatus.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// BatteryStatus.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

private enum Constants {
static let BATTERY_MASK: UInt8 = 0x3
}

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

let rawStatus = (statusBytes[0] & (Constants.BATTERY_MASK))
return BatteryStatus(rawValue: rawStatus) ?? .OK
}
}
12 changes: 12 additions & 0 deletions Sources/CombustionBLE/BleData/DeviceStatus.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,16 @@ public struct DeviceStatus {
public let color: ProbeColor
/// Probe mode
public let mode: ProbeMode
/// Battery Status
public let batteryStatus: BatteryStatus

private enum Constants {
// Locations of data in status packet
static let MIN_SEQ_RANGE = 0..<4
static let MAX_SEQ_RANGE = 4..<8
static let TEMPERATURE_RANGE = 8..<21
static let MODE_COLOR_ID_RANGE = 21..<22
static let BATTERY_STATUS_RANGE = 22..<23
}
}

Expand Down Expand Up @@ -80,5 +83,14 @@ extension DeviceStatus {
color = .COLOR1
mode = .Normal
}

// Decode battery status if its present in the advertising packet
if(data.count >= 23) {
let statusData = data.subdata(in: Constants.BATTERY_STATUS_RANGE)
batteryStatus = BatteryStatus.fromRawData(data: statusData)
}
else {
batteryStatus = .OK
}
}
}
44 changes: 29 additions & 15 deletions Sources/CombustionBLE/BleManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ protocol BleManagerDelegate: AnyObject {
func didDisconnectFrom(identifier: UUID)
func handleSetIDResponse(identifier: UUID, success: Bool)
func handleSetColorResponse(identifier: UUID, success: Bool)
func updateDeviceWithStatus(identifier: UUID, status: DeviceStatus)
func updateDeviceWithAdvertising(advertising: AdvertisingData, rssi: NSNumber, identifier: UUID)
func updateDeviceWithLogResponse(identifier: UUID, logResponse: LogResponse)
func updateDeviceWithSessionInformation(identifier: UUID, sessionInformation: SessionInformation)
func updateDeviceWithStatus(identifier: UUID, status: DeviceStatus)
func updateDeviceFwVersion(identifier: UUID, fwVersion: String)
func updateDeviceHwRevision(identifier: UUID, hwRevision: String)
}
Expand Down Expand Up @@ -221,30 +222,22 @@ extension BleManager: CBPeripheralDelegate {
}

public func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {

// Always enable notifications for Device status characteristic
if(characteristic.uuid == Constants.UART_TX_CHAR),
let statusChar = deviceStatusCharacteristics[peripheral.identifier.uuidString] {
// After enabling UART notification
// Enable notifications for Device status characteristic
peripheral.setNotifyValue(true, for: statusChar)

// Send request the session ID from device
sendRequest(identifier: peripheral.identifier.uuidString, request: SessionInfoRequest())
}

}

public func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
guard let data = characteristic.value else { return }

if characteristic.uuid == Constants.UART_TX_CHAR {
if let logResponse = Response.fromData(data) as? LogResponse {
if(logResponse.success) {
delegate?.updateDeviceWithLogResponse(identifier: peripheral.identifier, logResponse: logResponse)
}
}
else if let setIDResponse = Response.fromData(data) as? SetIDResponse {
delegate?.handleSetIDResponse(identifier: peripheral.identifier, success: setIDResponse.success)
}
else if let setColorResponse = Response.fromData(data) as? SetColorResponse {
delegate?.handleSetColorResponse(identifier: peripheral.identifier, success: setColorResponse.success)
}
handleUartData(data: data, identifier: peripheral.identifier)
}
else if characteristic.uuid == Constants.DEVICE_STATUS_CHAR {
if let status = DeviceStatus(fromData: data) {
Expand Down Expand Up @@ -275,4 +268,25 @@ extension BleManager: CBPeripheralDelegate {
}
}

private func handleUartData(data: Data, identifier: UUID) {
let responses = Response.fromData(data)

for response in responses {
if let logResponse = response as? LogResponse {
delegate?.updateDeviceWithLogResponse(identifier: identifier, logResponse: logResponse)
}
else if let setIDResponse = response as? SetIDResponse {
delegate?.handleSetIDResponse(identifier: identifier, success: setIDResponse.success)
}
else if let setColorResponse = response as? SetColorResponse {
delegate?.handleSetColorResponse(identifier: identifier, success: setColorResponse.success)
}
else if let sessionResponse = response as? SessionInfoResponse {
if(sessionResponse.success) {
delegate?.updateDeviceWithSessionInformation(identifier: identifier, sessionInformation: sessionResponse.info)
}
}
}
}

}
23 changes: 12 additions & 11 deletions Sources/CombustionBLE/Device.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public class Device : ObservableObject {
@Published public internal(set) var connectionState: ConnectionState = .disconnected

/// Signal strength to device
@Published public internal(set) var rssi : Int = Int.min
@Published public internal(set) var rssi: Int

/// Tracks whether the app should attempt to maintain a connection to the device.
@Published public internal(set) var maintainingConnection = false
Expand All @@ -66,8 +66,18 @@ public class Device : ObservableObject {
/// Time at which device was last updated
internal var lastUpdateTime = Date()

public init(identifier: UUID) {
public init(identifier: UUID, RSSI: NSNumber) {
self.identifier = identifier.uuidString
self.rssi = RSSI.intValue
}

func updateConnectionState(_ state: ConnectionState) {
connectionState = state

// If we were disconnected and we should be maintaining a connection, attempt to reconnect.
if(maintainingConnection && (connectionState == .disconnected || connectionState == .failed)) {
DeviceManager.shared.connectToDevice(self)
}
}

func updateDeviceStale() {
Expand Down Expand Up @@ -101,15 +111,6 @@ extension Device {
// Disconnect if connected
DeviceManager.shared.disconnectFromDevice(self)
}

func updateConnectionState(_ state: ConnectionState) {
connectionState = state

// If we were disconnected and we should be maintaining a connection, attempt to reconnect.
if(maintainingConnection && (connectionState == .disconnected || connectionState == .failed)) {
DeviceManager.shared.connectToDevice(self)
}
}
}


Expand Down
16 changes: 16 additions & 0 deletions Sources/CombustionBLE/DeviceManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ extension DeviceManager : BleManagerDelegate {
}

func updateDeviceWithLogResponse(identifier: UUID, logResponse: LogResponse) {
guard logResponse.success else { return }

if let probe = devices[identifier.uuidString] as? Probe {
probe.processLogResponse(logResponse: logResponse)
}
Expand All @@ -235,9 +237,23 @@ extension DeviceManager : BleManagerDelegate {
}
}

func updateDeviceWithSessionInformation(identifier: UUID, sessionInformation: SessionInformation) {
if let probe = devices[identifier.uuidString] as? Probe {
probe.updateWithSessionInformation(sessionInformation)
}
}

func updateDeviceFwVersion(identifier: UUID, fwVersion: String) {
if let device = devices[identifier.uuidString] {
device.firmareVersion = fwVersion

// TODO : remove this at some point
// Prior to v0.8.0, the firmware did not support the Session ID command
// Therefore, add a hardcoded session for backwards compatibility
if(Version.isBefore(deviceFirmware: fwVersion, comparison: "v0.8.0")) {
let fakeSessionInfo = SessionInformation(sessionID: 0, samplePeriod: 1000)
updateDeviceWithSessionInformation(identifier: identifier, sessionInformation: fakeSessionInfo)
}
}
}

Expand Down
Loading

0 comments on commit ff3978f

Please sign in to comment.