diff --git a/Example/Podfile.lock b/Example/Podfile.lock index e87f3d63..9d30a5a1 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -1,5 +1,5 @@ PODS: - - xDripG5 (0.7.0) + - xDripG5 (0.8.0) DEPENDENCIES: - xDripG5 (from `../`) @@ -9,8 +9,8 @@ EXTERNAL SOURCES: :path: ../ SPEC CHECKSUMS: - xDripG5: b0bfa28e1dc510799d919ab6a67badb56a024247 + xDripG5: 8779a4f495fd8eb81a3d75457afe9b95fb52f61d PODFILE CHECKSUM: 6b30cba971694d5258509315fb52eb645c9bc5e3 -COCOAPODS: 1.1.0.beta.2 +COCOAPODS: 1.1.0.rc.2 diff --git a/Example/xDripG5.xcodeproj/project.pbxproj b/Example/xDripG5.xcodeproj/project.pbxproj index be841e30..8a1bd720 100644 --- a/Example/xDripG5.xcodeproj/project.pbxproj +++ b/Example/xDripG5.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 06C991A3D94948120AD2A278 /* Pods_xDripG5_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42011659993839B43D24C553 /* Pods_xDripG5_Example.framework */; }; + 43846AC21D8F812A00799272 /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43846AC11D8F812A00799272 /* Data.swift */; }; 439FCA211C332AA4007DE84C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 439FCA1F1C332AA4007DE84C /* LaunchScreen.storyboard */; }; 439FCA231C332AE5007DE84C /* NSUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 439FCA221C332AE5007DE84C /* NSUserDefaults.swift */; }; 43E3979F1D569B340028E321 /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43E3979E1D569B340028E321 /* HKUnit.swift */; }; @@ -19,6 +20,7 @@ /* Begin PBXFileReference section */ 42011659993839B43D24C553 /* Pods_xDripG5_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_xDripG5_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 43846AC11D8F812A00799272 /* Data.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = ""; }; 439FCA201C332AA4007DE84C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 439FCA221C332AE5007DE84C /* NSUserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSUserDefaults.swift; sourceTree = ""; }; 43E3979E1D569B340028E321 /* HKUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HKUnit.swift; path = ../../xDripG5/HKUnit.swift; sourceTree = ""; }; @@ -78,6 +80,7 @@ isa = PBXGroup; children = ( 607FACD51AFB9204008FA782 /* AppDelegate.swift */, + 43846AC11D8F812A00799272 /* Data.swift */, 43E3979E1D569B340028E321 /* HKUnit.swift */, 439FCA221C332AE5007DE84C /* NSUserDefaults.swift */, 607FACD71AFB9204008FA782 /* ViewController.swift */, @@ -246,6 +249,7 @@ buildActionMask = 2147483647; files = ( 607FACD81AFB9204008FA782 /* ViewController.swift in Sources */, + 43846AC21D8F812A00799272 /* Data.swift in Sources */, 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */, 43E3979F1D569B340028E321 /* HKUnit.swift in Sources */, 439FCA231C332AE5007DE84C /* NSUserDefaults.swift in Sources */, @@ -365,7 +369,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = F3147B948B4F90A741304461 /* Pods-xDripG5_Example.debug.xcconfig */; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = xDripG5/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -381,7 +384,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = CFBD776BFE02F42998A8820B /* Pods-xDripG5_Example.release.xcconfig */; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = xDripG5/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; diff --git a/Example/xDripG5/AppDelegate.swift b/Example/xDripG5/AppDelegate.swift index 4cf8a5b8..f230f6d9 100644 --- a/Example/xDripG5/AppDelegate.swift +++ b/Example/xDripG5/AppDelegate.swift @@ -87,4 +87,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate, TransmitterDelegate { } } } + + func transmitter(_ transmitter: Transmitter, didReadUnknownData data: Data) { + if let vc = window?.rootViewController as? TransmitterDelegate { + DispatchQueue.main.async { + vc.transmitter(transmitter, didReadUnknownData: data) + } + } + } } diff --git a/Example/xDripG5/Data.swift b/Example/xDripG5/Data.swift new file mode 100644 index 00000000..81d92e53 --- /dev/null +++ b/Example/xDripG5/Data.swift @@ -0,0 +1,22 @@ +// +// Data.swift +// xDripG5 +// +// Created by Nate Racklyeft on 9/18/16. +// Copyright © 2016 Nathan Racklyeft. All rights reserved. +// + +import Foundation + + +extension Data { + var hexadecimalString: String { + let string = NSMutableString(capacity: count * 2) + + for byte in self { + string.appendFormat("%02x", byte) + } + + return string as String + } +} diff --git a/Example/xDripG5/ViewController.swift b/Example/xDripG5/ViewController.swift index 7cb49e21..faef5334 100644 --- a/Example/xDripG5/ViewController.swift +++ b/Example/xDripG5/ViewController.swift @@ -119,6 +119,11 @@ class ViewController: UIViewController, TransmitterDelegate, UITextFieldDelegate let date = glucose.readDate subtitleLabel.text = DateFormatter.localizedString(from: date, dateStyle: .none, timeStyle: .long) } + + func transmitter(_ transmitter: Transmitter, didReadUnknownData data: Data) { + titleLabel.text = NSLocalizedString("Unknown Data", comment: "Title displayed during unknown data response") + subtitleLabel.text = data.hexadecimalString + } } diff --git a/README.md b/README.md index 4373d6cf..28351e65 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # xDripG5 -[![CI Status](http://img.shields.io/travis/loudnate/xDripG5.svg?style=flat)](https://travis-ci.org/loudnate/xDripG5) +[![CI Status](http://img.shields.io/travis/LoopKit/xDripG5.svg?style=flat)](https://travis-ci.org/LoopKit/xDripG5) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![Version](https://img.shields.io/cocoapods/v/xDripG5.svg?style=flat)](http://cocoapods.org/pods/xDripG5) [![License](https://img.shields.io/cocoapods/l/xDripG5.svg?style=flat)](http://cocoapods.org/pods/xDripG5) @@ -21,7 +21,7 @@ This framework connects to a G5 Mobile Transmitter via Bluetooth LE. It does not xDripG5 is available through [Carthage](https://github.com/Carthage/Carthage). To install it, add the following line to your Cartfile: ```ruby -github "loudnate/xDripG5" +github "LoopKit/xDripG5" ``` Note that you'll need to confgure your target to link against `CommonCrypto.framework` in addition to `xDripG5.framework` @@ -48,7 +48,7 @@ If you plan to run your app alongside the G5 Mobile application, make sure to se ## Code of Conduct -Please note that this project is released with a [Contributor Code of Conduct](https://github.com/loudnate/LoopKit/blob/master/CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms. +Please note that this project is released with a [Contributor Code of Conduct](https://github.com/LoopKit/LoopKit/blob/master/CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms. ## License diff --git a/xDripG5.podspec b/xDripG5.podspec index 21fc5af1..8374f388 100644 --- a/xDripG5.podspec +++ b/xDripG5.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "xDripG5" - s.version = "0.7.0" + s.version = "0.8.0" s.summary = "An interface for communicating with the G5 glucose transmitter over Bluetooth." s.description = <<-DESC @@ -11,11 +11,10 @@ By using this framework in your own app, you can get access to your glucose read Please note this project is neither created nor backed by Dexcom, Inc. Use of this software is not intended for therapy. DESC - s.homepage = "https://github.com/loudnate/xDripG5" + s.homepage = "https://github.com/LoopKit/xDripG5" s.license = 'MIT' s.author = { "Nathan Racklyeft" => "loudnate@gmail.com" } - s.source = { :git => "https://github.com/loudnate/xDripG5.git", :tag => s.version.to_s } - s.social_media_url = 'https://twitter.com/loudnate' + s.source = { :git => "https://github.com/LoopKit/xDripG5.git", :tag => s.version.to_s } s.platform = :ios, '9.3' s.requires_arc = true diff --git a/xDripG5.xcodeproj/project.pbxproj b/xDripG5.xcodeproj/project.pbxproj index 2b5754e9..371c615f 100644 --- a/xDripG5.xcodeproj/project.pbxproj +++ b/xDripG5.xcodeproj/project.pbxproj @@ -9,6 +9,10 @@ /* Begin PBXBuildFile section */ 430D64C51CB7846A00FCA750 /* NSData+CRC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430D64C41CB7846A00FCA750 /* NSData+CRC.swift */; }; 43538C111D81220F0071CA5E /* NSData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43CABE101C350B2800005705 /* NSData.swift */; }; + 43846AC61D8F896C00799272 /* CalibrationDataRxMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43846AC51D8F896C00799272 /* CalibrationDataRxMessage.swift */; }; + 43846AC81D8F89BE00799272 /* CalibrationDataRxMessageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43846AC71D8F89BE00799272 /* CalibrationDataRxMessageTests.swift */; }; + 43880F981D9E19FC009061A8 /* TransmitterVersionRxMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43880F971D9E19FC009061A8 /* TransmitterVersionRxMessage.swift */; }; + 43880F9A1D9E1BD7009061A8 /* TransmitterVersionRxMessageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43880F991D9E1BD7009061A8 /* TransmitterVersionRxMessageTests.swift */; }; 43CABDF71C3506F100005705 /* xDripG5.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CABDF61C3506F100005705 /* xDripG5.h */; settings = {ATTRIBUTES = (Public, ); }; }; 43CABDFE1C3506F100005705 /* xDripG5.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43CABDF31C3506F100005705 /* xDripG5.framework */; }; 43CABE121C350B2800005705 /* BluetoothManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43CABE0E1C350B2800005705 /* BluetoothManager.swift */; }; @@ -74,6 +78,10 @@ /* Begin PBXFileReference section */ 430D64C41CB7846A00FCA750 /* NSData+CRC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSData+CRC.swift"; sourceTree = ""; }; + 43846AC51D8F896C00799272 /* CalibrationDataRxMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CalibrationDataRxMessage.swift; sourceTree = ""; }; + 43846AC71D8F89BE00799272 /* CalibrationDataRxMessageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CalibrationDataRxMessageTests.swift; sourceTree = ""; }; + 43880F971D9E19FC009061A8 /* TransmitterVersionRxMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransmitterVersionRxMessage.swift; sourceTree = ""; }; + 43880F991D9E1BD7009061A8 /* TransmitterVersionRxMessageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransmitterVersionRxMessageTests.swift; sourceTree = ""; }; 43CABDF31C3506F100005705 /* xDripG5.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = xDripG5.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 43CABDF61C3506F100005705 /* xDripG5.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xDripG5.h; sourceTree = ""; }; 43CABDF81C3506F100005705 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -182,13 +190,15 @@ 43CABE011C3506F100005705 /* xDripG5Tests */ = { isa = PBXGroup; children = ( - 43E397901D5692080028E321 /* GlucoseTests.swift */, + 43846AC71D8F89BE00799272 /* CalibrationDataRxMessageTests.swift */, 43DC87C11C8B520F005BC30D /* GlucoseRxMessageTests.swift */, + 43E397901D5692080028E321 /* GlucoseTests.swift */, 43CABE041C3506F100005705 /* Info.plist */, 43DC87BF1C8B509B005BC30D /* NSData.swift */, - 43F82BCB1D035AA4006F5DD7 /* TransmitterTimeRxMessageTests.swift */, - 43F82BD11D037040006F5DD7 /* SessionStopRxMessageTests.swift */, 43F82BD31D037227006F5DD7 /* SessionStartRxMessageTests.swift */, + 43F82BD11D037040006F5DD7 /* SessionStopRxMessageTests.swift */, + 43F82BCB1D035AA4006F5DD7 /* TransmitterTimeRxMessageTests.swift */, + 43880F991D9E1BD7009061A8 /* TransmitterVersionRxMessageTests.swift */, ); path = xDripG5Tests; sourceTree = ""; @@ -203,6 +213,7 @@ 43CE7CCB1CA73BCC003CC1B0 /* BatteryStatusTxMessage.swift */, 43CABE1B1C350B3D00005705 /* BondRequestTxMessage.swift */, 43CE7CD11CA73CBC003CC1B0 /* CalibrateGlucoseTxMessage.swift */, + 43846AC51D8F896C00799272 /* CalibrationDataRxMessage.swift */, 43CABE1C1C350B3D00005705 /* DisconnectTxMessage.swift */, 43CE7CC71CA73AEB003CC1B0 /* FirmwareVersionTxMessage.swift */, 43CE7CD31CA73CE8003CC1B0 /* GlucoseHistoryTxMessage.swift */, @@ -217,6 +228,7 @@ 43CABE211C350B3D00005705 /* TransmitterTimeRxMessage.swift */, 43CABE221C350B3D00005705 /* TransmitterTimeTxMessage.swift */, 43CE7CC91CA73B94003CC1B0 /* TransmitterVersionTxMessage.swift */, + 43880F971D9E19FC009061A8 /* TransmitterVersionRxMessage.swift */, ); path = Messages; sourceTree = ""; @@ -281,7 +293,7 @@ attributes = { LastSwiftUpdateCheck = 0730; LastUpgradeCheck = 0800; - ORGANIZATIONNAME = "Nathan Racklyeft"; + ORGANIZATIONNAME = "LoopKit Authors"; TargetAttributes = { 43CABDF21C3506F100005705 = { CreatedOnToolsVersion = 7.2; @@ -343,6 +355,7 @@ 43CABE261C350B3D00005705 /* AuthStatusRxMessage.swift in Sources */, 43CE7CD41CA73CE8003CC1B0 /* GlucoseHistoryTxMessage.swift in Sources */, 43E397931D56950C0028E321 /* HKUnit.swift in Sources */, + 43846AC61D8F896C00799272 /* CalibrationDataRxMessage.swift in Sources */, 43CE7CD01CA73C57003CC1B0 /* SessionStopTxMessage.swift in Sources */, 43CABE2A1C350B3D00005705 /* GlucoseTxMessage.swift in Sources */, 43CE7CC81CA73AEB003CC1B0 /* FirmwareVersionTxMessage.swift in Sources */, @@ -350,6 +363,7 @@ 43EEA7121D14DC0800CBBDA0 /* AESCrypt.m in Sources */, 43CE7CCE1CA73C22003CC1B0 /* SessionStartTxMessage.swift in Sources */, 43CABE2E1C350B3D00005705 /* TransmitterTimeTxMessage.swift in Sources */, + 43880F981D9E19FC009061A8 /* TransmitterVersionRxMessage.swift in Sources */, 43538C111D81220F0071CA5E /* NSData.swift in Sources */, 43CABE2C1C350B3D00005705 /* TransmitterMessage.swift in Sources */, 43CABE131C350B2800005705 /* BluetoothServices.swift in Sources */, @@ -373,9 +387,11 @@ files = ( 43F82BCC1D035AA4006F5DD7 /* TransmitterTimeRxMessageTests.swift in Sources */, 43F82BD41D037227006F5DD7 /* SessionStartRxMessageTests.swift in Sources */, + 43846AC81D8F89BE00799272 /* CalibrationDataRxMessageTests.swift in Sources */, 43DC87C01C8B509B005BC30D /* NSData.swift in Sources */, 43F82BD21D037040006F5DD7 /* SessionStopRxMessageTests.swift in Sources */, 43E397911D5692080028E321 /* GlucoseTests.swift in Sources */, + 43880F9A1D9E1BD7009061A8 /* TransmitterVersionRxMessageTests.swift in Sources */, 43DC87C21C8B520F005BC30D /* GlucoseRxMessageTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -412,7 +428,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 13; + CURRENT_PROJECT_VERSION = 14; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -462,7 +478,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 13; + CURRENT_PROJECT_VERSION = 14; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -492,7 +508,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 13; + DYLIB_CURRENT_VERSION = 14; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = xDripG5/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -512,7 +528,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 13; + DYLIB_CURRENT_VERSION = 14; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = xDripG5/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; diff --git a/xDripG5/BluetoothManager.swift b/xDripG5/BluetoothManager.swift index 2db9cef8..99da4fed 100644 --- a/xDripG5/BluetoothManager.swift +++ b/xDripG5/BluetoothManager.swift @@ -29,6 +29,12 @@ protocol BluetoothManagerDelegate: class { - returns: True if the peripheral should connect */ func bluetoothManager(_ manager: BluetoothManager, shouldConnectPeripheral peripheral: CBPeripheral) -> Bool + + /// Tells the delegate that the bluetooth manager received new data in the control characteristic. + /// + /// - parameter manager: The bluetooth manager + /// - parameter didReceiveControlResponse: The data received on the control characteristic + func bluetoothManager(_ manager: BluetoothManager, didReceiveControlResponse response: Data) } @@ -422,7 +428,6 @@ class BluetoothManager: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate } func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { - operationLock.lock() if operationConditions.remove(.valueUpdate(characteristic: characteristic, firstByte: characteristic.value?[0])) != nil || @@ -436,11 +441,15 @@ class BluetoothManager: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate } operationLock.unlock() + + if let data = characteristic.value { + delegate?.bluetoothManager(self, didReceiveControlResponse: data) + } } func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) { - self.operationLock.lock() + operationLock.lock() if operationConditions.remove(.writeUpdate(characteristic: characteristic)) != nil { operationError = error @@ -450,7 +459,7 @@ class BluetoothManager: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate } } - self.operationLock.unlock() + operationLock.unlock() } } diff --git a/xDripG5/Info.plist b/xDripG5/Info.plist index 3157e479..5d7827c2 100644 --- a/xDripG5/Info.plist +++ b/xDripG5/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 0.7.0 + 0.8.0 CFBundleSignature ???? CFBundleVersion diff --git a/xDripG5/Messages/BatteryStatusTxMessage.swift b/xDripG5/Messages/BatteryStatusTxMessage.swift index 0a768087..81e48dcd 100644 --- a/xDripG5/Messages/BatteryStatusTxMessage.swift +++ b/xDripG5/Messages/BatteryStatusTxMessage.swift @@ -11,4 +11,6 @@ import Foundation struct BatteryStatusTxMessage { let opcode: UInt8 = 0x22 + + // Response: 23003c012f01cd021f247bae } diff --git a/xDripG5/Messages/CalibrationDataRxMessage.swift b/xDripG5/Messages/CalibrationDataRxMessage.swift new file mode 100644 index 00000000..25032634 --- /dev/null +++ b/xDripG5/Messages/CalibrationDataRxMessage.swift @@ -0,0 +1,24 @@ +// +// CalibrationDataRxMessage.swift +// Pods +// +// Created by Nate Racklyeft on 9/18/16. +// +// + +import Foundation + + +struct CalibrationDataRxMessage: TransmitterRxMessage { + static let opcode: UInt8 = 0x33 + + init?(data: Data) { + guard data.count == 19 && data.crcValid() else { + return nil + } + + guard data[0] == type(of: self).opcode else { + return nil + } + } +} diff --git a/xDripG5/Messages/TransmitterVersionRxMessage.swift b/xDripG5/Messages/TransmitterVersionRxMessage.swift new file mode 100644 index 00000000..fa26c1c5 --- /dev/null +++ b/xDripG5/Messages/TransmitterVersionRxMessage.swift @@ -0,0 +1,30 @@ +// +// TransmitterVersionRxMessage.swift +// xDripG5 +// +// Created by Nate Racklyeft on 9/29/16. +// Copyright © 2016 Nathan Racklyeft. All rights reserved. +// + +import Foundation + + +struct TransmitterVersionRxMessage: TransmitterRxMessage { + static let opcode: UInt8 = 0x4b + let status: UInt8 + let firmwareVersion: [UInt8] + + init?(data: Data) { + guard data.count == 19 && data.crcValid() else { + return nil + } + + guard data[0] == type(of: self).opcode else { + return nil + } + + status = data[1] + firmwareVersion = data[2..<6] + } + +} diff --git a/xDripG5/NSData.swift b/xDripG5/NSData.swift index c823c93e..a1ee1c34 100644 --- a/xDripG5/NSData.swift +++ b/xDripG5/NSData.swift @@ -45,14 +45,14 @@ public extension Data { return dataArray } - +*/ subscript(range: Range) -> [UInt8] { var dataArray = [UInt8](repeating: 0, count: range.count) self.copyBytes(to: &dataArray, from: range) return dataArray } - +/* subscript(range: Range) -> [UInt16] { var dataArray = [UInt16](repeating: 0, count: range.count / 2) let buffer = UnsafeMutableBufferPointer(start: &dataArray, count: range.count) diff --git a/xDripG5/Transmitter.swift b/xDripG5/Transmitter.swift index e222ceba..692ca235 100644 --- a/xDripG5/Transmitter.swift +++ b/xDripG5/Transmitter.swift @@ -14,6 +14,8 @@ public protocol TransmitterDelegate: class { func transmitter(_ transmitter: Transmitter, didError error: Error) func transmitter(_ transmitter: Transmitter, didRead glucose: Glucose) + + func transmitter(_ transmitter: Transmitter, didReadUnknownData data: Data) } @@ -31,6 +33,8 @@ public final class Transmitter: BluetoothManagerDelegate { /// The initial activation date of the transmitter public private(set) var activationDate: Date? + private var lastTimeMessage: TransmitterTimeRxMessage? + public var passiveModeEnabled: Bool public weak var delegate: TransmitterDelegate? @@ -123,6 +127,35 @@ public final class Transmitter: BluetoothManagerDelegate { } } + func bluetoothManager(_ manager: BluetoothManager, didReceiveControlResponse response: Data) { + guard passiveModeEnabled else { return } + + guard response.count > 0 else { return } + + switch response[0] { + case GlucoseRxMessage.opcode: + if let glucoseMessage = GlucoseRxMessage(data: response), + let timeMessage = lastTimeMessage, + let activationDate = activationDate + { + self.delegate?.transmitter(self, didRead: Glucose(glucoseMessage: glucoseMessage, timeMessage: timeMessage, activationDate: activationDate)) + return + } + case CalibrationDataRxMessage.opcode, SessionStartRxMessage.opcode, SessionStopRxMessage.opcode: + return // Ignore these messages + case TransmitterTimeRxMessage.opcode: + if let timeMessage = TransmitterTimeRxMessage(data: response) { + self.activationDate = Date(timeIntervalSinceNow: -TimeInterval(timeMessage.currentTime)) + self.lastTimeMessage = timeMessage + return + } + default: + break + } + + delegate?.transmitter(self, didReadUnknownData: response) + } + // MARK: - Helpers private func authenticate() throws { @@ -235,6 +268,7 @@ public final class Transmitter: BluetoothManagerDelegate { } // Update and notify + self.lastTimeMessage = timeMessage self.activationDate = activationDate self.delegate?.transmitter(self, didRead: Glucose(glucoseMessage: glucoseMessage, timeMessage: timeMessage, activationDate: activationDate)) @@ -251,34 +285,6 @@ public final class Transmitter: BluetoothManagerDelegate { } catch let error { throw TransmitterError.controlError("Error enabling notification: \(error)") } - - let timeData: Data - do { - timeData = try bluetoothManager.waitForCharacteristicValueUpdate(.Control, expectingFirstByte: TransmitterTimeRxMessage.opcode) - } catch let error { - throw TransmitterError.controlError("Error waiting for time response: \(error)") - } - - guard let timeMessage = TransmitterTimeRxMessage(data: timeData) else { - throw TransmitterError.controlError("Unable to parse time response: \(timeData)") - } - - let activationDate = Date(timeIntervalSinceNow: -TimeInterval(timeMessage.currentTime)) - - let glucoseData: Data - do { - glucoseData = try bluetoothManager.waitForCharacteristicValueUpdate(.Control, expectingFirstByte: GlucoseRxMessage.opcode) - } catch let error { - throw TransmitterError.controlError("Error waiting for glucose response: \(error)") - } - - guard let glucoseMessage = GlucoseRxMessage(data: glucoseData) else { - throw TransmitterError.controlError("Unable to parse glucose response: \(glucoseData)") - } - - // Update and notify - self.activationDate = activationDate - self.delegate?.transmitter(self, didRead: Glucose(glucoseMessage: glucoseMessage, timeMessage: timeMessage, activationDate: activationDate)) } private var cryptKey: Data? { diff --git a/xDripG5Tests/CalibrationDataRxMessageTests.swift b/xDripG5Tests/CalibrationDataRxMessageTests.swift new file mode 100644 index 00000000..5125bd7b --- /dev/null +++ b/xDripG5Tests/CalibrationDataRxMessageTests.swift @@ -0,0 +1,30 @@ +// +// CalibrationDataRxMessageTests.swift +// xDripG5 +// +// Created by Nate Racklyeft on 9/18/16. +// Copyright © 2016 Nathan Racklyeft. All rights reserved. +// + +import XCTest +@testable import xDripG5 + + +class CalibrationDataRxMessageTests: XCTestCase { + + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testMessage() { + let data = Data(hexadecimalString: "33002b290090012900ae00800050e929001225")! + XCTAssertNotNil(CalibrationDataRxMessage(data: data)) + } + +} diff --git a/xDripG5Tests/Info.plist b/xDripG5Tests/Info.plist index f05ffa14..ab895996 100644 --- a/xDripG5Tests/Info.plist +++ b/xDripG5Tests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 0.7.0 + 0.8.0 CFBundleSignature ???? CFBundleVersion diff --git a/xDripG5Tests/TransmitterVersionRxMessageTests.swift b/xDripG5Tests/TransmitterVersionRxMessageTests.swift new file mode 100644 index 00000000..d4f40f72 --- /dev/null +++ b/xDripG5Tests/TransmitterVersionRxMessageTests.swift @@ -0,0 +1,22 @@ +// +// TransmitterVersionRxMessageTests.swift +// xDripG5 +// +// Created by Nate Racklyeft on 9/29/16. +// Copyright © 2016 Nathan Racklyeft. All rights reserved. +// + +import XCTest +@testable import xDripG5 + +class TransmitterVersionRxMessageTests: XCTestCase { + + func testRxMessage() { + let data = Data(hexadecimalString: "4b0001000011df2900005100037000f00009b6")! + let message = TransmitterVersionRxMessage(data: data)! + + XCTAssertEqual(0, message.status) + XCTAssertEqual([1, 0, 0, 17], message.firmwareVersion) + } + +}