add bubble

This commit is contained in:
huyan_18040019 2019-07-29 16:42:48 +08:00
parent b33e8d2bbc
commit 0c8b330d0e
8 changed files with 212 additions and 16 deletions

View File

@ -18,4 +18,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 347a5d9f3343257452289e61c10025c2eed103bb
COCOAPODS: 1.6.1
COCOAPODS: 1.7.3

View File

@ -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 */,

View File

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

View File

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

View File

@ -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:

View File

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

View File

@ -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()

View File

@ -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: