Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions RileyLinkBLEKit/Command.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ enum RileyLinkCommand: UInt8 {
case setSWEncoding = 11
case setPreamble = 12
case resetRadioConfig = 13
case getStatistics = 14
}

enum RileyLinkLEDType: UInt8 {
Expand Down Expand Up @@ -291,3 +292,11 @@ struct ResetRadioConfig: Command {
return Data(bytes: [RileyLinkCommand.resetRadioConfig.rawValue])
}
}

struct GetStatistics: Command {
typealias ResponseType = GetStatisticsResponse

var data: Data {
return Data(bytes: [RileyLinkCommand.getStatistics.rawValue])
}
}
33 changes: 32 additions & 1 deletion RileyLinkBLEKit/CommandSession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,27 @@ public enum CC111XRegister: UInt8 {
case paTable0 = 0x2e
}

public struct RileyLinkStatistics {
public let uptime: TimeInterval
public let radioRxOverflowCount: UInt16
public let radioRxFifoOverflowCount: UInt16
public let packetRxCount: UInt16
public let packetTxCount: UInt16
public let crcFailureCount: UInt16
public let spiSyncFailureCount: UInt16

public init(uptime: TimeInterval, radioRxOverflowCount: UInt16, radioRxFifoOverflowCount: UInt16, packetRxCount: UInt16, packetTxCount: UInt16, crcFailureCount: UInt16, spiSyncFailureCount: UInt16) {
self.uptime = uptime
self.radioRxOverflowCount = radioRxOverflowCount
self.radioRxFifoOverflowCount = radioRxFifoOverflowCount
self.packetRxCount = packetRxCount
self.packetTxCount = packetTxCount
self.crcFailureCount = crcFailureCount
self.spiSyncFailureCount = spiSyncFailureCount
}

}

public struct CommandSession {
let manager: PeripheralManager
let responseType: PeripheralManager.ResponseType
Expand Down Expand Up @@ -212,5 +233,15 @@ public struct CommandSession {
let command = ResetRadioConfig()
_ = try writeCommand(command, timeout: 0)
}


public func getRileyLinkStatistics() throws -> RileyLinkStatistics {
guard firmwareVersion.supportsRileyLinkStatistics else {
throw RileyLinkDeviceError.unsupportedCommand(.getStatistics)
}

let command = GetStatistics()
let response: GetStatisticsResponse = try writeCommand(command, timeout: 0)

return response.statistics
}
}
26 changes: 15 additions & 11 deletions RileyLinkBLEKit/PeripheralManager+RileyLink.swift
Original file line number Diff line number Diff line change
Expand Up @@ -321,27 +321,31 @@ extension PeripheralManager {
}

