PumpMessageSender.swift 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. //
  2. // PumpMessageSender.swift
  3. // RileyLink
  4. //
  5. // Created by Jaim Zuber on 3/2/17.
  6. // Copyright © 2017 Pete Schwamb. All rights reserved.
  7. //
  8. import Foundation
  9. import RileyLinkBLEKit
  10. import os.log
  11. private let standardPumpResponseWindow: TimeInterval = .milliseconds(200)
  12. private let log = OSLog(category: "PumpMessageSender")
  13. protocol PumpMessageSender {
  14. /// - Throws: LocalizedError
  15. func resetRadioConfig() throws
  16. /// - Throws: LocalizedError
  17. func updateRegister(_ address: CC111XRegister, value: UInt8) throws
  18. /// - Throws: LocalizedError
  19. func setBaseFrequency(_ frequency: Measurement<UnitFrequency>) throws
  20. /// Sends data to the pump, listening for a reply
  21. ///
  22. /// - Parameters:
  23. /// - data: The data to send
  24. /// - repeatCount: The number of times to repeat the message before listening begins
  25. /// - timeout: The length of time to listen for a response before timing out
  26. /// - retryCount: The number of times to repeat the send & listen sequence
  27. /// - Returns: The packet reply
  28. /// - Throws: LocalizedError
  29. func sendAndListen(_ data: Data, repeatCount: Int, timeout: TimeInterval, retryCount: Int) throws -> RFPacket
  30. /// - Throws: LocalizedError
  31. func listen(onChannel channel: Int, timeout: TimeInterval) throws -> RFPacket?
  32. /// - Throws: LocalizedError
  33. func send(_ data: Data, onChannel channel: Int, timeout: TimeInterval) throws
  34. /// - Throws: LocalizedError
  35. func setCCLEDMode(_ mode: RileyLinkLEDMode) throws
  36. /// - Throws: LocalizedError
  37. func getRileyLinkStatistics() throws -> RileyLinkStatistics
  38. }
  39. extension PumpMessageSender {
  40. /// - Throws: PumpOpsError.deviceError
  41. func send(_ msg: PumpMessage) throws {
  42. do {
  43. try send(MinimedPacket(outgoingData: msg.txData).encodedData(), onChannel: 0, timeout: 0)
  44. } catch let error as LocalizedError {
  45. throw PumpOpsError.deviceError(error)
  46. }
  47. }
  48. /// Sends a message to the pump, expecting a specific response body
  49. ///
  50. /// - Parameters:
  51. /// - message: The message to send
  52. /// - responseType: The expected response message type
  53. /// - repeatCount: The number of times to repeat the message before listening begins
  54. /// - timeout: The length of time to listen for a pump response
  55. /// - retryCount: The number of times to repeat the send & listen sequence
  56. /// - Returns: The expected response message body
  57. /// - Throws:
  58. /// - PumpOpsError.couldNotDecode
  59. /// - PumpOpsError.crosstalk
  60. /// - PumpOpsError.deviceError
  61. /// - PumpOpsError.noResponse
  62. /// - PumpOpsError.pumpError
  63. /// - PumpOpsError.unexpectedResponse
  64. /// - PumpOpsError.unknownResponse
  65. func getResponse<T: MessageBody>(to message: PumpMessage, responseType: MessageType = .pumpAck, repeatCount: Int = 0, timeout: TimeInterval = standardPumpResponseWindow, retryCount: Int = 3) throws -> T {
  66. log.debug("getResponse(%{public}@, %d, %f, %d)", String(describing: message), repeatCount, timeout, retryCount)
  67. let response = try sendAndListen(message, repeatCount: repeatCount, timeout: timeout, retryCount: retryCount)
  68. guard response.messageType == responseType, let body = response.messageBody as? T else {
  69. if let body = response.messageBody as? PumpErrorMessageBody {
  70. switch body.errorCode {
  71. case .known(let code):
  72. throw PumpOpsError.pumpError(code)
  73. case .unknown(let code):
  74. throw PumpOpsError.unknownPumpErrorCode(code)
  75. }
  76. } else {
  77. throw PumpOpsError.unexpectedResponse(response, from: message)
  78. }
  79. }
  80. return body
  81. }
  82. /// Sends a message to the pump, listening for a message in reply
  83. ///
  84. /// - Parameters:
  85. /// - message: The message to send
  86. /// - repeatCount: The number of times to repeat the message before listening begins
  87. /// - timeout: The length of time to listen for a pump response
  88. /// - retryCount: The number of times to repeat the send & listen sequence
  89. /// - Returns: The message reply
  90. /// - Throws: An error describing a failure in the sending or receiving of a message:
  91. /// - PumpOpsError.couldNotDecode
  92. /// - PumpOpsError.crosstalk
  93. /// - PumpOpsError.deviceError
  94. /// - PumpOpsError.noResponse
  95. /// - PumpOpsError.unknownResponse
  96. func sendAndListen(_ message: PumpMessage, repeatCount: Int = 0, timeout: TimeInterval = standardPumpResponseWindow, retryCount: Int = 3) throws -> PumpMessage {
  97. let rfPacket = try sendAndListenForPacket(message, repeatCount: repeatCount, timeout: timeout, retryCount: retryCount)
  98. guard let packet = MinimedPacket(encodedData: rfPacket.data) else {
  99. throw PumpOpsError.couldNotDecode(rx: rfPacket.data, during: message)
  100. }
  101. guard let response = PumpMessage(rxData: packet.data) else {
  102. // Unknown packet type or message type
  103. throw PumpOpsError.unknownResponse(rx: packet.data, during: message)
  104. }
  105. guard response.address == message.address else {
  106. throw PumpOpsError.crosstalk(response, during: message)
  107. }
  108. return response
  109. }
  110. /// - Throws:
  111. /// - PumpOpsError.noResponse
  112. /// - PumpOpsError.deviceError
  113. func sendAndListenForPacket(_ message: PumpMessage, repeatCount: Int = 0, timeout: TimeInterval = standardPumpResponseWindow, retryCount: Int = 3) throws -> RFPacket {
  114. let packet: RFPacket?
  115. do {
  116. packet = try sendAndListen(MinimedPacket(outgoingData: message.txData).encodedData(), repeatCount: repeatCount, timeout: timeout, retryCount: retryCount)
  117. } catch let error as LocalizedError {
  118. throw PumpOpsError.deviceError(error)
  119. }
  120. guard let rfPacket = packet else {
  121. throw PumpOpsError.noResponse(during: message)
  122. }
  123. return rfPacket
  124. }
  125. /// - Throws: PumpOpsError.deviceError
  126. func listenForPacket(onChannel channel: Int, timeout: TimeInterval) throws -> RFPacket? {
  127. do {
  128. return try listen(onChannel: channel, timeout: timeout)
  129. } catch let error as LocalizedError {
  130. throw PumpOpsError.deviceError(error)
  131. }
  132. }
  133. }