add bubble
This commit is contained in:
parent
b33e8d2bbc
commit
0c8b330d0e
|
@ -18,4 +18,4 @@ SPEC CHECKSUMS:
|
|||
|
||||
PODFILE CHECKSUM: 347a5d9f3343257452289e61c10025c2eed103bb
|
||||
|
||||
COCOAPODS: 1.6.1
|
||||
COCOAPODS: 1.7.3
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objectVersion = 51;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
A48D2DE552F4A356AA32746A /* Pods_xdrip.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 662BEA7F7991B9BD2E7D3EA4 /* Pods_xdrip.framework */; };
|
||||
EE9947E822EEDD2E00DCB876 /* CGMBubbleTransmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE9947E722EEDD2E00DCB876 /* CGMBubbleTransmitter.swift */; };
|
||||
F8025C0A21D94FD700ECF0C0 /* CBManagerState.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8025C0921D94FD700ECF0C0 /* CBManagerState.swift */; };
|
||||
F8025C1121DA5E8F00ECF0C0 /* BluetoothTransmitterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8025C1021DA5E8F00ECF0C0 /* BluetoothTransmitterDelegate.swift */; };
|
||||
F8025C1321DA683400ECF0C0 /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8025C1221DA683400ECF0C0 /* Data.swift */; };
|
||||
|
@ -190,6 +191,7 @@
|
|||
148E05A6AF0290AE5815B0F9 /* Pods-xdrip.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-xdrip.debug.xcconfig"; path = "Target Support Files/Pods-xdrip/Pods-xdrip.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
662BEA7F7991B9BD2E7D3EA4 /* Pods_xdrip.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_xdrip.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
E2648F65F347D56D7DFFFAB7 /* Pods-xdrip.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-xdrip.release.xcconfig"; path = "Target Support Files/Pods-xdrip/Pods-xdrip.release.xcconfig"; sourceTree = "<group>"; };
|
||||
EE9947E722EEDD2E00DCB876 /* CGMBubbleTransmitter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CGMBubbleTransmitter.swift; sourceTree = "<group>"; };
|
||||
F8025C0921D94FD700ECF0C0 /* CBManagerState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CBManagerState.swift; sourceTree = "<group>"; };
|
||||
F8025C1021DA5E8F00ECF0C0 /* BluetoothTransmitterDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BluetoothTransmitterDelegate.swift; sourceTree = "<group>"; };
|
||||
F8025C1221DA683400ECF0C0 /* Data.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = "<group>"; };
|
||||
|
@ -515,6 +517,14 @@
|
|||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EE9947E622EEDD0700DCB876 /* Bubble */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EE9947E722EEDD2E00DCB876 /* CGMBubbleTransmitter.swift */,
|
||||
);
|
||||
path = Bubble;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F8025C0B21D9513400ECF0C0 /* Extensions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -813,6 +823,7 @@
|
|||
F8A54AEC22D9156600934E7A /* Libre */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EE9947E622EEDD0700DCB876 /* Bubble */,
|
||||
F8A54AFB22D9179100934E7A /* Utilities */,
|
||||
F8A54AED22D9156600934E7A /* GNSEntry */,
|
||||
F8A54AEF22D9156600934E7A /* MiaoMiao */,
|
||||
|
@ -1282,16 +1293,11 @@
|
|||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-xdrip/Pods-xdrip-frameworks.sh",
|
||||
"${BUILT_PRODUCTS_DIR}/ActionClosurable/ActionClosurable.framework",
|
||||
"${PODS_ROOT}/Target Support Files/Pods-xdrip/Pods-xdrip-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ActionClosurable.framework",
|
||||
"${PODS_ROOT}/Target Support Files/Pods-xdrip/Pods-xdrip-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
|
@ -1379,6 +1385,7 @@
|
|||
F8A54AB822D9111900934E7A /* TransmitterBatteryInfo.swift in Sources */,
|
||||
F8B3A82D227F07D6004BA588 /* SettingsNavigationController.swift in Sources */,
|
||||
F8A54AB722D9111900934E7A /* CGMTransmitter.swift in Sources */,
|
||||
EE9947E822EEDD2E00DCB876 /* CGMBubbleTransmitter.swift in Sources */,
|
||||
F8B3A830227F085A004BA588 /* SettingsTableViewCell.swift in Sources */,
|
||||
F8A1586122EDB844007F5B5D /* ConstantsNotifications.swift in Sources */,
|
||||
F8B3A81C227DEC92004BA588 /* AlertEntriesAccessor.swift in Sources */,
|
||||
|
|
|
@ -4,6 +4,7 @@ enum ConstantsDefaultAlertLevels {
|
|||
static let defaultBatteryAlertLevelDexcomG5 = 300
|
||||
static let defaultBatteryAlertLevelDexcomG4 = 210
|
||||
static let defaultBatteryAlertLevelMiaoMiao = 20
|
||||
static let defaultBatteryAlertLevelBubble = 20
|
||||
static let defaultBatteryAlertLevelGNSEntry = 20
|
||||
static let defaultBatteryAlertLevelBlucon = 20
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ enum ConstantsLog {
|
|||
static let categoryBlueTooth = "bluetooth"
|
||||
/// for use in cgm transmitter miaomiao
|
||||
static let categoryCGMMiaoMiao = "cgmmiaomiao"
|
||||
/// for use in cgm transmitter bubble
|
||||
static let categoryCGMBubble = "cgmbubble"
|
||||
/// for use in cgm xdripg4
|
||||
static let categoryCGMxDripG4 = "cgmxdripg4"
|
||||
/// for use in firstview
|
||||
|
|
|
@ -64,6 +64,9 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
/// Blucon
|
||||
case Blucon = "Blucon"
|
||||
|
||||
/// Bubble
|
||||
case Bubble = "Bubble"
|
||||
|
||||
/// does the transmitter need a transmitter id ?
|
||||
///
|
||||
/// can be used in UI stuff, if reset not possible then there's no need to show that option in the settings UI
|
||||
|
@ -76,7 +79,7 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
case .dexcomG5, .dexcomG6:
|
||||
return true
|
||||
|
||||
case .miaomiao:
|
||||
case .miaomiao, .Bubble:
|
||||
return false
|
||||
|
||||
case .GNSentry:
|
||||
|
@ -102,7 +105,7 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
case .dexcomG5, .dexcomG6:
|
||||
return false
|
||||
|
||||
case .miaomiao:
|
||||
case .miaomiao, .Bubble:
|
||||
return true
|
||||
|
||||
case .GNSentry:
|
||||
|
@ -139,7 +142,7 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
}
|
||||
return nil
|
||||
|
||||
case .miaomiao, .GNSentry:
|
||||
case .miaomiao, .GNSentry, .Bubble:
|
||||
return nil
|
||||
|
||||
case .Blucon:
|
||||
|
@ -161,6 +164,9 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
case .miaomiao:
|
||||
return ConstantsDefaultAlertLevels.defaultBatteryAlertLevelMiaoMiao
|
||||
|
||||
case .Bubble:
|
||||
return ConstantsDefaultAlertLevels.defaultBatteryAlertLevelBubble
|
||||
|
||||
case .GNSentry:
|
||||
return ConstantsDefaultAlertLevels.defaultBatteryAlertLevelGNSEntry
|
||||
|
||||
|
@ -182,7 +188,7 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
case .dexcomG5, .dexcomG6:
|
||||
return true
|
||||
|
||||
case .miaomiao:
|
||||
case .miaomiao, .Bubble:
|
||||
return false
|
||||
|
||||
case .GNSentry:
|
||||
|
@ -205,7 +211,7 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
case .dexcomG5, .dexcomG6:
|
||||
return "voltA"
|
||||
|
||||
case .miaomiao:
|
||||
case .miaomiao, .Bubble:
|
||||
return "%"
|
||||
|
||||
case .GNSentry:
|
||||
|
@ -228,7 +234,7 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
case .dexcomG5, .dexcomG6:
|
||||
return true
|
||||
|
||||
case .miaomiao:
|
||||
case .miaomiao, .Bubble:
|
||||
return false
|
||||
|
||||
case .GNSentry:
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
import Foundation
|
||||
import CoreBluetooth
|
||||
import os
|
||||
|
||||
class CGMBubbleTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTransmitter {
|
||||
// MARK: - properties
|
||||
|
||||
/// service to be discovered
|
||||
let CBUUID_Service_Bubble: String = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||
/// receive characteristic
|
||||
let CBUUID_ReceiveCharacteristic_Bubble: String = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||
/// write characteristic
|
||||
let CBUUID_WriteCharacteristic_Bubble: String = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||
|
||||
/// expected device name
|
||||
let expectedDeviceNameBubble:String = "Bubble"
|
||||
|
||||
/// will be used to pass back bluetooth and cgm related events
|
||||
private(set) weak var cgmTransmitterDelegate: CGMTransmitterDelegate?
|
||||
|
||||
// maximum times resend request due to crc error
|
||||
let maxPacketResendRequests = 3;
|
||||
|
||||
/// for OS_log
|
||||
private let log = OSLog(subsystem: ConstantsLog.subSystem, category: ConstantsLog.categoryCGMBubble)
|
||||
|
||||
// used in parsing packet
|
||||
private var timeStampLastBgReading:Date
|
||||
|
||||
// counts number of times resend was requested due to crc error
|
||||
private var resendPacketCounter:Int = 0
|
||||
|
||||
/// used when processing Bubble data packet
|
||||
private var startDate:Date
|
||||
// receive buffer for bubble packets
|
||||
private var rxBuffer:Data
|
||||
// how long to wait for next packet before sending startreadingcommand
|
||||
private static let maxWaitForpacketInSeconds = 60.0
|
||||
// length of header added by Bubble in front of data dat is received from Libre sensor
|
||||
private let BubbleHeaderLength = 8
|
||||
|
||||
// MARK: - Initialization
|
||||
/// - parameters:
|
||||
/// - address: if already connected before, then give here the address that was received during previous connect, if not give nil
|
||||
init(address:String?, delegate:CGMTransmitterDelegate, timeStampLastBgReading:Date) {
|
||||
|
||||
// assign addressname and name or expected devicename
|
||||
var newAddressAndName:BluetoothTransmitter.DeviceAddressAndName = BluetoothTransmitter.DeviceAddressAndName.notYetConnected(expectedName: expectedDeviceNameBubble)
|
||||
if let address = address {
|
||||
newAddressAndName = BluetoothTransmitter.DeviceAddressAndName.alreadyConnectedBefore(address: address)
|
||||
}
|
||||
|
||||
// assign CGMTransmitterDelegate
|
||||
cgmTransmitterDelegate = delegate
|
||||
|
||||
// initialize rxbuffer
|
||||
rxBuffer = Data()
|
||||
startDate = Date()
|
||||
|
||||
//initialize timeStampLastBgReading
|
||||
self.timeStampLastBgReading = timeStampLastBgReading
|
||||
|
||||
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: nil, servicesCBUUIDs: [CBUUID(string: CBUUID_Service_Bubble)], CBUUID_ReceiveCharacteristic: CBUUID_ReceiveCharacteristic_Bubble, CBUUID_WriteCharacteristic: CBUUID_WriteCharacteristic_Bubble, startScanningAfterInit: CGMTransmitterType.Bubble.startScanningAfterInit())
|
||||
|
||||
// set self as delegate for BluetoothTransmitterDelegate - this parameter is defined in the parent class BluetoothTransmitter
|
||||
bluetoothTransmitterDelegate = self
|
||||
}
|
||||
|
||||
// MARK: - public functions
|
||||
|
||||
func sendStartReadingCommmand() -> Bool {
|
||||
if writeDataToPeripheral(data: Data([0x00, 0x00, 0x5]), type: .withoutResponse) {
|
||||
return true
|
||||
} else {
|
||||
os_log("in sendStartReadingCommmand, write failed", log: log, type: .error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - BluetoothTransmitterDelegate functions
|
||||
|
||||
func centralManagerDidConnect(address:String?, name:String?) {
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: address, name: name)
|
||||
}
|
||||
|
||||
func centralManagerDidFailToConnect(error: Error?) {
|
||||
}
|
||||
|
||||
func centralManagerDidUpdateState(state: CBManagerState) {
|
||||
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: state)
|
||||
}
|
||||
|
||||
func centralManagerDidDisconnectPeripheral(error: Error?) {
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidDisconnect()
|
||||
}
|
||||
|
||||
func peripheralDidUpdateNotificationStateFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
if error == nil && characteristic.isNotifying {
|
||||
_ = sendStartReadingCommmand()
|
||||
}
|
||||
}
|
||||
|
||||
var hardware = ""
|
||||
var firmware = ""
|
||||
var batteryPercentage = 0
|
||||
func peripheralDidUpdateValueFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
|
||||
if let value = characteristic.value {
|
||||
|
||||
//check if buffer needs to be reset
|
||||
if (Date() > startDate.addingTimeInterval(CGMBubbleTransmitter.maxWaitForpacketInSeconds - 1)) {
|
||||
os_log("in peripheral didUpdateValueFor, more than %{public}d seconds since last update - or first update since app launch, resetting buffer", log: log, type: .info, CGMBubbleTransmitter.maxWaitForpacketInSeconds)
|
||||
resetRxBuffer()
|
||||
}
|
||||
|
||||
if let firstByte = value.first {
|
||||
if firstByte == 192 {
|
||||
rxBuffer.append(value.subdata(in: 2..<10))
|
||||
return
|
||||
}
|
||||
|
||||
if firstByte == 128 {
|
||||
hardware = value[2].description + ".0"
|
||||
firmware = value[1].description + ".0"
|
||||
batteryPercentage = Int(value[4])
|
||||
|
||||
let _ = writeDataToPeripheral(data: Data([0x02, 0x00, 0x00, 0x00, 0x00, 0x2B]), type: .withoutResponse)
|
||||
}
|
||||
|
||||
if firstByte == 130 {
|
||||
rxBuffer.append(value.suffix(from: 4))
|
||||
}
|
||||
|
||||
if rxBuffer.count >= 352 {
|
||||
if (Crc.LibreCrc(data: &rxBuffer, headerOffset: BubbleHeaderLength)) {
|
||||
//get readings from buffer and send to delegate
|
||||
var result = parseLibreData(data: &rxBuffer, timeStampLastBgReadingStoredInDatabase: timeStampLastBgReading, headerOffset: BubbleHeaderLength)
|
||||
//TODO: sort glucosedata before calling newReadingsReceived
|
||||
cgmTransmitterDelegate?.cgmTransmitterInfoReceived(glucoseData: &result.glucoseData, transmitterBatteryInfo: TransmitterBatteryInfo.percentage(percentage: batteryPercentage), sensorState: result.sensorState, sensorTimeInMinutes: result.sensorTimeInMinutes, firmware: firmware, hardware: hardware, hardwareSerialNumber: nil, bootloader: nil, sensorSerialNumber: nil)
|
||||
|
||||
//set timeStampLastBgReading to timestamp of latest reading in the response so that next time we parse only the more recent readings
|
||||
if result.glucoseData.count > 0 {
|
||||
timeStampLastBgReading = result.glucoseData[0].timeStamp
|
||||
}
|
||||
|
||||
//reset the buffer
|
||||
resetRxBuffer()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
os_log("in peripheral didUpdateValueFor, value is nil, no further processing", log: log, type: .error)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: CGMTransmitter protocol functions
|
||||
|
||||
/// to ask pairing - empty function because G4 doesn't need pairing
|
||||
///
|
||||
/// this function is not implemented in BluetoothTransmitter.swift, otherwise it might be forgotten to look at in future CGMTransmitter developments
|
||||
func initiatePairing() {}
|
||||
|
||||
/// to ask transmitter reset - empty function because Bubble doesn't support reset
|
||||
///
|
||||
/// this function is not implemented in BluetoothTransmitter.swift, otherwise it might be forgotten to look at in future CGMTransmitter developments
|
||||
func reset(requested:Bool) {}
|
||||
|
||||
// MARK: - helpers
|
||||
|
||||
/// reset rxBuffer, reset startDate, stop packetRxMonitorTimer, set resendPacketCounter to 0
|
||||
private func resetRxBuffer() {
|
||||
rxBuffer = Data()
|
||||
startDate = Date()
|
||||
resendPacketCounter = 0
|
||||
}
|
||||
}
|
|
@ -595,6 +595,10 @@ final class RootViewController: UIViewController {
|
|||
cgmTransmitter = CGMMiaoMiaoTransmitter(address: UserDefaults.standard.bluetoothDeviceAddress, delegate: self, timeStampLastBgReading: Date(timeIntervalSince1970: 0))
|
||||
calibrator = Libre1Calibrator()
|
||||
|
||||
case .Bubble:
|
||||
cgmTransmitter = CGMBubbleTransmitter(address: UserDefaults.standard.bluetoothDeviceAddress, delegate: self, timeStampLastBgReading: Date(timeIntervalSince1970: 0))
|
||||
calibrator = Libre1Calibrator()
|
||||
|
||||
case .GNSentry:
|
||||
cgmTransmitter = CGMGNSEntryTransmitter(address: UserDefaults.standard.bluetoothDeviceAddress, delegate: self, timeStampLastBgReading: Date(timeIntervalSince1970: 0))
|
||||
calibrator = Libre1Calibrator()
|
||||
|
|
|
@ -28,7 +28,7 @@ class SettingsViewDexcomSettingsViewModel:SettingsViewModelProtocol {
|
|||
if let transmitterType = UserDefaults.standard.transmitterType {
|
||||
switch transmitterType {
|
||||
|
||||
case .dexcomG4, .miaomiao, .GNSentry, .Blucon:
|
||||
case .dexcomG4, .miaomiao, .GNSentry, .Blucon, .Bubble:
|
||||
return true
|
||||
|
||||
case .dexcomG5, .dexcomG6:
|
||||
|
|
Loading…
Reference in New Issue