addCondition(.valueUpdate(characteristic: characteristic, matching: { value in
guard let value = value else {
guard let value = value, value.count > 0 else {
log.debug("Empty response from RileyLink. Continuing to listen for command response.")
return false
}

log.debug("RL Recv(single): %@", value.hexadecimalString)

guard let response = R(data: value) else {
// We don't recognize the contents. Keep listening.
guard let code = ResponseCode(rawValue: value[0]) else {
let unknownCode = value[0..<1].hexadecimalString
log.debug("Unknown response code from RileyLink: %{public}@. Continuing to listen for command response.", unknownCode)
return false
}

switch response.code {
case .rxTimeout, .zeroData, .invalidParam, .unknownCommand:
log.debug("RileyLink response: %{public}@", String(describing: response))
capturedResponse = response
return true
switch code {
case .commandInterrupted:
// This is expected in cases where an "Idle" GetPacket command is running
log.debug("RileyLink response: %{public}@", String(describing: response))
log.debug("Idle command interrupted. Continuing to listen for command response.")
return false
case .success:
default:
guard let response = R(data: value) else {
log.debug("Unable to parse response.")
// We don't recognize the contents. Keep listening.
return false
}
log.debug("RileyLink response: %{public}@", String(describing: response))
capturedResponse = response
return true
}
Expand Down
15 changes: 15 additions & 0 deletions RileyLinkBLEKit/RadioFirmwareVersion.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ extension RadioFirmwareVersion {
return true
}

private var atLeastV2_2: Bool {
guard components.count >= 2 else {
return false;
}
let major = components[0]
let minor = components[1]
return major > 2 || (major == 2 && minor >= 2)
}


var supportsPreambleExtension: Bool {
return atLeastV2
}
Expand All @@ -69,6 +79,11 @@ extension RadioFirmwareVersion {
var needsExtraByteForUpdateRegisterCommand: Bool {
return !atLeastV2
}

var supportsRileyLinkStatistics: Bool {
return atLeastV2_2
}


}

37 changes: 37 additions & 0 deletions RileyLinkBLEKit/Response.swift
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,43 @@ struct GetVersionResponse: Response {
}
}

struct GetStatisticsResponse: Response {
let code: ResponseCode

let statistics: RileyLinkStatistics

init?(data: Data) {
guard data.count > 0, let code = ResponseCode(rawValue: data[data.startIndex]) else {
return nil
}

self.init(code: code, data: data[data.startIndex.advanced(by: 1)...])
}

init?(legacyData data: Data) {
self.init(code: .success, data: data)
}

private init?(code: ResponseCode, data: Data) {
self.code = code

guard data.count >= 16 else {
return nil
}

let uptime = TimeInterval(milliseconds: Double(data[data.startIndex...].toBigEndian(UInt32.self)))
let radioRxOverflowCount = data[data.startIndex.advanced(by: 4)...].toBigEndian(UInt16.self)
let radioRxFifoOverflowCount = data[data.startIndex.advanced(by: 6)...].toBigEndian(UInt16.self)
let packetRxCount = data[data.startIndex.advanced(by: 8)...].toBigEndian(UInt16.self)
let packetTxCount = data[data.startIndex.advanced(by: 10)...].toBigEndian(UInt16.self)
let crcFailureCount = data[data.startIndex.advanced(by: 12)...].toBigEndian(UInt16.self)
let spiSyncFailureCount = data[data.startIndex.advanced(by: 14)...].toBigEndian(UInt16.self)

self.statistics = RileyLinkStatistics(uptime: uptime, radioRxOverflowCount: radioRxOverflowCount, radioRxFifoOverflowCount: radioRxFifoOverflowCount, packetRxCount: packetRxCount, packetTxCount: packetTxCount, crcFailureCount: crcFailureCount, spiSyncFailureCount: spiSyncFailureCount)
}
}


struct PacketResponse: Response {
let code: ResponseCode
let packet: RFPacket?
Expand Down
3 changes: 3 additions & 0 deletions RileyLinkKit/PumpMessageSender.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ protocol PumpMessageSender {

/// - Throws: LocalizedError
func enableCCLEDs() throws

/// - Throws: LocalizedError
func getRileyLinkStatistics() throws -> RileyLinkStatistics
}

extension PumpMessageSender {
Expand Down
4 changes: 4 additions & 0 deletions RileyLinkKit/PumpOpsSession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,10 @@ extension PumpOpsSession {
}
}
}

public func getStatistics() throws -> RileyLinkStatistics {
return try session.getRileyLinkStatistics()
}

public func discoverCommands(in range: CountableClosedRange<UInt8>, _ updateHandler: (_ messages: [String]) -> Void) {

Expand Down
4 changes: 4 additions & 0 deletions RileyLinkKitTests/PumpOpsSynchronousTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,10 @@ func randomDataString(length:Int) -> String {
}

class PumpMessageSenderStub: PumpMessageSender {
func getRileyLinkStatistics() throws -> RileyLinkStatistics {
throw PumpOpsError.noResponse(during: "Tests")
}

func sendAndListen(_ data: Data, repeatCount: Int, timeout: TimeInterval, retryCount: Int) throws -> RFPacket? {
guard let decoded = MinimedPacket(encodedData: data),
let messageType = MessageType(rawValue: decoded.data[4])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,27 @@ extension CommandResponseViewController {
return NSLocalizedString("Discovering commands…", comment: "Progress message for discovering commands.")
}
}

static func getStatistics(ops: PumpOps?, device: RileyLinkDevice) -> T {
return T { (completionHandler) -> String in
ops?.runSession(withName: "Get Statistics", using: device) { (session) in
let response: String
do {
let stats = try session.getStatistics()
response = String(describing: stats)
} catch let error {
response = String(describing: error)
}

DispatchQueue.main.async {
completionHandler(response)
}
}

return NSLocalizedString("Get Statistics…", comment: "Progress message for getting statistics.")
}
}


static func dumpHistory(ops: PumpOps?, device: RileyLinkDevice) -> T {
return T { (completionHandler) -> String in
Expand Down Expand Up @@ -210,7 +231,7 @@ extension CommandResponseViewController {
static func enableLEDs(ops: PumpOps?, device: RileyLinkDevice) -> T {
return T { (completionHandler) -> String in
device.enableBLELEDs()
ops?.runSession(withName: "Read pump status", using: device) { (session) in
ops?.runSession(withName: "Enable LEDs", using: device) { (session) in
let response: String
do {
try session.enableCCLEDs()
Expand Down
7 changes: 7 additions & 0 deletions RileyLinkKitUI/RileyLinkDeviceTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ public class RileyLinkDeviceTableViewController: UITableViewController {
case readBasalSchedule
case enableLED
case discoverCommands
case getStatistics
}

private func cellForRow(_ row: DeviceRow) -> UITableViewCell? {
Expand Down Expand Up @@ -374,6 +375,10 @@ public class RileyLinkDeviceTableViewController: UITableViewController {

case .discoverCommands:
cell.textLabel?.text = NSLocalizedString("Discover Commands", comment: "The title of the command to discover commands")

case .getStatistics:
cell.textLabel?.text = NSLocalizedString("Get Statistics", comment: "The title of the command to get statistics")

}
}

Expand Down Expand Up @@ -452,6 +457,8 @@ public class RileyLinkDeviceTableViewController: UITableViewController {
vc = .enableLEDs(ops: ops, device: device)
case .discoverCommands:
vc = .discoverCommands(ops: ops, device: device)
case .getStatistics:
vc = .getStatistics(ops: ops, device: device)
}

if let cell = tableView.cellForRow(at: indexPath) {
Expand Down