G5 improvements

This commit is contained in:
Johan Degraeve 2019-02-07 23:53:38 +01:00
parent 21d608f17b
commit 51fe942fa5
13 changed files with 128 additions and 100 deletions

View File

@ -20,7 +20,7 @@
F8025E4E21ED450300ECF0C0 /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8025E4D21ED450300ECF0C0 /* Double.swift */; };
F8025E5021EE746400ECF0C0 /* CalibratorProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8025E4F21EE746400ECF0C0 /* CalibratorProtocol.swift */; };
F8025E5421EE8D2100ECF0C0 /* Libre1Calibrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8025E5321EE8D2100ECF0C0 /* Libre1Calibrator.swift */; };
F8025E5721F4A60900ECF0C0 /* CGMTransmitterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8025E5621F4A60900ECF0C0 /* CGMTransmitterProtocol.swift */; };
F8025E5721F4A60900ECF0C0 /* CGMTransmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8025E5621F4A60900ECF0C0 /* CGMTransmitter.swift */; };
F8025E6421F7BF3300ECF0C0 /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8025E6321F7BF3300ECF0C0 /* UserDefaults.swift */; };
F8025E6B21F7CD7600ECF0C0 /* UIStoryboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8025E6A21F7CD7600ECF0C0 /* UIStoryboard.swift */; };
F8025E6D21F7CD7C00ECF0C0 /* UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8025E6C21F7CD7C00ECF0C0 /* UIViewController.swift */; };
@ -84,7 +84,7 @@
F8025E4D21ED450300ECF0C0 /* Double.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Double.swift; sourceTree = "<group>"; };
F8025E4F21EE746400ECF0C0 /* CalibratorProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalibratorProtocol.swift; sourceTree = "<group>"; };
F8025E5321EE8D2100ECF0C0 /* Libre1Calibrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Libre1Calibrator.swift; sourceTree = "<group>"; };
F8025E5621F4A60900ECF0C0 /* CGMTransmitterProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGMTransmitterProtocol.swift; sourceTree = "<group>"; };
F8025E5621F4A60900ECF0C0 /* CGMTransmitter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGMTransmitter.swift; sourceTree = "<group>"; };
F8025E6321F7BF3300ECF0C0 /* UserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaults.swift; sourceTree = "<group>"; };
F8025E6A21F7CD7600ECF0C0 /* UIStoryboard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIStoryboard.swift; sourceTree = "<group>"; };
F8025E6C21F7CD7C00ECF0C0 /* UIViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewController.swift; sourceTree = "<group>"; };
@ -196,7 +196,7 @@
isa = PBXGroup;
children = (
F8025C0E21D95EC200ECF0C0 /* CGMTransmitterDelegate.swift */,
F8025E5621F4A60900ECF0C0 /* CGMTransmitterProtocol.swift */,
F8025E5621F4A60900ECF0C0 /* CGMTransmitter.swift */,
F85DC2FE21D3E83100B9F74A /* G4 */,
F897AAFC2202575600CDDD10 /* G5 */,
F8025C0621D8DCE700ECF0C0 /* MiaoMiao */,
@ -557,7 +557,7 @@
F897AB2622073C4B00CDDD10 /* AuthChallengeTxMessage.swift in Sources */,
F8AC425E21ADEBD60078C348 /* AppDelegate.swift in Sources */,
F897AB1D22059EA000CDDD10 /* TransmitterMessage.swift in Sources */,
F8025E5721F4A60900ECF0C0 /* CGMTransmitterProtocol.swift in Sources */,
F8025E5721F4A60900ECF0C0 /* CGMTransmitter.swift in Sources */,
F897AB3D220A243300CDDD10 /* ResetMessage.swift in Sources */,
F85DC30121D3F5CC00B9F74A /* CGMG4xDripTransmitter.swift in Sources */,
F8025C0A21D94FD700ECF0C0 /* CBManagerState.swift in Sources */,

View File

@ -47,27 +47,6 @@ extension Data {
}))
}
/*var hexadecimalString: String {
return map { String(format: "%02hhx", $0) }.joined()
}*/
/*var uint8: UInt8 {
get {
var number: UInt8 = 0
self.getBytes(&number, length: MemoryLayout.size(ofValue: number))
return number
}
}
var uint16: UInt16 {
get {
var number: UInt16 = 0
self.getBytes(&number, length: MemoryLayout.size(ofValue: number))
return number
}
}*/
///takes 4 bytes starting at position and converts to Uint32
func uint32 (position:Int)-> UInt32 {
let start = position
@ -84,6 +63,14 @@ extension Data {
return number
}
///takes 1 byte starting at position and converts to Uint8
func uint8 (position:Int)-> UInt8 {
let start = position
let end = start.advanced(by: 1)
let number: UInt8 = self.subdata(in: start..<end).toInt()
return number
}
//source Data.Swift CGMBLEKit
func to<T: FixedWidthInteger>(_: T.Type) -> T {
return self.withUnsafeBytes { (bytes: UnsafePointer<T>) in

View File

@ -0,0 +1,17 @@
import Foundation
protocol CGMTransmitter {
/// example MiaoMiao can detect new sensor, implementation should return true, Dexcom transmitter's can't
func canDetectNewSensor() -> Bool
/// get device address, cgmtransmitters should also derive from BlueToothTransmitter, hence no need to implement this function
func address() -> String?
/// get device name, cgmtransmitters should also derive from BlueToothTransmitter, hence no need to implement this function
func name() -> String?
/// start scanning, cgmtransmitters should also derive from BlueToothTransmitter, hence no need to implement this function
/// - returns:
/// the scanning result
func startScanning() -> BluetoothTransmitter.startScanningResult
}

View File

@ -1,6 +0,0 @@
import Foundation
protocol CGMTransmitterProtocol {
/// example MiaoMiao can detect new sensor, implementation should return true, Dexcom transmitter's can't
func canDetectNewSensor() -> Bool
}

View File

@ -2,7 +2,7 @@ import Foundation
import CoreBluetooth
import os
final class CGMG4xDripTransmitter: BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTransmitterProtocol {
final class CGMG4xDripTransmitter: BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTransmitter {
// MARK: - properties
/// uuid used for scanning, can be empty string, if empty string then scan all devices - only possible if app is in foreground

View File

@ -2,7 +2,7 @@ import Foundation
import CoreBluetooth
import os
class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTransmitterProtocol {
class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTransmitter {
// MARK: - properties
/// UUID's
@ -56,8 +56,11 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
/// is G5 reset necessary or not
private var G5ResetRequested:Bool
// G5 transmitter firmware version
// G5 transmitter firmware version - only used internally, if nil then it was never received
private var transmitterVersion:String?
// actual device address
private var actualDeviceAddress:String?
// MARK: - functions
@ -82,6 +85,7 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
var newAddressAndName:BluetoothTransmitter.DeviceAddressAndName = BluetoothTransmitter.DeviceAddressAndName.notYetConnected(expectedName: "DEXCOM" + transmitterID[transmitterID.index(transmitterID.startIndex, offsetBy: 4)..<transmitterID.endIndex])
if let address = address {
newAddressAndName = BluetoothTransmitter.DeviceAddressAndName.alreadyConnectedBefore(address: address)
actualDeviceAddress = address
}
// set timestampoflastg5reading to 0
@ -119,11 +123,19 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
// MARK: CBCentralManager overriden functions
override func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
if Date() < Date(timeInterval: 60, since: timeStampOfLastG5Reading) {
// will probably never come here because reconnect doesn't happen with scanning, hence diddiscover will never be called excep the very first time that an app tries to connect to a G5
os_log("diddiscover peripheral, but last reading was less than 1 minute ago, will ignore", log: log, type: .info)
} else {
super.centralManager(central, didDiscover: peripheral, advertisementData: advertisementData, rssi: RSSI)
}
}
override func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
//Date(timeInterval: (5*60), since: firstCalibrationTimeStamp)
if Date() < Date(timeInterval: 60, since: timeStampOfLastG5Reading) {
os_log("connected, but last reading was less than 1 minute ago, disconnecting", log: log, type: .info)
//TODO : isn't it better to just do nothing ? wait for dexcom to timeout ?
//TODO: is it not better to keep connection open till it times out ? should be tested with new device, see if battery drains, if it does, try with removing the disconnect - Spike also disconnects
disconnect()
} else {
super.centralManager(central, didConnect: peripheral)
@ -135,7 +147,7 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
// log error if any
if let error = error {
os_log("error: %{public}@", log: log, type: .error , error.localizedDescription)
os_log(" error: %{public}@", log: log, type: .error , error.localizedDescription)
}
if let characteristics = service.characteristics {
@ -152,11 +164,11 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
communicationCharacteristic = characteristic
case .CBUUID_Receive_Authentication:
receiveAuthenticationCharacteristic = characteristic
os_log("calling setNotifyValue true", log: log, type: .info)
os_log(" calling setNotifyValue true", log: log, type: .info)
peripheral.setNotifyValue(true, for: characteristic)
}
} else {
os_log("characteristic UUID unknown", log: log, type: .error)
os_log(" characteristic UUID unknown", log: log, type: .error)
}
}
} else {
@ -177,7 +189,7 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
// if status changed to poweredon, and if address = nil then superclass will not start the scanning
// but for DexcomG5 we can start scanning
if state == .poweredOn {
if (address == nil) {
if (actualDeviceAddress == nil) {
_ = startScanning()
}
}
@ -192,10 +204,10 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
func peripheralDidUpdateNotificationStateFor(characteristic: CBCharacteristic, error: Error?) {
os_log("in peripheralDidUpdateNotificationStateFor", log: log, type: .info)
if let error = error {
os_log("error: %{public}@", log: log, type: .error , error.localizedDescription)
os_log(" error: %{public}@", log: log, type: .error , error.localizedDescription)
}
let ASCIIstring = characteristic.uuid.uuidString
os_log("characteristic uuid: %{public}@", log: log, type: .info, ASCIIstring)
os_log(" characteristic uuid: %{public}@", log: log, type: .info, ASCIIstring)
if let characteristicValue = CBUUID_Characteristic_UUID(rawValue: ASCIIstring) {
switch characteristicValue {
case .CBUUID_Write_Control:
@ -213,7 +225,7 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
break
}
} else {
os_log("characteristicValue is nil", log: log, type: .error)
os_log(" characteristicValue is nil", log: log, type: .error)
}
}
@ -226,45 +238,50 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
if let value = characteristic.value {
//only for logging
let data = value.hexEncodedString()
os_log(" data = %{public}@", log: log, type: .debug, data)
os_log(" data = %{public}@", log: log, type: .debug, data)
//check type of message and process according to type
if let firstByte = value.first {
if let opCode = Opcode(rawValue: firstByte) {
os_log("opcode = %{public}@", log: log, type: .info, opCode.description)
os_log(" opcode = %{public}@", log: log, type: .info, opCode.description)
switch opCode {
case .authChallengeRx:
if let authChallengeRxMessage = AuthChallengeRxMessage(data: value) {
if !authChallengeRxMessage.bonded {
cgmTransmitterDelegate?.cgmTransmitterNeedsPairing()
os_log("transmitter needs paring", log: log, type: .info)
os_log(" transmitter needs paring", log: log, type: .info)
} else {
if let writeControlCharacteristic = writeControlCharacteristic {
setNotifyValue(true, for: writeControlCharacteristic)
} else {
os_log(" writeControlCharacteristic is nil, can not set notifyValue", log: log, type: .error)
}
}
}
if let writeControlCharacteristic = writeControlCharacteristic {
setNotifyValue(true, for: writeControlCharacteristic)
} else {
os_log("writeControlCharacteristic is nil, can not set notifyValue", log: log, type: .error)
os_log(" failed to create authChallengeRxMessage", log: log, type: .info)
}
case .authRequestRx:
if let authRequestRxMessage = AuthRequestRxMessage(data: value), let receiveAuthenticationCharacteristic = receiveAuthenticationCharacteristic {
guard let challengeHash = CGMG5Transmitter.computeHash(transmitterId, of: authRequestRxMessage.challenge) else {
os_log("failed to calculate challengeHash, no further processing", log: log, type: .error)
os_log(" failed to calculate challengeHash, no further processing", log: log, type: .error)
return
}
let authChallengeTxMessage = AuthChallengeTxMessage(challengeHash: challengeHash)
_ = writeDataToPeripheral(data: authChallengeTxMessage.data, characteristicToWriteTo: receiveAuthenticationCharacteristic, type: .withResponse)
} else {
os_log("writeControlCharacteristic is nil or authRequestRxMessage is nil", log: log, type: .error)
os_log(" writeControlCharacteristic is nil or authRequestRxMessage is nil", log: log, type: .error)
}
case .sensorDataRx:
if let sensorDataRxMessage = SensorDataRxMessage(data: value) {
if transmitterVersion != nil {
if Date() < Date(timeInterval: Constants.DexcomG5.batteryReadPeriodInHours * 60 * 60, since: timeStampOfLastBatteryReading) {
os_log("last battery reading was long time, ago requesting now", log: log, type: .info)
// transmitterversion was already recceived, let's see if we need to get the batterystatus
if Date() > Date(timeInterval: Constants.DexcomG5.batteryReadPeriodInHours * 60 * 60, since: timeStampOfLastBatteryReading) {
os_log(" last battery reading was long time, ago requesting now", log: log, type: .info)
if let writeControlCharacteristic = writeControlCharacteristic {
_ = writeDataToPeripheral(data: BatteryStatusTxMessage().data, characteristicToWriteTo: writeControlCharacteristic, type: .withResponse)
timeStampOfLastBatteryReading = Date()
} else {
os_log("writeControlCharacteristic is nil, can not send BatteryStatusTxMessage", log: log, type: .error)
os_log(" writeControlCharacteristic is nil, can not send BatteryStatusTxMessage", log: log, type: .error)
}
//TODO: strictly speaking a disconnect should be done after having written the data
} else {
@ -274,16 +291,16 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
if let writeControlCharacteristic = writeControlCharacteristic {
_ = writeDataToPeripheral(data: TransmitterVersionTxMessage().data, characteristicToWriteTo: writeControlCharacteristic, type: .withResponse)
} else {
os_log("writeControlCharacteristic is nil, can not send TransmitterVersionTxMessage", log: log, type: .error)
os_log(" writeControlCharacteristic is nil, can not send TransmitterVersionTxMessage", log: log, type: .error)
}
//TODO: strictly speaking a disconnect should be done after having written the data
}
//if reset was done recently, less than 5 minutes ago, then ignore the reading
if Date() < Date(timeInterval: 5 * 60, since: timeStampTransmitterReset) {
os_log("last transmitterreset was less than 5 minutes ago, ignoring this reading", log: log, type: .info)
os_log(" last transmitterreset was less than 5 minutes ago, ignoring this reading", log: log, type: .info)
} else {
if Date() < Date(timeInterval: 60, since: timeStampOfLastG5Reading) {
os_log("last reading was less than 1 minute ago, disconnecting", log: log, type: .info)
os_log(" last reading was less than 1 minute ago, disconnecting", log: log, type: .info)
} else {
timeStampOfLastG5Reading = Date()
let glucoseData = RawGlucoseData(timeStamp: sensorDataRxMessage.timestamp, glucoseLevelRaw: sensorDataRxMessage.unfiltered, glucoseLevelFiltered: sensorDataRxMessage.filtered)
@ -294,7 +311,7 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
//start processing now the sensorDataRxMessage
} else {
os_log("sensorDataRxMessagee is nil", log: log, type: .error)
os_log(" sensorDataRxMessagee is nil", log: log, type: .error)
}
case .resetRx:
processResetRxMessage(value: value)
@ -303,14 +320,14 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
case .transmitterVersionRx:
processTransmitterVersionRxMessage(value: value)
default:
os_log("unknown opcode received ", log: log, type: .error)
os_log(" unknown opcode received ", log: log, type: .error)
break
}
} else {
os_log("value doesn't start with a known opcode = %{public}d", log: log, type: .error, firstByte)
os_log(" value doesn't start with a known opcode = %{public}d", log: log, type: .error, firstByte)
}
} else {
os_log("characteristic.value is nil", log: log, type: .error)
os_log(" characteristic.value is nil", log: log, type: .error)
}
}
}
@ -329,7 +346,7 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
if let writeControlCharacteristic = writeControlCharacteristic {
_ = writeDataToPeripheral(data: SensorDataTxMessage().data, characteristicToWriteTo: writeControlCharacteristic, type: .withResponse)
} else {
os_log("writeControlCharacteristic is nil, not getsensordata", log: log, type: .error)
os_log(" writeControlCharacteristic is nil, not getsensordata", log: log, type: .error)
}
}
@ -340,7 +357,7 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
_ = writeDataToPeripheral(data: ResetTxMessage().data, characteristicToWriteTo: writeControlCharacteristic, type: .withResponse)
G5ResetRequested = false
} else {
os_log("writeControlCharacteristic is nil, not sending G5 reset", log: log, type: .error)
os_log(" writeControlCharacteristic is nil, not sending G5 reset", log: log, type: .error)
}
}
@ -367,7 +384,7 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
private func processBatteryStatusRxMessage(value:Data) {
if let batteryStatusRxMessage = BatteryStatusRxMessage(data: value) {
var emptyArray: [RawGlucoseData] = []
cgmTransmitterDelegate?.cgmTransmitterInfoReceived(glucoseData: &emptyArray, transmitterBatteryInfo: TransmitterBatteryInfo.DexcomG5(voltageA: batteryStatusRxMessage.voltageA, voltageB: batteryStatusRxMessage.voltageB, resist: batteryStatusRxMessage.resist), sensorState: nil, sensorTimeInMinutes: nil, firmware: nil, hardware: nil)
cgmTransmitterDelegate?.cgmTransmitterInfoReceived(glucoseData: &emptyArray, transmitterBatteryInfo: TransmitterBatteryInfo.DexcomG5(voltageA: batteryStatusRxMessage.voltageA, voltageB: batteryStatusRxMessage.voltageB, resist: batteryStatusRxMessage.resist, runtime: batteryStatusRxMessage.runtime, temperature: batteryStatusRxMessage.temperature), sensorState: nil, sensorTimeInMinutes: nil, firmware: nil, hardware: nil)
} else {
os_log("batteryStatusRxMessage is nil", log: log, type: .error)
}
@ -377,6 +394,8 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
if let transmitterVersionRxMessage = TransmitterVersionRxMessage(data: value) {
var emptyArray: [RawGlucoseData] = []
cgmTransmitterDelegate?.cgmTransmitterInfoReceived(glucoseData: &emptyArray, transmitterBatteryInfo: nil, sensorState: nil, sensorTimeInMinutes: nil, firmware: transmitterVersionRxMessage.firmwareVersion.hexEncodedString(), hardware: nil)
// assign transmitterVersion
transmitterVersion = transmitterVersionRxMessage.firmwareVersion.hexEncodedString()
} else {
os_log("transmitterVersionRxMessage is nil", log: log, type: .error)
}

View File

@ -6,6 +6,8 @@ struct BatteryStatusRxMessage: TransmitterRxMessage {
let voltageA: Int
let voltageB: Int
let resist: Int
let runtime: Int
let temperature:Int
init?(data: Data) {
guard data.count >= 12 && data.isCRCValid else {
@ -17,9 +19,11 @@ struct BatteryStatusRxMessage: TransmitterRxMessage {
}
status = data[1]
voltageA = data[2..<4].toInt()
voltageB = data[4..<6].toInt()
resist = data[6..<8].toInt()
voltageA = Int(data.uint16(position: 2))
voltageB = Int(data.uint16(position: 4))
resist = Int(data.uint16(position: 6))
runtime = Int(data.uint16(position: 8))
temperature = Int(data.uint8(position: 10))
}
}

View File

@ -2,7 +2,7 @@ import Foundation
import CoreBluetooth
import os
class CGMMiaoMiaoTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTransmitterProtocol {
class CGMMiaoMiaoTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTransmitter {
// MARK: - properties
/// service to be discovered

View File

@ -5,7 +5,7 @@ enum TransmitterBatteryInfo {
case percentage (percentage:Int)
/// Dexcom G5 (and also G6 ?) voltageA, voltageB and resist
case DexcomG5 (voltageA:Int, voltageB:Int, resist:Int)
case DexcomG5 (voltageA:Int, voltageB:Int, resist:Int, runtime:Int, temperature:Int)
/// Dexcom G4, batteryinfo (215 or something like that)
case DexcomG4 (level:Int)
@ -14,8 +14,8 @@ enum TransmitterBatteryInfo {
switch (self) {
case .DexcomG4(let level):
return "Battery Level = " + level.description
case .DexcomG5(let voltA, let voltB, let res):
return "VoltageA = " + voltA.description + " Voltage B = " + voltB.description + " resistance = " + res.description
case .DexcomG5(let voltA, let voltB, let res, let runt, let temp):
return "VoltageA = " + voltA.description + ", Voltage B = " + voltB.description + ", resistance = " + res.description + ", runtime = " + runt.description + ", temperature = " + temp.description
case .percentage(let perc):
return "Battery Percentage = " + perc.description
}

View File

@ -12,9 +12,9 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
public weak var bluetoothTransmitterDelegate:BluetoothTransmitterDelegate?
/// the address of the transmitter. If nil then transmitter never connected, so we don't know the name.
public private(set) var address:String?
private var deviceAddress:String?
/// the name of the transmitter. If nil then transmitter never connected, so we don't know the name
public private(set) var name:String?
private var deviceName:String?
/// uuid used for scanning, can be empty string, if empty string then scan all devices - only possible if app is in foreground
private let CBUUID_Advertisement:String?
@ -58,7 +58,7 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
init(addressAndName:BluetoothTransmitter.DeviceAddressAndName, CBUUID_Advertisement:String?, CBUUID_Service:String, CBUUID_ReceiveCharacteristic:String, CBUUID_WriteCharacteristic:String) {
switch addressAndName {
case .alreadyConnectedBefore(let newAddress):
address = newAddress
deviceAddress = newAddress
case .notYetConnected(let newexpectedName):
expectedName = newexpectedName
}
@ -177,8 +177,8 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
fileprivate func stopScanAndconnect(to peripheral: CBPeripheral) {
self.centralManager?.stopScan()
self.address = peripheral.identifier.uuidString
self.name = peripheral.name
self.deviceAddress = peripheral.identifier.uuidString
self.deviceName = peripheral.name
peripheral.delegate = self
self.peripheral = peripheral
@ -196,8 +196,8 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
}
fileprivate func retrievePeripherals(_ central:CBCentralManager) -> Bool {
if let address = address {
if let uuid = UUID(uuidString: address) {
if let deviceAddress = deviceAddress {
if let uuid = UUID(uuidString: deviceAddress) {
var peripheralArr = central.retrievePeripherals(withIdentifiers: [uuid])
if peripheralArr.count > 0 {
peripheral = peripheralArr[0]
@ -225,8 +225,8 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
os_log("Did discover peripheral with name: %{public}@", log: log, type: .info, String(describing: deviceName))
// check if stored address not nil, in which case we already connected before and we expect a full match with the already known device name
if let address = address {
if peripheral.identifier.uuidString == address {
if let deviceAddress = deviceAddress {
if peripheral.identifier.uuidString == deviceAddress {
os_log("stored address matches peripheral address, will try to connect", log: log, type: .info)
stopScanAndconnect(to: peripheral)
}
@ -370,6 +370,15 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
}
}
// MARK: methods to get address and name
func address() -> String? {
return deviceAddress
}
func name() -> String? {
return deviceName
}
// MARK: - helpers
private func initialize() {

View File

@ -17,7 +17,7 @@
<li><a href="#peripheraldidupdatenotificationstatefor">peripheralDidUpdateNotificationStateFor</a></li>
<li><a href="#peripheraldidupatevaluefor">peripheralDidUpdateValueFor</a></li>
</ul></li>
<li><a href="#protocolCGMTransmitterProtocol">conform to protocol CGMTransmitterProtocol</a>
<li><a href="#protocolCGMTransmitter">conform to protocol CGMTransmitter</a>
<ul>
<li><a href="#canDetectNewSensorprotocol">canDetectNewSensor</a></li>
</ul></li>
@ -40,6 +40,7 @@
<li><a href="#newSensorDetected">newSensorDetected</a></li>
<li><a href="#sensorNotDetected">sensorNotDetected</a></li>
<li><a href="#newReadingsReceived">newReadingsReceived</a></li>
<li><a href="#transmitterNeedsPairing">transmitterNeedsPairing</a></li>
</ul></li>
</ul></li>
<li><a href="#functionsandpropertiesavailableintransmitterclasses">Functions and properties available in transmitter classes</a>
@ -84,7 +85,7 @@ BluetoothTransmitter class to a specific transmitter class. Example when a disco
handles the reconnect but the delegate class can for instance show the connection status to the user. It will be informed about
the connection status via the function centralManagerDidConnect in the BluetoothTransmitterDelegate</p>
<p><strong>CGMTransmitterProtocol</strong> defines functions that CGM transmitter classes need to implement.</p>
<p><strong>CGMTransmitter</strong> defines functions that CGM transmitter classes need to implement.</p>
<p>The CGM transmitter communicates back to the caller via the <strong>CGMTransmitterDelegate</strong> protocol.<br>
Needs to be conformed to, for instance by a view controller, or manager, .. whatever<br>
@ -106,7 +107,7 @@ This protocol allows passing information like new readings, sensor detected, and
<p>If it's a CGM transmitter (it could also be a bloodglucose meter that transmits data over bluetooth)</p>
<ul>
<li>conform to the protocol CGMTransmitterProtocol</li>
<li>conform to the protocol CGMTransmitter</li>
</ul>
<h2><a name="protocolbluetoothtransmitterdelegate"></a>conform to protocol BluetoothTransmitterDelegate</h2>
@ -145,7 +146,7 @@ For other types of transmitters there may be nothing to do.<br></p>
<p>This will be the most important function, because it contains the data that needs to be processed by the specific transmitter class.</p>
<h2><a name="protocolCGMTransmitterProtocol"></a>conform to protocol CGMTransmitterProtocol</h2>
<h2><a name="protocolCGMTransmitter"></a>conform to protocol CGMTransmitter</h2>
<h3><a name="canDetectNewSensorprotocol"></a>canDetectNewSensor</h3>
@ -237,6 +238,10 @@ This will typically be called in centralManagerDidUpdateState</p>
<p>This is the most important function, it passes new readings to the delegate</p>
<h3><a name="transmitterNeedsPairing"></a>transmitterNeedsPairing</h3>
<p>The transmitter needs pairing, app should give warning to user to keep the app in the foreground</p>
<h1><a name="functionsandpropertiesavailableintransmitterclasses"></a>Functions and properties available in transmitter classes</h1>
<h2><a name="functionsinbluetoothtransmitterclasses"></a>Functions in BluetoothTransmitter classes</h2>

View File

@ -13,7 +13,7 @@
- [centralManagerDidUpdateState](#centralManagerDidUpdateState)
- [peripheralDidUpdateNotificationStateFor](#peripheraldidupdatenotificationstatefor)
- [peripheralDidUpdateValueFor](#peripheraldidupatevaluefor)
- [conform to protocol CGMTransmitterProtocol](#protocolCGMTransmitterProtocol)
- [conform to protocol CGMTransmitter](#protocolCGMTransmitter)
- [canDetectNewSensor](#canDetectNewSensorprotocol)
- [extend class BluetoothTransmitter](#extendclassbuetoothtransmitter)
- [initialize the super class BluetoothTransmitter](#initializebluetoothtransmitter)
@ -62,7 +62,7 @@ BluetoothTransmitter class to a specific transmitter class. Example when a disco
handles the reconnect but the delegate class can for instance show the connection status to the user. It will be informed about
the connection status via the function centralManagerDidConnect in the BluetoothTransmitterDelegate
**CGMTransmitterProtocol** defines functions that CGM transmitter classes need to implement.
**CGMTransmitter** defines functions that CGM transmitter classes need to implement.
The CGM transmitter communicates back to the caller via the **CGMTransmitterDelegate** protocol.<br>
Needs to be conformed to, for instance by a view controller, or manager, .. whatever<br>
@ -81,7 +81,7 @@ Every new type of bluetoothtransmitter needs to
If it's a CGM transmitter (it could also be a bloodglucose meter that transmits data over bluetooth)
* conform to the protocol CGMTransmitterProtocol
* conform to the protocol CGMTransmitter
## <a name="protocolbluetoothtransmitterdelegate"></a>conform to protocol BluetoothTransmitterDelegate
@ -119,7 +119,7 @@ For other types of transmitters there may be nothing to do.<br>
This will be the most important function, because it contains the data that needs to be processed by the specific transmitter class.
## <a name="protocolCGMTransmitterProtocol"></a>conform to protocol CGMTransmitterProtocol
## <a name="protocolCGMTransmitter"></a>conform to protocol CGMTransmitter
### <a name="canDetectNewSensorprotocol"></a>canDetectNewSensor

View File

@ -6,7 +6,7 @@ import UserNotifications
final class RootHomeViewController: UIViewController, CGMTransmitterDelegate {
// MARK: - Properties
var test:CGMG5Transmitter?//TODO: should be possible to define as cgmtransmitterprotocol ? that protocol should support a few more functions
var test:CGMTransmitter?
var address:String?
var name:String?
@ -75,13 +75,6 @@ final class RootHomeViewController: UIViewController, CGMTransmitterDelegate {
}
// called when transmitter considered to be connected
func cgmTransmitterdidConnect() {
address = test?.address
name = test?.name
os_log("didconnect to device with address %{public}@ and name %{public}@", log: log!, type: .info, address!,name!)
}
// Only MioaMiao will call this
func newSensorDetected() {
os_log("new sensor detected", log: log!, type: .info)
@ -98,7 +91,7 @@ final class RootHomeViewController: UIViewController, CGMTransmitterDelegate {
os_log("sensorstate %{public}@", log: log!, type: .debug, sensorState?.description ?? "no sensor state found")
os_log("firmware %{public}@", log: log!, type: .debug, firmware ?? "no firmware version found")
os_log("hardware %{public}@", log: log!, type: .debug, hardware ?? "no hardware version found")
os_log("transmitterBatteryInfo %{public}d", log: log!, type: .debug, transmitterBatteryInfo?.description ?? 0)
os_log("transmitterBatteryInfo %{public}@", log: log!, type: .debug, transmitterBatteryInfo?.description ?? 0)
os_log("sensor time in minutes %{public}d", log: log!, type: .debug, sensorTimeInMinutes ?? 0)
for (index, reading) in glucoseData.enumerated() {
os_log("Reading %{public}d, raw level = %{public}f, realDate = %{public}s", log: log!, type: .debug, index, reading.glucoseLevelRaw, reading.timeStamp.description)
@ -362,10 +355,10 @@ extension RootHomeViewController: UNUserNotificationCenterDelegate {
}
}
// MARK: - CGMTransmitterDelegate functions
// MARK: - CGMTransmitter protocol functions
func cgmTransmitterDidConnect() {
if let address = test?.address, let name = test?.name {
if let address = test?.address(), let name = test?.name() {
self.address = address
self.name = name
UserDefaults.standard.bluetoothDeviceAddress = address