[
  {
    "path": "LICENSE.md",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright {yyyy} {name of copyright owner}\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "LibreMonitor/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 14.10.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport UIKit\nimport CoreBluetooth\nimport UserNotifications\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDelegate {\n\n    var window: UIWindow?\n    var coreDataStack = CoreDataStack()\n\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {\n     \n        \n        // Allow local notifications for iOS 10\n        let center = UNUserNotificationCenter.current()\n        let options: UNAuthorizationOptions = [.alert, .badge, .sound]\n        center.requestAuthorization(options: options) { (granted, error) in\n            if granted {\n//                application.registerForRemoteNotifications()\n            }\n        }\n        \n        // Do not show a badge icon value unless data has been received\n        UIApplication.shared.applicationIconBadgeNumber = 0 // hide badge number\n   \n        \n        // Override point for customization after application launch.\n//        let splitViewController = self.window!.rootViewController as! UISplitViewController\n//        let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UINavigationController\n//        navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem\n//        splitViewController.delegate = self\n//\n//        let masterNavigationController = splitViewController.viewControllers[0] as! UINavigationController\n//        let controller = masterNavigationController.topViewController as! MasterViewController\n//        controller.managedObjectContext = self.persistentContainer.viewContext\n        \n        print(\"In didFinishLaunchingWithOptions\")\n        \n        let tabBarController = self.window?.rootViewController as! UITabBarController\n        \n        if let childViewControllers = tabBarController.viewControllers {\n            \n            for childViewController in childViewControllers where childViewController is UINavigationController {\n                let navigationController = childViewController as! UINavigationController\n                let bloodSugarTableViewController = navigationController.topViewController as! BloodSugarTableViewController\n                \n                // Set core data stack in view controller\n                bloodSugarTableViewController.coreDataStack = coreDataStack\n            }\n        }\n        \n        return true\n    }\n\n    func applicationWillResignActive(_ application: UIApplication) {\n        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.\n        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.\n        print(\"In applicationWillResignActive\")\n    }\n\n    func applicationDidEnterBackground(_ application: UIApplication) {\n        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.\n        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.\n        print(\"In applicationDidEnterBackground\")\n    }\n\n    func applicationWillEnterForeground(_ application: UIApplication) {\n        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.\n        print(\"In applicationWillEnterForeground\")\n    }\n\n    func applicationDidBecomeActive(_ application: UIApplication) {\n        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.\n        print(\"In applicationDidBecomeActive\")\n    }\n\n    func applicationWillTerminate(_ application: UIApplication) {\n        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.\n        // Saves changes in the application's managed object context before the application terminates.\n        print(\"In applicationWillTerminate\")\n        //        self.saveContext()\n        coreDataStack.saveContext()\n    }\n\n//    // MARK: - Split view\n//\n//    func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool {\n//        guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false }\n//        guard let topAsDetailController = secondaryAsNavController.topViewController as? DetailViewController else { return false }\n//        if topAsDetailController.detailItem == nil {\n//            // Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.\n//            return true\n//        }\n//        return false\n//    }\n//    // MARK: - Core Data stack\n//\n//    lazy var persistentContainer: NSPersistentContainer = {\n//        /*\n//         The persistent container for the application. This implementation\n//         creates and returns a container, having loaded the store for the\n//         application to it. This property is optional since there are legitimate\n//         error conditions that could cause the creation of the store to fail.\n//        */\n//        let container = NSPersistentContainer(name: \"LibreMonitor\")\n//        container.loadPersistentStores(completionHandler: { (storeDescription, error) in\n//            if let error = error as NSError? {\n//                // Replace this implementation with code to handle the error appropriately.\n//                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.\n//                 \n//                /*\n//                 Typical reasons for an error here include:\n//                 * The parent directory does not exist, cannot be created, or disallows writing.\n//                 * The persistent store is not accessible, due to permissions or data protection when the device is locked.\n//                 * The device is out of space.\n//                 * The store could not be migrated to the current model version.\n//                 Check the error message to determine what the actual problem was.\n//                 */\n//                fatalError(\"Unresolved error \\(error), \\(error.userInfo)\")\n//            }\n//        })\n//        return container\n//    }()\n//\n//    // MARK: - Core Data Saving support\n//\n//    func saveContext () {\n//        let context = persistentContainer.viewContext\n//        if context.hasChanges {\n//            do {\n//                try context.save()\n//            } catch {\n//                // Replace this implementation with code to handle the error appropriately.\n//                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.\n//                let nserror = error as NSError\n//                fatalError(\"Unresolved error \\(nserror), \\(nserror.userInfo)\")\n//            }\n//        }\n//    }\n\n}\n\n"
  },
  {
    "path": "LibreMonitor/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"83.5x83.5\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "LibreMonitor/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11134\" systemVersion=\"15F34\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"11106\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Llm-lL-Icb\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xb3-aO-Qok\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "LibreMonitor/BloodGlucose+CoreDataClass.swift",
    "content": "//\n//  BloodGlucose+CoreDataClass.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 14.10.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\nimport CoreData\n\n\npublic class BloodGlucose: NSManagedObject {\n\n}\n"
  },
  {
    "path": "LibreMonitor/BloodGlucose+CoreDataProperties.swift",
    "content": "//\n//  BloodGlucose+CoreDataProperties.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 14.10.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\nimport CoreData \n\nextension BloodGlucose {\n\n    @nonobjc public class func fetchRequest() -> NSFetchRequest<BloodGlucose> {\n        return NSFetchRequest<BloodGlucose>(entityName: \"BloodGlucose\");\n    }\n\n    @NSManaged public var bytes: String?\n    @NSManaged public var date: NSDate?\n    @NSManaged public var dateString: String?\n    @NSManaged public var id: Int32\n    @NSManaged public var type: Int16\n    @NSManaged public var value: Double\n    @NSManaged public var sensor: Sensor?\n\n}\n"
  },
  {
    "path": "LibreMonitor/Bluetooth/Data_types+Extensions.swift",
    "content": "//\n//  Data_types+Extensions.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 15.05.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\n\nextension IDNDataType {\n    \n    func deviceIDString() -> String {\n        \n        var _self = self  // make a copy of self to be able to access it via a pointer (does not work on self itself)\n        \n        // Extrakt device ID by creating an array from the tuple\n        \n        let deviceIDString = withUnsafePointer(to: &_self.deviceID, { (ptr) -> String? in\n            \n            let uint8Ptr = unsafeBitCast(ptr, to: UnsafePointer<UInt8>.self)\n            \n            var deviceIDString: String = String(format: \"%02X\", arguments: [uint8Ptr[0]])\n            for index in 1...12 {\n                deviceIDString += String(format: \":%02X\", arguments: [uint8Ptr[index]])\n            }\n            return deviceIDString\n        })\n        \n        print(deviceIDString!)\n        \n        return deviceIDString ?? \"no device id\"\n    }\n}\n\n\nextension SystemInformationDataType {\n    \n    func uidString() -> String {\n        \n        var _self = self  // make a copy of self to be able to access it via a pointer (does not work on self itself)\n        \n        // Extrakt UID by creating an array from the tuple\n        \n        let uidString = withUnsafePointer(to: &_self.uid, { (ptr) -> String? in\n            \n            let uint8Ptr = unsafeBitCast(ptr, to: UnsafePointer<UInt8>.self)\n            \n            var uidString: String = String(format: \"%02X\", arguments: [uint8Ptr[0]])\n            for index in 1...7 {\n                uidString += String(format: \"%02X\", arguments: [uint8Ptr[index]])\n//                uidString += String(format: \":%02X\", arguments: [uint8Ptr[index]])\n            }\n            return uidString\n        })\n        \n        print(uidString!)\n        \n        return uidString ?? \"no uid\"\n    }\n}\n\n\n//extension RawDataType {\n//    func byteString() -> String {\n//        \n//        var _self = self  // make a copy of self to be able to access it via a pointer (does not work on self itself)\n//        \n//        // Extrakt UID by creating an array from the tuple\n//        \n//        let byteString = withUnsafePointer(&_self.bytes, { (ptr) -> String? in\n//            \n//            let uint8Ptr = unsafeBitCast(ptr, UnsafePointer<UInt8>.self)\n//            \n//            var byteString: String = String(format: \"%02X\", arguments: [uint8Ptr[0]])\n//            for index in 1...5 {\n//                byteString += String(format: \"%02X\", arguments: [uint8Ptr[index]])\n//                //                uidString += String(format: \":%02X\", arguments: [uint8Ptr[index]])\n//            }\n//            return byteString\n//        })\n//        \n//        print(byteString!)\n//        \n//        return byteString ?? \"no bytes\"\n//    }\n//}\n\n"
  },
  {
    "path": "LibreMonitor/Bluetooth/NSData+CRC8.h",
    "content": "//\n//  NSData+CRC8.h\n//  Bluetooth LE Test\n//\n//  Created by Chas Conway on 12/11/13.\n//  Copyright (c) 2013 Chas Conway. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@interface NSData (CRC8)\n\n- (signed char)CRC8Checksum;\n\n//+ (signed char)CRC8ChecksumFromBuffer:(signed char *)dataBuffer bytesToRead:(signed char)bytesToRead;\n+ (signed char)CRC8ChecksumFromBuffer:(signed char *)dataBuffer bytesToRead:(uint16_t)bytesToRead; // changed to uint16_t by Uwi on 2016-12-26\n\n@end\n"
  },
  {
    "path": "LibreMonitor/Bluetooth/NSData+CRC8.m",
    "content": "//\n//  NSData+CRC8.m\n//  Bluetooth LE Test\n//\n//  Created by Chas Conway on 12/11/13.\n//  Copyright (c) 2013 Chas Conway. All rights reserved.\n//\n\n#import \"NSData+CRC8.h\"\n\n#define CRC8INIT  0x00\n#define CRC8POLY  0x18              //0X18 = X^8+X^5+X^4+X^0\n\n@implementation NSData (CRC8)\n\n- (signed char)CRC8Checksum {\n\t\n\tsigned char *buffer = malloc(self.length);\n\t[self getBytes:buffer length:self.length];\n\treturn [NSData CRC8ChecksumFromBuffer:buffer bytesToRead:self.length];\n}\n\n//+ (signed char)CRC8ChecksumFromBuffer:(signed char *)dataBuffer bytesToRead:(signed char)bytesToRead {\n+ (signed char)CRC8ChecksumFromBuffer:(signed char *)dataBuffer bytesToRead:(uint16_t)bytesToRead {  // changed to uint16_t by Uwi on 2016-12-26\n\t\n    signed char  crc;\n    uint16_t loop_count;\n    signed char  bit_counter;\n    signed char  data;\n    signed char  feedback_bit;\n    \n    crc = CRC8INIT;\n    \n    for (loop_count = 0; loop_count != bytesToRead; loop_count++)\n    {\n        data = dataBuffer[loop_count];\n        \n        bit_counter = 8;\n        do {\n            feedback_bit = (crc ^ data) & 0x01;\n            \n            if ( feedback_bit == 0x01 ) {\n                crc = crc ^ CRC8POLY;\n            }\n            crc = (crc >> 1) & 0x7F;\n            if ( feedback_bit == 0x01 ) {\n                crc = crc | 0x80;\n            }\n            \n            data = data >> 1;\n            bit_counter--;\n            \n        } while (bit_counter > 0);\n    }\n    \n    return crc;\n}\n\n@end\n"
  },
  {
    "path": "LibreMonitor/Bluetooth/NSData+SLIP.h",
    "content": "//\n//  NSData+SLIP.h\n//  Arduino Greenhouse\n//\n//  Created by Chas Conway on 5/23/14.\n//  Copyright (c) 2014 Chas Conway. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@interface NSData (SLIP)\n\n- (NSIndexSet *)indexesOfEndBytes;\n- (NSData *)unescapedData;\n\n- (BOOL)beginsWithEndByte;\n- (BOOL)endsWithEndByte;\n\n@end\n"
  },
  {
    "path": "LibreMonitor/Bluetooth/NSData+SLIP.m",
    "content": "//\n//  NSData+SLIP.m\n//  Arduino Greenhouse\n//\n//  Created by Chas Conway on 5/23/14.\n//  Copyright (c) 2014 Chas Conway. All rights reserved.\n//\n//  Modified by Uwe Petersen\n\n#import \"NSData+SLIP.h\"\n\n// Serial Line IP (SLIP) escaping constants\n#define ESCAPE_BYTE 0xDB\n#define END_BYTE    0xC0\n#define ESCAPED_ESCAPE_BYTE 0xDD\n#define ESCAPED_END_BYTE    0xDC\nconst uint8_t escapeSequence[1] = {ESCAPE_BYTE};\nconst uint8_t endSequence[1] = {END_BYTE};\nconst uint8_t escapedEndSequence[2] = {ESCAPE_BYTE, ESCAPED_END_BYTE};\nconst uint8_t escapedEscapeSequence[2] = {ESCAPE_BYTE, ESCAPED_ESCAPE_BYTE};\n\n@implementation NSData (SLIP)\n\n- (NSIndexSet *)indexesOfEndBytes {\n\t\n\t__block NSMutableIndexSet *endByteIndices = [NSMutableIndexSet new];\n\t\n\t[self enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {\n\t\t\n\t\tfor (NSInteger i = byteRange.location; i < (byteRange.location + byteRange.length); i++) {  // For each byte in the range\n\t\t\t\n\t\t\tuint8_t aByte = *((uint8_t *)bytes + i);\n\t\t\tif (aByte == END_BYTE) [endByteIndices addIndex:i];\n\t\t}\n\t}];\n\t\n\treturn endByteIndices;\n}\n\n- (NSData *)unescapedData {\n\t\n\tNSMutableData *outputData = [[NSMutableData alloc] initWithData:self];\n\n\tBOOL done = NO;\n    NSUInteger notYetUnescaped = 0; // 2016-06-30, Uwe Petersen:\n\twhile (!done) {  // Search for escaped END bytes\n\t\n        // 2016-06-30, Uwe Petersen:\n        NSRange resultRange = [outputData rangeOfData:[NSData dataWithBytes:escapedEndSequence length:2] options:0 range:NSMakeRange(notYetUnescaped, outputData.length - notYetUnescaped)];\n//        NSRange resultRange = [outputData rangeOfData:[NSData dataWithBytes:escapedEndSequence length:2] options:0 range:NSMakeRange(0, outputData.length)];\n\t\tif (resultRange.location != NSNotFound) {  // Found an occurance\n\t\t\t\n\t\t\t// Replace that escaped occurance with the unescaped value\n\t\t\t[outputData replaceBytesInRange:resultRange withBytes:endSequence length:1];\n            notYetUnescaped = resultRange.location + 1; // 2016-06-30, Uwe Petersen\n\t\t\n\t\t} else {  // Didn't find any more occurances, so exit while loop\n\t\t\t\n\t\t\tdone = YES;\n\t\t}\n\t}\n\t\n\tdone = NO;\n    notYetUnescaped = 0; // 2016-06-30, Uwe Petersen\n\twhile (!done) {  // Search for escaped ESCAPE bytes\n\t\t\n        // 2016-06-30, Uwe Petersen:\n        NSRange resultRange = [outputData rangeOfData:[NSData dataWithBytes:escapedEscapeSequence length:2] options:0 range:NSMakeRange(notYetUnescaped, outputData.length - notYetUnescaped)];\n//        NSRange resultRange = [outputData rangeOfData:[NSData dataWithBytes:escapedEscapeSequence length:2] options:0 range:NSMakeRange(0, outputData.length)];\n\t\tif (resultRange.location != NSNotFound) {  // Found an occurance\n\t\t\t\n\t\t\t// Replace that escaped occurance with the unescaped value\n\t\t\t[outputData replaceBytesInRange:resultRange withBytes:escapeSequence length:1];\n            notYetUnescaped = resultRange.location + 1; // 2016-06-30, Uwe Petersen\n\n\t\t\t\n\t\t} else {  // Didn't find any more occurances, so exit while loop\n\t\t\t\n\t\t\tdone = YES;\n\t\t}\n\t}\n\t\n\treturn [NSData dataWithData:outputData];\n}\n\n- (BOOL)beginsWithEndByte {\n\t\n\tNSIndexSet *endByteIndices = [self indexesOfEndBytes];\n\treturn [endByteIndices containsIndex:0];\n}\n\n- (BOOL)endsWithEndByte {\n\t\n\tNSIndexSet *endByteIndices = [self indexesOfEndBytes];\n\treturn [endByteIndices containsIndex:(self.length - 1)];\n}\n\n@end\n"
  },
  {
    "path": "LibreMonitor/Bluetooth/SLIPBuffer.swift",
    "content": "//\n//  SLIPBuffer.swift\n//  UBA-Demo\n//\n//  Created by Chas Conway on 2/4/15.\n//  Copyright (c) 2015 Chas Conway. All rights reserved.\n//\n//  Modified by Uwe Petersen\n\nimport Foundation\n\nlet PacketIdentifierLength = MemoryLayout<UInt16>.size\nlet PacketFlagsLength = MemoryLayout<UInt8>.size\nlet PacketChecksumLength = MemoryLayout<UInt8>.size\n\nprotocol SLIPBufferDelegate {\n\t\n\tfunc slipBufferReceivedPayload(_ payloadData: Data, payloadIdentifier: UInt16, txFlags: UInt8)\n}\n\n\nclass SLIPBuffer {\n\n    var rxBuffer = Data()\n\tvar delegate:SLIPBufferDelegate?\n\t\n\t/// Appends more escaped bytes (i.e. data that were received via bluetooth) to the buffer and scans the buffer for complete frames according to the Serial Line Internet Protocol (SLIP). If a complete frame is detected, its payload data is extracted and a delegate method is called.\n\t///\n    /// The bytes that are appended are escaped bytes according to the serial line internet protocol (SLIP). SLIP works as follows:\n    /// - A transmission packet (the payload data) is appended by a special \"END\" byte, which distinguishes the datagram boundaries in the byte stream.\n    /// - If the END byte occurs in the payload data to be sent, the two byte sequence [ESC, ESC_END] is sent instead.\n    /// - If the ESC byte occurs in the payload data to be sent, the two byte sequence [ESC, ESC_ESC] is sent instead.\n    /// - Variants of the protocol may also begin transmission packets (the payload data) with an END byte (which is the case in this realization of SLIP)\n    ///\n    /// The special bytes used by SLIP are:\n    /// - 0xC0 ... END     -> Frame End (and Frame Beginning in this realization)\n    /// - 0xDB ... ESC     -> Frame Escape\n    /// - 0xDC ... ESC_END -> Transposed Frame END\n    /// - 0xDD ... ESC_ESC -> Transposed Frame ESC\n    ///\n    /// Reference: https://en.m.wikipedia.org/wiki/Serial_Line_Internet_Protocol\n    ///\n\t/// - parameter escapedData: data with escape bytes to be appended to the buffer\n\tfunc appendEscapedBytes(_ escapedData: Data) {\n\t\t\n\t\trxBuffer.append(escapedData)\n\t\tscanRxBufferForFrames()\n\t}\n\t\n\t\n    /// Scans the buffer for complete frames according to the Serial Line Internet Protocol (SLIP). If a complete frame is detected, the crc is checked and the payload extracted and a delegate method called. \n    ///\n    /// Extracting the payload means the following steps: \n    /// - Extract the payload from the SLIP frame:\n    ///   - Remove the END byte at the beginning and at the end of the frame.\n    ///   - If the original payload data had contained the special bytes END (0xC0) or ESC (0xDB) they where replaced by the special byte sequences [END, ESC_END] ([0xC0, 0xDC]) and [ESC, ESC_ESC] ([0xDB, 0xDD]) because of the SLIP and this has to be reversed. \n    /// - Check CRC and remove the rcr bytes:\n    ///   - The datagram is appended with one byte containting a CRC8, calculated over the original payload data. This CRC8 is compared with the corresponding CRC8 of the payload data.\n    /// - If the CRCs are equal, a delegate method is called with the payload data (with the one appended CRC byte removed).\n    ///\n    /// The serial line internet protocol (SLIP) works as follows:\n    /// - A transmission packet (the payload data) is appended by a special \"END\" byte, which distinguishes the datagram boundaries in the byte stream.\n    /// - If the END byte occurs in the payload data to be sent, the two byte sequence [ESC, ESC_END] is sent instead.\n    /// - If the ESC byte occurs in the payload data to be sent, the two byte sequence [ESC, ESC_ESC] is sent instead.\n    /// - Variants of the protocol may also begin transmission packets (the payload data) with an END byte (which is the case in this realization of SLIP)\n    ///\n    /// The special bytes used by SLIP are:\n    /// - 0xC0 ... END     -> Frame End (and Frame Beginning in this realization)\n    /// - 0xDB ... ESC     -> Frame Escape\n    /// - 0xDC ... ESC_END -> Transposed Frame END\n    /// - 0xDD ... ESC_ESC -> Transposed Frame ESC\n    ///\n    /// Reference: https://en.m.wikipedia.org/wiki/Serial_Line_Internet_Protocol\n    ///\n    func scanRxBufferForFrames() {\n        \n        // get indices of all END bytes\n        // TODO: idexesOfEndBytes is an Objective-C-extension of NSData. Reprogram this in Swift for data type \"Data\"\n        guard let endByteIndices = NSData.init(data: rxBuffer).indexesOfEndBytes() else {\n            return\n        }\n\n        // Loop over the END bytes and search for a complete frame, i.e. a sequence of bytes as follows: [END ... at-least-two-bytes ... END]\n\t\tvar previousEndByteIndex = NSNotFound\n        for endByteIndex in endByteIndices {\n            \n            print(String(endByteIndex.description) as Any)\n            \n            if (previousEndByteIndex != NSNotFound) {\n                \n                if endByteIndex - previousEndByteIndex > 2 {  // Contains at least one byte and checksum byte\n                    \n                    print(\"Identified a potential SLIP frame\")\n                    \n                    print(self.rxBuffer.debugDescription)\n                    \n                    // Extact the frame (END byte at beginning and end are aleady removed)\n                    let escapedPacket = self.rxBuffer.subdata(in: Range((previousEndByteIndex + 1)..<endByteIndex))\n                    \n                    // Decode the packet (undo SLIP)\n                    self.decodeSLIPPacket(escapedPacket)\n                    \n                } else {\n                    \n                    print(\"Ignoring improbable SLIP frame\")\n                }\n            }\n            previousEndByteIndex = endByteIndex\n        }\n    \n\t\t// Remove byte in buffer up to, but not including, the previous END byte, i.e. cut of everything before the beginning of the frame.\n\t\tif previousEndByteIndex != NSNotFound {\n            rxBuffer.removeSubrange(0..<previousEndByteIndex)\n        }\n    }\n\t\n\t/// Decode the escape packet.\n\t///\n    /// Decoding means that the ESC and END bytes that have been added to the packet to transfer it according to the slip (serial line internet protocol) are now removed from the escapedPacket. After that the delegate is called with the resulting unescaped packet.\n    ///\n\t/// - parameter escapedPacket: packet that still contains ESC and END bytes (as they were needed for the serial line internet protocol)\n\tfunc decodeSLIPPacket(_ escapedPacket:Data) {\n\t\t\n\t\t// Remove SLIP escaping\n        guard let unescapedPacket = (escapedPacket as NSData).unescaped() else {\n            return\n        }\n\t\t\n\t\t// Extract embedded checksum from packet\n        var embeddedChecksumByte:UInt8 = 0\n        unescapedPacket.copyBytes(to: &embeddedChecksumByte, from: Range((unescapedPacket.count - PacketChecksumLength)..<unescapedPacket.count))\n        \n        \n        // 2016-07-30, Uwe Petersen: get unescaped packet without checksum\n        let unescapedPacketWithoutChecksum = unescapedPacket.subdata(in: Range(0..<(unescapedPacket.count-PacketChecksumLength)))\n\t\t\n        // Calculate checksum on payload bytes (2016-06-30, Uwe Petersen: seems to be an error to calculate on unescaped packet. Changed to escaped packet)\n        let checksummedData = escapedPacket.subdata(in: Range(0..<escapedPacket.count - PacketChecksumLength))\n        let calculatedChecksum = (checksummedData as NSData).crc8Checksum()\n        \n        if UInt8(bitPattern: calculatedChecksum) == embeddedChecksumByte { // crc is calulated as Int8 and thus has to be converted to UInt8\n\t\t\t\n\t\t\tif let aDelegate = delegate {\n\t\t\t\t\n\t\t\t\t// Extract payload and payload ID. (2016-06-30, Uwe Petersen: seems to be an error to calculate on unescaped packet. Changed to escaped packet)\n\t\t\t\tvar identifier: UInt16 = 0;\n                let _ = unescapedPacketWithoutChecksum.copyBytes(to: UnsafeMutableBufferPointer(start: &identifier, count: 1), from: Range(0..<PacketIdentifierLength))\n\t\t\t\t\n                \n                // 2016-06-30, Uwe Petersen: seems to be an error to calculate on unescaped packet. Changed to escaped packet\n                var txFlags: UInt8 = 0;\n                unescapedPacketWithoutChecksum.copyBytes(to: &txFlags, from: Range((PacketIdentifierLength-1)..<(PacketIdentifierLength-1+PacketFlagsLength)))\n                \n                let payloadData = unescapedPacketWithoutChecksum.subdata(in: Range( (PacketIdentifierLength + PacketFlagsLength)..<unescapedPacketWithoutChecksum.count ))\n\t\t\t\t\n\t\t\t\t// Notify delegate with payloadData \n\t\t\t\taDelegate.slipBufferReceivedPayload(payloadData, payloadIdentifier: identifier, txFlags: txFlags)\n\t\t\t}\n\t\t\t\n\t\t} else {\n\n            print(\"SLIP frame failed checksum\")\n        }\n\t}\n}\n"
  },
  {
    "path": "LibreMonitor/Bluetooth/SimbleeManager.swift",
    "content": "//\n//  SimbleeManager.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 23.04.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n//  How does the Simblee work?\n//\n//    1.) Services\n///       The Simblee has only one service. By convention the service UUID is set to \"2220\" (this \n//        could be changed in the arduino code any time):\n//\n//        Service:\n//        \"<CBService: 0x14c72a810, isPrimary = YES, UUID = 2220>\"\n//\n//    2.) Characteristics\n//        Simble provides three Characteristics: one read and two write characteristics. This is\n//        a \"hard coded\" feature of the simblee and cannot be changed. The debugDescription \n//        of these three characteristics is as follows:\n//\n//        a) Read Characteristic:\n//               \"<CBCharacteristic: 0x14c7664e0, UUID = 2221, properties = 0x12, value = (null), notifying = NO>\"\n//           ... with properties:\n//              __C.CBCharacteristicProperties(rawValue: 18)\n//              Broadcast:                            [false]\n//              Read:                                 [true]\n//              WriteWithoutResponse:                 [false]\n//              Write:                                [false]\n//              Notify:                               [true]\n//              Indicate:                             [false]\n//              AuthenticatedSignedWrites:            [false]\n//              ExtendedProperties:                   [false]\n//              NotifyEncryptionRequired:             [false]\n//              BroaIndicateEncryptionRequireddcast:  [false]\n//\n//        b) First Write Characteristic:\n//              \"<CBCharacteristic: 0x14c766620, UUID = 2222, properties = 0xC, value = (null), notifying = NO>\"\n//           ... with properties:\n//              __C.CBCharacteristicProperties(rawValue: 12)\n//              Broadcast:                            [false]\n//              Read:                                 [false]\n//              WriteWithoutResponse:                 [true]\n//              Write:                                [true]\n//              Notify:                               [false]\n//              Indicate:                             [false]\n//              AuthenticatedSignedWrites:            [false]\n//              ExtendedProperties:                   [false]\n//              NotifyEncryptionRequired:             [false]\n//              BroaIndicateEncryptionRequireddcast:  [false]\n//\n//        c) Second Write Characteristic:\n//              \"<CBCharacteristic: 0x14c766720, UUID = 2223, properties = 0xC, value = (null), notifying = NO>\"\n//           ... with properties:\n//              __C.CBCharacteristicProperties(rawValue: 12)\n//              Broadcast:                            [false]\n//              Read:                                 [false]\n//              WriteWithoutResponse:                 [true]\n//              Write:                                [true]\n//              Notify:                               [false]\n//              Indicate:                             [false]\n//              AuthenticatedSignedWrites:            [false]\n//              ExtendedProperties:                   [false]\n//              NotifyEncryptionRequired:             [false]\n//              BroaIndicateEncryptionRequireddcast:  [false]\n//\n//   3.) Further information on Simblee services and characteristics can be found on\n//       http://forum.rfduino.com/index.php?topic=1066.15\n//\n\nimport Foundation\nimport UIKit\nimport CoreBluetooth\n\n\npublic enum SimbleeManagerState: String {\n    case Unassigned = \"Unassigned\"\n    case Scanning = \"Scanning\"\n    case Disconnected = \"Disconnected\"\n    case DisconnectedManually = \"Disconnected manually\"\n    case Connecting = \"Connecting\"\n    case Connected = \"Connected\"\n    case Notifying = \"Notifying\"\n}\n\nprotocol SimbleeManagerDelegate {\n    func simbleeManagerPeripheralStateChanged(_ state:SimbleeManagerState)\n    func simbleeManagerReceivedMessage(_ messageIdentifier:UInt16, txFlags:UInt8, payloadData:Data)\n}\n\nclass SimbleeManager: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate, SLIPBufferDelegate {\n    \n    // MARK: - Properties\n    var centralManager: CBCentralManager!\n    var peripheral: CBPeripheral?\n    var slipBuffer = SLIPBuffer()\n    \n    fileprivate let serviceUUIDs:[CBUUID]? = [CBUUID(string: \"2220\")]\n    \n    var BLEScanDuration = 3.0\n    \n    var delegate: SimbleeManagerDelegate? {\n        didSet {\n            // Help delegate initialize by sending current state directly after delegate assignment\n            delegate?.simbleeManagerPeripheralStateChanged(state)\n        }\n    }\n    \n    var state: SimbleeManagerState = .Unassigned {\n        didSet {\n            // Help delegate initialize by sending current state directly after delegate assignment\n            delegate?.simbleeManagerPeripheralStateChanged(state)\n        }\n    }\n    \n    // MARK: - Mehods\n    \n    override init() {\n        super.init()\n        centralManager = CBCentralManager(delegate: self, queue: nil, options: nil)\n        slipBuffer.delegate = self\n    }\n    \n    func scanForSimblee() {\n        if centralManager.state == .poweredOn {\n            print (\"Start scanning for Simblee\")\n            centralManager.scanForPeripherals(withServices: serviceUUIDs, options: nil)\n            state = .Scanning\n        }\n    }\n    \n    func connect() {\n        if let peripheral = peripheral {\n            peripheral.delegate = self\n            centralManager.stopScan()\n            centralManager.connect(peripheral, options: nil)\n            state = .Connecting        }\n    }\n    \n    func disconnectManually() {\n        switch state {\n        case .Connected, .Connecting, .Notifying:\n            state = .DisconnectedManually  // to avoid reconnect in didDisconnetPeripheral\n            centralManager.cancelPeripheralConnection(peripheral!)\n        default:\n            break\n        }\n//        if state == .Connected || peripheral?.state == .Connecting {\n//            centralManager.cancelPeripheralConnection(peripheral!)\n//        }\n    }\n    \n    \n    // MARK: - CBCentralManagerDelegate\n    \n    func centralManagerDidUpdateState(_ central: CBCentralManager) {\n        print(\"centralManagerDidUpdateState\")\n        // TODO: maybe handle the case of bluetooth beeing switched of (and sometimes later) on again here by stopping and restarting scanning\n    }\n    \n    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {\n        print(\"didDiscoverPeripheral with name \\(peripheral.name)\")\n        \n        self.peripheral = peripheral\n        connect()\n    }\n    \n    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {\n        print(\"didConnectPeripheral\")\n        state = .Connected\n        // Discover all Services. This might be helpful if writing is needed some time\n        peripheral.discoverServices(nil)\n    }\n    \n    func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {\n        print(\"didFailToConnectPeripheral\")\n        state = .Disconnected\n    }\n    \n    func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {\n        print(\"didDisconnectPeripheral\")\n        switch state {\n        case .DisconnectedManually:\n            state = .Disconnected\n        default:\n            state = .Disconnected\n            scanForSimblee()\n        }\n        // Keep this code in case you want it some later time: it is used for reconnection only in background mode\n//        state = .Disconnected\n//        // Start scanning, if disconnection occurred in background mode\n//        if UIApplication.sharedApplication().applicationState == .Background ||\n//            UIApplication.sharedApplication().applicationState == .Inactive {\n//            scanForSimblee()\n//        }\n    }\n    \n    \n    // MARK: - CBPeripheralDelegate\n    \n    \n    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {\n    \n        print(\"didDiscoverServices\")\n        if let services = peripheral.services {\n            print(\"Discovered services on RFduino\");\n            for service in services {\n                peripheral.discoverCharacteristics(nil, for: service)\n//                print(\"Service: \")\n//                debugPrint(service.debugDescription)\n            }\n        }\n    }\n    \n    \n    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {\n\n        print(\"didDiscoverCharacteristicsForService\");\n        if let error = error {\n            print(\"An error occured: \\(error.localizedDescription)\")\n        }\n\n        if let characteristics = service.characteristics {\n            for characteristic in characteristics {\n//                print(\"Characteristic: \")\n//                debugPrint(characteristic.debugDescription)\n//                print(\"... with properties: \")\n//                debugPrint(characteristic.properties)\n//                print(\"Broadcast:                           \", [characteristic.properties.contains(.Broadcast)])\n//                print(\"Read:                                \", [characteristic.properties.contains(.Read)])\n//                print(\"WriteWithoutResponse:                \", [characteristic.properties.contains(.WriteWithoutResponse)])\n//                print(\"Write:                               \", [characteristic.properties.contains(.Write)])\n//                print(\"Notify:                              \", [characteristic.properties.contains(.Notify)])\n//                print(\"Indicate:                            \", [characteristic.properties.contains(.Indicate)])\n//                print(\"AuthenticatedSignedWrites:           \", [characteristic.properties.contains(.AuthenticatedSignedWrites )])\n//                print(\"ExtendedProperties:                  \", [characteristic.properties.contains(.ExtendedProperties)])\n//                print(\"NotifyEncryptionRequired:            \", [characteristic.properties.contains(.NotifyEncryptionRequired)])\n//                print(\"BroaIndicateEncryptionRequireddcast: \", [characteristic.properties.contains(.IndicateEncryptionRequired)])\n                \n                // Choose the notifiying characteristic and Register to be notified whenever the simblee transmits\n                if (characteristic.properties.intersection(.notify)) == .notify {\n                    peripheral.setNotifyValue(true, for: characteristic)\n                }\n            }\n        } else {\n            print(\"Discovered characteristics on RFduino, but no characteristics listed. There must be some error.\");\n        }\n    }\n\n    \n    func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {\n        print(\"didUpdateNotificationStateForCharacteristic\")\n        if let error = error {\n            print(\"An error occured: \\(error.localizedDescription)\")\n        }\n        state = .Notifying\n    }\n    \n    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {\n        print(\"didUpdateValueForCharacteristic\")\n        if let error = error {\n            print(\"Characteristic update error = \\(error.localizedDescription)\")\n        } else {\n            if let value = characteristic.value {\n                slipBuffer.appendEscapedBytes(value)\n            }\n        }\n    }\n    \n    \n    // MARK: - SLIPBufferDelegate\n    \n    \n    func slipBufferReceivedPayload(_ payloadData: Data, payloadIdentifier: UInt16, txFlags: UInt8) {\n        \n        // Inform delegate\n        if let delegate = delegate {\n            delegate.simbleeManagerReceivedMessage(payloadIdentifier, txFlags: txFlags, payloadData: payloadData)\n        }\n    }\n    \n\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "LibreMonitor/Bluetooth/constants.h",
    "content": "// Define unique identifiers for each data packet here. This identifier is transfered together with the data and can be used in the corresponding iOS app to identify a packet, even if there are packets of the same type\n\n#define ALL_BYTES 0x1007   //\n#define IDN_DATA 0x2001    //\n#define SYSTEM_INFORMATION_DATA 0x2002  //\n#define BATTERY_DATA 0x2005     //\n\n"
  },
  {
    "path": "LibreMonitor/Bluetooth/data_types.h",
    "content": "// Data types for data to be transfered\n// Need a struct with one variable and the packed attribute to make this an array in swift (in a simple way\n\n\n// Battery\ntypedef struct  __attribute__((packed)) {\n    float voltage;\n    float temperature;\n} BatteryDataType;\n\n\n/// System information command response\n/// @detail Contains the relevant information received with the system information command is already distributed into the follwing parameters. See the BM019 manual and the CR95HF manual for information on the the codes and flag meanings\n/// @param resultCode 0x80 if no error\n/// @param responseFlags\n/// @param infoFlags bit 0 is set to 1 in case of error\n/// @param errorCode error code\n/// @param uid 8 bytes containing the uid, order already reversed, e.g. (colons only inserted for readability): E0:07:A0:00:00:0C:48:BD. All zeros in case of an error.\ntypedef struct  __attribute__((packed)) {\n    uint8_t uid[8];\n    uint8_t resultCode;\n    uint8_t responseFlags;\n    uint8_t infoFlags;\n    uint8_t errorCode;\n} SystemInformationDataType;\n\n\n/// IDN command response, which is the device ID\n/// @detail Contains the relevant information received with the IDN command is already distributed into the follwing parameters. See the BM019 manual and the CR95HF manual for information on the the codes and flag meanings\n/// @param resultCode 0x00 if no error\n/// @param deiceID 13 bytes containing the device ID.\ntypedef struct  __attribute__((packed)) {\n    uint8_t resultCode;\n    uint8_t deviceID[13];\n    uint8_t romCRC[2];\n} IDNDataType;\n\n\n/// The first 344 bytes of data as read from FRAM of the Freestyle Libre Sensor\n/// @detail Contains 24 byes of header, 296 bytes of body with blood sugar data\n/// and 24 bytes of footer\n/// @param bytes 344 bytes containing the the raw data\ntypedef struct  __attribute__((packed)) {\n    uint8_t allBytes[344];\n} AllBytesDataType;\n\n"
  },
  {
    "path": "LibreMonitor/HeaderData+CoreDataClass.swift",
    "content": "//\n//  HeaderData+CoreDataClass.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 14.10.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\nimport CoreData\n\n@objc(HeaderData)\npublic class HeaderData: NSManagedObject {\n\n}\n"
  },
  {
    "path": "LibreMonitor/HeaderData+CoreDataProperties.swift",
    "content": "//\n//  HeaderData+CoreDataProperties.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 14.10.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\nimport CoreData\n\n\nextension HeaderData {\n\n    @nonobjc public class func fetchRequest() -> NSFetchRequest<HeaderData> {\n        return NSFetchRequest<HeaderData>(entityName: \"HeaderData\");\n    }\n\n    @NSManaged public var bytes: String?\n    @NSManaged public var date: NSDate?\n\n}\n"
  },
  {
    "path": "LibreMonitor/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UIBackgroundModes</key>\n\t<array>\n\t\t<string>bluetooth-central</string>\n\t</array>\n\t<key>UIFileSharingEnabled</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t\t<string>healthkit</string>\n\t</array>\n\t<key>UIStatusBarTintParameters</key>\n\t<dict>\n\t\t<key>UINavigationBar</key>\n\t\t<dict>\n\t\t\t<key>Style</key>\n\t\t\t<string>UIBarStyleDefault</string>\n\t\t\t<key>Translucent</key>\n\t\t\t<false/>\n\t\t</dict>\n\t</dict>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "LibreMonitor/LibreMonitor-Bridging-Header.h",
    "content": "//\n//  Use this file to import your target's public headers that you would like to expose to Swift.\n//\n#import \"NSData+CRC8.h\"\n#import \"NSData+SLIP.h\"\n#import \"constants.h\"\n#import \"data_types.h\"\n\n"
  },
  {
    "path": "LibreMonitor/LibreMonitor.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.developer.healthkit</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "LibreMonitor/LibreMonitor.xcdatamodeld/.xccurrentversion",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>_XCCurrentVersionName</key>\n\t<string>LibreMonitor.xcdatamodel</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "LibreMonitor/LibreMonitor.xcdatamodeld/LibreMonitor.xcdatamodel/contents",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<model type=\"com.apple.IDECoreDataModeler.DataModel\" documentVersion=\"1.0\" lastSavedToolsVersion=\"1\" systemVersion=\"11A491\" minimumToolsVersion=\"Automatic\" sourceLanguage=\"Swift\" userDefinedModelVersionIdentifier=\"\">\n    <entity name=\"Event\" representedClassName=\"Event\" codeGenerationType=\"class\">\n        <attribute name=\"timestamp\" optional=\"YES\" attributeType=\"Date\"/>\n    </entity>\n    <elements>\n        <element name=\"Event\" positionX=\"261\" positionY=\"189\" width=\"128\" height=\"60\"/>\n    </elements>\n    <entity name=\"BloodGlucose\" representedClassName=\".BloodGlucose\" syncable=\"YES\">\n        <attribute name=\"bytes\" optional=\"YES\" attributeType=\"String\" syncable=\"YES\"/>\n        <attribute name=\"date\" optional=\"YES\" attributeType=\"Date\" usesScalarValueType=\"NO\" syncable=\"YES\"/>\n        <attribute name=\"dateString\" optional=\"YES\" attributeType=\"String\" syncable=\"YES\"/>\n        <attribute name=\"id\" optional=\"YES\" attributeType=\"Integer 32\" defaultValueString=\"0\" usesScalarValueType=\"YES\" syncable=\"YES\"/>\n        <attribute name=\"type\" optional=\"YES\" attributeType=\"Integer 16\" defaultValueString=\"0\" usesScalarValueType=\"YES\" syncable=\"YES\"/>\n        <attribute name=\"value\" optional=\"YES\" attributeType=\"Double\" defaultValueString=\"0.0\" usesScalarValueType=\"YES\" indexed=\"YES\" syncable=\"YES\"/>\n        <relationship name=\"sensor\" optional=\"YES\" maxCount=\"1\" deletionRule=\"Nullify\" destinationEntity=\"Sensor\" inverseName=\"bloodGlucose\" inverseEntity=\"Sensor\" syncable=\"YES\"/>\n    </entity>\n    <entity name=\"HeaderData\" representedClassName=\"HeaderData\" syncable=\"YES\">\n        <attribute name=\"bytes\" optional=\"YES\" attributeType=\"String\" syncable=\"YES\"/>\n        <attribute name=\"date\" optional=\"YES\" attributeType=\"Date\" usesScalarValueType=\"NO\" syncable=\"YES\"/>\n    </entity>\n    <entity name=\"Reader\" representedClassName=\".Reader\" syncable=\"YES\">\n        <attribute name=\"batteryVoltage\" optional=\"YES\" attributeType=\"Double\" defaultValueString=\"0.0\" usesScalarValueType=\"YES\" syncable=\"YES\"/>\n        <attribute name=\"temperature\" optional=\"YES\" attributeType=\"Double\" defaultValueString=\"0.0\" usesScalarValueType=\"YES\" syncable=\"YES\"/>\n        <attribute name=\"uid\" optional=\"YES\" attributeType=\"String\" syncable=\"YES\"/>\n    </entity>\n    <entity name=\"Sensor\" representedClassName=\".Sensor\" syncable=\"YES\">\n        <attribute name=\"lastScanDate\" optional=\"YES\" attributeType=\"Date\" usesScalarValueType=\"NO\" syncable=\"YES\"/>\n        <attribute name=\"minutesSinceStart\" optional=\"YES\" attributeType=\"Integer 32\" defaultValueString=\"0\" usesScalarValueType=\"YES\" syncable=\"YES\"/>\n        <attribute name=\"startDate\" optional=\"YES\" attributeType=\"Date\" usesScalarValueType=\"NO\" syncable=\"YES\"/>\n        <attribute name=\"uid\" optional=\"YES\" attributeType=\"String\" syncable=\"YES\"/>\n        <relationship name=\"bloodGlucose\" optional=\"YES\" toMany=\"YES\" deletionRule=\"Nullify\" destinationEntity=\"BloodGlucose\" inverseName=\"sensor\" inverseEntity=\"BloodGlucose\" syncable=\"YES\"/>\n    </entity>\n    <elements>\n        <element name=\"Event\" positionX=\"207\" positionY=\"-135\" width=\"128\" height=\"58\"/>\n        <element name=\"BloodGlucose\" positionX=\"43\" positionY=\"81\" width=\"128\" height=\"148\"/>\n        <element name=\"HeaderData\" positionX=\"189\" positionY=\"-18\" width=\"128\" height=\"75\"/>\n        <element name=\"Reader\" positionX=\"288\" positionY=\"261\" width=\"128\" height=\"88\"/>\n        <element name=\"Sensor\" positionX=\"261\" positionY=\"84\" width=\"128\" height=\"118\"/>\n    </elements>\n</model>"
  },
  {
    "path": "LibreMonitor/LibreMonitorUITests-Bridging-Header.h",
    "content": "//\n//  Use this file to import your target's public headers that you would like to expose to Swift.\n//\n#import \"NSData+CRC8.h\"\n#import \"NSData+SLIP.h\"\n#import \"constants.h\"\n#import \"data_types.h\"\n"
  },
  {
    "path": "LibreMonitor/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11201\" systemVersion=\"16A323\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"W2V-7Y-4OF\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"11161\"/>\n        <capability name=\"Constraints to layout margins\" minToolsVersion=\"6.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Blood Sugar Table View Controller-->\n        <scene sceneID=\"ImT-lg-bzr\">\n            <objects>\n                <tableViewController modalPresentationStyle=\"overFullScreen\" id=\"50o-9a-5MG\" customClass=\"BloodSugarTableViewController\" customModule=\"LibreMonitor\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <tableView key=\"view\" clipsSubviews=\"YES\" contentMode=\"scaleToFill\" alwaysBounceVertical=\"YES\" dataMode=\"prototypes\" style=\"plain\" separatorStyle=\"default\" rowHeight=\"44\" sectionHeaderHeight=\"28\" sectionFooterHeight=\"28\" id=\"IGA-Af-Q7c\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"64\" width=\"375\" height=\"554\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <prototypes>\n                            <tableViewCell clipsSubviews=\"YES\" contentMode=\"scaleToFill\" selectionStyle=\"default\" indentationWidth=\"10\" reuseIdentifier=\"Cell\" textLabel=\"geB-0N-HCr\" detailTextLabel=\"7Ok-y7-eKF\" style=\"IBUITableViewCellStyleValue2\" id=\"KSA-Qo-0iw\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"28\" width=\"375\" height=\"44\"/>\n                                <autoresizingMask key=\"autoresizingMask\"/>\n                                <tableViewCellContentView key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" tableViewCell=\"KSA-Qo-0iw\" id=\"f3z-vb-S0d\">\n                                    <frame key=\"frameInset\" width=\"375\" height=\"43.5\"/>\n                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                    <subviews>\n                                        <label opaque=\"NO\" multipleTouchEnabled=\"YES\" contentMode=\"left\" text=\"Title\" textAlignment=\"right\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" id=\"geB-0N-HCr\">\n                                            <frame key=\"frameInset\" minX=\"15\" minY=\"15\" width=\"91\" height=\"14.5\"/>\n                                            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                            <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"12\"/>\n                                            <color key=\"textColor\" red=\"0.0\" green=\"0.47843137250000001\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                            <nil key=\"highlightedColor\"/>\n                                        </label>\n                                        <label opaque=\"NO\" multipleTouchEnabled=\"YES\" contentMode=\"left\" text=\"Detail\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" id=\"7Ok-y7-eKF\">\n                                            <frame key=\"frameInset\" minX=\"112\" minY=\"15\" width=\"33\" height=\"14.5\"/>\n                                            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                            <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"12\"/>\n                                            <color key=\"textColor\" red=\"0.0\" green=\"0.0\" blue=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                            <nil key=\"highlightedColor\"/>\n                                        </label>\n                                    </subviews>\n                                </tableViewCellContentView>\n                            </tableViewCell>\n                            <tableViewCell clipsSubviews=\"YES\" contentMode=\"scaleToFill\" selectionStyle=\"default\" indentationWidth=\"10\" reuseIdentifier=\"BloodSugarGraphTableViewCell\" rowHeight=\"331\" id=\"jdB-cO-2dn\" customClass=\"BloodSugarGraphViewTableViewCell\" customModule=\"LibreMonitor\" customModuleProvider=\"target\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"72\" width=\"375\" height=\"331\"/>\n                                <autoresizingMask key=\"autoresizingMask\"/>\n                                <tableViewCellContentView key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" tableViewCell=\"jdB-cO-2dn\" id=\"g5L-6G-F7W\">\n                                    <frame key=\"frameInset\" width=\"375\" height=\"330.5\"/>\n                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                    <subviews>\n                                        <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"U1C-fo-eIu\" customClass=\"BloodSugarGraphView\" customModule=\"LibreMonitor\" customModuleProvider=\"target\">\n                                            <color key=\"backgroundColor\" red=\"0.97488003280000002\" green=\"0.63108614230000004\" blue=\"0.54087663860000001\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                            <color key=\"tintColor\" red=\"0.21386732429999999\" green=\"1\" blue=\"0.15152120020000001\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                        </view>\n                                    </subviews>\n                                    <constraints>\n                                        <constraint firstItem=\"U1C-fo-eIu\" firstAttribute=\"width\" secondItem=\"g5L-6G-F7W\" secondAttribute=\"width\" id=\"IJa-Mw-X6T\"/>\n                                        <constraint firstItem=\"U1C-fo-eIu\" firstAttribute=\"height\" secondItem=\"g5L-6G-F7W\" secondAttribute=\"height\" id=\"Kzb-7c-cLU\"/>\n                                        <constraint firstItem=\"U1C-fo-eIu\" firstAttribute=\"centerY\" secondItem=\"g5L-6G-F7W\" secondAttribute=\"centerY\" id=\"T67-rZ-fMN\"/>\n                                        <constraint firstItem=\"U1C-fo-eIu\" firstAttribute=\"centerX\" secondItem=\"g5L-6G-F7W\" secondAttribute=\"centerX\" id=\"c4W-Lb-viC\"/>\n                                    </constraints>\n                                </tableViewCellContentView>\n                                <connections>\n                                    <outlet property=\"barChartView\" destination=\"U1C-fo-eIu\" id=\"yRf-2P-7bE\"/>\n                                    <outlet property=\"lineChartView\" destination=\"U1C-fo-eIu\" id=\"iPw-k8-YjO\"/>\n                                </connections>\n                            </tableViewCell>\n                        </prototypes>\n                        <connections>\n                            <outlet property=\"dataSource\" destination=\"50o-9a-5MG\" id=\"Yga-5N-Ao6\"/>\n                            <outlet property=\"delegate\" destination=\"50o-9a-5MG\" id=\"f68-gz-v0t\"/>\n                        </connections>\n                    </tableView>\n                    <extendedEdge key=\"edgesForExtendedLayout\"/>\n                    <navigationItem key=\"navigationItem\" id=\"LSU-c9-uSa\"/>\n                    <refreshControl key=\"refreshControl\" opaque=\"NO\" multipleTouchEnabled=\"YES\" contentMode=\"center\" enabled=\"NO\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" id=\"ES1-fl-YYX\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1000\" height=\"1000\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                        <attributedString key=\"attributedTitle\">\n                            <fragment content=\"Aktualisierung alle zwei Minuten im Status &quot;Notifying&quot;.\">\n                                <attributes>\n                                    <font key=\"NSFont\" metaFont=\"smallSystem\"/>\n                                    <paragraphStyle key=\"NSParagraphStyle\" alignment=\"center\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" lineHeightMultiple=\"1\" tighteningFactorForTruncation=\"0.0\"/>\n                                </attributes>\n                            </fragment>\n                        </attributedString>\n                        <connections>\n                            <action selector=\"doRefresh:\" destination=\"50o-9a-5MG\" eventType=\"valueChanged\" id=\"dGD-br-dHx\"/>\n                        </connections>\n                    </refreshControl>\n                    <connections>\n                        <segue destination=\"RRb-Vb-fEk\" kind=\"showDetail\" identifier=\"ChangeBloodGlucoseAdjustments\" id=\"rkq-Eh-apj\"/>\n                    </connections>\n                </tableViewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"rfD-Rn-XvB\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"1239\" y=\"1000\"/>\n        </scene>\n        <!--Adjustments Table View Controller-->\n        <scene sceneID=\"KrO-eT-0KU\">\n            <objects>\n                <tableViewController id=\"p1I-y2-sJ2\" customClass=\"AdjustmentsTableViewController\" customModule=\"LibreMonitor\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <tableView key=\"view\" clipsSubviews=\"YES\" contentMode=\"scaleToFill\" alwaysBounceVertical=\"YES\" dataMode=\"static\" style=\"grouped\" rowHeight=\"44\" sectionHeaderHeight=\"18\" sectionFooterHeight=\"18\" id=\"6ty-D7-GsN\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"0.93725490199999995\" green=\"0.93725490199999995\" blue=\"0.95686274510000002\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <sections>\n                            <tableViewSection headerTitle=\"Adjustments\" footerTitle=\"Use offset and slope to adjust the values as good as possible to those of the Freestyle Libre Reader\" id=\"raR-VJ-2GJ\">\n                                <cells>\n                                    <tableViewCell clipsSubviews=\"YES\" contentMode=\"scaleToFill\" selectionStyle=\"default\" indentationWidth=\"10\" id=\"KhQ-e7-kta\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"119.5\" width=\"375\" height=\"44\"/>\n                                        <autoresizingMask key=\"autoresizingMask\"/>\n                                        <tableViewCellContentView key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" tableViewCell=\"KhQ-e7-kta\" id=\"1J4-j6-1aL\">\n                                            <frame key=\"frameInset\" width=\"375\" height=\"43.5\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                            <subviews>\n                                                <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Offset\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"XaO-BA-G9S\">\n                                                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                    <color key=\"textColor\" red=\"0.0\" green=\"0.0\" blue=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                    <nil key=\"highlightedColor\"/>\n                                                </label>\n                                                <textField opaque=\"NO\" clipsSubviews=\"YES\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"left\" contentVerticalAlignment=\"center\" text=\"120\" borderStyle=\"roundedRect\" textAlignment=\"right\" minimumFontSize=\"17\" clearButtonMode=\"always\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"6rr-p0-qrk\">\n                                                    <constraints>\n                                                        <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"120\" id=\"KIY-lx-ceo\"/>\n                                                    </constraints>\n                                                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"14\"/>\n                                                    <textInputTraits key=\"textInputTraits\" keyboardType=\"numbersAndPunctuation\"/>\n                                                </textField>\n                                            </subviews>\n                                            <constraints>\n                                                <constraint firstItem=\"6rr-p0-qrk\" firstAttribute=\"baseline\" secondItem=\"XaO-BA-G9S\" secondAttribute=\"baseline\" id=\"K1Q-va-Zzy\"/>\n                                                <constraint firstItem=\"6rr-p0-qrk\" firstAttribute=\"trailing\" secondItem=\"1J4-j6-1aL\" secondAttribute=\"trailingMargin\" id=\"gJb-g7-heD\"/>\n                                                <constraint firstItem=\"XaO-BA-G9S\" firstAttribute=\"leading\" secondItem=\"1J4-j6-1aL\" secondAttribute=\"leadingMargin\" constant=\"10\" id=\"pgd-Lb-eVi\"/>\n                                                <constraint firstItem=\"6rr-p0-qrk\" firstAttribute=\"top\" secondItem=\"1J4-j6-1aL\" secondAttribute=\"topMargin\" id=\"z9w-uj-8jJ\"/>\n                                            </constraints>\n                                        </tableViewCellContentView>\n                                    </tableViewCell>\n                                    <tableViewCell clipsSubviews=\"YES\" contentMode=\"scaleToFill\" selectionStyle=\"default\" indentationWidth=\"10\" id=\"OHa-VS-zrB\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"163.5\" width=\"375\" height=\"44\"/>\n                                        <autoresizingMask key=\"autoresizingMask\"/>\n                                        <tableViewCellContentView key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" tableViewCell=\"OHa-VS-zrB\" id=\"JqF-JX-s9v\">\n                                            <frame key=\"frameInset\" width=\"375\" height=\"43.5\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                            <subviews>\n                                                <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" preservesSuperviewLayoutMargins=\"YES\" text=\"Slope\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zNa-Ly-leh\">\n                                                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                    <color key=\"textColor\" red=\"0.0\" green=\"0.0\" blue=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                    <nil key=\"highlightedColor\"/>\n                                                </label>\n                                                <textField opaque=\"NO\" clipsSubviews=\"YES\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"left\" contentVerticalAlignment=\"center\" text=\"13\" borderStyle=\"roundedRect\" textAlignment=\"right\" minimumFontSize=\"17\" clearButtonMode=\"always\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"f1a-bL-AF1\">\n                                                    <constraints>\n                                                        <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"120\" id=\"sjq-Sh-ISQ\"/>\n                                                    </constraints>\n                                                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"14\"/>\n                                                    <textInputTraits key=\"textInputTraits\" keyboardType=\"numbersAndPunctuation\"/>\n                                                </textField>\n                                            </subviews>\n                                            <constraints>\n                                                <constraint firstItem=\"zNa-Ly-leh\" firstAttribute=\"leading\" secondItem=\"JqF-JX-s9v\" secondAttribute=\"leadingMargin\" constant=\"10\" id=\"7gb-Gc-QoT\"/>\n                                                <constraint firstItem=\"zNa-Ly-leh\" firstAttribute=\"centerY\" secondItem=\"JqF-JX-s9v\" secondAttribute=\"centerY\" id=\"AcC-oz-nwR\"/>\n                                                <constraint firstItem=\"f1a-bL-AF1\" firstAttribute=\"centerY\" secondItem=\"zNa-Ly-leh\" secondAttribute=\"centerY\" id=\"qXh-Hq-0XW\"/>\n                                                <constraint firstItem=\"f1a-bL-AF1\" firstAttribute=\"trailing\" secondItem=\"JqF-JX-s9v\" secondAttribute=\"trailingMargin\" id=\"zYl-eK-blb\"/>\n                                            </constraints>\n                                        </tableViewCellContentView>\n                                    </tableViewCell>\n                                </cells>\n                            </tableViewSection>\n                        </sections>\n                        <connections>\n                            <outlet property=\"dataSource\" destination=\"p1I-y2-sJ2\" id=\"iFC-8a-rKQ\"/>\n                            <outlet property=\"delegate\" destination=\"p1I-y2-sJ2\" id=\"4G7-sw-9L9\"/>\n                        </connections>\n                    </tableView>\n                    <navigationItem key=\"navigationItem\" id=\"V9s-LS-E01\"/>\n                    <connections>\n                        <outlet property=\"offsetTextField\" destination=\"6rr-p0-qrk\" id=\"MdT-ZU-Xrt\"/>\n                        <outlet property=\"slopeTextField\" destination=\"f1a-bL-AF1\" id=\"01j-ZC-4f6\"/>\n                    </connections>\n                </tableViewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"g2J-9j-6dp\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"2829\" y=\"1000\"/>\n        </scene>\n        <!--Grafik-->\n        <scene sceneID=\"ItB-yR-jGL\">\n            <objects>\n                <navigationController automaticallyAdjustsScrollViewInsets=\"NO\" id=\"Aqc-Zr-wxr\" sceneMemberID=\"viewController\">\n                    <tabBarItem key=\"tabBarItem\" title=\"Grafik\" id=\"m5f-C6-Iyo\"/>\n                    <toolbarItems/>\n                    <navigationBar key=\"navigationBar\" contentMode=\"scaleToFill\" id=\"D5j-St-ijw\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"320\" height=\"44\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </navigationBar>\n                    <nil name=\"viewControllers\"/>\n                    <connections>\n                        <segue destination=\"50o-9a-5MG\" kind=\"relationship\" relationship=\"rootViewController\" id=\"mac-75-ac4\"/>\n                    </connections>\n                </navigationController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"6xi-6N-6sh\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"442\" y=\"1000\"/>\n        </scene>\n        <!--Tab Bar Controller-->\n        <scene sceneID=\"eSi-nN-T7n\">\n            <objects>\n                <tabBarController automaticallyAdjustsScrollViewInsets=\"NO\" id=\"W2V-7Y-4OF\" sceneMemberID=\"viewController\">\n                    <toolbarItems/>\n                    <tabBar key=\"tabBar\" contentMode=\"scaleToFill\" id=\"NAN-gf-Fb0\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1000\" height=\"1000\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                        <color key=\"backgroundColor\" red=\"0.0\" green=\"0.0\" blue=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                    </tabBar>\n                    <connections>\n                        <segue destination=\"Aqc-Zr-wxr\" kind=\"relationship\" relationship=\"viewControllers\" id=\"qst-Qa-KIQ\"/>\n                        <segue destination=\"XyS-H7-wRd\" kind=\"relationship\" relationship=\"viewControllers\" id=\"dZb-aa-FZd\"/>\n                    </connections>\n                </tabBarController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iJp-75-dO7\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"-370\" y=\"1000\"/>\n        </scene>\n        <!--Acknowledgements-->\n        <scene sceneID=\"Fu4-Xg-VqK\">\n            <objects>\n                <viewController title=\"Acknowledgements\" id=\"XyS-H7-wRd\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Cl1-q4-umi\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"4UX-Pj-Oe1\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"za1-0o-Q3C\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <textView clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" alwaysBounceVertical=\"YES\" editable=\"NO\" usesAttributedText=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wh2-vh-DhE\">\n                                <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                <attributedString key=\"attributedText\">\n                                    <fragment>\n                                        <string key=\"content\">The following sets forth attribution notices for third party software that may be contained in portions of this product.\n\n---\nThe following software or parts of it may be included in this product: </string>\n                                        <attributes>\n                                            <font key=\"NSFont\" metaFont=\"system\" size=\"10\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment>\n                                        <string key=\"content\" base64-UTF8=\"YES\">\nCg\n</string>\n                                        <attributes>\n                                            <font key=\"NSFont\" size=\"10\" name=\"HelveticaNeue\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment>\n                                        <string key=\"content\" base64-UTF8=\"YES\">\nCg\n</string>\n                                        <attributes>\n                                            <font key=\"NSFont\" size=\"10\" name=\"HelveticaNeue\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\" allowsDefaultTighteningForTruncation=\"NO\">\n                                                <tabStops>\n                                                    <textTab alignment=\"left\" location=\"28\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"56\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"84\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"112\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"140\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"168\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"196\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"224\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"252\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"280\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"308\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"336\">\n                                                        <options/>\n                                                    </textTab>\n                                                </tabStops>\n                                            </paragraphStyle>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment content=\"CryptoSwift\">\n                                        <attributes>\n                                            <font key=\"NSFont\" size=\"12\" name=\".AppleSystemUIFont\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment>\n                                        <string key=\"content\" base64-UTF8=\"YES\">\nCg\n</string>\n                                        <attributes>\n                                            <font key=\"NSFont\" size=\"10\" name=\"HelveticaNeue\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment>\n                                        <string key=\"content\" base64-UTF8=\"YES\">\nCg\n</string>\n                                        <attributes>\n                                            <font key=\"NSFont\" size=\"10\" name=\"HelveticaNeue\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\" allowsDefaultTighteningForTruncation=\"NO\">\n                                                <tabStops>\n                                                    <textTab alignment=\"left\" location=\"28\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"56\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"84\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"112\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"140\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"168\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"196\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"224\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"252\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"280\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"308\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"336\">\n                                                        <options/>\n                                                    </textTab>\n                                                </tabStops>\n                                            </paragraphStyle>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment>\n                                        <mutableString key=\"content\">see https://github.com/krzyzanowskim/CryptoSwift\n\nCopyright (C) 2014 Marcin Krzyżanowski &lt;marcin.krzyzanowski@gmail.com&gt;\nThis software is provided 'as-is', without any express or implied warranty. \n\nIn no event will the authors be held liable for any damages arising from the use of this software. \n\nPermission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:\n\n- The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.\n- Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n- This notice may not be removed or altered from any source or binary distribution.\n\n\n---\nThe following software or parts of it may be included in this product: </mutableString>\n                                        <attributes>\n                                            <font key=\"NSFont\" metaFont=\"system\" size=\"10\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment>\n                                        <string key=\"content\" base64-UTF8=\"YES\">\nCg\n</string>\n                                        <attributes>\n                                            <font key=\"NSFont\" size=\"10\" name=\"HelveticaNeue\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment>\n                                        <string key=\"content\" base64-UTF8=\"YES\">\nCg\n</string>\n                                        <attributes>\n                                            <font key=\"NSFont\" size=\"10\" name=\"HelveticaNeue\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\" allowsDefaultTighteningForTruncation=\"NO\">\n                                                <tabStops>\n                                                    <textTab alignment=\"left\" location=\"28\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"56\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"84\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"112\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"140\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"168\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"196\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"224\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"252\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"280\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"308\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"336\">\n                                                        <options/>\n                                                    </textTab>\n                                                </tabStops>\n                                            </paragraphStyle>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment content=\"RFduinoUBP\">\n                                        <attributes>\n                                            <font key=\"NSFont\" size=\"12\" name=\".SFNSText\"/>\n                                            <font key=\"NSOriginalFont\" size=\"12\" name=\".SFNSText\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment>\n                                        <string key=\"content\" base64-UTF8=\"YES\">\nCg\n</string>\n                                        <attributes>\n                                            <font key=\"NSFont\" size=\"10\" name=\"HelveticaNeue\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment>\n                                        <string key=\"content\" base64-UTF8=\"YES\">\nCg\n</string>\n                                        <attributes>\n                                            <font key=\"NSFont\" size=\"10\" name=\"HelveticaNeue\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\" allowsDefaultTighteningForTruncation=\"NO\">\n                                                <tabStops>\n                                                    <textTab alignment=\"left\" location=\"28\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"56\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"84\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"112\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"140\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"168\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"196\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"224\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"252\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"280\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"308\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"336\">\n                                                        <options/>\n                                                    </textTab>\n                                                </tabStops>\n                                            </paragraphStyle>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment>\n                                        <mutableString key=\"content\">see https://github.com/cconway/RFduinoUBP\n\nThe MIT License (MIT)\n\nCopyright (c) 2015 cconway\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE. ---\nThe following software or parts of it may be included in this product: RFduinoUBP, see https://github.com/cconway/RFduinoUBP\n\n\n---\nThe following software or parts of it may be included in this product: </mutableString>\n                                        <attributes>\n                                            <font key=\"NSFont\" metaFont=\"system\" size=\"10\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment>\n                                        <string key=\"content\" base64-UTF8=\"YES\">\nCg\n</string>\n                                        <attributes>\n                                            <font key=\"NSFont\" size=\"10\" name=\"HelveticaNeue\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment>\n                                        <string key=\"content\" base64-UTF8=\"YES\">\nCg\n</string>\n                                        <attributes>\n                                            <font key=\"NSFont\" size=\"10\" name=\"HelveticaNeue\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\" allowsDefaultTighteningForTruncation=\"NO\">\n                                                <tabStops>\n                                                    <textTab alignment=\"left\" location=\"28\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"56\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"84\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"112\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"140\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"168\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"196\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"224\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"252\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"280\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"308\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"336\">\n                                                        <options/>\n                                                    </textTab>\n                                                </tabStops>\n                                            </paragraphStyle>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment content=\"Charts\">\n                                        <attributes>\n                                            <font key=\"NSFont\" size=\"12\" name=\".AppleSystemUIFont\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment>\n                                        <string key=\"content\" base64-UTF8=\"YES\">\nCg\n</string>\n                                        <attributes>\n                                            <font key=\"NSFont\" size=\"10\" name=\"HelveticaNeue\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment>\n                                        <string key=\"content\" base64-UTF8=\"YES\">\nCg\n</string>\n                                        <attributes>\n                                            <font key=\"NSFont\" size=\"10\" name=\"HelveticaNeue\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\" allowsDefaultTighteningForTruncation=\"NO\">\n                                                <tabStops>\n                                                    <textTab alignment=\"left\" location=\"28\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"56\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"84\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"112\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"140\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"168\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"196\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"224\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"252\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"280\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"308\">\n                                                        <options/>\n                                                    </textTab>\n                                                    <textTab alignment=\"left\" location=\"336\">\n                                                        <options/>\n                                                    </textTab>\n                                                </tabStops>\n                                            </paragraphStyle>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment>\n                                        <mutableString key=\"content\">see hhttps://github.com/danielgindi/Charts\n\n  Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright {yyyy} {name of copyright owner}\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n</mutableString>\n                                        <attributes>\n                                            <font key=\"NSFont\" metaFont=\"system\" size=\"10\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                        </attributes>\n                                    </fragment>\n                                </attributedString>\n                                <textInputTraits key=\"textInputTraits\" autocapitalizationType=\"sentences\"/>\n                            </textView>\n                        </subviews>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                        <constraints>\n                            <constraint firstItem=\"wh2-vh-DhE\" firstAttribute=\"width\" secondItem=\"za1-0o-Q3C\" secondAttribute=\"width\" id=\"00F-ce-7sG\"/>\n                            <constraint firstItem=\"wh2-vh-DhE\" firstAttribute=\"top\" secondItem=\"Cl1-q4-umi\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"dqZ-N9-a7w\"/>\n                            <constraint firstItem=\"wh2-vh-DhE\" firstAttribute=\"centerX\" secondItem=\"za1-0o-Q3C\" secondAttribute=\"centerX\" id=\"dxA-Vz-5Lr\"/>\n                            <constraint firstItem=\"wh2-vh-DhE\" firstAttribute=\"height\" secondItem=\"za1-0o-Q3C\" secondAttribute=\"height\" id=\"e5W-L2-DD4\"/>\n                        </constraints>\n                    </view>\n                    <tabBarItem key=\"tabBarItem\" title=\"Aknwoledgements\" id=\"cqu-02-OO6\"/>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"KsD-cc-ZmE\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"410\" y=\"1751\"/>\n        </scene>\n        <!--Navigation Controller-->\n        <scene sceneID=\"PcD-8F-rWp\">\n            <objects>\n                <navigationController automaticallyAdjustsScrollViewInsets=\"NO\" id=\"RRb-Vb-fEk\" sceneMemberID=\"viewController\">\n                    <toolbarItems/>\n                    <navigationBar key=\"navigationBar\" contentMode=\"scaleToFill\" id=\"TeE-cz-f4e\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"320\" height=\"44\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </navigationBar>\n                    <nil name=\"viewControllers\"/>\n                    <connections>\n                        <segue destination=\"p1I-y2-sJ2\" kind=\"relationship\" relationship=\"rootViewController\" id=\"8ew-YJ-gwy\"/>\n                    </connections>\n                </navigationController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"eNH-XW-Zjn\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"2031\" y=\"1000\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "LibreMonitor/Model/CRC.swift",
    "content": "//\n//  CRC.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 26.07.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n//\n//  Part of this code is taken from\n//  CRC.swift\n//  CryptoSwift\n//\n//  Created by Marcin Krzyzanowski on 25/08/14.\n//  Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.\n//\n\nimport Foundation\n\nfinal class Crc {\n    /// Table of precalculated crc16 values\n    static let crc16table: [UInt16] = [0, 4489, 8978, 12955, 17956, 22445, 25910, 29887, 35912, 40385, 44890, 48851, 51820, 56293, 59774, 63735, 4225, 264, 13203, 8730, 22181, 18220, 30135, 25662, 40137, 36160, 49115, 44626, 56045, 52068, 63999, 59510, 8450, 12427, 528, 5017, 26406, 30383, 17460, 21949, 44362, 48323, 36440, 40913, 60270, 64231, 51324, 55797, 12675, 8202, 4753, 792, 30631, 26158, 21685, 17724, 48587, 44098, 40665, 36688, 64495, 60006, 55549, 51572, 16900, 21389, 24854, 28831, 1056, 5545, 10034, 14011, 52812, 57285, 60766, 64727, 34920, 39393, 43898, 47859, 21125, 17164, 29079, 24606, 5281, 1320, 14259, 9786, 57037, 53060, 64991, 60502, 39145, 35168, 48123, 43634, 25350, 29327, 16404, 20893, 9506, 13483, 1584, 6073, 61262, 65223, 52316, 56789, 43370, 47331, 35448, 39921, 29575, 25102, 20629, 16668, 13731, 9258, 5809, 1848, 65487, 60998, 56541, 52564, 47595, 43106, 39673, 35696, 33800, 38273, 42778, 46739, 49708, 54181, 57662, 61623, 2112, 6601, 11090, 15067, 20068, 24557, 28022, 31999, 38025, 34048, 47003, 42514, 53933, 49956, 61887, 57398, 6337, 2376, 15315, 10842, 24293, 20332, 32247, 27774, 42250, 46211, 34328, 38801, 58158, 62119, 49212, 53685, 10562, 14539, 2640, 7129, 28518, 32495, 19572, 24061, 46475, 41986, 38553, 34576, 62383, 57894, 53437, 49460, 14787, 10314, 6865, 2904, 32743, 28270, 23797, 19836, 50700, 55173, 58654, 62615, 32808, 37281, 41786, 45747, 19012, 23501, 26966, 30943, 3168, 7657, 12146, 16123, 54925, 50948, 62879, 58390, 37033, 33056, 46011, 41522, 23237, 19276, 31191, 26718, 7393, 3432, 16371, 11898, 59150, 63111, 50204, 54677, 41258, 45219, 33336, 37809, 27462, 31439, 18516, 23005, 11618, 15595, 3696, 8185, 63375, 58886, 54429, 50452, 45483, 40994, 37561, 33584, 31687, 27214, 22741, 18780, 15843, 11370, 7921, 3960]\n\n\n\n\n    /// Calculates crc16. Taken from https://github.com/krzyzanowskim/CryptoSwift with modifications (reversing and byte swapping) to adjust for crc as used by Freestyle Libre\n    ///\n    /// - parameter message: Array of bytes for which the crc is to be calculated\n    /// - parameter seed:    seed for crc\n    ///\n    /// - returns: crc16\n    static func crc16(_ message:[UInt8], seed: UInt16? = nil) -> UInt16 {\n        var crc: UInt16 = seed != nil ? seed! : 0x0000\n        \n        // calculate crc\n        for chunk in BytesSequence(chunkSize: 256, data: message) {\n            for b in chunk {\n                crc = (crc >> 8) ^ crc16table[Int((crc ^ UInt16(b)) & 0xFF)]\n            }\n        }\n        \n        // reverse the bits (modification by Uwe Petersen, 2016-06-059\n        var reverseCrc = UInt16(0)\n        for _ in 0..<16 {\n            reverseCrc = reverseCrc << 1 | crc & 1\n            crc >>= 1\n        }\n        \n        // swap bytes and return (modification by Uwe Petersen, 2016-06-059\n        return reverseCrc.byteSwapped\n    }\n\n\n    /// Checks crc for an array of bytes.\n    ///\n    /// Assumes that the first two bytes are the crc16 of the bytes array and compares the corresponding value with the crc16 calculated over the rest of the array of bytes.\n    ///\n    /// - parameter bytes: Array of bytes with a crc in the first two bytes\n    ///\n    /// - returns: true if crc is valid\n    static func hasValidCrc16InFirstTwoBytes(_ bytes: [UInt8]) -> Bool {\n        \n        print(Array(bytes.dropFirst(2)))\n        let calculatedCrc = Crc.crc16(Array(bytes.dropFirst(2)), seed: 0xffff)\n        let enclosedCrc =  (UInt16(bytes[0]) << 8) | UInt16(bytes[1])\n        \n//        print(String(format: \"Calculated crc is %X and enclosed crc is %x\", arguments: [calculatedCrc, enclosedCrc]))\n        \n        return calculatedCrc == enclosedCrc\n    }\n    \n}\n\n/// Struct BytesSequence, taken from https://github.com/krzyzanowskim/CryptoSwift\nstruct BytesSequence: Sequence {\n    let chunkSize: Int\n    let data: Array<UInt8>\n    \n    func makeIterator() -> AnyIterator<ArraySlice<UInt8>> {\n        \n        var offset:Int = 0\n        \n        return AnyIterator {\n            let end = Swift.min(self.chunkSize, self.data.count - offset)\n            let result = self.data[offset..<offset + end]\n            offset += result.count\n            return !result.isEmpty ? result : nil\n        }\n    }\n}\n"
  },
  {
    "path": "LibreMonitor/Model/LibreSensor.swift",
    "content": "//\n//  LibreSensor.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 15.05.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\n\nclass LibreSensor {\n    \n    var uid: String\n    \n    lazy var serialNumber: String = {\n        \n        // The serial number of the sensor can be derived from its uid.\n        //\n        // The numbers an letters of the serial number are coded a compressed scheme that uses only 32 numbers and letters,\n        // by omitting the letters B, I, O and S. This information is stored in consecutive units of five bits.\n        //\n        // The encding thus is as follows:\n        //   index: 0 1 2 3 4 5 6 7 8 9 10     11 12 13 14 15 16     17 18 19 20 21     22 23 24      25 26 27 28 29 30 31\n        //   char:  0 1 2 3 4 5 6 7 8 9  A (B)  C  D  E  F  G  H (I)  J  K  L  M  N (O)  P  Q  R (S)   T  U  V  W  X  Y  Z\n        //\n        // Example:\n        //    Uid is E0 07 A0 00 00 25 90 5E, and the corresponding serial number is \"0M00009DHCR\"\n        //           \\   / \\              /\n        //            -+-   -----+--------\n        //             |         |\n        //             |         +-- This part encodes the serial number, see below\n        //             +-- Standard first two bytes, where 0x07 is the code for \"Texas Instruments Tag-it™\", see https://en.wikipedia.org/wiki/ISO/IEC_15693\n        //\n        //   1.) Convert the part without E007, i.e. A0 00 00 25 90 5E to binary representation\n        //\n        //            A    0     0    0     0    0     2    5     9    0     5    E\n        //          1010 0000  0000 0000  0000 0000  0010 0101  1001 0000  0101 1110\n        //\n        //   2.) Split this binary array in units of five bits length from the beginning and pad with two zeros at the end and\n        //       calculate the corresponding integer and retreive the corresponding char from the table above\n        //\n        //     +--  1010 0000  0000 0000  0000 0000  0010 0101  1001 0000  0101 1110   + 00\n        //     |\n        //     +->  10100 00000 00000 00000 00000 01001 01100 10000 01011 11000\n        //            |     |     |     |     |     |     |     |     |     |\n        //            |     |     |     |     |     |     |     |     |     +- = 24 -> \"R\"\n        //            |     |     |     |     |     |     |     |     +------- = 11 -> \"C\"\n        //            |     |     |     |     |     |     |     +------------- = 16 -> \"H\"\n        //            |     |     |     |     |     |     +------------------- = 12 -> \"D\"\n        //            |     |     |     |     |     +------------------------- =  9 -> \"9\"\n        //            |     |     |     |     +------------------------------- =  0 -> \"0\"\n        //            |     |     |     +------------------------------------- =  0 -> \"0\"\n        //            |     |     +------------------------------------------- =  0 -> \"0\"\n        //            |     +------------------------------------------------- =  0 -> \"0\"\n        //            +------------------------------------------------------- = 20 -> \"M\"\n        //\n        //   3.) Prepend \"0\" at the beginning an thus receive \"0M00009DHCR\"\n        \n        \n        let lookupTable = [\"0\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"A\",\"C\",\"D\",\"E\",\"F\",\"G\",\"H\",\"J\",\"K\",\"L\",\"M\",\"N\",\"P\",\"Q\",\"R\",\"T\",\"U\",\"V\",\"W\",\"X\",\"Y\",\"Z\"]\n        let uidString = self.uid.substring(from: self.uid.characters.index(self.uid.startIndex, offsetBy: 4)) // \"E007A0000025905E\" -> \"A0000025905E\"\n        \n        var serialNumber = \"\"\n        \n        guard uidString.lengthOfBytes(using: String.Encoding.ascii) == 12,\n            let uidAsInt = Int(uidString, radix: 16) // \"A0000025905E\"  -> 175921862905950\n            else {return \"\"}\n        \n        let uidAsBinaryString = String(uidAsInt, radix: 2) + \"00\"  // -> \"10100000000000000000000000100101100100000101111000\"\n        let length = uidAsBinaryString.lengthOfBytes(using: String.Encoding.ascii)\n        \n        for index in stride(from: 0, to: length, by: 5) {\n            if index + 4 < length {\n                let startIndex = uidAsBinaryString.startIndex\n                let leftIndex = uidAsBinaryString.index(startIndex, offsetBy: index)\n                let rightIndex = uidAsBinaryString.index(startIndex, offsetBy: index+5)\n                let range = leftIndex..<rightIndex\n                let fiveBits = uidAsBinaryString.substring(with: range)\n                \n                if let theInt = Int(fiveBits, radix: 2) , theInt >= 0 && theInt < lookupTable.count {\n                    serialNumber += lookupTable[theInt] // \"10100\" -> 20 -> \"M\"\n                }\n            }\n        }\n        serialNumber = \"0\" + serialNumber  // \"M00009DHCR\" -> \"0M00009DHCR\"\n        return serialNumber\n    }()\n    \n    lazy var prettyUid: String = {\n        \n        var prettyUid = self.uid\n        let length = self.uid.lengthOfBytes(using: String.Encoding.ascii)\n        for index in stride(from: 2, to: length, by: 2).reversed() {\n            prettyUid.insert(Character(\":\"), at: prettyUid.characters.index(prettyUid.startIndex, offsetBy: index))\n        }\n        return prettyUid\n    }()\n    \n    \n    init(withUID uid: String) {\n        self.uid = uid\n    }\n    \n}\n"
  },
  {
    "path": "LibreMonitor/Model/Measurement.swift",
    "content": "//\n//  Measurement.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 25.08.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\n\n\n/// Structure for one glucose measurement including value, date and raw data bytes\nstruct Measurement {\n    /// The date for this measurement\n    let date: Date\n    /// The bytes as read from the sensor. All data is derived from this \\\"raw data\"\n    let bytes: [UInt8]\n    /// The bytes as String\n    let byteString: String\n    /// The raw value as read from the sensor\n    let rawValue: Int\n    /// slope to calculate glucose from raw value in (mg/dl)/raw\n    let slope: Double\n    /// glucose offset to be added in mg/dl\n    let offset: Double\n    /// The glucose value in mg/dl\n    let glucose: Double\n    /// Initialize a new glucose measurement\n    ///\n    /// - parameter bytes:  raw data bytes as read from the sensor\n    /// - parameter slope:  slope to calculate glucose from raw value in (mg/dl)/raw\n    /// - parameter offset: glucose offset to be added in mg/dl\n    /// - parameter date:   date of the measurement\n    ///\n    /// - returns: Measurement\n    init(bytes: [UInt8], slope: Double = 0.1, offset: Double = 0.0, date: Date) {\n        self.bytes = bytes\n        self.byteString = bytes.reduce(\"\", {$0 + String(format: \"%02X\", arguments: [$1])})\n        self.rawValue = (Int(bytes[1]) << 8) & 0x0F00 + Int(bytes[0])\n        self.slope = slope\n        self.offset = offset\n        self.glucose = offset + slope * Double(rawValue)\n        self.date = date\n    }\n    var description: String {\n        return String(\"Glucose: \\(glucose) (mg/dl), date:  \\(date), slope: \\(slope), offset: \\(offset),rawValue: \\(rawValue), bytes: \\(bytes)\" )\n    }\n}\n"
  },
  {
    "path": "LibreMonitor/Model/SensorData.swift",
    "content": "//\n//  SensorData\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 26.07.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\n\n\n/// Structure for data from Freestyle Libre sensor\n/// To be initialized with the bytes as read via nfc. Provides all derived data.\nstruct SensorData {\n    \n    /// Number of bytes of sensor data to be used (read only), i.e. 344 bytes (24 for header, 296 for body and 24 for footer)\n    let numberOfBytes = 344 // Header and body and footer of Freestyle Libre data (i.e. 40 blocks of 8 bytes)\n    /// Array of 344 bytes as read via nfc\n    let bytes: [UInt8]\n    /// Subarray of 24 header bytes\n    let header: [UInt8]\n    /// Subarray of 296 body bytes\n    let body: [UInt8]\n    /// Subarray of 24 footer bytes\n    let footer: [UInt8]\n    /// Date when data was read from sensor\n    let date: Date\n    /// Minutes (approx) since start of sensor\n    let minutesSinceStart: Int\n    /// Index on the next block of trend data that the sensor will measure and store\n    let nextTrendBlock: Int\n    /// Index on the next block of history data that the sensor will create from trend data and store\n    let nextHistoryBlock: Int\n    /// true if the header crc, stored in the first two bytes, is equal to the calculated crc\n    var hasValidHeaderCRC: Bool {\n        return Crc.hasValidCrc16InFirstTwoBytes(header)\n    }\n    /// true if the body crc, stored in the first two bytes, is equal to the calculated crc\n    var hasValidBodyCRC: Bool {\n        return Crc.hasValidCrc16InFirstTwoBytes(body)\n    }\n    /// true if the footer crc, stored in the first two bytes, is equal to the calculated crc\n    var hasValidFooterCRC: Bool {\n        return Crc.hasValidCrc16InFirstTwoBytes(footer)\n    }\n    \n    /// Sensor state (ready, failure, starting etc.)\n    var state: SensorState {\n        switch header[4] {\n        case 01:\n            return SensorState.notYetStarted\n        case 02:\n            return SensorState.starting\n        case 03:\n            return SensorState.ready\n        case 04:\n            return SensorState.expired\n        case 05:\n            return SensorState.shutdown\n        case 06:\n            return SensorState.failure\n        default:\n            return SensorState.unknown\n        }\n    }\n    \n    \n    init?(bytes: [UInt8], date: Date = Date()) {\n        guard bytes.count == numberOfBytes else {\n            return nil\n        }\n        self.bytes = bytes\n        self.date = date\n        \n        let headerRange =   0..<24   //  24 bytes, i.e.  3 blocks a 8 bytes\n        let bodyRange   =  24..<320  // 296 bytes, i.e. 37 blocks a 8 bytes\n        let footerRange = 320..<344  //  24 bytes, i.e.  3 blocks a 8 bytes\n        \n        self.header = Array(bytes[headerRange])\n        self.body   = Array(bytes[bodyRange])\n        self.footer = Array(bytes[footerRange])\n        \n        self.nextTrendBlock = Int(body[2])\n        self.nextHistoryBlock = Int(body[3])\n        self.minutesSinceStart = Int(body[293]) << 8 + Int(body[292])\n    }\n\n    \n    /// Get array of 16 trend glucose measurements. \n    /// Each array is sorted such that the most recent value is at index 0 and corresponds to the time when the sensor was read, i.e. self.date. The following measurements are each one more minute behind, i.e. -1 minute, -2 mintes, -3 minutes, ... -15 minutes.\n    ///\n    /// - parameter offset: offset in mg/dl that is added\n    /// - parameter slope:  slope in (mg/dl)/ raw\n    ///\n    /// - returns: Array of Measurements\n    func trendMeasurements(_ offset: Double = 0.0, slope: Double = 0.1) -> [Measurement] {\n        var measurements = [Measurement]()\n        \n        // Trend data is stored in body from byte 4 to byte 4+96=100 in units of 6 bytes. Index on data such that most recent block is first.\n        for blockIndex in 0...15 {\n            \n            var index = 4 + (nextTrendBlock - 1 - blockIndex) * 6 // runs backwards\n            if index < 4 {\n                index = index + 96 // if end of ring buffer is reached shift to beginning of ring buffer\n            }\n            \n            let range = index..<index+6\n            let measurementBytes = Array(body[range])\n            let measurementDate = date.addingTimeInterval(Double(-60 * blockIndex))\n            \n            let measurement = Measurement(bytes: measurementBytes, slope: slope, offset: offset, date: measurementDate)\n            \n            measurements.append(measurement)\n        }\n        return measurements\n    }\n    \n    \n    /// Get array of 32 history glucose measurements. \n    /// Each array is sorted such that the most recent value is at index 0. This most recent value corresponds to -(minutesSinceStart - 3) % 15 + 3. The following measurements are each 15 more minutes behind, i.e. -15 minutes behind, -30 minutes, -45 minutes, ... .\n    ///\n    /// - parameter offset: offset in mg/dl that is added\n    /// - parameter slope:  slope in (mg/dl)/ raw\n    ///\n    /// - returns: Array of Measurements\n    func historyMeasurements(_ offset: Double = 0.0, slope: Double = 0.1) -> [Measurement] {\n      \n        let mostRecentHistoryDate = date.addingTimeInterval( 60.0 * -Double( (minutesSinceStart - 3) % 15 + 3 ) )\n        var measurements = [Measurement]()\n        // History data is stored in body from byte 100 to byte 100+192-1=291 in units of 6 bytes. Index on data such that most recent block is first.\n        for blockIndex in 0..<32 {\n            \n            var index = 100 + (nextHistoryBlock - 1 - blockIndex) * 6 // runs backwards\n            if index < 100 {\n                index = index + 192 // if end of ring buffer is reached shift to beginning of ring buffer\n            }\n            \n            let range = index..<index+6\n            let measurementBytes = Array(body[range])\n            let measurementDate = mostRecentHistoryDate.addingTimeInterval(Double(-900 * blockIndex)) // 900 = 60 * 15\n            \n            let measurement = Measurement(bytes: measurementBytes, slope: slope, offset: offset, date: measurementDate)\n            \n            measurements.append(measurement)\n        }\n        return measurements\n    }\n    \n\n}\n\n\n\n"
  },
  {
    "path": "LibreMonitor/Model/SensorState.swift",
    "content": "//\n//  SensorState.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 31.07.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\n\n/// State of the freestyle libre sensor\n///\n/// - notYetStarted: 0x01 sensor not yet started\n/// - starting:      0x02 sensor is in the starting phase\n/// - ready:         0x03 sensor is ready, i.e. in normal operation mode\n/// - stateFour:     0x04 state with yet unknown meaning\n/// - expired:       0x05 sensor is expired\n/// - failure:       0x06 sensor has an error\n/// - unknown:       any other state\nenum SensorState {\n    case notYetStarted\n    case starting\n    case ready\n    case expired\n    case shutdown\n    case failure\n    case unknown\n    \n    init(){\n        self = .unknown\n    }\n    \n    var description: String {\n        switch self {\n        case .notYetStarted:\n            return \"Sensor not yet startet\"\n        case .starting:\n            return \"Sensor in starting phase\"\n        case .ready:\n            return \"Sensor is ready\"\n        case .expired:\n            return \"Sensor is expired\"\n        case .shutdown:\n            return \"Sensor is shut down\"\n        case .failure:\n            return \"Sensor has failure\"\n        default:\n            return \"Unknown sensor state\"\n        }\n    }\n}\n"
  },
  {
    "path": "LibreMonitor/ModelCoreData/BloodGlucose+CoreDataClass.swift",
    "content": "//\n//  BloodGlucose+CoreDataClass.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 09.10.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\nimport CoreData\n\n\npublic class BloodGlucose: NSManagedObject {\n\n}\n"
  },
  {
    "path": "LibreMonitor/ModelCoreData/BloodGlucose+CoreDataProperties.swift",
    "content": "//\n//  BloodGlucose+CoreDataProperties.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 09.10.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\nimport CoreData\n\nextension BloodGlucose {\n\n    @nonobjc public class func fetchRequest() -> NSFetchRequest<BloodGlucose> {\n        return NSFetchRequest<BloodGlucose>(entityName: \"BloodGlucose\");\n    }\n\n    @NSManaged public var bytes: String?\n    @NSManaged public var dateString: String?\n    @NSManaged public var id: Int32\n    @NSManaged public var type: Int16\n    @NSManaged public var value: Double\n    @NSManaged public var date: NSDate?\n    @NSManaged public var sensor: Sensor?\n\n}\n"
  },
  {
    "path": "LibreMonitor/ModelCoreData/CoreDataStack.swift",
    "content": "//\n//  CoreDataStack.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 13.04.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\nimport UIKit\nimport CoreData\n\nclass CoreDataStack: NSObject {\n    \n//    var managedObjectContext: NSManagedObjectContext\n    \n    override init() {\n    }\n//    override init() {\n//        \n//        // This resource is the same name as your xcdatamodeld contained in your project.\n//        guard let modelURL = NSBundle.mainBundle().URLForResource(\"DataModel\", withExtension:\"momd\") else {\n//            fatalError(\"Error loading model from bundle\")\n//        }\n//        \n//        // The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.\n//        guard let mom = NSManagedObjectModel(contentsOfURL: modelURL) else {\n//            fatalError(\"Error initializing mom from: \\(modelURL)\")\n//        }\n//        \n//        let psc = NSPersistentStoreCoordinator(managedObjectModel: mom)\n//        \n//        managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)\n//        managedObjectContext.persistentStoreCoordinator = psc\n//        \n//        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {\n//            let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)\n//            let docURL = urls[urls.endIndex-1]\n//            /* The directory the application uses to store the Core Data store file.\n//             This code uses a file named \"DataModel.sqlite\" in the application's documents directory.\n//             */\n//            let storeURL = docURL.URLByAppendingPathComponent(\"DataModel.sqlite\")\n//            do {\n//                try psc.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: nil)\n//            } catch {\n//                fatalError(\"Error migrating store: \\(error)\")\n//            }\n//        }\n//    }\n    \n    \n    lazy var applicationDocumentsDirectory: URL = {\n        // The directory the application uses to store the Core Data store file. This code uses a directory named \"UPP.LibreMonitor\" in the application's documents Application Support directory.\n        var urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)\n        return urls[urls.count-1]\n    }()\n    \n    lazy var managedObjectModel: NSManagedObjectModel = {\n        // The managed object model for the application. This property is not optional. It is a fatal error for the application not to be able to find and load its model.\n        let modelURL = Bundle.main.url(forResource: \"LibreMonitor\", withExtension: \"momd\")!\n        return NSManagedObjectModel(contentsOf: modelURL)!\n    }()\n    \n    lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {\n        // The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.\n        // Create the coordinator and store\n        let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)\n        let url = self.applicationDocumentsDirectory.appendingPathComponent(\"SingleViewCoreData.sqlite\")\n        var failureReason = \"There was an error creating or loading the application's saved data.\"\n        do {\n            try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: nil)\n        } catch {\n            // Report any error we got.\n            var dict = [String: AnyObject]()\n            dict[NSLocalizedDescriptionKey] = \"Failed to initialize the application's saved data\" as AnyObject?\n            dict[NSLocalizedFailureReasonErrorKey] = failureReason as AnyObject?\n            \n            dict[NSUnderlyingErrorKey] = error as NSError\n            let wrappedError = NSError(domain: \"YOUR_ERROR_DOMAIN\", code: 9999, userInfo: dict)\n            // Replace this with code to handle the error appropriately.\n            // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.\n            NSLog(\"Unresolved error \\(wrappedError), \\(wrappedError.userInfo)\")\n            abort()\n        }\n        \n        return coordinator\n    }()\n    \n    lazy var managedObjectContext: NSManagedObjectContext = {\n        // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.\n        let coordinator = self.persistentStoreCoordinator\n        var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)\n        managedObjectContext.persistentStoreCoordinator = coordinator\n        return managedObjectContext\n    }()\n    \n    // MARK: - Core Data Saving support\n    \n    func saveContext () {\n        if managedObjectContext.hasChanges {\n            do {\n                try managedObjectContext.save()\n            } catch {\n                // Replace this implementation with code to handle the error appropriately.\n                // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.\n                let nserror = error as NSError\n                NSLog(\"Unresolved error \\(nserror), \\(nserror.userInfo)\")\n                abort()\n            }\n        }\n    }\n    \n}\n"
  },
  {
    "path": "LibreMonitor/ModelCoreData/HeaderData+CoreDataClass.swift",
    "content": "//\n//  HeaderData+CoreDataClass.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 09.10.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\nimport CoreData\n\n@objc(HeaderData)\npublic class HeaderData: NSManagedObject {\n\n}\n"
  },
  {
    "path": "LibreMonitor/ModelCoreData/HeaderData+CoreDataProperties.swift",
    "content": "//\n//  HeaderData+CoreDataProperties.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 09.10.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\nimport CoreData\n\n\nextension HeaderData {\n\n    @nonobjc public class func fetchRequest() -> NSFetchRequest<HeaderData> {\n        return NSFetchRequest<HeaderData>(entityName: \"HeaderData\");\n    }\n\n    @NSManaged public var bytes: String?\n    @NSManaged public var date: NSDate?\n\n}\n"
  },
  {
    "path": "LibreMonitor/ModelCoreData/Reader+CoreDataClass.swift",
    "content": "//\n//  Reader+CoreDataClass.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 09.10.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\nimport CoreData\n\n\npublic class Reader: NSManagedObject {\n\n}\n"
  },
  {
    "path": "LibreMonitor/ModelCoreData/Reader+CoreDataProperties.swift",
    "content": "//\n//  Reader+CoreDataProperties.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 09.10.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\nimport CoreData\n\n\nextension Reader {\n\n    @nonobjc public class func fetchRequest() -> NSFetchRequest<Reader> {\n        return NSFetchRequest<Reader>(entityName: \"Reader\");\n    }\n\n    @NSManaged public var batteryVoltage: Double\n    @NSManaged public var temperature: Double\n    @NSManaged public var uid: String?\n\n}\n"
  },
  {
    "path": "LibreMonitor/ModelCoreData/Sensor+CoreDataClass.swift",
    "content": "//\n//  Sensor+CoreDataClass.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 09.10.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\nimport CoreData\n\n\npublic class Sensor: NSManagedObject {\n\n}\n"
  },
  {
    "path": "LibreMonitor/ModelCoreData/Sensor+CoreDataProperties.swift",
    "content": "//\n//  Sensor+CoreDataProperties.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 09.10.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\nimport CoreData\n\nextension Sensor {\n\n    @nonobjc public class func fetchRequest() -> NSFetchRequest<Sensor> {\n        return NSFetchRequest<Sensor>(entityName: \"Sensor\");\n    }\n\n    @NSManaged public var startDate: NSDate?\n    @NSManaged public var uid: String?\n    @NSManaged public var lastScanDate: NSDate?\n    @NSManaged public var minutesSinceStart: Int32\n    @NSManaged public var bloodGlucose: NSSet?\n\n}\n\n// MARK: Generated accessors for bloodGlucose\nextension Sensor {\n\n    @objc(addBloodGlucoseObject:)\n    @NSManaged public func addToBloodGlucose(_ value: BloodGlucose)\n\n    @objc(removeBloodGlucoseObject:)\n    @NSManaged public func removeFromBloodGlucose(_ value: BloodGlucose)\n\n    @objc(addBloodGlucose:)\n    @NSManaged public func addToBloodGlucose(_ values: NSSet)\n\n    @objc(removeBloodGlucose:)\n    @NSManaged public func removeFromBloodGlucose(_ values: NSSet)\n\n}\n"
  },
  {
    "path": "LibreMonitor/Reader+CoreDataClass.swift",
    "content": "//\n//  Reader+CoreDataClass.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 14.10.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\nimport CoreData\n\n\npublic class Reader: NSManagedObject {\n\n}\n"
  },
  {
    "path": "LibreMonitor/Reader+CoreDataProperties.swift",
    "content": "//\n//  Reader+CoreDataProperties.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 14.10.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\nimport CoreData\n\n\nextension Reader {\n\n    @nonobjc public class func fetchRequest() -> NSFetchRequest<Reader> {\n        return NSFetchRequest<Reader>(entityName: \"Reader\");\n    }\n\n    @NSManaged public var batteryVoltage: Double\n    @NSManaged public var temperature: Double\n    @NSManaged public var uid: String?\n\n}\n"
  },
  {
    "path": "LibreMonitor/Sensor+CoreDataClass.swift",
    "content": "//\n//  Sensor+CoreDataClass.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 14.10.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\nimport CoreData\n\n\npublic class Sensor: NSManagedObject {\n\n}\n"
  },
  {
    "path": "LibreMonitor/Sensor+CoreDataProperties.swift",
    "content": "//\n//  Sensor+CoreDataProperties.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 14.10.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\nimport CoreData \n\nextension Sensor {\n\n    @nonobjc public class func fetchRequest() -> NSFetchRequest<Sensor> {\n        return NSFetchRequest<Sensor>(entityName: \"Sensor\");\n    }\n\n    @NSManaged public var lastScanDate: NSDate?\n    @NSManaged public var minutesSinceStart: Int32\n    @NSManaged public var startDate: NSDate?\n    @NSManaged public var uid: String?\n    @NSManaged public var bloodGlucose: NSSet?\n\n}\n\n// MARK: Generated accessors for bloodGlucose\nextension Sensor {\n\n    @objc(addBloodGlucoseObject:)\n    @NSManaged public func addToBloodGlucose(_ value: BloodGlucose)\n\n    @objc(removeBloodGlucoseObject:)\n    @NSManaged public func removeFromBloodGlucose(_ value: BloodGlucose)\n\n    @objc(addBloodGlucose:)\n    @NSManaged public func addToBloodGlucose(_ values: NSSet)\n\n    @objc(removeBloodGlucose:)\n    @NSManaged public func removeFromBloodGlucose(_ values: NSSet)\n\n}\n"
  },
  {
    "path": "LibreMonitor/SimbleeCode/crc8.h",
    "content": "// LICENSES: [077915]\n// -----------------------------------\n// The contents of this file contains the aggregate of contributions\n//   covered under one or more licences. The full text of those licenses\n//   can be found in the \"LICENSES\" file at the top level of this project\n//   identified by the MD5 fingerprints listed above.\n//\n// Uwe Petersen: Modified version to test transmission part in iOS\n\n\n\n#import <Foundation/Foundation.h>\n\ntypedef uint8_t byte;\n\n\nbyte CRC8(void *data_in, byte number_of_bytes_to_read);\n"
  },
  {
    "path": "LibreMonitor/SimbleeCode/crc8.m",
    "content": "// LICENSES: [077915]\n// -----------------------------------\n// The contents of this file contains the aggregate of contributions\n//   covered under one or more licences. The full text of those licenses\n//   can be found in the \"LICENSES\" file at the top level of this project\n//   identified by the MD5 fingerprints listed above.\n//\n//\n// Uwe Petersen: Modified version to test transmission part in iOS\n\n\n#include \"crc8.h\"\n\n#define CRC8INIT  0x00\n#define CRC8POLY  0x18      // 0X18 = X^8+X^5+X^4+X^0\n\nbyte CRC8(void *bytes, byte number_of_bytes_to_read) {\n    \n    byte *data_in = (byte*) bytes;\n    byte  crc;\n    uint16_t loop_count;\n    byte  bit_counter;\n    byte  data;\n    byte  feedback_bit;\n    \n    crc = CRC8INIT;\n    \n    for (loop_count = 0; loop_count != number_of_bytes_to_read; loop_count++)\n    {\n        data = data_in[loop_count];\n        \n        bit_counter = 8;\n        do {\n            feedback_bit = (crc ^ data) & 0x01;\n            \n            if ( feedback_bit == 0x01 ) {\n                crc = crc ^ CRC8POLY;\n            }\n            crc = (crc >> 1) & 0x7F;\n            if ( feedback_bit == 0x01 ) {\n                crc = crc | 0x80;\n            }\n            \n            data = data >> 1;\n            bit_counter--;\n            \n        } while (bit_counter > 0);\n    }\n    \n    return crc;\n}\n\n"
  },
  {
    "path": "LibreMonitor/SimbleeCode/libUBP.h",
    "content": "//\n// Uwe Petersen: Modified version to test transmission part in iOS\n\n#import <Foundation/Foundation.h>\n\ntypedef uint8_t byte;\n\n\n#ifndef libUBP_h\n#define libUBP_h\n#endif\n\n\ntypedef enum {\n    \n    UBP_TxFlagNone = 0 << 0,\n    UBP_TxFlagIsRPC = 1 << 0,\n    UBP_TxFlagRequiresACK = 1 << 1\n    \n} UBP_TxFlags;\n\n\n// Public\n\nvoid UBP_pump();\nbool UBP_queuePacketTransmission(unsigned short packetIdentifier, UBP_TxFlags txFlags, const char *packetBytes, unsigned short byteCount);\n\n//bool UBP_isBusy();\n\n// 2016-06-26: Needed for tests\nvoid getTxBuffer(char *txBuffer, int *txBufferLength);\nvoid SimbleeBLE_onConnect();\nvoid SimbleeBLE_onDisconnect();\n\n\n\n\n// Private\n\nvoid _UBP_pumpTxQueue();\n\n//void _UBP_ingestRxBytes(char *receivedBytes, int byteCount);\n\nint _UBP_makeEscapedCopy(const char *inputBuffer, unsigned short inputBufferLength, char *outputBuffer, unsigned short outputBufferLength);\n\nint _UBP_makeUnEscapedCopy(const char *inputBuffer, unsigned short inputBufferLength, char *outputBuffer);\n\nvoid _UBP_hostDisconnected();\n\n\n// To be implemented by end-user externally\n//extern void UBP_incomingChecksumFailed() __attribute__((weak));\n\n//extern void UBP_receivedPacket(unsigned short packetIdentifier, UBP_TxFlags txFlags, void *packetBuffer) __attribute__((weak));\n\n//extern void UBP_didAdvertise(bool start) __attribute__((weak));\n\n//extern void UBP_didConnect() __attribute__((weak));\n\n//extern void UBP_didDisconnect() __attribute__((weak));\n\n\n"
  },
  {
    "path": "LibreMonitor/SimbleeCode/libUBP.m",
    "content": "//\n// Uwe Petersen: Modified version to test transmission part in iOS\n\n#import \"libUBP.h\"\n#import \"crc8.h\"\n\n// Build-time configurations\n//#define BUFFER_LENGTH 64 // Uwe changed this on 2016-01-04\n#define BUFFER_LENGTH 400 // Uwe changed this on 2016-07-24\n#define TX_CHUNK_SIZE 20\n#define PACKET_ID_SIZE 2\n\n// Serial Line IP (SLIP) escaping constants\n#define ESCAPE_BYTE 0xDB\n#define END_BYTE    0xC0\n#define ESCAPED_ESCAPE_BYTE 0xDD\n#define ESCAPED_END_BYTE    0xDC\nconst char escapeSequence_[1] = {ESCAPE_BYTE};\nconst char endSequence_[1] = {END_BYTE};\nconst char escapedEndSequence_[2] = {ESCAPE_BYTE, ESCAPED_END_BYTE};\nconst char escapedEscapeSequence_[2] = {ESCAPE_BYTE, ESCAPED_ESCAPE_BYTE};\n\n// Buffers\nchar ubpTxBuffer[BUFFER_LENGTH];\nint ubpTxBufferLength = 0;\nint ubpTxBufferSentByteCount = 0;\nchar ubpRxBuffer[BUFFER_LENGTH];\nint ubpRxBufferLength = 0;\nchar ubpUnescapedRxBufferBuffer[BUFFER_LENGTH];\nint ubpUnescapedRxBufferBufferLength = 0;\n\n// State Variables\nbool UBP_isTxPending = false;\nbool hostIsConnected = true;\n//bool hostIsConnected = false;\n\n// 2016-06-27: for testing purposes simulate simblee\nchar simbleeBuffer[BUFFER_LENGTH];\nint simbleeBufferLength = 0;\n\n/*\n// Functions\nbool UBP_isBusy() {\n    \n    return UBP_isTxPending;\n}\n */\nvoid UBP_pump() {\n    \n    _UBP_pumpTxQueue();\n}\n\n\nvoid _UBP_pumpTxQueue() {\n    \n    if (UBP_isTxPending) {\n        \n        char *nextByteToSend = ubpTxBuffer + ubpTxBufferSentByteCount;\n        \n        // Try sending the next chunk\n        if (ubpTxBufferSentByteCount < ubpTxBufferLength && hostIsConnected) {  // Haven't already sent all the bytes\n            \n            int retryRemainingCount = 1000;  // Limit the number of times we retry sending to avoid getting into an infinite loop\n            int remainingByteCount = ubpTxBufferLength - ubpTxBufferSentByteCount;\n            \n            if (remainingByteCount >= TX_CHUNK_SIZE) {  // Can fill the TX output buffer\n                \n                // Send is queued (the ble stack delays send to the start of the next tx window)\n                while (hostIsConnected && retryRemainingCount > 0) {\n                    retryRemainingCount--;\n                };\n                // 2016-06-27: This changed to the above to enable testing\n                // while ( SimbleeBLE.send(nextByteToSend, TX_CHUNK_SIZE) == false && hostIsConnected && retryRemainingCount > 0) {\n                //         retryRemainingCount--;\n                // };  // send() returns false if all tx buffers in use (can't enqueue, try again later)\n                \n                ubpTxBufferSentByteCount += TX_CHUNK_SIZE;\n                \n            } else {  // Only partial TX buffer remaining to send\n                \n                // Send is queued (the ble stack delays send to the start of the next tx window)\n                while ( hostIsConnected && retryRemainingCount > 0) {\n                    retryRemainingCount--;\n                };  // send() returns false if all tx buffers in use (can't enqueue, try again later)\n                // 2016-06-27: This changed to the above to enable testing\n                // while ( SimbleeBLE.send(nextByteToSend, remainingByteCount) == false && hostIsConnected && retryRemainingCount > 0) {\n                //     retryRemainingCount--;\n                // };  // send() returns false if all tx buffers in use (can't enqueue, try again later)\n                \n                ubpTxBufferSentByteCount += remainingByteCount;\n                \n                UBP_isTxPending = false;\n            }\n        }\n    }\n}\n/*\nvoid _UBP_ingestRxBytes(char *receivedBytes, int byteCount) {\n    \n    Serial.print(byteCount);\n    Serial.println(\" bytes receieved\");\n    \n    // NOTE: Assuming not called unless len > 0\n    \n    // Determine what to do with incoming fragment\n    if ( *receivedBytes == END_BYTE ) {  // Fragment has leading END byte, signals start of packet\n        \n        // Set fragment as the beginning of the reconstruction buffer\n        memcpy(ubpRxBuffer, receivedBytes, byteCount);\n        ubpRxBufferLength = byteCount;\n        \n    } else if (ubpRxBufferLength > 0) {  // Already have fragments in the reconstruction buffer\n        \n        // Append fragment to reconstruction buffer\n        memcpy(ubpRxBuffer + ubpRxBufferLength, receivedBytes, byteCount);\n        ubpRxBufferLength += byteCount;\n        \n    }\n    \n    \n    // Check RX buffer for trailing END byte\n    if ( *(ubpRxBuffer + ubpRxBufferLength - 1) == END_BYTE) {  // RX buffer ends with END byte, looks like packet is complete\n        \n        byte firstNonControlIndex = 1;\n        byte escapedDataLength = ubpRxBufferLength - 2;  // \"- 2\" for leading/trailing control chars\n        \n        // Un-escape the incoming payload\n        ubpUnescapedRxBufferBufferLength = _UBP_makeUnEscapedCopy(ubpRxBuffer + firstNonControlIndex, escapedDataLength, ubpUnescapedRxBufferBuffer);\n        byte payloadDataLength = ubpUnescapedRxBufferBufferLength - 1;  // -1 to account for checksum\n        \n        // Calculate checksum over payload, i.e. all bytes except for last checksum byte)\n        char calculatedChecksum = CRC8(ubpUnescapedRxBufferBuffer, payloadDataLength * sizeof(byte));\n        \n        // Extract embedded checksum value\n        char receivedChecksum = *(ubpUnescapedRxBufferBuffer + payloadDataLength);  // NOTE: Omitting '-1' because checksum byte comes just after payloadDataLength\n        \n        // Verify the checksum\n        if (calculatedChecksum == receivedChecksum) {\n            \n            unsigned short packetIdentifier = *(ubpUnescapedRxBufferBuffer);\n            UBP_TxFlags txFlags = (UBP_TxFlags) *(ubpUnescapedRxBufferBuffer + PACKET_ID_SIZE);\n            \n            if (UBP_receivedPacket) {\n                \n                void *packetBuffer = (ubpUnescapedRxBufferBuffer + PACKET_ID_SIZE + 1);  // skip <identifier length> + <tx flags length>\n                UBP_receivedPacket(packetIdentifier, txFlags, packetBuffer);\n            }\n            \n        } else {\n            \n            Serial.println(\"Incoming packet checksum invalid\");\n            \n            // Reset\n            ubpRxBufferLength = 0;\n            ubpUnescapedRxBufferBufferLength = 0;\n            \n            if (UBP_incomingChecksumFailed) {\n                \n                UBP_incomingChecksumFailed();\n            }\n        }\n        \n    }  // else haven't RX'd final fragment yet, keep waiting\n}\n*/\n\n// only needed to retreive the data for testing\nvoid getTxBuffer(char *txBuffer, int *txBufferLength) {\n    for (int i=0; i<ubpTxBufferLength; i++) {\n        txBuffer[i] = ubpTxBuffer[i];\n    }\n    *txBufferLength = ubpTxBufferLength;\n}\n\nbool UBP_queuePacketTransmission(unsigned short packetIdentifier, UBP_TxFlags txFlags, const char *packetBytes, unsigned short byteCount) {\n    \n    if (UBP_isTxPending) {  // Preexisting transmission still in progress\n        \n        // Serial.println(\"Could not queue packet because preexisting transmission is still in progress\");\n        return false;\n        \n    } else {  // Ready to queue a new transmission\n        \n        if (hostIsConnected == false) return ubpTxBuffer;\n        \n        ubpTxBufferLength = 0;\n        \n        // Start off with the END_BYTE as required for SLIP\n        ubpTxBuffer[0] = END_BYTE;\n        ubpTxBufferLength++;\n        \n        // Prepend the packet identifier\n        memcpy(ubpTxBuffer + ubpTxBufferLength, &packetIdentifier, sizeof(packetIdentifier));  // TODO: Escape the identifier\n        ubpTxBufferLength += sizeof(packetIdentifier);\n        \n        // Append the transmission flags\n        ubpTxBuffer[ubpTxBufferLength] = txFlags;\n        ubpTxBufferLength++;\n        \n        // Copy the escaped contents of packetBytes into the TX buffer following the packet identifier\n        int escapedByteCount = _UBP_makeEscapedCopy(packetBytes, byteCount, ubpTxBuffer + ubpTxBufferLength, BUFFER_LENGTH);\n        if (escapedByteCount != -1) {  // Escaping succeeded\n            \n            ubpTxBufferLength += escapedByteCount;\n            int payloadLength = ubpTxBufferLength - 1;  // Length so far minus leading END byte    //sizeof(packetIdentifier) + escapedByteCount;  // <identifier length> + <escaped content length>\n            \n            // Calculate and append checksum\n            byte checksumValue = CRC8(ubpTxBuffer + 1, payloadLength);  // Checksum over all payload bytes (minus the leading END byte, checksum, and trailing END byte)\n            *(ubpTxBuffer + ubpTxBufferLength) = checksumValue;\n            ubpTxBufferLength++;\n            \n            // Append trailing END byte\n            *(ubpTxBuffer + ubpTxBufferLength) = END_BYTE;\n            ubpTxBufferLength++;\n            \n            // Mark as ready to begin transmission\n            ubpTxBufferSentByteCount = 0;\n            UBP_isTxPending = true;\n            \n        } else {\n            \n            return false;  // Return false if we couldn't escape the content because it was going to overflow the output buffer\n        }\n    }\n    // FIXME: 2016-06-27: this was missing in the original code\n    return true;\n}\n\nint _UBP_makeEscapedCopy(const char *inputBuffer, unsigned short inputBufferLength, char *outputBuffer, unsigned short outputBufferLength) {\n    \n    unsigned int bytesCopied = 0;\n    const char *inputBytes = inputBuffer;  // Cast here to avoid compiler warnings later\n    \n    for (char i = 0; i < inputBufferLength; i++) {  // For each byte to append\n        \n        // Escape any control characters. Refer to Serial Line IP (SLIP) spec.\n        char aByte = *(inputBytes + i);\n        if (aByte ==  (char) ESCAPE_BYTE) {  // Escape an ESCAPE_BYTE\n//      if (aByte == ESCAPE_BYTE) {  // Escape an ESCAPE_BYTE\n            \n            if (bytesCopied + 1 >= outputBufferLength) return -1;  // Would¥ overflow destination buffer\n            else {\n                *(outputBuffer + bytesCopied++) = ESCAPE_BYTE;  // Write ESCAPE_BYTE to buffer and increment offset\n                *(outputBuffer + bytesCopied++) = ESCAPED_ESCAPE_BYTE;  // Write escaped ESCAPE_BYTE to buffer and increment offset\n            }\n            \n//        } else if (aByte == END_BYTE) {  // Escape an END_BYTE\n        } else if (aByte == (char) END_BYTE) {  // Escape an END_BYTE\n            \n            if (bytesCopied + 1 >= outputBufferLength) return -1;  // Would overflow destination buffer\n            else {\n                *(outputBuffer + bytesCopied++) = ESCAPE_BYTE;  // Write ESCAPE_BYTE to buffer and increment offset\n                *(outputBuffer + bytesCopied++) = ESCAPED_END_BYTE;  // Write escaped END_BYTE to buffer and increment offset\n            }\n            \n        } else {  // Not a control character\n            \n            if (bytesCopied >= outputBufferLength) return -1;  // Would overflow destination buffer\n            else *(outputBuffer + bytesCopied++) = aByte;  // Copy the unmolested byte to the buffer and increment offset\n        }\n    }\n    \n    return bytesCopied;\n}\n\n/*\n\nint _UBP_makeUnEscapedCopy(const char *inputBuffer, unsigned short inputBufferLength, char *outputBuffer) {\n    \n    bool done = false;\n    char * destinationBufferPtr = outputBuffer;\n    const char * sourceBufferPtr = inputBuffer;\n    \n    // UNESCAPE END Sequence_\n    while (!done && (sourceBufferPtr - inputBuffer) < inputBufferLength) {\n        \n        char * substringPtr = strstr(sourceBufferPtr, escapedEndSequence_);\n        if (substringPtr == NULL) done = true;\n        else {\n            \n            // Copy bytes between last-copied byte and next escape byte\n            char lengthToCopy = substringPtr - sourceBufferPtr;  // How many bytes between last byte copied and next escape byte\n            memcpy(destinationBufferPtr, sourceBufferPtr, lengthToCopy);\n            destinationBufferPtr += lengthToCopy;\n            sourceBufferPtr += lengthToCopy;\n            \n            // Replace escaped source sequence with unescaped version during copy, increment pointer\n            memcpy(destinationBufferPtr, endSequence_, sizeof(endSequence_));\n            destinationBufferPtr += sizeof(endSequence_);\n            \n            // Increment pointer past escaped end Sequence_\n            sourceBufferPtr += sizeof(escapedEndSequence_);\n        }\n    }\n    \n    // UNESCAPE ESCAPE SEQUENCE\n    done = false;\n    while (!done && (sourceBufferPtr - inputBuffer) < inputBufferLength) {\n        \n        char * substringPtr = strstr(sourceBufferPtr, escapedEscapeSequence_);\n        if (substringPtr == NULL) done = true;\n        else {\n            \n            // Copy bytes between last-copied byte and next escape byte\n            char lengthToCopy = substringPtr - sourceBufferPtr;  // How many bytes between last byte copied and next escape byte\n            memcpy(destinationBufferPtr, sourceBufferPtr, lengthToCopy);\n            destinationBufferPtr += lengthToCopy;\n            sourceBufferPtr += lengthToCopy;\n            \n            // Replace escaped source sequence with unescaped version during copy, increment pointer\n            memcpy(destinationBufferPtr, escapeSequence_, sizeof(escapeSequence_));\n            destinationBufferPtr += sizeof(escapeSequence_);\n            \n            // Increment pointer past escaped end Sequence_\n            sourceBufferPtr += sizeof(escapedEscapeSequence_);\n        }\n    }\n    \n    // COPY ANY TRAILING BYTES\n    char lengthToCopy = (inputBuffer + inputBufferLength) - sourceBufferPtr;  // How many bytes remain to be copied\n    memcpy(destinationBufferPtr, sourceBufferPtr, lengthToCopy);\n    destinationBufferPtr += lengthToCopy;\n    sourceBufferPtr += lengthToCopy;\n    \n    return (destinationBufferPtr - outputBuffer);  // Return the total number of bytes copied to the destination buffer\n}\n\n */\n\nvoid _UBP_hostDisconnected() {\n    \n    hostIsConnected = false;\n    \n    // Reset TX subsystem\n    UBP_isTxPending = false;\n    \n    // Reset RX subsystem\n    ubpRxBufferLength = 0;\n    \n    // Invoke user callback\n    // 2016-06-28: commentet out for testing\n//    if (UBP_didDisconnect) UBP_didDisconnect();\n}\n\n\n// RFduino EVENTS\n// ----------------------------------------------------\n//void SimbleeBLE_onAdvertisement(bool start) {\n//    \n//    if (UBP_didAdvertise) UBP_didAdvertise(start);\n//}\n//\nvoid SimbleeBLE_onConnect() {\n    \n    hostIsConnected = true;\n    \n    // 2016-06-29: uncommented and added for testing purposes\n    // if (UBP_didConnect) UBP_didConnect();\n    UBP_isTxPending = false;\n}\n\n//void SimbleeBLE_onReceive(char *data, int len) {\n//    \n//    _UBP_ingestRxBytes(data, len);\n//}\n\nvoid SimbleeBLE_onDisconnect() {\n    \n    _UBP_hostDisconnected();\n}\n\n\n"
  },
  {
    "path": "LibreMonitor/ViewControllers/AdjustmentsTableViewController.swift",
    "content": "//\n//  AdjustmentsTableViewController.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 27.05.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\nimport UIKit\n\nclass AdjustmentsTableViewController: UITableViewController, UITextFieldDelegate {\n    \n\n    let numberFormatter = NumberFormatter()\n    \n    @IBOutlet weak var offsetTextField: UITextField!\n    @IBOutlet weak var slopeTextField: UITextField!\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        numberFormatter.numberStyle = .decimal\n        offsetTextField.delegate = self // for handling return key\n        slopeTextField.delegate = self\n        \n        let bloodGlucoseOffset = UserDefaults.standard.double(forKey: \"bloodGlucoseOffset\")\n        let bloodGlucoseSlope = UserDefaults.standard.double(forKey: \"bloodGlucoseSlope\")\n        \n        offsetTextField.text = numberFormatter.string(from: NSNumber(value: bloodGlucoseOffset))\n        slopeTextField.text = numberFormatter.string(from: NSNumber(value: bloodGlucoseSlope))\n                \n        self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(AdjustmentsTableViewController.didTapSaveButton))\n        self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .undo, target: self, action: #selector(AdjustmentsTableViewController.didTapUndoButton))\n    }\n    \n    func textFieldShouldReturn(_ textField: UITextField) -> Bool {\n        checkInputForTextField(textField)\n        return true\n    }\n    \n    \n    func didTapSaveButton() {\n        checkInputForTextField(offsetTextField)\n        checkInputForTextField(slopeTextField)\n    }\n    \n    func checkInputForTextField(_ textField: UITextField) {\n        guard let aNumber = numberFormatter.number(from: textField.text!) else {\n            displayAlertForTextField(textField)\n            return\n        }\n        \n        switch textField {\n        case offsetTextField:\n            let bloodGlucoseOffset = Double(aNumber)\n            UserDefaults.standard.set(bloodGlucoseOffset, forKey: \"bloodGlucoseOffset\")\n        case slopeTextField:\n            let bloodGlucoseSlope = Double(aNumber)\n            UserDefaults.standard.set(bloodGlucoseSlope, forKey: \"bloodGlucoseSlope\")\n        default:\n            fatalError(\"Fatal Error in \\(#file): textField not handled in switch case\")\n            break\n        }\n        \n        // update table view\n        NotificationCenter.default.post(name: Notification.Name(rawValue: \"updateBloodSugarTableViewController\"), object: self)\n        \n        resignFirstResponder()\n        navigationController?.dismiss(animated: true, completion: nil)\n    }\n    \n    func didTapUndoButton() {\n        resignFirstResponder()\n        navigationController?.dismiss(animated: true, completion: nil)\n    }\n    \n    func displayAlertForTextField(_ textField: UITextField) {\n        let message = String(format: \"\\\"\\(textField.text!)\\\" ist kein gültiger Wert, bitte korrigieren.\", [])\n        let alertController = UIAlertController(title: \"Ungültige Eingabe\", message: message, preferredStyle: .alert)\n        let defaultAction = UIAlertAction(title: \"OK\", style: .default, handler: nil)\n        alertController.addAction(defaultAction)\n        \n        present(alertController, animated: true, completion: nil)\n    }\n}\n"
  },
  {
    "path": "LibreMonitor/ViewControllers/BloodSugarTableViewController.swift",
    "content": "//\n//  TableViewController.swift\n//\n//  Created by Uwe Petersen on 01.02.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\n\nimport UIKit\nimport CoreBluetooth\nimport CoreData\nimport UserNotifications\n\n\nclass BloodSugarTableViewController: UITableViewController, SimbleeManagerDelegate {\n    \n    var coreDataStack = CoreDataStack()\n    var simbleeManager = SimbleeManager()\n    \n    var sensorData: SensorData?\n    var trendMeasurements: [Measurement]?\n    var historyMeasurements: [Measurement]?\n    var batteryVoltage = 0.0\n    \n    var bloodGlucoseOffset: Double!\n    var bloodGlucoseSlope: Double!\n    var sensor: LibreSensor?\n    \n\n    var deviceID = \"-\"\n    var temperatureString = \"_\"\n    \n    var timeInMinutesSinceStartOfSensor = 0\n    var timeOfLastScan = Date()\n    var transmissionDuration = TimeInterval()\n    var timeOfTransmissionStart = Date()\n    \n    \n    var dateFormatter = DateFormatter()\n    var timeFormatter = DateFormatter()\n    \n    var notificationTimer = Timer()\n    var showNotification = true\n    \n    \n    /// Enum for the sections of this table view\n    fileprivate enum Section: Int {\n        case connectionData, generalData, graph, trendData, historyData\n        /// Count of enum cases (has to be adjusted to this/each very enum)\n        /// Source: http://stackoverflow.com/questions/27094878/how-do-i-get-the-count-of-a-swift-enum\n        static let count: Int = {\n            var max: Int = 0\n            while let _ = Section(rawValue: max) { max += 1 }\n            return max\n        }()\n    }\n    \n    \n    @IBAction func doRefresh(_ sender: UIRefreshControl) {\n        sender.endRefreshing()\n        tableView.reloadData()\n    }\n    \n    // MARK: - View Controller life ciycle\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        // Do any additional setup after loading the view, typically from a nib.\n        // self.navigationItem.leftBarButtonItem = self.editButtonItem()\n        simbleeManager.delegate = self\n        self.title = \"LibreMonitor\"\n        \n        let connectButtonTitle = connectButtonTitleForState(simbleeManager.state)\n        let conncectButton = UIBarButtonItem(title: connectButtonTitle, style: .plain, target: self, action: #selector(BloodSugarTableViewController.didTapConnectButton))\n        self.navigationItem.rightBarButtonItem = conncectButton\n        \n        bloodGlucoseOffset = UserDefaults.standard.double(forKey: \"bloodGlucoseOffset\")\n        bloodGlucoseSlope = UserDefaults.standard.double(forKey: \"bloodGlucoseSlope\")\n        if bloodGlucoseSlope <= 0.00001 {\n            bloodGlucoseSlope = 1.0\n            UserDefaults.standard.set(bloodGlucoseSlope, forKey: \"bloodGlucoseSlope\")\n        }\n        \n        \n        dateFormatter.dateFormat = \"yyyy-MM-dd\"\n        timeFormatter.dateFormat = \"HH:mm:ss\"\n    }\n    \n    override func viewWillAppear(_ animated: Bool) {\n        super.viewWillAppear(animated)\n        \n        bloodGlucoseOffset = UserDefaults.standard.double(forKey: \"bloodGlucoseOffset\")\n        bloodGlucoseSlope = UserDefaults.standard.double(forKey: \"bloodGlucoseSlope\")\n        \n        // Notification for updating table view after application did become active again\n        NotificationCenter.default.addObserver(self, selector: #selector(BloodSugarTableViewController.updateTableView), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil)\n        // Notification for updating table view after having changed the offset and/of slope\n        NotificationCenter.default.addObserver(self, selector: #selector(BloodSugarTableViewController.updateTableView), name: NSNotification.Name(rawValue: \"updateBloodSugarTableViewController\"), object: nil)\n    }\n    \n    override func viewWillDisappear(_ animated: Bool) {\n        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil)\n        super.viewWillDisappear(true)\n    }\n    \n    \n    func didTapConnectButton() {\n        switch (simbleeManager.state) {\n        case .Unassigned:\n            simbleeManager.scanForSimblee()\n        case .Scanning:\n            simbleeManager.centralManager.stopScan()\n            simbleeManager.state = .Disconnected\n        case .Connected, .Connecting, .Notifying:\n            simbleeManager.disconnectManually()\n        case .Disconnected, .DisconnectedManually:\n            simbleeManager.connect()\n        }\n    }\n    \n    \n    func updateTableView() {\n        self.tableView.reloadData()\n    }\n    \n\n    // MARK: - Table View\n    \n    override func numberOfSections(in tableView: UITableView) -> Int {\n        return Section.count\n    }\n    \n    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {\n        switch Section(rawValue: section)! {\n        case .connectionData: return 3\n        case .generalData: return 7\n        case .graph: return 1\n        case .trendData: return 16\n        case .historyData: return 32\n        }\n    }\n    \n    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {\n        \n        if (indexPath as NSIndexPath).section == 2 {\n            \n            // Draw graph\n            let cell = tableView.dequeueReusableCell(withIdentifier: \"BloodSugarGraphTableViewCell\", for: indexPath)\n            guard let theCell = cell as? BloodSugarGraphViewTableViewCell else {return cell}\n\n            if let trendMeasurements = trendMeasurements, let historyMeasurements = historyMeasurements {\n                theCell.lineChartView.trendMeasurements = trendMeasurements\n                theCell.lineChartView.historyMeasurements = historyMeasurements\n                theCell.lineChartView.setGlucoseCharts(trendMeasurements, historyMeasurements: historyMeasurements)\n                theCell.setNeedsDisplay()\n                theCell.lineChartView.setNeedsDisplay()\n            }\n            return theCell\n        } else {\n            let cell = tableView.dequeueReusableCell(withIdentifier: \"Cell\", for: indexPath)\n            self.configureCell(cell, atIndexPath: indexPath)\n            return cell\n        }\n    }\n    \n    override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {\n        // Return false if you do not want the specified item to be editable.\n        return true\n    }\n    \n    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {\n        if (indexPath as NSIndexPath).section == 0 && (indexPath as NSIndexPath).row == 0 {\n            didTapConnectButton()\n        } else if (indexPath as NSIndexPath).section == 0 && (indexPath as NSIndexPath).row == 2 {\n            // ChangeBloodGlucoseAdjustments\n            performSegue(withIdentifier: \"ChangeBloodGlucoseAdjustments\", sender: self)\n        }\n    }\n    \n    \n    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {\n        switch section {\n        case 0: return \"Connection\"\n        case 1: return \"General data\"\n        case 2:\n            let seconds = (NSDate() as NSDate).timeIntervalSince(timeOfLastScan).truncatingRemainder(dividingBy: 60.0)\n            let minutes = (Date().timeIntervalSince(timeOfLastScan) - seconds) / 60.0\n            return String(format: \"Graph from %2.0f:%02.0f minutes ago\", arguments: [minutes, seconds])\n        case 3: return \"Last 15 minutes\"\n        case 4: return \"Last eight hours\"\n        case 5: return \"Neue Letzte 15 Minuten\"\n        case 6: return \"Neue Letzte 8 Stunden\"\n        default: return nil\n        }\n    }\n    \n    \n    func configureCell(_ cell: UITableViewCell, atIndexPath indexPath: IndexPath) {\n        cell.backgroundColor = UIColor.white\n        cell.detailTextLabel?.textColor = UIColor.black\n        cell.accessoryType = .none\n        \n        switch Section(rawValue: (indexPath as NSIndexPath).section)! {\n        case .connectionData:\n            switch (indexPath as NSIndexPath).row {\n            case 0:\n                cell.textLabel?.text = \"Simblee status\"\n                cell.detailTextLabel?.text = simbleeManager.state.rawValue\n                cell.backgroundColor = colorForConnectionState()\n            case 1:\n                cell.textLabel?.text = \"Last scan:\"\n                if let sennsorData = sensorData {\n                    cell.detailTextLabel?.text = String(format: \"on \\(dateFormatter.string(from: sennsorData.date as Date)), at \\(timeFormatter.string(from: sennsorData.date as Date)) o'clock, in %.2f s\", arguments: [transmissionDuration])\n                    \n                    if Date().timeIntervalSince(sennsorData.date as Date) > 240.0 {\n                        cell.backgroundColor = UIColor.red\n                    }\n                }\n            case 2:\n                cell.textLabel?.text = \"Offset / Slope:\"\n                cell.detailTextLabel?.text = String(format: \"%.0f mg/dl, %.4f\", arguments: [bloodGlucoseOffset, bloodGlucoseSlope])\n                cell.accessoryType = .disclosureIndicator\n            default: break\n            }\n        case .generalData:\n            switch (indexPath as NSIndexPath).row {\n            case 0:\n                cell.textLabel?.text = \"BM019 ID\"\n                cell.detailTextLabel?.text = deviceID\n            case 1:\n                var crcString = String()\n                var color = UIColor()\n                if let sensorData = sensorData {\n                    crcString += \", crcs: \\(sensorData.hasValidHeaderCRC), \\(sensorData.hasValidBodyCRC), \\(sensorData.hasValidFooterCRC)\"\n                    color = colorForSensorState( (sensorData.hasValidHeaderCRC && sensorData.hasValidBodyCRC && sensorData.hasValidFooterCRC) )\n                } else {\n                    crcString = \", nil\"\n                    color = UIColor.lightGray\n                }\n                cell.textLabel?.text = \"Sensor SN\"\n                if let sensor = sensor {\n                    cell.detailTextLabel?.text =  sensor.serialNumber + crcString // + \" (\" + sensor.prettyUid  + \")\"\n                } else {\n                    cell.detailTextLabel?.text = \"\"\n                }\n                cell.backgroundColor = color\n                \n                \n            case 2:\n                cell.textLabel?.text = \"Environment\"\n                cell.detailTextLabel?.text = String(format: \"%3.1f V\", arguments: [batteryVoltage]) + \", \" + temperatureString\n                if batteryVoltage < 3.0 {\n                    cell.backgroundColor = UIColor.orange\n                }\n            case 3:\n                cell.textLabel?.text = \"Blocks\"\n                if let sennsorData = sensorData {\n                    cell.detailTextLabel?.text = \"Trend: \\(sennsorData.nextTrendBlock), history: \\(sennsorData.nextHistoryBlock), minutes: \\(sennsorData.minutesSinceStart)\"\n                }\n            case 4:\n                cell.textLabel?.text = \"Glucose\"\n                \n                if let trendMeasurements = trendMeasurements {\n                    let currentGlucose = trendMeasurements[0].glucose\n                    let longDelta = currentGlucose - trendMeasurements[15].glucose\n                    let shortDelta = (currentGlucose - trendMeasurements[8].glucose) * 2.0 * 16.0/15.0\n                    let longPrediction = currentGlucose + longDelta\n                    let shortPrediction = currentGlucose + shortDelta\n                    cell.detailTextLabel?.text = String(format: \"%0.0f, Delta: %0.0f (%0.0f), Prognosis: %0.0f (%0.0f)\", arguments: [currentGlucose, longDelta, shortDelta, longPrediction, shortPrediction])\n                    if longPrediction < 70.0 || shortPrediction < 70.0 || longPrediction > 180.0 || shortPrediction > 180.0 || (abs(longDelta) > 30.0 && abs(shortDelta) > 30.0) {\n                        cell.detailTextLabel?.textColor = UIColor.red\n                    } else {\n                        cell.detailTextLabel?.textColor = UIColor.black\n                    }\n                }\n\n            case 5:\n                cell.textLabel?.text = \"Sensor started\"\n                if let sennsorData = sensorData {\n                    let minutes = sennsorData.minutesSinceStart\n                    let days = Int( Double(minutes) / 24.0 / 60.0 )\n                    let hours = Int( Double(minutes) / 60.0 ) - days*24\n                    let minutesRest = minutes - days*24*60 - hours*60\n                    cell.detailTextLabel?.text = String(format: \"%d day(s), %d hour(s) and %d minute(s) ago\", arguments: [days, hours, minutesRest])\n                }\n//                cell.detailTextLabel?.text = startOfSensorString\n            case 6:\n                cell.textLabel?.text = \"Sensor status\"\n                if let sennsorData = sensorData {\n                    cell.detailTextLabel?.text = sennsorData.state.description\n                } else {\n                    cell.detailTextLabel?.text = \"nil\"\n                }\n            default:\n                cell.textLabel?.text = \"Something ...\"\n                cell.detailTextLabel?.text = \"... didn't work\"\n            }\n        case .graph:\n            break\n            \n        case .trendData:\n            let index = (indexPath as NSIndexPath).row\n            if let measurements = trendMeasurements {\n                let timeAsString = timeFormatter.string(from: measurements[index].date as Date)\n                let dateAsString = dateFormatter.string(from: measurements[index].date as Date)\n                \n                cell.textLabel?.text = String(format: \"%0.1f mg/dl\", measurements[index].glucose)\n                \n                let rawString = String(format: \"%0d\", measurements[index].rawValue)\n//                let temp =  (Int(measurements[index].bytes[4] & 0x0F) << 6) + Int(measurements[index].bytes[3]) >> 2\n//                let hugo = Int(measurements[index].bytes[3] & 3)\n                let temp =  (Int(measurements[index].bytes[5] & 0x0F) << 8) + Int(measurements[index].bytes[4])\n                let hugo = Int(measurements[index].bytes[3])\n                cell.detailTextLabel?.text = \"\\(timeAsString), \\(rawString), \\(measurements[index].byteString), \\(temp), \\(hugo), \\(dateAsString), \\(index)\"\n            }\n\n        case .historyData:\n            let index = (indexPath as NSIndexPath).row\n            if let measurements = historyMeasurements {\n                let timeAsString = timeFormatter.string(from: measurements[index].date as Date)\n                let dateAsString = dateFormatter.string(from: measurements[index].date as Date)\n                \n                cell.textLabel?.text = String(format: \"%0.1f mg/dl\", measurements[index].glucose)\n                \n                let rawString = String(format: \"%0d\", measurements[index].rawValue)\n//                let temp =  (Int(measurements[index].bytes[4] & 0x0F) << 6) + Int(measurements[index].bytes[3]) >> 2\n//                let hugo = Int(measurements[index].bytes[3] & 3)\n                let temp =  (Int(measurements[index].bytes[5] & 0x0F) << 8) + Int(measurements[index].bytes[4])\n                let hugo = Int(measurements[index].bytes[3])\n                cell.detailTextLabel?.text = \"\\(timeAsString), \\(rawString), \\(measurements[index].byteString), \\(temp), \\(hugo), \\(dateAsString), \\(index)\"\n            }\n        }\n    }\n    \n    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {\n        if (indexPath as NSIndexPath).section == 2 {\n            return CGFloat(300)\n        }\n        return CGFloat(20)\n    }\n    override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {\n        return CGFloat(20)\n    }\n    \n    \n    // MARK: - Navigation\n    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {\n        print(\"Prepare for segue\")\n        if segue.identifier == \"ChangeBloodGlucoseAdjustments\" {\n            print(\"Segue ChangeBloodGlucoseAdjustments\")\n        }\n    }\n    \n    \n    // MARK: - SimbleeManagerDelegate \n    \n    func simbleeManagerPeripheralStateChanged(_ state: SimbleeManagerState) {\n        self.navigationItem.rightBarButtonItem?.title? = connectButtonTitleForState(state)\n        \n        switch state {\n        case .Unassigned, .Connecting, .Connected, .Scanning, .Disconnected, .DisconnectedManually:\n            self.triggerNotificationContentForBadgeIcon(value: 0)  // no badge number if not notifying\n        case .Notifying:\n            break\n        }\n        tableView.reloadData()\n    }\n    \n    func simbleeManagerReceivedMessage(_ messageIdentifier: UInt16, txFlags: UInt8, payloadData: Data) {\n        print(\"Received SLIP payload with ID = \\(messageIdentifier)\")\n\n        switch messageIdentifier {\n        case 0x2002: // system information data, including UID (e.g. E0:07:A0:00:00:0C:48:BD\")\n            \n            // Convention: System Information data is the first packet sent via bluetooth, thus delete all internal data and reload table view\n            \n            timeOfTransmissionStart = Date()\n            deviceID = \"-\"\n            \n            print(payloadData.debugDescription)\n            \n            var systemInformationData = SystemInformationDataType(uid: (0, 0, 0, 0, 0, 0, 0, 0), resultCode: 0, responseFlags: 0, infoFlags: 0, errorCode: 0)\n            (payloadData as NSData).getBytes(&systemInformationData, length: payloadData.count)      // get payload data into corresponding memory -> tuples\n            \n            print(String(format: \"result code %02X\", arguments: [systemInformationData.resultCode]))\n            print(String(format: \"response flags %02X\", arguments: [systemInformationData.responseFlags]))\n            print(String(format: \"info flags %02X\", arguments: [systemInformationData.infoFlags]))\n            print(String(format: \"error code %02X\", arguments: [systemInformationData.errorCode]))\n            \n            let uidString = systemInformationData.uidString()\n            sensor = LibreSensor(withUID: uidString)\n            \n            //  Convention: System Information data is the first packet sent from RFDuino, thus delete all internal data and reload table view\n            tableView.reloadData()\n            \n        case 0x2005: // Battery\n            \n            var batteryDataPayload = BatteryDataType(voltage: 0, temperature: 0)\n            \n            (payloadData as NSData).getBytes(&batteryDataPayload, length:payloadData.count)\n            batteryVoltage = Double(batteryDataPayload.voltage)\n            temperatureString = String(format: \"%4.1f °C\", arguments: [batteryDataPayload.temperature])\n            \n        case 0x1007: // all data bytes (all 344 bytes, i.e. 43 blocks)\n            print(\"received all data bytes packet\")\n\n            var bytes = [UInt8](repeating: 0, count: 344)\n            (payloadData as NSData).getBytes(&bytes, length: 344)\n            sensorData = SensorData(bytes: bytes, date: Date())\n            if let sennsorData = sensorData {\n                trendMeasurements = sennsorData.trendMeasurements(bloodGlucoseOffset, slope: bloodGlucoseSlope)\n                historyMeasurements = sennsorData.historyMeasurements(bloodGlucoseOffset, slope: bloodGlucoseSlope)\n                notificationForGlucoseMeasurements(trendMeasurements!)\n\n                if let historyMeasurements = historyMeasurements  ,  sennsorData.hasValidBodyCRC && sennsorData.hasValidHeaderCRC && sennsorData.state == .ready {\n                   \n                    // fetch all records that are newer than the oldest history measurement of the new data\n                    let dateFormatter = DateFormatter()\n                    dateFormatter.dateFormat = \"yyyy-MM-dd HH:mm:ss\"\n                    \n                    let request = BloodGlucose.fetchRequest() as NSFetchRequest<BloodGlucose>\n                    do {\n                        let fetchedBloodGlucoses = try coreDataStack.managedObjectContext.fetch(request)\n                        \n                        // Loop over all and check if new data exists and store the new data if not yet existent \n                        historyMeasurements.forEach({measurement in\n                            \n                            var storeMeasurement = true\n                            \n                            // Check if there is already a record stored for the same time\n                            for bloodGlucose in fetchedBloodGlucoses {\n\n                                // Store value if dates are less than two mintues apart from each other (in either direction)\n                                if let bloodGlucoseDate = bloodGlucose.date, abs(bloodGlucoseDate.timeIntervalSince(measurement.date)) < 2.0 * 60.0 {\n                                    storeMeasurement = false\n                                    break\n                                }\n                            }\n                            // Store if there isn't a measurement yet for this time and if it is a possible value (i.e. greater than zero and greater than offset)\n                            // if storeMeasurement && (measurement.glucose > bloodGlucoseOffset) && (measurement.glucose > 0.0) {\n                            // Weird xcode 8.1 error enforces to reverse the comparison\n                            if storeMeasurement && (bloodGlucoseOffset < measurement.glucose) && (0.0 < measurement.glucose) {\n                                if let glucose = NSEntityDescription.insertNewObject(forEntityName: \"BloodGlucose\", into: coreDataStack.managedObjectContext) as? BloodGlucose {\n                                    glucose.date = measurement.date as NSDate?\n                                    glucose.bytes = measurement.byteString\n                                    glucose.value = measurement.glucose\n                                    glucose.dateString = dateFormatter.string(from: measurement.date as Date)\n                                }\n                            }\n                        })\n                        coreDataStack.saveContext()\n \n                    } catch {\n                        fatalError(\"Failed to fetch BloodGlucose: \\(error)\")\n                    }\n                }\n                \n                \n            } else {\n                trendMeasurements = nil\n                historyMeasurements = nil\n            }\n            tableView.reloadData()\n            \n            \n        case 0x2001: // IDN data, including device ID, example: RESPONSE CODE: 0 LENGTH: 15, DEVICE ID: 4E 46 43 20 46 53 32 4A 41 53 54 32 0, ROM CRC: 75D2\n            \n            // Convention: IDN data is the last packet sent via bluetooth\n            \n            print(payloadData.debugDescription)\n            \n            var idnData = IDNDataType(resultCode: 0, deviceID: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), romCRC: (0, 0))\n            (payloadData as NSData).getBytes(&idnData, length: payloadData.count)      // get payload data into corresponding memory -> tuples\n            \n            print(String(format: \"resultCode %02X\", arguments: [idnData.resultCode]))\n            \n            let deviceIDString = idnData.deviceIDString()\n            print(deviceIDString)\n            \n            self.deviceID = deviceIDString\n            \n            timeOfLastScan = Date()\n            \n            transmissionDuration = Date().timeIntervalSince(timeOfTransmissionStart)\n            \n            // Convention: the idn data is the last packet sent from RFDuino within a cycle, thus reload table view after having received it\n            tableView.reloadData()\n            \n            \n        default:\n            break\n        }\n    }\n    \n    \n    // MARK: - Helper functions\n    \n    func colorForConnectionState() -> UIColor {\n        switch (simbleeManager.state) {\n        case .Unassigned, .Disconnected, .DisconnectedManually:\n            return UIColor.red\n        case .Scanning, .Connecting, .Connected:\n            return UIColor(red: CGFloat(0.9), green: CGFloat(0.9), blue: CGFloat(1), alpha: CGFloat(1))\n        case .Notifying:\n            return UIColor.green\n        }\n    }\n    \n    func colorForSensorState(_ bool: Bool) -> UIColor {\n        if bool == false {\n            return UIColor.red\n        }\n        return UIColor.white\n    }\n    \n    func connectButtonTitleForState(_ state: SimbleeManagerState) -> String {\n        switch state {\n        case .Unassigned, .Disconnected, .DisconnectedManually:\n            return \"connect\"\n        case .Connected, .Connecting, .Scanning, .Notifying:\n            return \"disconnect\"\n        }\n    }\n    \n    // MARK: - Notifications and badge icon\n    \n    func notificationForGlucoseMeasurements(_ trendMeasurements: [Measurement] ) {\n        \n        let currentGlucose = trendMeasurements[0].glucose\n        let longDelta = currentGlucose - trendMeasurements[15].glucose\n        let shortDelta = (currentGlucose - trendMeasurements[8].glucose) * 2.0 * 16.0/15.0\n        let longPrediction = currentGlucose + longDelta\n        let shortPrediction = currentGlucose + shortDelta\n        \n        // Show alert if conditions are reached\n        if ((longPrediction > 0 && (longPrediction < 60.0 || longPrediction > 180.0)) ||\n            (shortPrediction > 0 && (shortPrediction < 66.0 || shortPrediction > 180.0)) ||\n            (abs(longDelta) > 30.0 && abs(shortDelta) > 30.0)) && showNotification {\n            \n\n            let body = String(format: \"%0.0f --> %0.0f (%0.0f), Delta: %0.0f (%0.0f)\", arguments: [currentGlucose, longPrediction, shortPrediction, longDelta, shortDelta])\n            let content = self.notificationContentForBloodSugarWarning(body)\n            let timeTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.5, repeats: false)\n            let request = UNNotificationRequest(identifier: \"LocalNotification\", content: content, trigger: timeTrigger)\n            UNUserNotificationCenter.current().add(request) { error in\n                if let error = error {\n                    // Do something with error\n                    print(\"Error, blood sugar notification could not be triggered due to: \\(error)\")\n                } else {\n                    // Request was added successfully\n                    print(\"triggered blood sugar notification\")\n                }\n            }\n            \n            // timer to hide notification for 10 minutes\n            showNotification = false\n            notificationTimer = Timer.scheduledTimer(timeInterval: TimeInterval(10.0*60.0), target: self,  selector: #selector(BloodSugarTableViewController.notificationTimerFired), userInfo: nil, repeats: false)\n        }\n        //        UIApplication.sharedApplication().cancelAllLocalNotifications()\n        \n        self.triggerNotificationContentForBadgeIcon(value: Int(round(longPrediction)))\n    }\n    \n    \n    func triggerNotificationContentForBadgeIcon(value: Int) {\n        \n        UIApplication.shared.applicationIconBadgeNumber = value\n\n//        let content = UNMutableNotificationContent()\n//        content.badge = NSNumber(value: value)\n//\n//        let timeTrigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 1, repeats: false)\n//        let request = UNNotificationRequest(identifier: \"Badge\", content: content, trigger: timeTrigger)\n//        UNUserNotificationCenter.current().add(request) { error in\n//            if let error = error {\n//                // Do something with error\n//                print(\"Error, badge notification could not be triggered due to \\(error)\")\n//            } else {\n//                // Request was added successfully\n//                print(\"triggered badge notification\")\n//            }\n//        }\n    }\n    \n    \n    /// Returns a UNMutableNotificationContent with a body\n    ///\n    /// - parameter body: body to be displayd\n    ///\n    /// - returns: the notification content\n    func   notificationContentForBloodSugarWarning(_ body: String) -> UNMutableNotificationContent {\n        \n        let content = UNMutableNotificationContent()\n        content.title = \"Glukose beachten\"\n        content.subtitle = \"Notification Subtitle\"\n        content.body = body\n        //        content.badge = 1\n        content.sound = UNNotificationSound.default()\n        content.categoryIdentifier = \"GLUCOSE_WARNING_CATEGORY\"\n        content.userInfo = [\"UUID\": \"123456789\" ] // assign a unique identifier to the notification so that we can retrieve it later\n        return content\n    }\n    \n    \n    func notificationTimerFired() {\n        showNotification = true\n    }\n}\n\n\n\n"
  },
  {
    "path": "LibreMonitor/Views/BloodSugarGraphView.swift",
    "content": "//\n//  BloodSugarGraphView.swift\n//\n//  Created by Uwe Petersen on 23.03.16.\n//\n//  Blood sugar data ranges from time of last scan to approx 8 hours before. This data shall be plotted completeley. \n//  But the inital x-range of the graph shall be from the current time/date to 8 hours backwards. \n//  The user might pan and zoom to see other parts of the data.\n\nimport Foundation\nimport UIKit\nimport Charts\n\nclass BloodSugarGraphView: LineChartView {\n\n    var trendMeasurements: [Measurement]?\n    var historyMeasurements: [Measurement]?\n    \n    lazy var dateValueFormatter: DateValueFormatter = {\n        let dateFormatter = DateFormatter()\n        dateFormatter.dateFormat = \"HH:mm\"\n        return DateValueFormatter(dateFormatter: dateFormatter)\n    }()\n\n    \n    // Just the outlets are needed here, for these UI elements to be accessible from the corresponding parent table view controller\n    // target action and that stuff is then all handled from within the table view controller\n    \n    required init?(coder aDecoder: NSCoder) {\n        super.init(coder: aDecoder)\n    }\n    \n    /// Draws a line chart with glucose over time for trend and history measurments.\n    ///\n    /// - parameter trendMeasurements:   trend measurement data (16 values for now and last 15 minutes)\n    /// - parameter historyMeasurements: history measurement data (32 values for last eight hours, each beeing 15 minutes apart)\n    func setGlucoseCharts(_ trendMeasurements: [Measurement]?, historyMeasurements: [Measurement]?) {\n        \n        self.noDataText = \"No blood sugar data available\"\n        \n        guard let trendMeasurements = trendMeasurements, let historyMeasurements = historyMeasurements else {return}\n        \n        // Trend data set (data needs to be ordered from lowest x-value to highest x-value)\n        var trendEntries = [ChartDataEntry]()\n        trendMeasurements.reversed().forEach{\n            let timeIntervall = $0.date.timeIntervalSince1970\n            trendEntries.append(ChartDataEntry(x: timeIntervall, y: $0.glucose))\n        }\n        let trendLineChartDataSet = LineChartDataSet(values: trendEntries, label: \"Trend\")\n\n        // History data set (data needs to be ordered from lowest x-value to highest x-value)\n        var historyEntries = [ChartDataEntry]()\n        historyMeasurements.reversed().forEach{\n            let timeIntervall = $0.date.timeIntervalSince1970\n            historyEntries.append(ChartDataEntry(x: timeIntervall, y: $0.glucose))\n        }\n        let historyLineChartDataSet = LineChartDataSet(values: historyEntries, label: \"History\")\n        \n        // format data sets and create line chart with the data sets\n        formatLineChartDataSet(historyLineChartDataSet)\n        formatLineChartDataSet(trendLineChartDataSet)\n        let lineChartData = LineChartData(dataSets: [historyLineChartDataSet, trendLineChartDataSet])\n        print(lineChartData.debugDescription)\n        \n        lineChartData.setValueFont(NSUIFont.systemFont(ofSize: CGFloat(9.0)))\n        \n        // Line for upper and lower threshold of ideal glucose values\n        let lowerLimitLine = ChartLimitLine(limit: 70.0)\n        let upperLimitLine = ChartLimitLine(limit: 100.0)\n        self.rightAxis.addLimitLine(lowerLimitLine)\n        self.rightAxis.addLimitLine(upperLimitLine)\n        self.rightAxis.drawLimitLinesBehindDataEnabled = true\n        \n        // the blood sugar graph\n        self.data = lineChartData\n        self.chartDescription?.text = \"LibreMonitor\"\n        self.chartDescription?.font = NSUIFont.systemFont(ofSize: CGFloat(4))\n        \n        self.xAxis.valueFormatter = dateValueFormatter\n\n        // Display the last 8 hours (no matter of the date range of the data to be plotted)\n\n        let oldXAxisMaximum = self.xAxis.axisMaximum          // i.e. date when the chart was refreshed last time\n        let highestXValue = lineChartData.xMax                // i.e. date of last scan (or sample)\n        self.xAxis.axisMaximum = Date().timeIntervalSince1970 // set maximum to current date\n\n        \n        // Adjust zoom and x-offset\n        if self.xAxis.axisMaximum - highestXValue > 10.0 * 60.0 {\n            // if last sample was more than 10 minutes ago, zoom out such that all the last 8 hours are displayed. The rest of the data can be displayed e.g. by paning\n            self.fitScreen()\n            let xTimeRange = self.xAxis.axisMaximum - self.xAxis.axisMinimum\n            let eightHours = 8.0 * 3600.0\n            let scaleX = xTimeRange / eightHours\n            let xOffset = xTimeRange - eightHours\n            self.zoom(scaleX: CGFloat(scaleX), scaleY: 1, x: CGFloat(xOffset), y: 0)\n        } else {\n            // otherwise keep zoom ratio but shift line to the left about the amount of time since the last date the chart was refresehd\n            let offsetXMaximum = self.xAxis.axisMaximum - oldXAxisMaximum\n            self.zoom(scaleX: 1, scaleY: 1, x: CGFloat(offsetXMaximum), y: 0)\n        }\n        \n        self.notifyDataSetChanged()\n    }\n    \n    \n    /// Formats the line and the data points.\n    ///\n    /// Formatted are circle radius, line width and line mode (cubic)\n    ///\n    /// - parameter lineChartDataSet: lineChartDataSet to be formatted\n    func formatLineChartDataSet (_ lineChartDataSet: LineChartDataSet) {\n        lineChartDataSet.circleRadius = CGFloat(3.0)\n        lineChartDataSet.mode = .cubicBezier\n        lineChartDataSet.cubicIntensity = 0.05\n        lineChartDataSet.lineWidth = lineChartDataSet.lineWidth * CGFloat(3.0)\n    }\n}\n\n\n/// Formatter class for time values (x-axis) of blood sugar graph.\n///\n/// The x-axis ticks are shown as time of day in \"HH:mm\"-format.\nclass DateValueFormatter: NSObject, IAxisValueFormatter {\n    var dateFormatter = DateFormatter()\n    \n    init(dateFormatter: DateFormatter) {\n        self.dateFormatter = dateFormatter\n//        self.dateFormatter.dateFormat = \"HH:mm\"\n        \n    }\n    func stringForValue(_ value: Double, axis: AxisBase?) -> String {\n        return dateFormatter.string(from: Date(timeIntervalSince1970: value))\n    }\n}\n"
  },
  {
    "path": "LibreMonitor/Views/BloodSugarGraphViewTableViewCell.swift",
    "content": "//\n//  BloodSugarGraphViewTableViewCell.swift\n//\n//  Created by Uwe Petersen on 23.03.16.\n//\n\nimport Foundation\nimport UIKit\nimport Charts\n\nclass BloodSugarGraphViewTableViewCell: UITableViewCell {\n    \n    \n    // Just the outlets are needed here, for these UI elements to be accessible from the corresponding parent table view controller\n    // target action and that stuff is then all handled from within the table view controller\n    @IBOutlet weak var barChartView: BloodSugarGraphView!\n    @IBOutlet weak var lineChartView: BloodSugarGraphView!\n    \n    required init?(coder aDecoder: NSCoder) {\n        super.init(coder: aDecoder)\n    }    \n}\n"
  },
  {
    "path": "LibreMonitor.ino",
    "content": "///\n///   LibreMonitor\n/// \n///   Copyright (c) 2015 Uwe Petersen, all right reserved\n///\n///   Wiring connections:\n///\n///      BM019            RFDuino/Simblee\n///      DIN:  pin 2      IRQ:  GPIO pin 2\n///      SS:   pin 3      SS:   GPIO pin 3\n///      MISO: pin 4      MISO: GPIO pin 4\n///      MOSI: pin 5      MOSI: GPIO pin 5\n///      SCK:  pin 6      SCK:  GPIO pin 6\n///      SS0:  pin 7      +3V-pin\n///      GND:  pin 10     GND-pin\n///\n///      BM019            BM019\n///      SS0:  pin 7       VDD:  pin 8 (Output 3,3V from BM019)\n///      \n///      BM019            Lipo Power source (I use a 100mAh lip which lasts a full day\n///      VIN:  pin 9      \"+\" of lipo / lipo charger\n///      GND:  pin 10     GND/\"-\" of lipo / lipo charger\n///\n///      You can place a switch between GND of lipo/lipo-charger and GND of the BM019 \n///\n///      If wired as suggested above, then you have to change the Simblee SPI pins for SS, MOSI, MISO and SCK. \n///      This is done in the variant.h file. In my case this file is located in\n///\n///         /Users/[my user name]/Library/Arduino15/packages/Simblee/hardware/Simblee/1.0.0/variants/Simblee\n///\n///      In this file set the defines for the SPI pins as follows:\n///\n///         #define PIN_SPI_SS           (3u)\n///         #define PIN_SPI_MOSI         (5u)\n///         #define PIN_SPI_MISO         (4u)\n///         #define PIN_SPI_SCK          (6u)\n///\n///\n///   Acknowledgements:\n///\n///      RFDuinoUBP\n///\n///         This code uses portions of RFduinoUB, which can be retrieved from \n///              https://github.com/cconway/RFduinoUBP under the following license:\n///         The MIT License (MIT)\n///         Copyright (c) 2015 cconway\n///         Permission is hereby granted, free of charge, to any person obtaining a copy\n///         of this software and associated documentation files (the \"Software\"), to deal\n///         in the Software without restriction, including without limitation the rights\n///         to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n///         copies of the Software, and to permit persons to whom the Software is\n///         furnished to do so, subject to the following conditions:\n///         The above copyright notice and this permission notice shall be included in all\n///         copies or substantial portions of the Software.\n///         THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n///         IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n///         FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n///         AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n///         LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n///         OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n///         SOFTWARE.\n///\n///      Solutions Cubed LLC  \n///\n///         The author is grateful to Solutions Cubed LLC, see http://www.solutions-cubed.com, \n///         for providing helpful code samples for their BM019 nfc module, portions of which are \n///         used within this code. \n///\n\n// Include application, user and local libraries\n#include <SimbleeBLE.h>\n#include <SimbleeForMobile.h>\n#include <SPI.h>               // the sensor communicates using SPI, so include the library\n// This code uses the SLIP protocol to transer the data via bluetooth, see https://github.com/cconway/RFduinoUBP\n#include <constants.h>\n#include <crc8.h>\n#include <data_types.h>\n#include <libUBP.h>\n#include <SPIstuff.h>\n\n\n// Define variables and constants\n\n/* CR95HF Commands */\n#define IDN               0x01  // identification number of CR95HF\n#define SELECT_PROTOCOL   0x02  // select protocol\n#define POLL              0x03  // poll\n#define SENDRECEIVE       0x04  // send and receive data (most commonly used)\n#define READ              0x05  // read values from registers internal to CR95HF\n#define WRITE             0x06  // write values to registers internal to CR95HF\n#define ECHO              0x55\n\n// send receive commands for ISO/IEC 15693 protocol\n#define INVENTORY               0x01  // receives information about tags in range\n#define STAY_QUIET              0x02  // selected unit will not send back a response\n#define READ_BLOCK              0x20  // read single block of memory from RF tag\n#define WRITE_BLOCK             0x21  // write single block to memory of RF tag\n#define LOCK_BLOCK              0x22  // permanently locks a block of memory on RF tag\n#define READ_BLOCKS             0x23  // reads multiple blocks of memory from RF tag\n#define WRITE_BLOCKS            0x24  // writes multiple blocks of memory to RF tag\n#define SELECT                  0x25  // used to select a specific tag for communication via the uid\n#define RESET_TO_READY          0x26  // resets RF tag to ready state\n#define WRITE_AFI               0x27  // writes application family identifier to RF tag\n#define LOCK_AFI                0x28  // permanently locks application family identifier\n#define WRITE_DSFID             0x29  // writes data storage format identifier to RF tag\n#define LOCK_DSFID              0x2A  // permanentlylocks data storage format identifier\n#define GET_SYSTEM_INFORMATION  0x2B  // gets information from RF tag that includes memory\n// block size in bytes and number of memory blocks\n#define GET_BLOCKS_SECURITY_STATUS  0x2C\n\n// Request flag with bits set these rules:\n//     Bit  Flag name           Description\n//      1   Sub-carrier flag    0 ... single sub-carrier used\n//                              1 ... two sub-carriers used\n//      2   Data rate flag      0 ... low data rate is used\n//                              1 ... high data rate is used\n//      3   Inventory flag      State determines how bits 5-8 are defined\n//                              0 ... flag not set\n//                              1 ... flag set\n//      4   Protocol            0: no protocol extension\n//          extension flag      1: protocol format is extended\n//   If Inventory flag = 0 (not set):\n//      5   Select flag         0: request shall be executed based on setting of the address flag\n//                              1: request shall be executed only by devices in the selected state\n//      6   Address flag        0: request is not addressed\n//                              1: request is addressed, optional UID field is present\n//      7   Option flag         Meaning is defined by the command description, if not used set to 0\n//      8   reserved\n//   If Inventory flag = 1 (set):\n//      5   AFI flag            0: AFI field is not present\n//                              1: AFI field is present\n//      6   Number of           0: 16 slots\n//          slots flag          1: 1 slot\n//      7   Option flag         Meaning is defined by the command description, if not used set to 0\n//      8   reserved\n//\n//  Helper bit field by to quickly calculate integers from hex and vice versa:\n//      Bit no.:     8   7   6   5      4   3   2   1\n//      value:     128  64  32  16      8   4   2   1\n//      choose:      0   0   0   0      4   0   2   1   result is 0x03\n//\n// request flags byte, 0x26 means:\n//   single sub carrier, high data rate, inventory flag set, no protocoll extentsion, AFI not present, one slot)\n\n\n// Settings\n\n//#define DEBUG\n\nconst int SS_PIN = 3;   // Slave Select pin, changed to new value on 2016-03-21\nconst int IRQ_PIN = 2;  // IRQ/DIN pin used for wake-up pulse\nbyte RXBuffer[400];     // receive buffer\nbyte dataBuffer[400];   // buffer for Freestyle Libre byte data\nbyte NFCReady = 0;      // used to track NFC state\nconst int SPI_FREQUENCY = 2000; // max. for CR95HF is 2000 = 2 MHz\n//const uint64_t SLEEP_DURATION = 20000;  // Duration of Simblee ultra low power mode in ms\nconst uint64_t SLEEP_DURATION = 120000;  // Duration of Simblee ultra low power mode in ms\n\n// Code\n\nvoid setupPins() {\n  Serial.println(\"Setting Simblee pins ...\");\n  pinMode(IRQ_PIN, OUTPUT);\n  pinMode(SS_PIN, OUTPUT);\n  // Commented out by Uwi on 15.11.2015: was not needed obviously\n  //    digitalWrite(SS_PIN, HIGH);\n  Serial.println(\"... done setting Simblee pins.\");\n}\n\nvoid setupSPI() {\n  Serial.println(\"Setting up SPI ...\");\n  SPI.begin();\n  SPI.setDataMode(SPI_MODE0);\n  SPI.setBitOrder(MSBFIRST);\n  SPI.setFrequency(SPI_FREQUENCY);\n  Serial.println(\"... done setting up SPI.\");\n}\n// --------------------------\n\nvoid setupBluetoothConnection() {\n  Serial.println(\"Setup Bluetooth stack and start connection...\");\n  SimbleeBLE.deviceName = \"LibreCGM\";\n  SimbleeBLE.customUUID = \"2220\";\n  SimbleeBLE.advertisementData = \"data\";\n  SimbleeBLE.advertisementInterval = MILLISECONDS(500);  // Default was 300\n  SimbleeBLE.txPowerLevel = 4;  // Possible values: -20, -16, -12, -8, -4, 0 or +4 (dbM)  // up to 20016-05-17 this was 0\n  //    SimbleeBLE.txPowerLevel = -4;  // Possible values: -20, -16, -12, -8, -4, 0 or +4 (dbM)  // up to 20016-05-17 this was 0\n  SimbleeBLE.begin();           // Start the BLE stack\n  Serial.println(\"... done seting up Bluetooth stack and starting connection.\");\n}\n\n// Add setup code\nvoid setup() {\n  Serial.begin(9600);\n  setupPins();  // set RFduino/Simblee pins\n  setupSPI();\n\n  Serial.println(\"Please provide power to the BM019 within the next 5 seconds ...\");\n  delay(5000);\n\n  sendWakeupPulse(IRQ_PIN);  // wake up BM019 and set to SPI (since SS_0 is wired up to be HIGH)\n  readWakeUPEventRegister(SS_PIN, RXBuffer);\n  setupBluetoothConnection();\n}\n\n\n\n// SetProtocol_Command programs the CR95HF for ISO/IEC 15693 operation.\n// If the correct response is received the serial monitor is used to display successful programming.\n// Warning: if the parameters of the protocol are changed, e.g. sub carrier, then the request flags\n// of the other commands (e.g. inventory, read single block) have to be changed accordingly.\nvoid SetProtocol_Command() {\n\n  // step 1 send the command\n  digitalWrite(SS_PIN, LOW);\n  SPI.transfer(0x00);  // SPI control byte to send command to CR95HF\n  SPI.transfer(0x02);  // Set protocol command\n  SPI.transfer(0x02);  // length of data to follow\n  SPI.transfer(0x01);  // code for ISO/IEC 15693\n  SPI.transfer(0x0F);  // Up till 2016-06-13: crc16, single, 30%, wait for SOF (wrong: Wait for SOF, 100% modulation, append CRC)\n  //    SPI.transfer(0x0D);  // Up till 2016-06-13: crc16, single, 30%, wait for SOF (wrong: Wait for SOF, 100% modulation, append CRC)\n  digitalWrite(SS_PIN, HIGH);\n  delay(1);\n\n  // step 2, poll for data ready\n  pollSPIUntilResponsIsReady(SS_PIN, RXBuffer);\n\n  // step 3, read the data\n  receiveSPIResponse(SS_PIN, RXBuffer);\n#ifdef DEBUG\n  Serial.println(\"RXBuffer is\");\n  for (byte i = 0; i < 2; i++) {\n    Serial.print(RXBuffer[i], HEX);\n    Serial.print(\" \");\n  }\n#endif\n  if ((RXBuffer[0] == 0) & (RXBuffer[1] == 0)) {\n    Serial.println(\"PROTOCOL SET-\");  //\n    NFCReady = 1; // NFC is ready\n  } else {\n    Serial.println(\"BAD RESPONSE TO SET PROTOCOL\");\n    NFCReady = 0; // NFC not ready\n  }\n  Serial.println(\" \");\n}\n\n// Reads the single block of 8 bytes with number blockNum from the BM019.\n// The BM019 has 244 Blocks of 8 bytes that can be read via ISO 15693 commands. The blocks are numbered 0 to 243.\n// Returns the result code of the command response (that indicates wether there was success or an error)\nbyte ReadSingleBlockReturn(int blockNum) {\n\n  RXBuffer[0] = SENDRECEIVE;   // command code for send receive CR95HF command\n  RXBuffer[1] = 0x03;          // length of data that follows (3 bytes)\n  //    RXBuffer[2] = 0x02;          // request Flags byte, single carrier, high data rate\n  RXBuffer[2] = 0x03;        // request Flags byte dual carrier, high data rate\n  RXBuffer[3] = 0x20;          // Inventory Command for ISO/IEC 15693\n  RXBuffer[4] = blockNum;      // Block number\n\n  // step 1 send the command\n  sendSPICommand(SS_PIN, RXBuffer, 5);\n\n  // step 2, poll for data ready\n  pollSPIUntilResponsIsReady(SS_PIN, RXBuffer);\n\n  // step 3, read the data\n  receiveSPIResponse(SS_PIN, RXBuffer);\n\n  delay(1);\n#ifdef DEBUG\n  // Print to Serial\n  if (RXBuffer[0] == 128)  {\n    Serial.printf(\"The block #%d:\", blockNum);\n    for (byte i = 3; i < RXBuffer[1] + 3 - 4; i++) {\n      Serial.print(RXBuffer[i], HEX);\n      Serial.print(\" \");\n    }\n  } else {\n    Serial.print(\"NO Single block available - \");\n    Serial.print(\"RESPONSE CODE: \");\n    Serial.println(RXBuffer[0], HEX);\n  }\n  Serial.println(\" \");\n#endif\n\n  return RXBuffer[0];  // result code of command response\n}\n\n\n\n/// @brief  Sends command to BM019 and receives response serveral times until response with no error, max maxTrial times.\n/// @detail After maxTrials trials the last response is returned, even  if there is still an error.\n/// @detail Warning: Ensure that RXBuffer has appropriate size.\n/// @param  ssPin slave select pin for SPI digital write\n/// @param  RXBuffer buffer used for command and response\n/// @param  maxTrials max number of trials\nvoid runSPICommandUntilNoError(int ssPin, byte *command, int length, byte *RXBuffer, int maxTrials) {\n\n  int count = 0;\n  bool success;\n  do {\n    delay(1);\n#ifdef DEBUG\n    Serial.printf(\"Before: Count: %d, success: %b, RXBuffer[0]: %x \\r\\n\", count, success, RXBuffer[0]);\n#endif\n    count++;\n\n    // clear RXBuffer with zeros\n    memset(RXBuffer, 0, sizeof(RXBuffer));\n\n    // run SPI command\n    sendPollReceiveSPINew(ssPin, command, sizeof(command), RXBuffer);\n    success = responseHasNoError(RXBuffer);\n\n#ifdef DEBUG\n    Serial.printf(\"After: Count: %d, success: %b, RXBuffer[0]: %x \\r\\n\", count, success, RXBuffer[0]);\n#endif\n\n  } while ( !success && (count < maxTrials));\n  delay(1);\n#ifdef DEBUG\n  Serial.printf(\"Exiting at count: %d, RXBuffer[0]: %x \\r\\n\", count, RXBuffer[0]);\n#endif\n}\n\n/// @brief  Sends IDN command to BM019 and receives response serveral times until response with no error, max maxTrial times.\n/// @detail After maxTrials trials the last response is returned, even  if there is still an error.\n/// @detail Warning: Ensure that RXBuffer has appropriate size.\n/// @param  ssPin slave select pin for SPI digital write\n/// @param  RXBuffer buffer used for command and response\n/// @param  maxTrials max number of trials\nvoid runIDNCommandUntilNoError(int ssPin, byte *command, int length, byte *RXBuffer, int maxTrials) {\n\n  int count = 0;\n  bool success;\n  do {\n\n#ifdef DEBUG\n    Serial.printf(\"Before: Count: %d, success: %b, RXBuffer[0]: %x \\r\\n\", count, success, RXBuffer[0]);\n#endif\n    count++;\n\n    // clear RXBuffer with zeros\n    memset(RXBuffer, 0, sizeof(RXBuffer));\n\n    // run SPI command\n    sendPollReceiveSPINew(ssPin, command, sizeof(command), RXBuffer);\n    success = idnResponseHasNoError(RXBuffer);\n\n#ifdef DEBUG\n    Serial.printf(\"After: Count: %d, success: %b, RXBuffer[0]: %x \\r\\n\", count, success, RXBuffer[0]);\n#endif\n  } while ( !success && (count < maxTrials));\n  delay(10);\n#ifdef DEBUG\n  Serial.printf(\"Exiting at count: %d, RXBuffer[0]: %x \\r\\n\", count, RXBuffer[0]);\n#endif\n}\n\n\n/// Runs the system information command several times, i.e. maxTrials times or until a response with no error is gotten, whatever happens first.\n/// @param ssPin SS_PIN used for SPI\n/// @param RXBuffer buffer used for send and receive\n/// @param maxTrials maximum number of trials. If reached, the result is returned, even if there still is an error present\n/// @brief  Get system information from BM019\n/// @details  The response is read into RXBuffer and that's it, no matter if there is an error or not.\n/// @n Command format for CR95HF:\n/// @n 8 bits for request flags,\n/// @n 8 bits for the get system information command,i.e 0x2B,\n/// @n 64 bits for an optional UID (not used in non-addressed modes).\n/// @details Example get system info command (CR95HF command embedded in BM019 command):\n/// @details 0x04 ... BM019 send/receive command code\n/// @details 0x02 ... BM019 length of CR95HF command data that follows\n/// @details 0x02 ... CR95HF request flags byte (high data rate used)\n/// @details 0x2B ... CR95HF get system information command\n/// @n\n/// @n\n/// @details Example CR95HF response with no error:\n/// @details 0x80      ... result code\n/// @details 0x12      ... length of following data (12 bytes)\n/// @details 0x00      ... response flags\n/// @details 0x0F      ... info flags\n/// @details 0x69 0x55 0x19 0x38 0x42 0x20 0x02 0xE0 ... data: UID\n/// @details 0x00      ... DSFID (supported and field is present in response if bit 1 of info flags is set)\n/// @details 0x00      ... AFI (supported and field is present in response if bit 2 of info flags is set)\n/// @details 0x3F 0X03 ... memory size (supported and field is present in response if bit 3 of info flags is set)\n/// @details 0x20      ... IC Ref (supported and field is present in response if bit 4 of info flags is set)\n/// @details 0xB4 0xA9 ... CRC16\n/// @details 0x00      ... error\n/// @n\n/// @details Example CR95HF response with error (bit 0 of response flag is set)\n/// @details 0x01      ... response flags\n/// @details 0x01      ... error code (returned when error bit is set)\n/// @details 0xB4 0xA9 ... CRC16\n/// @details 0X01      ... (error CRC16 or collision error bits)\nvoid runSystemInformationCommandUntilNoError(int ssPin, byte *RXBuffer, int maxTrials) {\n#ifdef DEBUG\n  Serial.printf(\"ssPin: %d, maxTrials: %d, RXBuffer[0]: %x \\r\\n\", ssPin, maxTrials, RXBuffer[0]);\n#endif\n  byte command[4];\n  command[0] = 0x04;   // command code for send receive CR95HF command\n  command[1] = 0x02;   // length of data that follows (3 bytes)\n  command[2] = 0x03;   // request Flags byte, dual sub carrier\n  //    command[2] = 0x02;   // request Flags byte, single sub carrier\n  command[3] = 0x2B;   // get system information command for ISO/IEC 15693\n  delay(10);\n#ifdef DEBUG\n  Serial.printf(\"ssPin: %d, maxTrials: %d, RXBuffer[0]: %x \\r\\n\", ssPin, maxTrials, RXBuffer[0]);\n#endif\n  // run command until no error, but only max 10 times\n  runSPICommandUntilNoError(ssPin, command, sizeof(command), RXBuffer, maxTrials);\n}\n\n/// Runs the inventory  command several times, i.e. maxTrials times or until a response with no error is gotten, whatever happens first.\n/// @param ssPin SS_PIN used for SPI\n/// @param RXBuffer buffer used for send and receive\n/// @param maxTrials maximum number of trials. If reached, the result is returned, even if there still is an error present\nvoid runIDNCommand(int ssPin, byte *RXBuffer, int maxTrials) {\n\n#ifdef DEBUG\n  Serial.printf(\"ssPin: %d, maxTrials: %d, RXBuffer[0]: %x \\r\\n\", ssPin, maxTrials, RXBuffer[0]);\n#endif\n\n  byte command[2];\n  command[0] = 0x01;   // command code for send receive CR95HF command\n  command[1] = 0x00;   // length of data that follows (0 bytes)\n  delay(10);\n\n#ifdef DEBUG\n  Serial.printf(\"ssPin: %d, maxTrials: %d, RXBuffer[0]: %x \\r\\n\", ssPin, maxTrials, RXBuffer[0]);\n#endif\n  // run command until no error, but only max 10 times\n  runIDNCommandUntilNoError(ssPin, command, sizeof(command), RXBuffer, maxTrials);\n}\n\n\n//Example response of CR95HF for inventory command and data positions/indices\n//+------+--------+----------------------------------------------------------------------+\n//|Result| Length | Data                                                                 |\n//| code |        +--------+-----+---------------------------------------+---------+-----+\n//|      |        |Response|     |                                       |         |     |\n//|      |        | flags  |DSFID| UID                                   |CRC16    |Error|\n//+------+--------+--------+---------------------------------------------+---------+-----+\n//| 0x80 |0x0D(13)| 0x00   |0x00 |0x51 0x69 0x19 0x38 0x42 0x20 0x02 0xE0|0x84 0x28|0x00 |\n//+------+--------+--------+-----+---------------------------------------+---------+-----+\n//|   0  |  1     |   2    |  3  | 4    5    6    7    8    9    10   11 | 12   13 | 14  |\n//+------+--------+--------+-----+---------------------------------------+---------+-----+\n//                    0       1    2    3    4    5    6    7     8    9   10   11   12\n//\n\n/// Retreive idn data from RXBuffer from IDN command\n/// This ist the struct later to be transmitted via bluetooth\n/// @detail There is no error possible in the response since this is just pure device information and thus not rely on RFID and a tag in the field\n/// @param RXBuffer buffer containing the response from the IDN command\n/// @param idnType struct with retreived data\nIDNDataType idnDataFromIDNResponse(byte *RXBuffer) {\n\n  IDNDataType idnData;\n  idnData.resultCode = RXBuffer[0];\n\n  // Device ID has 13 bytes\n  for (int i = 0; i < 13; i++) {\n    idnData.deviceID[i] = RXBuffer[i + 2]; // TODO: cchek and continue here\n  }\n\n  // ROM CRC are the last two bytes of the data\n  int length = RXBuffer[2];\n  idnData.romCRC[0] = RXBuffer[length - 2];\n  idnData.romCRC[1] = RXBuffer[length - 1];\n\n  return idnData;\n}\n\n\n\n/// Retreive system information from RXBuffer from system information command\n/// This ist the struct later to be transmitted via bluetooth\n/// @param RXBuffer buffer containing the response from the system information command\n/// @param SystemInformationType struct with retreived data\nSystemInformationDataType systemInformationDataFromGetSystemInformationResponse(byte *RXBuffer) {\n  //    SystemInformationType retreiveSystemInformationValues(byte *RXBuffer) {\n\n  SystemInformationDataType systemInformationData;\n\n  systemInformationData.resultCode = RXBuffer[0];\n  systemInformationData.responseFlags = RXBuffer[2];\n\n  // check for no error in result code and handle accordingly\n  if (systemInformationData.resultCode == 0x80) { // no error in result code\n\n    // check for no error in response flags\n    if ((systemInformationData.responseFlags & 0x01) == 0) {\n      // no error in response flags\n      systemInformationData.infoFlags = RXBuffer[3];\n      for (int i = 0; i < 8; i++) {\n        systemInformationData.uid[i] = RXBuffer[11 - i];\n      }\n      systemInformationData.errorCode = RXBuffer[RXBuffer[1] + 2 - 1];\n    } else {\n      // error case\n      systemInformationData.errorCode = RXBuffer[3];\n    }\n  } else {\n    // error case\n    clearBuffer(systemInformationData.uid);\n    systemInformationData.errorCode = RXBuffer[3];\n  }\n  return systemInformationData;\n}\n\n\n/// Sends a packet of data (c-struct) via bluetooth to a smartphone application\n/// @detail Any packet to be transfered is a c-struct. These structs are defined in data_types.h.\n/// @param packetIdentifier identifier that can be used to treat a packet separately in the app. Identifiers are defined in constants.h\n/// @param txFlags don't know yet, what these are fore\n/// @param *packetBytes pointer on the c-struct, that is the packet\n/// @param byteCount number of bytes to be transfered\nbool pumpViaBluetooth(unsigned short packetIdentifier, UBP_TxFlags txFlags, const char *packetBytes, unsigned short byteCount) {\n\n  bool success = UBP_queuePacketTransmission(packetIdentifier, txFlags, packetBytes, byteCount);\n\n  delay(1);\n#ifdef DEBUG\n  if (success) Serial.println(\"Packet queued successfully\");\n  else Serial.println(\"Failed to enqueue packet\");\n#endif\n  // put your main code here, to run repeatedly:\n  while (UBP_isBusy() == true) UBP_pump();\n}\n\n/// Returns the voltage on the RFDuino VDD pin as a float in Volts.\n/// Code is from the RFDuino Forum, see http://forum.rfduino.com/index.php?topic=265.0 for details\nfloat voltageOnVDD() {\n  analogReference(VBG);                // Sets the Reference to 1.2V band gap\n  analogSelection(VDD_1_3_PS);         // Selects VDD with 1/3 prescaling as the analog source\n  int sensorValue = analogRead(1);     // the pin has no meaning, it uses VDD pin\n  return sensorValue * (3.6 / 1023.0); // convert value to voltage;\n}\n\n/// Print all data of systemInformationData to serial console\nvoid printSystemInformationData(SystemInformationDataType systemInformationData) {\n\n  Serial.println(\"Printing system information data to serial output:\");\n\n  Serial.printf(\"Result code: %x\\r\\n\", systemInformationData.resultCode);\n  Serial.printf(\"Response flags: %x\\r\\n\", systemInformationData.responseFlags);\n\n  Serial.printf(\"uid: %x\", systemInformationData.uid[0]);\n  for (int i = 1; i < 8; i++) {\n    Serial.printf(\":%x\", systemInformationData.uid[i]);\n  }\n  Serial.println(\"\");\n\n  Serial.printf(\"Error code: %x\\r\\n\", systemInformationData.errorCode);\n}\n\n///===================================================================================================\n// The loop\n///===================================================================================================\n\nvoid loop() {\n\n#ifdef DEBUG\n  Serial.println(\"In the loop\");\n#endif\n\n  // Start up BM019 if not yet started\n  if (NFCReady == 0) {\n\n    delay(100);\n    SetProtocol_Command(); // ISO 15693 settings\n    Serial.println(\"After SetProtocoll_Command()\");\n    delay(100);\n\n  } else {\n\n\n    // ------- Read system information from BM019 ----------------------------------------------------------------------------\n    //#ifdef DEBUG\n    Serial.println(\"Get system information command ...\");\n    //#endif\n    runSystemInformationCommandUntilNoError(SS_PIN, RXBuffer, 10);\n\n#ifdef DEBUG\n    Serial.println(\"... retreive system information ...\");\n#endif\n    SystemInformationDataType systemInformationData = systemInformationDataFromGetSystemInformationResponse(RXBuffer);\n\n\n\n    //------- Read IDN information from BM019 (IDN Command) -------------------------------------------------------------------\n\n    //#ifdef DEBUG\n    Serial.println(\"IDN command ...\");\n    //#endif\n    runIDNCommand(SS_PIN, RXBuffer, 10);\n#ifdef DEBUG\n    Serial.println(\"... retreive IDN information ...\");\n#endif\n    IDNDataType idnData = idnDataFromIDNResponse(RXBuffer);\n\n\n\n    // ----------- Read 43 data blocks into RXBuffer ---------------\n\n    //#ifdef DEBUG\n    Serial.println(\"Read all data\");\n    //#endif\n\n    for (int i = 0; i < sizeof(RXBuffer); i++) {\n      RXBuffer[i] = 0;\n    }\n    for (int i = 0; i < sizeof(dataBuffer); i++) {\n      dataBuffer[i] = 0;\n    }\n\n    byte resultCode = 0;\n    int trials = 0;\n    int maxTrials = 10;\n    for (int i = 0; i < 43; i++) { // Need only 43 of 244 blocks\n      resultCode = ReadSingleBlockReturn(i);\n\n#ifdef DEBUG\n      printf(\"resultCode 0x%x\\n\\r\", resultCode);\n#endif\n      if (resultCode != 0x80 && trials < maxTrials) {\n        printf(\"Error 0x%x\\n\\r\", resultCode);\n        i--;        // repeat same block if error occured, but\n        trials++;   // not more than maxTrials times per block\n      } else if (trials >= maxTrials) {\n        break;\n      } else {\n        trials = 0;\n\n        for (int j = 3; j < RXBuffer[1] + 3 - 4; j++) {\n          dataBuffer[i * 8 + j - 3] = RXBuffer[j];\n#ifdef DEBUG\n          Serial.print(RXBuffer[j], HEX);\n          Serial.print(\" \");\n#endif\n        }\n      }\n    }\n\n    // ----------- All data collected, send BM019 to hibernate -------------------------\n\n    //#ifdef DEBUG\n    Serial.println(\"Sending CR95HF to hibernate ...\");\n    //#endif\n    sendCR95HFToHibernate(SS_PIN);\n\n\n\n    // ------- Transmit system information data via bluetooth. By convention this is the first transmission -----------------\n\n    bool ergo = pumpViaBluetooth(SYSTEM_INFORMATION_DATA, UBP_TxFlagIsRPC, (char *) &systemInformationData, sizeof(SystemInformationDataType));\n#ifdef DEBUG\n    printSystemInformationData(systemInformationData);\n#endif\n\n\n\n    //-------- transmit dataBuffer via bluetooth ---------------------------------------------------------\n\n    AllBytesDataType allBytes;\n#ifdef DEBUG\n    Serial.println(\"----about to send all data bytes packet\");\n#endif\n    for (int i = 0; i < sizeof(allBytes.allBytes); i++) {\n      allBytes.allBytes[i] = 0;\n    }\n    for (int i = 0; i < 344; i++) {\n      allBytes.allBytes[i] = dataBuffer[i];\n    }\n    //#ifdef DEBUG\n    Serial.printf(\"Sizeof ist : %d\\n\", sizeof(AllBytesDataType));\n    //#endif\n    bool success = UBP_queuePacketTransmission(ALL_BYTES, UBP_TxFlagIsRPC, (char *) &allBytes, sizeof(AllBytesDataType));\n#ifdef DEBUG\n    if (success) Serial.println(\"----all data bytes packet queued successfully\");\n    else Serial.println(\"----Failed to enqueue all data bytes packet\");\n#endif\n    while (UBP_isBusy() == true) UBP_pump();\n\n    //-------- Read Battery level and Simblee temperature and transmit via bluetooth ---------------------\n\n    BatteryDataType batteryData;\n    batteryData.voltage = voltageOnVDD();\n    batteryData.temperature = Simblee_temperature(CELSIUS);\n\n#ifdef DEBUG\n    Serial.printf(\"Battery voltage: %f\\r\\n\", batteryData.voltage);\n#endif\n    // Transmitt via bluetooth\n    success = UBP_queuePacketTransmission(BATTERY_DATA, UBP_TxFlagIsRPC, (char *) &batteryData, sizeof(BatteryDataType));\n    //        if (success) Serial.println(\"Battery data packet queued successfully\");\n    //        else Serial.println(\"Failed to enqueue battery data packet\");\n    // put your main code here, to run repeatedly:\n    while (UBP_isBusy() == true) UBP_pump();\n\n#ifdef DEBUG\n    Serial.printf(\"Sent Battery voltage: %f\\r\\n\", batteryData.voltage);\n#endif\n\n\n    //-------- transmit IDN data via bluetooth. By convention this is the last transmission -----------------\n\n    ergo = pumpViaBluetooth(IDN_DATA, UBP_TxFlagNone, (char *) &idnData, sizeof(IDNDataType));\n    success = UBP_queuePacketTransmission(IDN_DATA, UBP_TxFlagIsRPC, (char *) &idnData, sizeof(IDNDataType));\n    delay(10);\n#ifdef DEBUG\n    if (success) Serial.println(\"IDN data packet queued successfully\");\n    else Serial.println(\"Failed to enqueue IDN data packet\");\n#endif\n    // put your main code here, to run repeatedly:\n    while (UBP_isBusy() == true) UBP_pump();\n\n#ifdef DEBUG\n    Serial.printf(\"IDN: %x\", idnData.deviceID[0]);\n    for (int i = 1; i < 13; i++) {\n      Serial.printf(\":%x\", idnData.deviceID[i]);\n    }\n    Serial.println(\"... done\");\n#endif\n\n\n    //--------- send Simblee into ultra low power mode ---------------------------------------------------\n\n    //#ifdef DEBUG\n    Serial.println(\"Sending RFDuino to sleep ...\");\n    //#endif\n    Simblee_ULPDelay(SLEEP_DURATION); //\n\n\n    //--------- send Simblee woke up again, now also wake up BM019 and repeat the loope cycle ------------\n\n#ifdef DEBUG\n    Serial.println(\"... RFDuino woke up again\");\n    Serial.println(\"Wake up CR95HF with wake up pulse...\");\n#endif\n    sendWakeupPulse(IRQ_PIN);  // Wake up BM019 (low pulse on IRQ_PIN)\n    readWakeUPEventRegister(SS_PIN, RXBuffer);\n    setupSPI();\n\n    delay(10);\n    SetProtocol_Command(); // ISO 15693 settings\n    delay(100);\n\n#ifdef DEBUG\n    Serial.println(\"... CR95HF woke up again. Receiving wake up response\");\n#endif\n  }\n}\n\n\n"
  },
  {
    "path": "LibreMonitor.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t9F659E798C0CD22711C55DE6 /* Pods_LibreMonitorUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 887C2B24AC9C0E842F9CE127 /* Pods_LibreMonitorUITests.framework */; };\n\t\tC60178961E3E7FE5008FCF3A /* BluetoothTestData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C60178951E3E7FE5008FCF3A /* BluetoothTestData.swift */; };\n\t\tC61C296C1DB16C60009A5885 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C61C296B1DB16C60009A5885 /* Main.storyboard */; };\n\t\tC65E6DA21E45070800A85E0E /* TransmissionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C65E6DA11E45070800A85E0E /* TransmissionTests.swift */; };\n\t\tC6652F1E1DB1801D00237E7D /* crc8.m in Sources */ = {isa = PBXBuildFile; fileRef = C6652F1B1DB1801D00237E7D /* crc8.m */; };\n\t\tC6652F1F1DB1801D00237E7D /* libUBP.m in Sources */ = {isa = PBXBuildFile; fileRef = C6652F1D1DB1801D00237E7D /* libUBP.m */; };\n\t\tC6822D661DB13F2200D08393 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822D651DB13F2200D08393 /* AppDelegate.swift */; };\n\t\tC6822D691DB13F2200D08393 /* LibreMonitor.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = C6822D671DB13F2200D08393 /* LibreMonitor.xcdatamodeld */; };\n\t\tC6822D721DB13F2200D08393 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C6822D711DB13F2200D08393 /* Assets.xcassets */; };\n\t\tC6822D751DB13F2200D08393 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C6822D731DB13F2200D08393 /* LaunchScreen.storyboard */; };\n\t\tC6822D801DB13F2200D08393 /* LibreMonitorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822D7F1DB13F2200D08393 /* LibreMonitorTests.swift */; };\n\t\tC6822D8B1DB13F2200D08393 /* LibreMonitorUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822D8A1DB13F2200D08393 /* LibreMonitorUITests.swift */; };\n\t\tC6822DAA1DB1616300D08393 /* Data_types+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822DA31DB1616300D08393 /* Data_types+Extensions.swift */; };\n\t\tC6822DAB1DB1616300D08393 /* NSData+CRC8.m in Sources */ = {isa = PBXBuildFile; fileRef = C6822DA51DB1616300D08393 /* NSData+CRC8.m */; };\n\t\tC6822DAC1DB1616300D08393 /* NSData+SLIP.m in Sources */ = {isa = PBXBuildFile; fileRef = C6822DA71DB1616300D08393 /* NSData+SLIP.m */; };\n\t\tC6822DAD1DB1616300D08393 /* SimbleeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822DA81DB1616300D08393 /* SimbleeManager.swift */; };\n\t\tC6822DAE1DB1616300D08393 /* SLIPBuffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822DA91DB1616300D08393 /* SLIPBuffer.swift */; };\n\t\tC6822DB51DB1618400D08393 /* CRC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822DB01DB1618400D08393 /* CRC.swift */; };\n\t\tC6822DB61DB1618400D08393 /* LibreSensor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822DB11DB1618400D08393 /* LibreSensor.swift */; };\n\t\tC6822DB71DB1618400D08393 /* Measurement.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822DB21DB1618400D08393 /* Measurement.swift */; };\n\t\tC6822DB81DB1618400D08393 /* SensorData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822DB31DB1618400D08393 /* SensorData.swift */; };\n\t\tC6822DB91DB1618400D08393 /* SensorState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822DB41DB1618400D08393 /* SensorState.swift */; };\n\t\tC6822DBD1DB161AB00D08393 /* AdjustmentsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822DBB1DB161AB00D08393 /* AdjustmentsTableViewController.swift */; };\n\t\tC6822DBE1DB161AB00D08393 /* BloodSugarTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822DBC1DB161AB00D08393 /* BloodSugarTableViewController.swift */; };\n\t\tC6822DC21DB161C700D08393 /* BloodSugarGraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822DC01DB161C700D08393 /* BloodSugarGraphView.swift */; };\n\t\tC6822DC31DB161C700D08393 /* BloodSugarGraphViewTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822DC11DB161C700D08393 /* BloodSugarGraphViewTableViewCell.swift */; };\n\t\tC6822DC51DB161F900D08393 /* LibreMonitorTestSensorData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822DC41DB161F900D08393 /* LibreMonitorTestSensorData.swift */; };\n\t\tC6822DC81DB162E900D08393 /* CoreDataStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822DC71DB162E900D08393 /* CoreDataStack.swift */; };\n\t\tC6822DD51DB1631D00D08393 /* BloodGlucose+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822DCB1DB1631D00D08393 /* BloodGlucose+CoreDataClass.swift */; };\n\t\tC6822DD61DB1631D00D08393 /* BloodGlucose+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822DCC1DB1631D00D08393 /* BloodGlucose+CoreDataProperties.swift */; };\n\t\tC6822DD71DB1631D00D08393 /* Reader+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822DCD1DB1631D00D08393 /* Reader+CoreDataClass.swift */; };\n\t\tC6822DD81DB1631D00D08393 /* Reader+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822DCE1DB1631D00D08393 /* Reader+CoreDataProperties.swift */; };\n\t\tC6822DD91DB1631D00D08393 /* Sensor+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822DCF1DB1631D00D08393 /* Sensor+CoreDataClass.swift */; };\n\t\tC6822DDA1DB1631D00D08393 /* Sensor+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822DD01DB1631D00D08393 /* Sensor+CoreDataProperties.swift */; };\n\t\tC6822DDB1DB1631D00D08393 /* HeaderData+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822DD11DB1631D00D08393 /* HeaderData+CoreDataClass.swift */; };\n\t\tC6822DDC1DB1631D00D08393 /* HeaderData+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6822DD21DB1631D00D08393 /* HeaderData+CoreDataProperties.swift */; };\n\t\tC6DDBDBB1DC512410048D275 /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C6DDBDBA1DC512410048D275 /* HealthKit.framework */; };\n\t\tF1BB69F1B49E13B76E4A90C4 /* Pods_LibreMonitor.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EAD184EB2119C8F78D731C7E /* Pods_LibreMonitor.framework */; };\n\t\tF8C71C986A327FDC6776D4B2 /* Pods_LibreMonitorTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 402C08AB93E799ED917B1043 /* Pods_LibreMonitorTests.framework */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\tC6822D7C1DB13F2200D08393 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = C6822D5A1DB13F2200D08393 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = C6822D611DB13F2200D08393;\n\t\t\tremoteInfo = LibreMonitor;\n\t\t};\n\t\tC6822D871DB13F2200D08393 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = C6822D5A1DB13F2200D08393 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = C6822D611DB13F2200D08393;\n\t\t\tremoteInfo = LibreMonitor;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\t20B072583FD87F7318BD08D0 /* Pods-LibreMonitorTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-LibreMonitorTests.debug.xcconfig\"; path = \"Pods/Target Support Files/Pods-LibreMonitorTests/Pods-LibreMonitorTests.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t402C08AB93E799ED917B1043 /* Pods_LibreMonitorTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LibreMonitorTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t771CB977837C430DB5630E78 /* Pods-LibreMonitor.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-LibreMonitor.release.xcconfig\"; path = \"Pods/Target Support Files/Pods-LibreMonitor/Pods-LibreMonitor.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t887C2B24AC9C0E842F9CE127 /* Pods_LibreMonitorUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LibreMonitorUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t9C01D6FD2C7EC8B142986E40 /* Pods-LibreMonitor.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-LibreMonitor.debug.xcconfig\"; path = \"Pods/Target Support Files/Pods-LibreMonitor/Pods-LibreMonitor.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tC60178951E3E7FE5008FCF3A /* BluetoothTestData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BluetoothTestData.swift; sourceTree = \"<group>\"; };\n\t\tC61C296B1DB16C60009A5885 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = \"<group>\"; };\n\t\tC65E6DA11E45070800A85E0E /* TransmissionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransmissionTests.swift; sourceTree = \"<group>\"; };\n\t\tC6652F1A1DB1801D00237E7D /* crc8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crc8.h; path = SimbleeCode/crc8.h; sourceTree = \"<group>\"; };\n\t\tC6652F1B1DB1801D00237E7D /* crc8.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = crc8.m; path = SimbleeCode/crc8.m; sourceTree = \"<group>\"; };\n\t\tC6652F1C1DB1801D00237E7D /* libUBP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = libUBP.h; path = SimbleeCode/libUBP.h; sourceTree = \"<group>\"; };\n\t\tC6652F1D1DB1801D00237E7D /* libUBP.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = libUBP.m; path = SimbleeCode/libUBP.m; sourceTree = \"<group>\"; };\n\t\tC6652F201DB1812C00237E7D /* LibreMonitorTests-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = \"LibreMonitorTests-Bridging-Header.h\"; sourceTree = \"<group>\"; };\n\t\tC6652F211DB181E900237E7D /* LibreMonitor-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = \"LibreMonitor-Bridging-Header.h\"; sourceTree = \"<group>\"; };\n\t\tC6822D621DB13F2200D08393 /* LibreMonitor.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LibreMonitor.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tC6822D651DB13F2200D08393 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tC6822D681DB13F2200D08393 /* LibreMonitor.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = LibreMonitor.xcdatamodel; sourceTree = \"<group>\"; };\n\t\tC6822D711DB13F2200D08393 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tC6822D741DB13F2200D08393 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tC6822D761DB13F2200D08393 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tC6822D7B1DB13F2200D08393 /* LibreMonitorTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LibreMonitorTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tC6822D7F1DB13F2200D08393 /* LibreMonitorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibreMonitorTests.swift; sourceTree = \"<group>\"; };\n\t\tC6822D811DB13F2200D08393 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tC6822D861DB13F2200D08393 /* LibreMonitorUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LibreMonitorUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tC6822D8A1DB13F2200D08393 /* LibreMonitorUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibreMonitorUITests.swift; sourceTree = \"<group>\"; };\n\t\tC6822D8C1DB13F2200D08393 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tC6822DA11DB1616300D08393 /* constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = constants.h; path = Bluetooth/constants.h; sourceTree = \"<group>\"; };\n\t\tC6822DA21DB1616300D08393 /* data_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = data_types.h; path = Bluetooth/data_types.h; sourceTree = \"<group>\"; };\n\t\tC6822DA31DB1616300D08393 /* Data_types+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = \"Data_types+Extensions.swift\"; path = \"Bluetooth/Data_types+Extensions.swift\"; sourceTree = \"<group>\"; };\n\t\tC6822DA41DB1616300D08393 /* NSData+CRC8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"NSData+CRC8.h\"; path = \"Bluetooth/NSData+CRC8.h\"; sourceTree = \"<group>\"; };\n\t\tC6822DA51DB1616300D08393 /* NSData+CRC8.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = \"NSData+CRC8.m\"; path = \"Bluetooth/NSData+CRC8.m\"; sourceTree = \"<group>\"; };\n\t\tC6822DA61DB1616300D08393 /* NSData+SLIP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"NSData+SLIP.h\"; path = \"Bluetooth/NSData+SLIP.h\"; sourceTree = \"<group>\"; };\n\t\tC6822DA71DB1616300D08393 /* NSData+SLIP.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = \"NSData+SLIP.m\"; path = \"Bluetooth/NSData+SLIP.m\"; sourceTree = \"<group>\"; };\n\t\tC6822DA81DB1616300D08393 /* SimbleeManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SimbleeManager.swift; path = Bluetooth/SimbleeManager.swift; sourceTree = \"<group>\"; };\n\t\tC6822DA91DB1616300D08393 /* SLIPBuffer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SLIPBuffer.swift; path = Bluetooth/SLIPBuffer.swift; sourceTree = \"<group>\"; };\n\t\tC6822DB01DB1618400D08393 /* CRC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CRC.swift; path = Model/CRC.swift; sourceTree = \"<group>\"; };\n\t\tC6822DB11DB1618400D08393 /* LibreSensor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LibreSensor.swift; path = Model/LibreSensor.swift; sourceTree = \"<group>\"; };\n\t\tC6822DB21DB1618400D08393 /* Measurement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Measurement.swift; path = Model/Measurement.swift; sourceTree = \"<group>\"; };\n\t\tC6822DB31DB1618400D08393 /* SensorData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SensorData.swift; path = Model/SensorData.swift; sourceTree = \"<group>\"; };\n\t\tC6822DB41DB1618400D08393 /* SensorState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SensorState.swift; path = Model/SensorState.swift; sourceTree = \"<group>\"; };\n\t\tC6822DBB1DB161AB00D08393 /* AdjustmentsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AdjustmentsTableViewController.swift; path = ViewControllers/AdjustmentsTableViewController.swift; sourceTree = \"<group>\"; };\n\t\tC6822DBC1DB161AB00D08393 /* BloodSugarTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BloodSugarTableViewController.swift; path = ViewControllers/BloodSugarTableViewController.swift; sourceTree = \"<group>\"; };\n\t\tC6822DC01DB161C700D08393 /* BloodSugarGraphView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BloodSugarGraphView.swift; path = Views/BloodSugarGraphView.swift; sourceTree = \"<group>\"; };\n\t\tC6822DC11DB161C700D08393 /* BloodSugarGraphViewTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BloodSugarGraphViewTableViewCell.swift; path = Views/BloodSugarGraphViewTableViewCell.swift; sourceTree = \"<group>\"; };\n\t\tC6822DC41DB161F900D08393 /* LibreMonitorTestSensorData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LibreMonitorTestSensorData.swift; sourceTree = \"<group>\"; };\n\t\tC6822DC71DB162E900D08393 /* CoreDataStack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CoreDataStack.swift; path = ModelCoreData/CoreDataStack.swift; sourceTree = \"<group>\"; };\n\t\tC6822DCB1DB1631D00D08393 /* BloodGlucose+CoreDataClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = \"BloodGlucose+CoreDataClass.swift\"; sourceTree = \"<group>\"; };\n\t\tC6822DCC1DB1631D00D08393 /* BloodGlucose+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = \"BloodGlucose+CoreDataProperties.swift\"; sourceTree = \"<group>\"; };\n\t\tC6822DCD1DB1631D00D08393 /* Reader+CoreDataClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = \"Reader+CoreDataClass.swift\"; sourceTree = \"<group>\"; };\n\t\tC6822DCE1DB1631D00D08393 /* Reader+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = \"Reader+CoreDataProperties.swift\"; sourceTree = \"<group>\"; };\n\t\tC6822DCF1DB1631D00D08393 /* Sensor+CoreDataClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = \"Sensor+CoreDataClass.swift\"; sourceTree = \"<group>\"; };\n\t\tC6822DD01DB1631D00D08393 /* Sensor+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = \"Sensor+CoreDataProperties.swift\"; sourceTree = \"<group>\"; };\n\t\tC6822DD11DB1631D00D08393 /* HeaderData+CoreDataClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = \"HeaderData+CoreDataClass.swift\"; sourceTree = \"<group>\"; };\n\t\tC6822DD21DB1631D00D08393 /* HeaderData+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = \"HeaderData+CoreDataProperties.swift\"; sourceTree = \"<group>\"; };\n\t\tC6DDBDBA1DC512410048D275 /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = System/Library/Frameworks/HealthKit.framework; sourceTree = SDKROOT; };\n\t\tC6DDBDBC1DC512420048D275 /* LibreMonitor.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = LibreMonitor.entitlements; sourceTree = \"<group>\"; };\n\t\tD8227FF2A03737CDDF22876F /* Pods-LibreMonitorUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-LibreMonitorUITests.debug.xcconfig\"; path = \"Pods/Target Support Files/Pods-LibreMonitorUITests/Pods-LibreMonitorUITests.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tEAD184EB2119C8F78D731C7E /* Pods_LibreMonitor.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LibreMonitor.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tECBB8DB6FD66440727AC6903 /* Pods-LibreMonitorTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-LibreMonitorTests.release.xcconfig\"; path = \"Pods/Target Support Files/Pods-LibreMonitorTests/Pods-LibreMonitorTests.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tF858C2A695CEC9FB81DC9A5A /* Pods-LibreMonitorUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-LibreMonitorUITests.release.xcconfig\"; path = \"Pods/Target Support Files/Pods-LibreMonitorUITests/Pods-LibreMonitorUITests.release.xcconfig\"; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tC6822D5F1DB13F2200D08393 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tF1BB69F1B49E13B76E4A90C4 /* Pods_LibreMonitor.framework in Frameworks */,\n\t\t\t\tC6DDBDBB1DC512410048D275 /* HealthKit.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tC6822D781DB13F2200D08393 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tF8C71C986A327FDC6776D4B2 /* Pods_LibreMonitorTests.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tC6822D831DB13F2200D08393 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t9F659E798C0CD22711C55DE6 /* Pods_LibreMonitorUITests.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t8F126C8830CE9383D368A1DE /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9C01D6FD2C7EC8B142986E40 /* Pods-LibreMonitor.debug.xcconfig */,\n\t\t\t\t771CB977837C430DB5630E78 /* Pods-LibreMonitor.release.xcconfig */,\n\t\t\t\t20B072583FD87F7318BD08D0 /* Pods-LibreMonitorTests.debug.xcconfig */,\n\t\t\t\tECBB8DB6FD66440727AC6903 /* Pods-LibreMonitorTests.release.xcconfig */,\n\t\t\t\tD8227FF2A03737CDDF22876F /* Pods-LibreMonitorUITests.debug.xcconfig */,\n\t\t\t\tF858C2A695CEC9FB81DC9A5A /* Pods-LibreMonitorUITests.release.xcconfig */,\n\t\t\t);\n\t\t\tname = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC12F12DE60464196E06F6804 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC6DDBDBA1DC512410048D275 /* HealthKit.framework */,\n\t\t\t\tEAD184EB2119C8F78D731C7E /* Pods_LibreMonitor.framework */,\n\t\t\t\t402C08AB93E799ED917B1043 /* Pods_LibreMonitorTests.framework */,\n\t\t\t\t887C2B24AC9C0E842F9CE127 /* Pods_LibreMonitorUITests.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC6652F121DB17FC100237E7D /* SimbleeCode */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC6652F1A1DB1801D00237E7D /* crc8.h */,\n\t\t\t\tC6652F1B1DB1801D00237E7D /* crc8.m */,\n\t\t\t\tC6652F1C1DB1801D00237E7D /* libUBP.h */,\n\t\t\t\tC6652F1D1DB1801D00237E7D /* libUBP.m */,\n\t\t\t);\n\t\t\tname = SimbleeCode;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC6822D591DB13F2200D08393 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC6822D641DB13F2200D08393 /* LibreMonitor */,\n\t\t\t\tC6822D7E1DB13F2200D08393 /* LibreMonitorTests */,\n\t\t\t\tC6822D891DB13F2200D08393 /* LibreMonitorUITests */,\n\t\t\t\tC6822D631DB13F2200D08393 /* Products */,\n\t\t\t\t8F126C8830CE9383D368A1DE /* Pods */,\n\t\t\t\tC12F12DE60464196E06F6804 /* Frameworks */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC6822D631DB13F2200D08393 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC6822D621DB13F2200D08393 /* LibreMonitor.app */,\n\t\t\t\tC6822D7B1DB13F2200D08393 /* LibreMonitorTests.xctest */,\n\t\t\t\tC6822D861DB13F2200D08393 /* LibreMonitorUITests.xctest */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC6822D641DB13F2200D08393 /* LibreMonitor */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC6DDBDBC1DC512420048D275 /* LibreMonitor.entitlements */,\n\t\t\t\tC6822DC61DB162D600D08393 /* ModelCoreData */,\n\t\t\t\tC6822DBF1DB161B300D08393 /* Views */,\n\t\t\t\tC6822DBA1DB1619100D08393 /* ViewControllers */,\n\t\t\t\tC6822DAF1DB1617400D08393 /* Model */,\n\t\t\t\tC6822DA01DB1614C00D08393 /* Bluetooth */,\n\t\t\t\tC6822D651DB13F2200D08393 /* AppDelegate.swift */,\n\t\t\t\tC61C296B1DB16C60009A5885 /* Main.storyboard */,\n\t\t\t\tC6822D711DB13F2200D08393 /* Assets.xcassets */,\n\t\t\t\tC6822D731DB13F2200D08393 /* LaunchScreen.storyboard */,\n\t\t\t\tC6822D761DB13F2200D08393 /* Info.plist */,\n\t\t\t\tC6822D671DB13F2200D08393 /* LibreMonitor.xcdatamodeld */,\n\t\t\t\tC6652F211DB181E900237E7D /* LibreMonitor-Bridging-Header.h */,\n\t\t\t);\n\t\t\tpath = LibreMonitor;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC6822D7E1DB13F2200D08393 /* LibreMonitorTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC60178951E3E7FE5008FCF3A /* BluetoothTestData.swift */,\n\t\t\t\tC6822D7F1DB13F2200D08393 /* LibreMonitorTests.swift */,\n\t\t\t\tC6822DC41DB161F900D08393 /* LibreMonitorTestSensorData.swift */,\n\t\t\t\tC65E6DA11E45070800A85E0E /* TransmissionTests.swift */,\n\t\t\t\tC6652F121DB17FC100237E7D /* SimbleeCode */,\n\t\t\t\tC6652F201DB1812C00237E7D /* LibreMonitorTests-Bridging-Header.h */,\n\t\t\t\tC6822D811DB13F2200D08393 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = LibreMonitorTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC6822D891DB13F2200D08393 /* LibreMonitorUITests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC6822D8A1DB13F2200D08393 /* LibreMonitorUITests.swift */,\n\t\t\t\tC6822D8C1DB13F2200D08393 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = LibreMonitorUITests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC6822DA01DB1614C00D08393 /* Bluetooth */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC6822DA11DB1616300D08393 /* constants.h */,\n\t\t\t\tC6822DA21DB1616300D08393 /* data_types.h */,\n\t\t\t\tC6822DA31DB1616300D08393 /* Data_types+Extensions.swift */,\n\t\t\t\tC6822DA41DB1616300D08393 /* NSData+CRC8.h */,\n\t\t\t\tC6822DA51DB1616300D08393 /* NSData+CRC8.m */,\n\t\t\t\tC6822DA61DB1616300D08393 /* NSData+SLIP.h */,\n\t\t\t\tC6822DA71DB1616300D08393 /* NSData+SLIP.m */,\n\t\t\t\tC6822DA81DB1616300D08393 /* SimbleeManager.swift */,\n\t\t\t\tC6822DA91DB1616300D08393 /* SLIPBuffer.swift */,\n\t\t\t);\n\t\t\tname = Bluetooth;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC6822DAF1DB1617400D08393 /* Model */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC6822DB01DB1618400D08393 /* CRC.swift */,\n\t\t\t\tC6822DB11DB1618400D08393 /* LibreSensor.swift */,\n\t\t\t\tC6822DB21DB1618400D08393 /* Measurement.swift */,\n\t\t\t\tC6822DB31DB1618400D08393 /* SensorData.swift */,\n\t\t\t\tC6822DB41DB1618400D08393 /* SensorState.swift */,\n\t\t\t);\n\t\t\tname = Model;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC6822DBA1DB1619100D08393 /* ViewControllers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC6822DBB1DB161AB00D08393 /* AdjustmentsTableViewController.swift */,\n\t\t\t\tC6822DBC1DB161AB00D08393 /* BloodSugarTableViewController.swift */,\n\t\t\t);\n\t\t\tname = ViewControllers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC6822DBF1DB161B300D08393 /* Views */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC6822DC01DB161C700D08393 /* BloodSugarGraphView.swift */,\n\t\t\t\tC6822DC11DB161C700D08393 /* BloodSugarGraphViewTableViewCell.swift */,\n\t\t\t);\n\t\t\tname = Views;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC6822DC61DB162D600D08393 /* ModelCoreData */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC6822DCB1DB1631D00D08393 /* BloodGlucose+CoreDataClass.swift */,\n\t\t\t\tC6822DCC1DB1631D00D08393 /* BloodGlucose+CoreDataProperties.swift */,\n\t\t\t\tC6822DCD1DB1631D00D08393 /* Reader+CoreDataClass.swift */,\n\t\t\t\tC6822DCE1DB1631D00D08393 /* Reader+CoreDataProperties.swift */,\n\t\t\t\tC6822DCF1DB1631D00D08393 /* Sensor+CoreDataClass.swift */,\n\t\t\t\tC6822DD01DB1631D00D08393 /* Sensor+CoreDataProperties.swift */,\n\t\t\t\tC6822DD11DB1631D00D08393 /* HeaderData+CoreDataClass.swift */,\n\t\t\t\tC6822DD21DB1631D00D08393 /* HeaderData+CoreDataProperties.swift */,\n\t\t\t\tC6822DC71DB162E900D08393 /* CoreDataStack.swift */,\n\t\t\t);\n\t\t\tname = ModelCoreData;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tC6822D611DB13F2200D08393 /* LibreMonitor */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = C6822D8F1DB13F2200D08393 /* Build configuration list for PBXNativeTarget \"LibreMonitor\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tACC5AE5D94CFB4897C7237F1 /* [CP] Check Pods Manifest.lock */,\n\t\t\t\tC6822D5E1DB13F2200D08393 /* Sources */,\n\t\t\t\tC6822D5F1DB13F2200D08393 /* Frameworks */,\n\t\t\t\tC6822D601DB13F2200D08393 /* Resources */,\n\t\t\t\t7ABA004F1E59594A6108DE52 /* [CP] Embed Pods Frameworks */,\n\t\t\t\t19AB2018DB2E7FFBCFDA6F6B /* [CP] Copy Pods Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = LibreMonitor;\n\t\t\tproductName = LibreMonitor;\n\t\t\tproductReference = C6822D621DB13F2200D08393 /* LibreMonitor.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\tC6822D7A1DB13F2200D08393 /* LibreMonitorTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = C6822D921DB13F2200D08393 /* Build configuration list for PBXNativeTarget \"LibreMonitorTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tBDD349C2E88A839DFD7221CD /* [CP] Check Pods Manifest.lock */,\n\t\t\t\tC6822D771DB13F2200D08393 /* Sources */,\n\t\t\t\tC6822D781DB13F2200D08393 /* Frameworks */,\n\t\t\t\tC6822D791DB13F2200D08393 /* Resources */,\n\t\t\t\t937C85C62A3BBC97CAB8CD1C /* [CP] Embed Pods Frameworks */,\n\t\t\t\tA86EDE06FCDE9DED1918E865 /* [CP] Copy Pods Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\tC6822D7D1DB13F2200D08393 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = LibreMonitorTests;\n\t\t\tproductName = LibreMonitorTests;\n\t\t\tproductReference = C6822D7B1DB13F2200D08393 /* LibreMonitorTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\tC6822D851DB13F2200D08393 /* LibreMonitorUITests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = C6822D951DB13F2200D08393 /* Build configuration list for PBXNativeTarget \"LibreMonitorUITests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t4B935F2F04D9D35ADFEF9391 /* [CP] Check Pods Manifest.lock */,\n\t\t\t\tC6822D821DB13F2200D08393 /* Sources */,\n\t\t\t\tC6822D831DB13F2200D08393 /* Frameworks */,\n\t\t\t\tC6822D841DB13F2200D08393 /* Resources */,\n\t\t\t\t951B3668E1ADFC92ED178434 /* [CP] Embed Pods Frameworks */,\n\t\t\t\tA725505D03BE411795C63648 /* [CP] Copy Pods Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\tC6822D881DB13F2200D08393 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = LibreMonitorUITests;\n\t\t\tproductName = LibreMonitorUITests;\n\t\t\tproductReference = C6822D861DB13F2200D08393 /* LibreMonitorUITests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.ui-testing\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tC6822D5A1DB13F2200D08393 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0800;\n\t\t\t\tLastUpgradeCheck = 0820;\n\t\t\t\tORGANIZATIONNAME = \"Uwe Petersen\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tC6822D611DB13F2200D08393 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tDevelopmentTeam = 26F6YWJYL8;\n\t\t\t\t\t\tLastSwiftMigration = 0810;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t\tSystemCapabilities = {\n\t\t\t\t\t\t\tcom.apple.BackgroundModes = {\n\t\t\t\t\t\t\t\tenabled = 1;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tcom.apple.HealthKit = {\n\t\t\t\t\t\t\t\tenabled = 1;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t\tC6822D7A1DB13F2200D08393 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tDevelopmentTeam = 26F6YWJYL8;\n\t\t\t\t\t\tLastSwiftMigration = 0800;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t\tTestTargetID = C6822D611DB13F2200D08393;\n\t\t\t\t\t};\n\t\t\t\t\tC6822D851DB13F2200D08393 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tDevelopmentTeam = 26F6YWJYL8;\n\t\t\t\t\t\tLastSwiftMigration = 0800;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t\tTestTargetID = C6822D611DB13F2200D08393;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = C6822D5D1DB13F2200D08393 /* Build configuration list for PBXProject \"LibreMonitor\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = C6822D591DB13F2200D08393;\n\t\t\tproductRefGroup = C6822D631DB13F2200D08393 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tC6822D611DB13F2200D08393 /* LibreMonitor */,\n\t\t\t\tC6822D7A1DB13F2200D08393 /* LibreMonitorTests */,\n\t\t\t\tC6822D851DB13F2200D08393 /* LibreMonitorUITests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tC6822D601DB13F2200D08393 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tC6822D751DB13F2200D08393 /* LaunchScreen.storyboard in Resources */,\n\t\t\t\tC6822D721DB13F2200D08393 /* Assets.xcassets in Resources */,\n\t\t\t\tC61C296C1DB16C60009A5885 /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tC6822D791DB13F2200D08393 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tC6822D841DB13F2200D08393 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t19AB2018DB2E7FFBCFDA6F6B /* [CP] Copy Pods Resources */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"[CP] Copy Pods Resources\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${SRCROOT}/Pods/Target Support Files/Pods-LibreMonitor/Pods-LibreMonitor-resources.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t4B935F2F04D9D35ADFEF9391 /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_ROOT}/../Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t7ABA004F1E59594A6108DE52 /* [CP] Embed Pods Frameworks */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"[CP] Embed Pods Frameworks\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${SRCROOT}/Pods/Target Support Files/Pods-LibreMonitor/Pods-LibreMonitor-frameworks.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t937C85C62A3BBC97CAB8CD1C /* [CP] Embed Pods Frameworks */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"[CP] Embed Pods Frameworks\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${SRCROOT}/Pods/Target Support Files/Pods-LibreMonitorTests/Pods-LibreMonitorTests-frameworks.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t951B3668E1ADFC92ED178434 /* [CP] Embed Pods Frameworks */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"[CP] Embed Pods Frameworks\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${SRCROOT}/Pods/Target Support Files/Pods-LibreMonitorUITests/Pods-LibreMonitorUITests-frameworks.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tA725505D03BE411795C63648 /* [CP] Copy Pods Resources */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"[CP] Copy Pods Resources\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${SRCROOT}/Pods/Target Support Files/Pods-LibreMonitorUITests/Pods-LibreMonitorUITests-resources.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tA86EDE06FCDE9DED1918E865 /* [CP] Copy Pods Resources */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"[CP] Copy Pods Resources\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${SRCROOT}/Pods/Target Support Files/Pods-LibreMonitorTests/Pods-LibreMonitorTests-resources.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tACC5AE5D94CFB4897C7237F1 /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_ROOT}/../Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tBDD349C2E88A839DFD7221CD /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_ROOT}/../Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tC6822D5E1DB13F2200D08393 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tC6822DDA1DB1631D00D08393 /* Sensor+CoreDataProperties.swift in Sources */,\n\t\t\t\tC6822DC81DB162E900D08393 /* CoreDataStack.swift in Sources */,\n\t\t\t\tC6822DC21DB161C700D08393 /* BloodSugarGraphView.swift in Sources */,\n\t\t\t\tC6822DD81DB1631D00D08393 /* Reader+CoreDataProperties.swift in Sources */,\n\t\t\t\tC6822DD51DB1631D00D08393 /* BloodGlucose+CoreDataClass.swift in Sources */,\n\t\t\t\tC6822DDC1DB1631D00D08393 /* HeaderData+CoreDataProperties.swift in Sources */,\n\t\t\t\tC6822DAC1DB1616300D08393 /* NSData+SLIP.m in Sources */,\n\t\t\t\tC6822D661DB13F2200D08393 /* AppDelegate.swift in Sources */,\n\t\t\t\tC6822DB61DB1618400D08393 /* LibreSensor.swift in Sources */,\n\t\t\t\tC6822D691DB13F2200D08393 /* LibreMonitor.xcdatamodeld in Sources */,\n\t\t\t\tC6822DD61DB1631D00D08393 /* BloodGlucose+CoreDataProperties.swift in Sources */,\n\t\t\t\tC6822DC31DB161C700D08393 /* BloodSugarGraphViewTableViewCell.swift in Sources */,\n\t\t\t\tC6822DB71DB1618400D08393 /* Measurement.swift in Sources */,\n\t\t\t\tC6822DB91DB1618400D08393 /* SensorState.swift in Sources */,\n\t\t\t\tC6822DDB1DB1631D00D08393 /* HeaderData+CoreDataClass.swift in Sources */,\n\t\t\t\tC6822DD71DB1631D00D08393 /* Reader+CoreDataClass.swift in Sources */,\n\t\t\t\tC6822DB81DB1618400D08393 /* SensorData.swift in Sources */,\n\t\t\t\tC6822DBD1DB161AB00D08393 /* AdjustmentsTableViewController.swift in Sources */,\n\t\t\t\tC6822DBE1DB161AB00D08393 /* BloodSugarTableViewController.swift in Sources */,\n\t\t\t\tC6822DAD1DB1616300D08393 /* SimbleeManager.swift in Sources */,\n\t\t\t\tC6822DB51DB1618400D08393 /* CRC.swift in Sources */,\n\t\t\t\tC6822DAE1DB1616300D08393 /* SLIPBuffer.swift in Sources */,\n\t\t\t\tC6822DAB1DB1616300D08393 /* NSData+CRC8.m in Sources */,\n\t\t\t\tC6822DAA1DB1616300D08393 /* Data_types+Extensions.swift in Sources */,\n\t\t\t\tC6822DD91DB1631D00D08393 /* Sensor+CoreDataClass.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tC6822D771DB13F2200D08393 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tC60178961E3E7FE5008FCF3A /* BluetoothTestData.swift in Sources */,\n\t\t\t\tC6822DC51DB161F900D08393 /* LibreMonitorTestSensorData.swift in Sources */,\n\t\t\t\tC6652F1F1DB1801D00237E7D /* libUBP.m in Sources */,\n\t\t\t\tC65E6DA21E45070800A85E0E /* TransmissionTests.swift in Sources */,\n\t\t\t\tC6652F1E1DB1801D00237E7D /* crc8.m in Sources */,\n\t\t\t\tC6822D801DB13F2200D08393 /* LibreMonitorTests.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tC6822D821DB13F2200D08393 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tC6822D8B1DB13F2200D08393 /* LibreMonitorUITests.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\tC6822D7D1DB13F2200D08393 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = C6822D611DB13F2200D08393 /* LibreMonitor */;\n\t\t\ttargetProxy = C6822D7C1DB13F2200D08393 /* PBXContainerItemProxy */;\n\t\t};\n\t\tC6822D881DB13F2200D08393 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = C6822D611DB13F2200D08393 /* LibreMonitor */;\n\t\t\ttargetProxy = C6822D871DB13F2200D08393 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\tC6822D731DB13F2200D08393 /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tC6822D741DB13F2200D08393 /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tC6822D8D1DB13F2200D08393 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tC6822D8E1DB13F2200D08393 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tC6822D901DB13F2200D08393 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 9C01D6FD2C7EC8B142986E40 /* Pods-LibreMonitor.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = LibreMonitor/LibreMonitor.entitlements;\n\t\t\t\tDEVELOPMENT_TEAM = 26F6YWJYL8;\n\t\t\t\tINFOPLIST_FILE = LibreMonitor/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = UPP.LibreMonitor;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"LibreMonitor/LibreMonitor-Bridging-Header.h\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 3.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tC6822D911DB13F2200D08393 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 771CB977837C430DB5630E78 /* Pods-LibreMonitor.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = LibreMonitor/LibreMonitor.entitlements;\n\t\t\t\tDEVELOPMENT_TEAM = 26F6YWJYL8;\n\t\t\t\tINFOPLIST_FILE = LibreMonitor/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = UPP.LibreMonitor;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"LibreMonitor/LibreMonitor-Bridging-Header.h\";\n\t\t\t\tSWIFT_VERSION = 3.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tC6822D931DB13F2200D08393 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 20B072583FD87F7318BD08D0 /* Pods-LibreMonitorTests.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tDEVELOPMENT_TEAM = 26F6YWJYL8;\n\t\t\t\tINFOPLIST_FILE = LibreMonitorTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tNEW_SETTING = \"\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = UPP.LibreMonitorTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"LibreMonitorTests/LibreMonitorTests-Bridging-Header.h\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 3.0;\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/LibreMonitor.app/LibreMonitor\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tC6822D941DB13F2200D08393 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = ECBB8DB6FD66440727AC6903 /* Pods-LibreMonitorTests.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tDEVELOPMENT_TEAM = 26F6YWJYL8;\n\t\t\t\tINFOPLIST_FILE = LibreMonitorTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tNEW_SETTING = \"\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = UPP.LibreMonitorTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"LibreMonitorTests/LibreMonitorTests-Bridging-Header.h\";\n\t\t\t\tSWIFT_VERSION = 3.0;\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/LibreMonitor.app/LibreMonitor\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tC6822D961DB13F2200D08393 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = D8227FF2A03737CDDF22876F /* Pods-LibreMonitorUITests.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = \"$(inherited)\";\n\t\t\t\tDEVELOPMENT_TEAM = 26F6YWJYL8;\n\t\t\t\tINFOPLIST_FILE = LibreMonitorUITests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = UPP.LibreMonitorUITests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 3.0;\n\t\t\t\tTEST_TARGET_NAME = LibreMonitor;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tC6822D971DB13F2200D08393 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = F858C2A695CEC9FB81DC9A5A /* Pods-LibreMonitorUITests.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = \"$(inherited)\";\n\t\t\t\tDEVELOPMENT_TEAM = 26F6YWJYL8;\n\t\t\t\tINFOPLIST_FILE = LibreMonitorUITests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = UPP.LibreMonitorUITests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 3.0;\n\t\t\t\tTEST_TARGET_NAME = LibreMonitor;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tC6822D5D1DB13F2200D08393 /* Build configuration list for PBXProject \"LibreMonitor\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tC6822D8D1DB13F2200D08393 /* Debug */,\n\t\t\t\tC6822D8E1DB13F2200D08393 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tC6822D8F1DB13F2200D08393 /* Build configuration list for PBXNativeTarget \"LibreMonitor\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tC6822D901DB13F2200D08393 /* Debug */,\n\t\t\t\tC6822D911DB13F2200D08393 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tC6822D921DB13F2200D08393 /* Build configuration list for PBXNativeTarget \"LibreMonitorTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tC6822D931DB13F2200D08393 /* Debug */,\n\t\t\t\tC6822D941DB13F2200D08393 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tC6822D951DB13F2200D08393 /* Build configuration list for PBXNativeTarget \"LibreMonitorUITests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tC6822D961DB13F2200D08393 /* Debug */,\n\t\t\t\tC6822D971DB13F2200D08393 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCVersionGroup section */\n\t\tC6822D671DB13F2200D08393 /* LibreMonitor.xcdatamodeld */ = {\n\t\t\tisa = XCVersionGroup;\n\t\t\tchildren = (\n\t\t\t\tC6822D681DB13F2200D08393 /* LibreMonitor.xcdatamodel */,\n\t\t\t);\n\t\t\tcurrentVersion = C6822D681DB13F2200D08393 /* LibreMonitor.xcdatamodel */;\n\t\t\tpath = LibreMonitor.xcdatamodeld;\n\t\t\tsourceTree = \"<group>\";\n\t\t\tversionGroupType = wrapper.xcdatamodel;\n\t\t};\n/* End XCVersionGroup section */\n\t};\n\trootObject = C6822D5A1DB13F2200D08393 /* Project object */;\n}\n"
  },
  {
    "path": "LibreMonitor.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:LibreMonitor.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "LibreMonitor.xcodeproj/xcuserdata/Uwe.xcuserdatad/xcschemes/LibreMonitor.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0820\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"C6822D611DB13F2200D08393\"\n               BuildableName = \"LibreMonitor.app\"\n               BlueprintName = \"LibreMonitor\"\n               ReferencedContainer = \"container:LibreMonitor.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"C6822D7A1DB13F2200D08393\"\n               BuildableName = \"LibreMonitorTests.xctest\"\n               BlueprintName = \"LibreMonitorTests\"\n               ReferencedContainer = \"container:LibreMonitor.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"C6822D851DB13F2200D08393\"\n               BuildableName = \"LibreMonitorUITests.xctest\"\n               BlueprintName = \"LibreMonitorUITests\"\n               ReferencedContainer = \"container:LibreMonitor.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"C6822D611DB13F2200D08393\"\n            BuildableName = \"LibreMonitor.app\"\n            BlueprintName = \"LibreMonitor\"\n            ReferencedContainer = \"container:LibreMonitor.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"C6822D611DB13F2200D08393\"\n            BuildableName = \"LibreMonitor.app\"\n            BlueprintName = \"LibreMonitor\"\n            ReferencedContainer = \"container:LibreMonitor.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"C6822D611DB13F2200D08393\"\n            BuildableName = \"LibreMonitor.app\"\n            BlueprintName = \"LibreMonitor\"\n            ReferencedContainer = \"container:LibreMonitor.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "LibreMonitor.xcodeproj/xcuserdata/Uwe.xcuserdatad/xcschemes/xcschememanagement.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>SchemeUserState</key>\n\t<dict>\n\t\t<key>LibreMonitor.xcscheme</key>\n\t\t<dict>\n\t\t\t<key>orderHint</key>\n\t\t\t<integer>0</integer>\n\t\t</dict>\n\t</dict>\n\t<key>SuppressBuildableAutocreation</key>\n\t<dict>\n\t\t<key>C6822D611DB13F2200D08393</key>\n\t\t<dict>\n\t\t\t<key>primary</key>\n\t\t\t<true/>\n\t\t</dict>\n\t\t<key>C6822D7A1DB13F2200D08393</key>\n\t\t<dict>\n\t\t\t<key>primary</key>\n\t\t\t<true/>\n\t\t</dict>\n\t\t<key>C6822D851DB13F2200D08393</key>\n\t\t<dict>\n\t\t\t<key>primary</key>\n\t\t\t<true/>\n\t\t</dict>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "LibreMonitor.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"group:LibreMonitor.xcodeproj\">\n   </FileRef>\n   <FileRef\n      location = \"group:Pods/Pods.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "LibreMonitor.xcworkspace/xcuserdata/Uwe.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Bucket\n   type = \"0\"\n   version = \"2.0\">\n   <Breakpoints>\n      <BreakpointProxy\n         BreakpointExtensionID = \"Xcode.Breakpoint.FileBreakpoint\">\n         <BreakpointContent\n            shouldBeEnabled = \"Yes\"\n            ignoreCount = \"0\"\n            continueAfterRunningActions = \"No\"\n            filePath = \"LibreMonitor/Model/HealthManager.swift\"\n            timestampString = \"499522065.570329\"\n            startingColumnNumber = \"9223372036854775807\"\n            endingColumnNumber = \"9223372036854775807\"\n            startingLineNumber = \"166\"\n            endingLineNumber = \"166\">\n         </BreakpointContent>\n      </BreakpointProxy>\n      <BreakpointProxy\n         BreakpointExtensionID = \"Xcode.Breakpoint.FileBreakpoint\">\n         <BreakpointContent\n            shouldBeEnabled = \"No\"\n            ignoreCount = \"0\"\n            continueAfterRunningActions = \"No\"\n            filePath = \"LibreMonitor/Bluetooth/NSData+CRC8.m\"\n            timestampString = \"504464734.229976\"\n            startingColumnNumber = \"9223372036854775807\"\n            endingColumnNumber = \"9223372036854775807\"\n            startingLineNumber = \"56\"\n            endingLineNumber = \"56\"\n            landmarkName = \"+CRC8ChecksumFromBuffer:bytesToRead:\"\n            landmarkType = \"7\">\n         </BreakpointContent>\n      </BreakpointProxy>\n      <BreakpointProxy\n         BreakpointExtensionID = \"Xcode.Breakpoint.FileBreakpoint\">\n         <BreakpointContent\n            shouldBeEnabled = \"No\"\n            ignoreCount = \"0\"\n            continueAfterRunningActions = \"No\"\n            filePath = \"LibreMonitor/Bluetooth/NSData+CRC8.m\"\n            timestampString = \"504464734.229976\"\n            startingColumnNumber = \"9223372036854775807\"\n            endingColumnNumber = \"9223372036854775807\"\n            startingLineNumber = \"53\"\n            endingLineNumber = \"53\"\n            landmarkName = \"+CRC8ChecksumFromBuffer:bytesToRead:\"\n            landmarkType = \"7\">\n         </BreakpointContent>\n      </BreakpointProxy>\n      <BreakpointProxy\n         BreakpointExtensionID = \"Xcode.Breakpoint.FileBreakpoint\">\n         <BreakpointContent\n            shouldBeEnabled = \"No\"\n            ignoreCount = \"0\"\n            continueAfterRunningActions = \"No\"\n            filePath = \"LibreMonitor/ViewControllers/BloodSugarTableViewController.swift\"\n            timestampString = \"504479991.758528\"\n            startingColumnNumber = \"9223372036854775807\"\n            endingColumnNumber = \"9223372036854775807\"\n            startingLineNumber = \"371\"\n            endingLineNumber = \"371\"\n            landmarkName = \"simbleeManagerReceivedMessage(_:txFlags:payloadData:)\"\n            landmarkType = \"7\">\n         </BreakpointContent>\n      </BreakpointProxy>\n      <BreakpointProxy\n         BreakpointExtensionID = \"Xcode.Breakpoint.FileBreakpoint\">\n         <BreakpointContent\n            shouldBeEnabled = \"No\"\n            ignoreCount = \"0\"\n            continueAfterRunningActions = \"No\"\n            filePath = \"LibreMonitor/Bluetooth/SLIPBuffer.swift\"\n            timestampString = \"504480206.689479\"\n            startingColumnNumber = \"9223372036854775807\"\n            endingColumnNumber = \"9223372036854775807\"\n            startingLineNumber = \"139\"\n            endingLineNumber = \"139\"\n            landmarkName = \"decodeSLIPPacket(_:)\"\n            landmarkType = \"7\">\n         </BreakpointContent>\n      </BreakpointProxy>\n      <BreakpointProxy\n         BreakpointExtensionID = \"Xcode.Breakpoint.FileBreakpoint\">\n         <BreakpointContent\n            shouldBeEnabled = \"No\"\n            ignoreCount = \"0\"\n            continueAfterRunningActions = \"No\"\n            filePath = \"LibreMonitor/Bluetooth/SLIPBuffer.swift\"\n            timestampString = \"504480657.511635\"\n            startingColumnNumber = \"9223372036854775807\"\n            endingColumnNumber = \"9223372036854775807\"\n            startingLineNumber = \"138\"\n            endingLineNumber = \"138\"\n            landmarkName = \"decodeSLIPPacket(_:)\"\n            landmarkType = \"7\">\n         </BreakpointContent>\n      </BreakpointProxy>\n      <BreakpointProxy\n         BreakpointExtensionID = \"Xcode.Breakpoint.FileBreakpoint\">\n         <BreakpointContent\n            shouldBeEnabled = \"Yes\"\n            ignoreCount = \"0\"\n            continueAfterRunningActions = \"No\"\n            filePath = \"LibreMonitorTests/LibreMonitorTests.swift\"\n            timestampString = \"507995642.096269\"\n            startingColumnNumber = \"9223372036854775807\"\n            endingColumnNumber = \"9223372036854775807\"\n            startingLineNumber = \"108\"\n            endingLineNumber = \"108\"\n            landmarkName = \"transmission(forPayload:packetIdentifier:)\"\n            landmarkType = \"7\">\n         </BreakpointContent>\n      </BreakpointProxy>\n      <BreakpointProxy\n         BreakpointExtensionID = \"Xcode.Breakpoint.FileBreakpoint\">\n         <BreakpointContent\n            shouldBeEnabled = \"Yes\"\n            ignoreCount = \"0\"\n            continueAfterRunningActions = \"No\"\n            filePath = \"LibreMonitorTests/SimbleeCode/libUBP.m\"\n            timestampString = \"507926865.02826\"\n            startingColumnNumber = \"9223372036854775807\"\n            endingColumnNumber = \"9223372036854775807\"\n            startingLineNumber = \"59\"\n            endingLineNumber = \"59\"\n            landmarkName = \"_UBP_pumpTxQueue()\"\n            landmarkType = \"9\">\n         </BreakpointContent>\n      </BreakpointProxy>\n      <BreakpointProxy\n         BreakpointExtensionID = \"Xcode.Breakpoint.FileBreakpoint\">\n         <BreakpointContent\n            shouldBeEnabled = \"No\"\n            ignoreCount = \"0\"\n            continueAfterRunningActions = \"No\"\n            filePath = \"LibreMonitorTests/SimbleeCode/libUBP.m\"\n            timestampString = \"507926933.030084\"\n            startingColumnNumber = \"9223372036854775807\"\n            endingColumnNumber = \"9223372036854775807\"\n            startingLineNumber = \"178\"\n            endingLineNumber = \"178\"\n            landmarkName = \"UBP_queuePacketTransmission()\"\n            landmarkType = \"9\">\n         </BreakpointContent>\n      </BreakpointProxy>\n      <BreakpointProxy\n         BreakpointExtensionID = \"Xcode.Breakpoint.FileBreakpoint\">\n         <BreakpointContent\n            shouldBeEnabled = \"No\"\n            ignoreCount = \"0\"\n            continueAfterRunningActions = \"No\"\n            filePath = \"LibreMonitorTests/SimbleeCode/libUBP.m\"\n            timestampString = \"507927454.722968\"\n            startingColumnNumber = \"9223372036854775807\"\n            endingColumnNumber = \"9223372036854775807\"\n            startingLineNumber = \"232\"\n            endingLineNumber = \"232\"\n            landmarkName = \"_UBP_makeEscapedCopy()\"\n            landmarkType = \"9\">\n         </BreakpointContent>\n      </BreakpointProxy>\n      <BreakpointProxy\n         BreakpointExtensionID = \"Xcode.Breakpoint.FileBreakpoint\">\n         <BreakpointContent\n            shouldBeEnabled = \"No\"\n            ignoreCount = \"0\"\n            continueAfterRunningActions = \"No\"\n            filePath = \"LibreMonitorTests/SimbleeCode/libUBP.m\"\n            timestampString = \"507985099.799846\"\n            startingColumnNumber = \"9223372036854775807\"\n            endingColumnNumber = \"9223372036854775807\"\n            startingLineNumber = \"239\"\n            endingLineNumber = \"239\"\n            landmarkName = \"_UBP_makeEscapedCopy()\"\n            landmarkType = \"9\">\n         </BreakpointContent>\n      </BreakpointProxy>\n      <BreakpointProxy\n         BreakpointExtensionID = \"Xcode.Breakpoint.FileBreakpoint\">\n         <BreakpointContent\n            shouldBeEnabled = \"Yes\"\n            ignoreCount = \"0\"\n            continueAfterRunningActions = \"No\"\n            filePath = \"LibreMonitorTests/LibreMonitorTests.swift\"\n            timestampString = \"507995628.084306\"\n            startingColumnNumber = \"9223372036854775807\"\n            endingColumnNumber = \"9223372036854775807\"\n            startingLineNumber = \"85\"\n            endingLineNumber = \"85\"\n            landmarkName = \"slipBufferReceivedPayload(_:payloadIdentifier:txFlags:)\"\n            landmarkType = \"7\">\n         </BreakpointContent>\n      </BreakpointProxy>\n   </Breakpoints>\n</Bucket>\n"
  },
  {
    "path": "LibreMonitorRFduino.ino",
    "content": "//#include <RFduinoBLE.h>\n\n///\n///   LibreMonitor\n/// \n///   Copyright (c) 2015 Uwe Petersen, all right reserved\n///\n///   Wiring connections:\n///\n///      BM019            RFduino/Simblee\n///      DIN:  pin 2      IRQ:  GPIO pin 2\n///      SS:   pin 3      SS:   GPIO pin 3\n///      MISO: pin 4      MISO: GPIO pin 4\n///      MOSI: pin 5      MOSI: GPIO pin 5\n///      SCK:  pin 6      SCK:  GPIO pin 6\n///      SS0:  pin 7      +3V-pin\n///      GND:  pin 10     GND-pin\n///\n///      BM019            BM019\n///      SS0:  pin 7       VDD:  pin 8 (Output 3,3V from BM019)\n///      \n///      BM019            Lipo Power source (I use a 100mAh lip which lasts a full day\n///      VIN:  pin 9      \"+\" of lipo / lipo charger\n///      GND:  pin 10     GND/\"-\" of lipo / lipo charger\n///\n///      You can place a switch between GND of lipo/lipo-charger and GND of the BM019 \n///\n///      SPI-WIRING\n///      If wired as suggested above, then you have to change the Simblee SPI pins for SS, MOSI, MISO and SCK. \n///      This is done in the variant.h file. In my case this file is located (dependent on the Simblee/RFduino \n///      version) in\n///\n///         /Users/[my user name]/Library/Arduino15/packages/Simblee/hardware/Simblee/1.0.0/variants/Simblee or \n///         /Users/[my user name]/Library/Arduino15/packages/RFduino/hardware/RFduino/2.3.3/variants\n///\n///      In this file set the defines for the SPI pins as follows:\n///\n///         #define PIN_SPI_SS           (3u)\n///         #define PIN_SPI_MOSI         (5u)\n///         #define PIN_SPI_MISO         (4u)\n///         #define PIN_SPI_SCK          (6u)\n///\n///\n///   Acknowledgements:\n///\n///      RFduinoUBP\n///\n///         This code uses portions of RFduinoUB, which can be retrieved from \n///              https://github.com/cconway/RFduinoUBP under the following license:\n///         The MIT License (MIT)\n///         Copyright (c) 2015 cconway\n///         Permission is hereby granted, free of charge, to any person obtaining a copy\n///         of this software and associated documentation files (the \"Software\"), to deal\n///         in the Software without restriction, including without limitation the rights\n///         to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n///         copies of the Software, and to permit persons to whom the Software is\n///         furnished to do so, subject to the following conditions:\n///         The above copyright notice and this permission notice shall be included in all\n///         copies or substantial portions of the Software.\n///         THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n///         IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n///         FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n///         AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n///         LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n///         OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n///         SOFTWARE.\n///\n///      Solutions Cubed LLC  \n///\n///         The author is grateful to Solutions Cubed LLC, see http://www.solutions-cubed.com, \n///         for providing helpful code samples for their BM019 nfc module, portions of which are \n///         used within this code. \n///\n///\n///   Choose between Simblee or RFduino hardware\n///\n///   If you want to switch between RFduino and Simblee or vice versa, be aware of the following tasks:\n///     1. Follow the instructions in the simblee quick start guide (https://www.simblee.com/Simblee_Quickstart_Guide_v1.1.0.pdf) \n///        or the RFduino dcoumentation (https://github.com/RFduino/RFduino/blob/master/README.md) on how to install the \n///        arduino libraries needed.\n///     2. Set your additional board manager in the Arduino IDE preferences to either Simblee or RFduino. \n///        With the Arduino IDE open, click on Arduino > Preferences\n///        a) For Simblee: Copy and Paste the following link into Additional Boards Manager \n///           URLs: https://www.simblee.com/package_simblee166_index.json then press “OK”\n///        b) For RFduino: Add http://rfduino.com/package_rfduino166_index.json to Additional Board Manager URLs and save.\n///     3. Go to Tools > Board: > Boards Manager... and install the corresponding board.\n///     4. Go to Go to Tools > Board: and choose the Simblee or RFduino board.\n///     5. In the arduino IDE goto sketch and incorporate the RFduinoBLE or the SimbleBLE library respectively\n///     6. If you had to install the Simblee or RFduino package be sure to reconfigure the SPI wiring in the\n///        variants.h file, as explained in the SPI-WIRING section in the above comments on wiring connections\n///     7. Set the following #define to SIMBLEE for using a Simblee or comment it out to use a RFduino\n///     8. Do the same in the libUPB.cpp in the corresponding library for this project.\n///\n//#define SIMBLEE   // IF a Simblee is used, you have to define SIMBLEE, otherwise it is assumed you use a RFduino.\n\n// Include application, user and local libraries\n#ifdef SIMBLEE\n#include <SimbleeBLE.h>\n#include <SimbleeForMobile.h>\n#else\n#include <RFduinoBLE.h>\n#endif\n\n#include <SPI.h>               // the sensor communicates using SPI, so include the library\n// This code uses the SLIP protocol to transer the data via bluetooth, see https://github.com/cconway/RFduinoUBP\n#include <constants.h>\n#include <crc8.h>\n#include <data_types.h>\n#include <libUBP.h>\n#include <SPIstuff.h>\n\n\n// Define variables and constants\n\n/* CR95HF Commands */\n#define IDN               0x01  // identification number of CR95HF\n#define SELECT_PROTOCOL   0x02  // select protocol\n#define POLL              0x03  // poll\n#define SENDRECEIVE       0x04  // send and receive data (most commonly used)\n#define READ              0x05  // read values from registers internal to CR95HF\n#define WRITE             0x06  // write values to registers internal to CR95HF\n#define ECHO              0x55\n\n// send receive commands for ISO/IEC 15693 protocol\n#define INVENTORY               0x01  // receives information about tags in range\n#define STAY_QUIET              0x02  // selected unit will not send back a response\n#define READ_BLOCK              0x20  // read single block of memory from RF tag\n#define WRITE_BLOCK             0x21  // write single block to memory of RF tag\n#define LOCK_BLOCK              0x22  // permanently locks a block of memory on RF tag\n#define READ_BLOCKS             0x23  // reads multiple blocks of memory from RF tag\n#define WRITE_BLOCKS            0x24  // writes multiple blocks of memory to RF tag\n#define SELECT                  0x25  // used to select a specific tag for communication via the uid\n#define RESET_TO_READY          0x26  // resets RF tag to ready state\n#define WRITE_AFI               0x27  // writes application family identifier to RF tag\n#define LOCK_AFI                0x28  // permanently locks application family identifier\n#define WRITE_DSFID             0x29  // writes data storage format identifier to RF tag\n#define LOCK_DSFID              0x2A  // permanentlylocks data storage format identifier\n#define GET_SYSTEM_INFORMATION  0x2B  // gets information from RF tag that includes memory\n// block size in bytes and number of memory blocks\n#define GET_BLOCKS_SECURITY_STATUS  0x2C\n\n// Request flag with bits set these rules:\n//     Bit  Flag name           Description\n//      1   Sub-carrier flag    0 ... single sub-carrier used\n//                              1 ... two sub-carriers used\n//      2   Data rate flag      0 ... low data rate is used\n//                              1 ... high data rate is used\n//      3   Inventory flag      State determines how bits 5-8 are defined\n//                              0 ... flag not set\n//                              1 ... flag set\n//      4   Protocol            0: no protocol extension\n//          extension flag      1: protocol format is extended\n//   If Inventory flag = 0 (not set):\n//      5   Select flag         0: request shall be executed based on setting of the address flag\n//                              1: request shall be executed only by devices in the selected state\n//      6   Address flag        0: request is not addressed\n//                              1: request is addressed, optional UID field is present\n//      7   Option flag         Meaning is defined by the command description, if not used set to 0\n//      8   reserved\n//   If Inventory flag = 1 (set):\n//      5   AFI flag            0: AFI field is not present\n//                              1: AFI field is present\n//      6   Number of           0: 16 slots\n//          slots flag          1: 1 slot\n//      7   Option flag         Meaning is defined by the command description, if not used set to 0\n//      8   reserved\n//\n//  Helper bit field by to quickly calculate integers from hex and vice versa:\n//      Bit no.:     8   7   6   5      4   3   2   1\n//      value:     128  64  32  16      8   4   2   1\n//      choose:      0   0   0   0      4   0   2   1   result is 0x03\n//\n// request flags byte, 0x26 means:\n//   single sub carrier, high data rate, inventory flag set, no protocoll extentsion, AFI not present, one slot)\n\n\n// Settings\n\n#define DEBUG\n\nconst int SS_PIN = 3;   // Slave Select pin, changed to new value on 2016-03-21\nconst int IRQ_PIN = 2;  // IRQ/DIN pin used for wake-up pulse\nbyte RXBuffer[400];     // receive buffer\nbyte dataBuffer[400];   // buffer for Freestyle Libre byte data\nbyte NFCReady = 0;      // used to track NFC state\nconst int SPI_FREQUENCY = 2000; // max. for CR95HF is 2000 = 2 MHz\nconst uint64_t SLEEP_DURATION = 20000;  // Duration of Simblee ultra low power mode in ms\n//const uint64_t SLEEP_DURATION = 120000;  // Duration of Simblee ultra low power mode in ms\n\n// Code\n\nvoid setupPins() {\n  Serial.println(\"Setting Simblee pins ...\");\n  pinMode(IRQ_PIN, OUTPUT);\n  pinMode(SS_PIN, OUTPUT);\n  // Commented out by Uwi on 15.11.2015: was not needed obviously\n  //    digitalWrite(SS_PIN, HIGH);\n  Serial.println(\"... done setting Simblee pins.\");\n}\n\nvoid setupSPI() {\n  Serial.println(\"Setting up SPI ...\");\n  SPI.begin();\n  SPI.setDataMode(SPI_MODE0);\n  SPI.setBitOrder(MSBFIRST);\n  SPI.setFrequency(SPI_FREQUENCY);\n  Serial.println(\"... done setting up SPI.\");\n}\n// --------------------------\n\nvoid setupBluetoothConnection() {\n  Serial.println(\"Setup Bluetooth stack and start connection...\");\n#ifdef SIMBLEE\n  SimbleeBLE.deviceName = \"LibreCGM\";\n  SimbleeBLE.customUUID = \"2220\";\n  SimbleeBLE.advertisementData = \"data\";\n  SimbleeBLE.advertisementInterval = MILLISECONDS(500);  // Default was 300\n  SimbleeBLE.txPowerLevel = 4;  // Possible values: -20, -16, -12, -8, -4, 0 or +4 (dbM)  // up to 20016-05-17 this was 0\n  //    SimbleeBLE.txPowerLevel = -4;  // Possible values: -20, -16, -12, -8, -4, 0 or +4 (dbM)  // up to 20016-05-17 this was 0\n  SimbleeBLE.begin();           // Start the BLE stack\n#else\n  RFduinoBLE.deviceName = \"LibreCGM\";\n//  RFduinoBLE.customUUID = \"2220\";\n  RFduinoBLE.advertisementData = \"data\";\n  RFduinoBLE.advertisementInterval = MILLISECONDS(500);  // Default was 300\n  RFduinoBLE.txPowerLevel = 4;  // Possible values: -20, -16, -12, -8, -4, 0 or +4 (dbM)  // up to 20016-05-17 this was 0\n  //    SimbleeBLE.txPowerLevel = -4;  // Possible values: -20, -16, -12, -8, -4, 0 or +4 (dbM)  // up to 20016-05-17 this was 0\n  RFduinoBLE.begin();           // Start the BLE stack\n#endif\n  Serial.println(\"... done seting up Bluetooth stack and starting connection.\");\n}\n\n// Add setup code\nvoid setup() {\n  Serial.begin(9600);\n  setupPins();  // set RFduino/Simblee pins\n  setupSPI();\n\n  Serial.println(\"Please provide power to the BM019 within the next 5 seconds ...\");\n  delay(5000);\n\n  sendWakeupPulse(IRQ_PIN);  // wake up BM019 and set to SPI (since SS_0 is wired up to be HIGH)\n  readWakeUPEventRegister(SS_PIN, RXBuffer);\n  setupBluetoothConnection();\n}\n\n\n\n// SetProtocol_Command programs the CR95HF for ISO/IEC 15693 operation.\n// If the correct response is received the serial monitor is used to display successful programming.\n// Warning: if the parameters of the protocol are changed, e.g. sub carrier, then the request flags\n// of the other commands (e.g. inventory, read single block) have to be changed accordingly.\nvoid SetProtocol_Command() {\n\n  // step 1 send the command\n  digitalWrite(SS_PIN, LOW);\n  SPI.transfer(0x00);  // SPI control byte to send command to CR95HF\n  SPI.transfer(0x02);  // Set protocol command\n  SPI.transfer(0x02);  // length of data to follow\n  SPI.transfer(0x01);  // code for ISO/IEC 15693\n  SPI.transfer(0x0F);  // Up till 2016-06-13: crc16, single, 30%, wait for SOF (wrong: Wait for SOF, 100% modulation, append CRC)\n  //    SPI.transfer(0x0D);  // Up till 2016-06-13: crc16, single, 30%, wait for SOF (wrong: Wait for SOF, 100% modulation, append CRC)\n  digitalWrite(SS_PIN, HIGH);\n  delay(1);\n\n  // step 2, poll for data ready\n  pollSPIUntilResponsIsReady(SS_PIN, RXBuffer);\n\n  // step 3, read the data\n  receiveSPIResponse(SS_PIN, RXBuffer);\n#ifdef DEBUG\n  Serial.println(\"RXBuffer is\");\n  for (byte i = 0; i < 2; i++) {\n    Serial.print(RXBuffer[i], HEX);\n    Serial.print(\" \");\n  }\n#endif\n  if ((RXBuffer[0] == 0) & (RXBuffer[1] == 0)) {\n    Serial.println(\"PROTOCOL SET-\");  //\n    NFCReady = 1; // NFC is ready\n  } else {\n    Serial.println(\"BAD RESPONSE TO SET PROTOCOL\");\n    NFCReady = 0; // NFC not ready\n  }\n  Serial.println(\" \");\n}\n\n\n// Reads the single block of 8 bytes with number blockNum from the BM019.\n// The BM019 has 244 Blocks of 8 bytes that can be read via ISO 15693 commands. The blocks are numbered 0 to 243.\n// Returns the result code of the command response (that indicates wether there was success or an error)\nbyte ReadSingleBlockReturn(int blockNum) {\n\n  RXBuffer[0] = SENDRECEIVE;   // command code for send receive CR95HF command\n  RXBuffer[1] = 0x03;          // length of data that follows (3 bytes)\n  //    RXBuffer[2] = 0x02;          // request Flags byte, single carrier, high data rate\n  RXBuffer[2] = 0x03;        // request Flags byte dual carrier, high data rate\n  RXBuffer[3] = 0x20;          // read single block Command for ISO/IEC 15693\n  RXBuffer[4] = blockNum;      // Block number\n\n  // step 1 send the command\n  sendSPICommand(SS_PIN, RXBuffer, 5);\n\n  // step 2, poll for data ready\n  pollSPIUntilResponsIsReady(SS_PIN, RXBuffer);\n\n  // step 3, read the data\n  receiveSPIResponse(SS_PIN, RXBuffer);\n\n  delay(1);\n#ifdef DEBUG\n  // Print to Serial\n  if (RXBuffer[0] == 128)  {\n    Serial.printf(\"The block #%d:\", blockNum);\n    for (byte i = 3; i < RXBuffer[1] + 3 - 4; i++) {\n      Serial.print(RXBuffer[i], HEX);\n      Serial.print(\" \");\n    }\n  } else {\n    Serial.print(\"NO Single block available - \");\n    Serial.print(\"RESPONSE CODE: \");\n    Serial.println(RXBuffer[0], HEX);\n  }\n  Serial.println(\" \");\n#endif\n\n  return RXBuffer[0];  // result code of command response\n}\n\n\n\n/// @brief  Sends command to BM019 and receives response serveral times until response with no error, max maxTrial times.\n/// @detail After maxTrials trials the last response is returned, even  if there is still an error.\n/// @detail Warning: Ensure that RXBuffer has appropriate size.\n/// @param  ssPin slave select pin for SPI digital write\n/// @param  RXBuffer buffer used for command and response\n/// @param  maxTrials max number of trials\nvoid runSPICommandUntilNoError(int ssPin, byte *command, int length, byte *RXBuffer, int maxTrials) {\n\n  int count = 0;\n  bool success;\n  do {\n    delay(1);\n#ifdef DEBUG\n    Serial.printf(\"Before: Count: %d, success: %b, RXBuffer[0]: %x \\r\\n\", count, success, RXBuffer[0]);\n#endif\n    count++;\n\n    // clear RXBuffer with zeros\n    memset(RXBuffer, 0, sizeof(RXBuffer));\n\n    // run SPI command\n    sendPollReceiveSPINew(ssPin, command, sizeof(command), RXBuffer);\n    success = responseHasNoError(RXBuffer);\n\n#ifdef DEBUG\n    Serial.printf(\"After: Count: %d, success: %b, RXBuffer[0]: %x \\r\\n\", count, success, RXBuffer[0]);\n#endif\n\n  } while ( !success && (count < maxTrials));\n  delay(1);\n#ifdef DEBUG\n  Serial.printf(\"Exiting at count: %d, RXBuffer[0]: %x \\r\\n\", count, RXBuffer[0]);\n#endif\n}\n\n/// @brief  Sends IDN command to BM019 and receives response serveral times until response with no error, max maxTrial times.\n/// @detail After maxTrials trials the last response is returned, even  if there is still an error.\n/// @detail Warning: Ensure that RXBuffer has appropriate size.\n/// @param  ssPin slave select pin for SPI digital write\n/// @param  RXBuffer buffer used for command and response\n/// @param  maxTrials max number of trials\nvoid runIDNCommandUntilNoError(int ssPin, byte *command, int length, byte *RXBuffer, int maxTrials) {\n\n  int count = 0;\n  bool success;\n  do {\n\n#ifdef DEBUG\n    Serial.printf(\"Before: Count: %d, success: %b, RXBuffer[0]: %x \\r\\n\", count, success, RXBuffer[0]);\n#endif\n    count++;\n\n    // clear RXBuffer with zeros\n    memset(RXBuffer, 0, sizeof(RXBuffer));\n\n    // run SPI command\n    sendPollReceiveSPINew(ssPin, command, sizeof(command), RXBuffer);\n    success = idnResponseHasNoError(RXBuffer);\n\n#ifdef DEBUG\n    Serial.printf(\"After: Count: %d, success: %b, RXBuffer[0]: %x \\r\\n\", count, success, RXBuffer[0]);\n#endif\n  } while ( !success && (count < maxTrials));\n  delay(10);\n#ifdef DEBUG\n  Serial.printf(\"Exiting at count: %d, RXBuffer[0]: %x \\r\\n\", count, RXBuffer[0]);\n#endif\n}\n\n\n/// Runs the system information command several times, i.e. maxTrials times or until a response with no error is gotten, whatever happens first.\n/// @param ssPin SS_PIN used for SPI\n/// @param RXBuffer buffer used for send and receive\n/// @param maxTrials maximum number of trials. If reached, the result is returned, even if there still is an error present\n/// @brief  Get system information from BM019\n/// @details  The response is read into RXBuffer and that's it, no matter if there is an error or not.\n/// @n Command format for CR95HF:\n/// @n 8 bits for request flags,\n/// @n 8 bits for the get system information command,i.e 0x2B,\n/// @n 64 bits for an optional UID (not used in non-addressed modes).\n/// @details Example get system info command (CR95HF command embedded in BM019 command):\n/// @details 0x04 ... BM019 send/receive command code\n/// @details 0x02 ... BM019 length of CR95HF command data that follows\n/// @details 0x02 ... CR95HF request flags byte (high data rate used)\n/// @details 0x2B ... CR95HF get system information command\n/// @n\n/// @n\n/// @details Example CR95HF response with no error:\n/// @details 0x80      ... result code\n/// @details 0x12      ... length of following data (12 bytes)\n/// @details 0x00      ... response flags\n/// @details 0x0F      ... info flags\n/// @details 0x69 0x55 0x19 0x38 0x42 0x20 0x02 0xE0 ... data: UID\n/// @details 0x00      ... DSFID (supported and field is present in response if bit 1 of info flags is set)\n/// @details 0x00      ... AFI (supported and field is present in response if bit 2 of info flags is set)\n/// @details 0x3F 0X03 ... memory size (supported and field is present in response if bit 3 of info flags is set)\n/// @details 0x20      ... IC Ref (supported and field is present in response if bit 4 of info flags is set)\n/// @details 0xB4 0xA9 ... CRC16\n/// @details 0x00      ... error\n/// @n\n/// @details Example CR95HF response with error (bit 0 of response flag is set)\n/// @details 0x01      ... response flags\n/// @details 0x01      ... error code (returned when error bit is set)\n/// @details 0xB4 0xA9 ... CRC16\n/// @details 0X01      ... (error CRC16 or collision error bits)\nvoid runSystemInformationCommandUntilNoError(int ssPin, byte *RXBuffer, int maxTrials) {\n#ifdef DEBUG\n  Serial.printf(\"ssPin: %d, maxTrials: %d, RXBuffer[0]: %x \\r\\n\", ssPin, maxTrials, RXBuffer[0]);\n#endif\n  byte command[4];\n  command[0] = 0x04;   // command code for send receive CR95HF command\n  command[1] = 0x02;   // length of data that follows (3 bytes)\n  command[2] = 0x03;   // request Flags byte, dual sub carrier\n  //    command[2] = 0x02;   // request Flags byte, single sub carrier\n  command[3] = 0x2B;   // get system information command for ISO/IEC 15693\n  delay(10);\n#ifdef DEBUG\n  Serial.printf(\"ssPin: %d, maxTrials: %d, RXBuffer[0]: %x \\r\\n\", ssPin, maxTrials, RXBuffer[0]);\n#endif\n  // run command until no error, but only max 10 times\n  runSPICommandUntilNoError(ssPin, command, sizeof(command), RXBuffer, maxTrials);\n}\n\n/// Runs the inventory  command several times, i.e. maxTrials times or until a response with no error is gotten, whatever happens first.\n/// @param ssPin SS_PIN used for SPI\n/// @param RXBuffer buffer used for send and receive\n/// @param maxTrials maximum number of trials. If reached, the result is returned, even if there still is an error present\nvoid runIDNCommand(int ssPin, byte *RXBuffer, int maxTrials) {\n\n#ifdef DEBUG\n  Serial.printf(\"ssPin: %d, maxTrials: %d, RXBuffer[0]: %x \\r\\n\", ssPin, maxTrials, RXBuffer[0]);\n#endif\n\n  byte command[2];\n  command[0] = 0x01;   // command code for send receive CR95HF command\n  command[1] = 0x00;   // length of data that follows (0 bytes)\n  delay(10);\n\n#ifdef DEBUG\n  Serial.printf(\"ssPin: %d, maxTrials: %d, RXBuffer[0]: %x \\r\\n\", ssPin, maxTrials, RXBuffer[0]);\n#endif\n  // run command until no error, but only max 10 times\n  runIDNCommandUntilNoError(ssPin, command, sizeof(command), RXBuffer, maxTrials);\n}\n\n\n//Example response of CR95HF for inventory command and data positions/indices\n//+------+--------+----------------------------------------------------------------------+\n//|Result| Length | Data                                                                 |\n//| code |        +--------+-----+---------------------------------------+---------+-----+\n//|      |        |Response|     |                                       |         |     |\n//|      |        | flags  |DSFID| UID                                   |CRC16    |Error|\n//+------+--------+--------+---------------------------------------------+---------+-----+\n//| 0x80 |0x0D(13)| 0x00   |0x00 |0x51 0x69 0x19 0x38 0x42 0x20 0x02 0xE0|0x84 0x28|0x00 |\n//+------+--------+--------+-----+---------------------------------------+---------+-----+\n//|   0  |  1     |   2    |  3  | 4    5    6    7    8    9    10   11 | 12   13 | 14  |\n//+------+--------+--------+-----+---------------------------------------+---------+-----+\n//                    0       1    2    3    4    5    6    7     8    9   10   11   12\n//\n\n/// Retreive idn data from RXBuffer from IDN command\n/// This ist the struct later to be transmitted via bluetooth\n/// @detail There is no error possible in the response since this is just pure device information and thus not rely on RFID and a tag in the field\n/// @param RXBuffer buffer containing the response from the IDN command\n/// @param idnType struct with retreived data\nIDNDataType idnDataFromIDNResponse(byte *RXBuffer) {\n\n  IDNDataType idnData;\n  idnData.resultCode = RXBuffer[0];\n\n  // Device ID has 13 bytes\n  for (int i = 0; i < 13; i++) {\n    idnData.deviceID[i] = RXBuffer[i + 2]; // TODO: cchek and continue here\n  }\n\n  // ROM CRC are the last two bytes of the data\n  int length = RXBuffer[2];\n  idnData.romCRC[0] = RXBuffer[length - 2];\n  idnData.romCRC[1] = RXBuffer[length - 1];\n\n  return idnData;\n}\n\n\n\n/// Retreive system information from RXBuffer from system information command\n/// This ist the struct later to be transmitted via bluetooth\n/// @param RXBuffer buffer containing the response from the system information command\n/// @param SystemInformationType struct with retreived data\nSystemInformationDataType systemInformationDataFromGetSystemInformationResponse(byte *RXBuffer) {\n  //    SystemInformationType retreiveSystemInformationValues(byte *RXBuffer) {\n\n  SystemInformationDataType systemInformationData;\n\n  systemInformationData.resultCode = RXBuffer[0];\n  systemInformationData.responseFlags = RXBuffer[2];\n\n  // check for no error in result code and handle accordingly\n  if (systemInformationData.resultCode == 0x80) { // no error in result code\n\n    // check for no error in response flags\n    if ((systemInformationData.responseFlags & 0x01) == 0) {\n      // no error in response flags\n      systemInformationData.infoFlags = RXBuffer[3];\n      for (int i = 0; i < 8; i++) {\n        systemInformationData.uid[i] = RXBuffer[11 - i];\n      }\n      systemInformationData.errorCode = RXBuffer[RXBuffer[1] + 2 - 1];\n    } else {\n      // error case\n      systemInformationData.errorCode = RXBuffer[3];\n    }\n  } else {\n    // error case\n    clearBuffer(systemInformationData.uid);\n    systemInformationData.errorCode = RXBuffer[3];\n  }\n  return systemInformationData;\n}\n\n\n/// Sends a packet of data (c-struct) via bluetooth to a smartphone application\n/// @detail Any packet to be transfered is a c-struct. These structs are defined in data_types.h.\n/// @param packetIdentifier identifier that can be used to treat a packet separately in the app. Identifiers are defined in constants.h\n/// @param txFlags don't know yet, what these are fore\n/// @param *packetBytes pointer on the c-struct, that is the packet\n/// @param byteCount number of bytes to be transfered\nbool pumpViaBluetooth(unsigned short packetIdentifier, UBP_TxFlags txFlags, const char *packetBytes, unsigned short byteCount) {\n\n  bool success = UBP_queuePacketTransmission(packetIdentifier, txFlags, packetBytes, byteCount);\n\n  delay(1);\n#ifdef DEBUG\n  if (success) Serial.println(\"Packet queued successfully\");\n  else Serial.println(\"Failed to enqueue packet\");\n#endif\n  // put your main code here, to run repeatedly:\n  while (UBP_isBusy() == true) UBP_pump();\n}\n\n/// Returns the voltage on the Simblee/RFduino VDD pin as a float in Volts.\n/// Code is from the RFduino Forum, see http://forum.rfduino.com/index.php?topic=265.0 for details\nfloat voltageOnVDD() {\n  analogReference(VBG);                // Sets the Reference to 1.2V band gap\n  analogSelection(VDD_1_3_PS);         // Selects VDD with 1/3 prescaling as the analog source\n  int sensorValue = analogRead(1);     // the pin has no meaning, it uses VDD pin\n  return sensorValue * (3.6 / 1023.0); // convert value to voltage;\n}\n\n/// Print all data of systemInformationData to serial console\nvoid printSystemInformationData(SystemInformationDataType systemInformationData) {\n\n  Serial.println(\"Printing system information data to serial output:\");\n\n  Serial.printf(\"Result code: %x\\r\\n\", systemInformationData.resultCode);\n  Serial.printf(\"Response flags: %x\\r\\n\", systemInformationData.responseFlags);\n\n  Serial.printf(\"uid: %x\", systemInformationData.uid[0]);\n  for (int i = 1; i < 8; i++) {\n    Serial.printf(\":%x\", systemInformationData.uid[i]);\n  }\n  Serial.println(\"\");\n\n  Serial.printf(\"Error code: %x\\r\\n\", systemInformationData.errorCode);\n}\n\n///===================================================================================================\n// The loop\n///===================================================================================================\n\nvoid loop() {\n\n#ifdef DEBUG\n  Serial.println(\"In the loop\");\n#endif\n\n  // Start up BM019 if not yet started\n  if (NFCReady == 0) {\n\n    delay(100);\n    SetProtocol_Command(); // ISO 15693 settings\n    Serial.println(\"After SetProtocoll_Command()\");\n    delay(100);\n\n  } else {\n\n\n    // ------- Read system information from BM019 ----------------------------------------------------------------------------\n//#ifdef DEBUG\n    Serial.println(\"Get system information command ...\");\n//#endif\n    runSystemInformationCommandUntilNoError(SS_PIN, RXBuffer, 10);\n\n#ifdef DEBUG\n    Serial.println(\"... retreive system information ...\");\n#endif\n    SystemInformationDataType systemInformationData = systemInformationDataFromGetSystemInformationResponse(RXBuffer);\n\n\n\n    //------- Read IDN information from BM019 (IDN Command) -------------------------------------------------------------------\n\n    //#ifdef DEBUG\n    Serial.println(\"IDN command ...\");\n    //#endif\n    runIDNCommand(SS_PIN, RXBuffer, 10);\n#ifdef DEBUG\n    Serial.println(\"... retreive IDN information ...\");\n#endif\n    IDNDataType idnData = idnDataFromIDNResponse(RXBuffer);\n\n\n    // ----------- Read 43 data blocks into RXBuffer ---------------\n\n    //#ifdef DEBUG\n    Serial.println(\"Read all data\");\n    //#endif\n\n    for (int i = 0; i < sizeof(RXBuffer); i++) {\n      RXBuffer[i] = 0;\n    }\n    for (int i = 0; i < sizeof(dataBuffer); i++) {\n      dataBuffer[i] = 0;\n    }\n\n    byte resultCode = 0;\n    int trials = 0;\n    int maxTrials = 10;\n    for (int i = 0; i < 43; i++) { // Need only 43 of 244 blocks\n      resultCode = ReadSingleBlockReturn(i);\n\n#ifdef DEBUG\n      printf(\"resultCode 0x%x\\n\\r\", resultCode);\n#endif\n      if (resultCode != 0x80 && trials < maxTrials) {\n        printf(\"Error 0x%x\\n\\r\", resultCode);\n        i--;        // repeat same block if error occured, but\n        trials++;   // not more than maxTrials times per block\n      } else if (trials >= maxTrials) {\n        break;\n      } else {\n        trials = 0;\n\n        for (int j = 3; j < RXBuffer[1] + 3 - 4; j++) {\n          dataBuffer[i * 8 + j - 3] = RXBuffer[j];\n#ifdef DEBUG\n          Serial.print(RXBuffer[j], HEX);\n          Serial.print(\" \");\n#endif\n        }\n      }\n    }\n\n    // ----------- All data collected, send BM019 to hibernate -------------------------\n\n    //#ifdef DEBUG\n    Serial.println(\"Sending CR95HF to hibernate ...\");\n    //#endif\n    sendCR95HFToHibernate(SS_PIN);\n\n\n\n    // ------- Transmit system information data via bluetooth. By convention this is the first transmission -----------------\n\n    bool ergo = pumpViaBluetooth(SYSTEM_INFORMATION_DATA, UBP_TxFlagIsRPC, (char *) &systemInformationData, sizeof(SystemInformationDataType));\n#ifdef DEBUG\n    printSystemInformationData(systemInformationData);\n#endif\n\n\n\n    //-------- transmit dataBuffer via bluetooth ---------------------------------------------------------\n\n    AllBytesDataType allBytes;\n#ifdef DEBUG\n    Serial.println(\"----about to send all data bytes packet\");\n#endif\n    for (int i = 0; i < sizeof(allBytes.allBytes); i++) {\n      allBytes.allBytes[i] = 0;\n    }\n    for (int i = 0; i < 344; i++) {\n      allBytes.allBytes[i] = dataBuffer[i];\n    }\n    //#ifdef DEBUG\n    Serial.printf(\"Sizeof ist : %d\\n\", sizeof(AllBytesDataType));\n    //#endif\n    bool success = UBP_queuePacketTransmission(ALL_BYTES, UBP_TxFlagIsRPC, (char *) &allBytes, sizeof(AllBytesDataType));\n#ifdef DEBUG\n    if (success) Serial.println(\"----all data bytes packet queued successfully\");\n    else Serial.println(\"----Failed to enqueue all data bytes packet\");\n#endif\n    while (UBP_isBusy() == true) UBP_pump();\n\n    //-------- Read Battery level and Simblee temperature and transmit via bluetooth ---------------------\n\n    BatteryDataType batteryData;\n    batteryData.voltage = voltageOnVDD();\n#ifdef SIMBLEE\n    batteryData.temperature = Simblee_temperature(CELSIUS);\n#else\n    batteryData.temperature = RFduino_temperature(CELSIUS);\n#endif\n\n#ifdef DEBUG\n    Serial.printf(\"Battery voltage: %f\\r\\n\", batteryData.voltage);\n#endif\n    // Transmitt via bluetooth\n    success = UBP_queuePacketTransmission(BATTERY_DATA, UBP_TxFlagIsRPC, (char *) &batteryData, sizeof(BatteryDataType));\n    //        if (success) Serial.println(\"Battery data packet queued successfully\");\n    //        else Serial.println(\"Failed to enqueue battery data packet\");\n    // put your main code here, to run repeatedly:\n    while (UBP_isBusy() == true) UBP_pump();\n\n#ifdef DEBUG\n    Serial.printf(\"Sent Battery voltage: %f\\r\\n\", batteryData.voltage);\n#endif\n\n\n    //-------- transmit IDN data via bluetooth. By convention this is the last transmission -----------------\n\n    ergo = pumpViaBluetooth(IDN_DATA, UBP_TxFlagNone, (char *) &idnData, sizeof(IDNDataType));\n    success = UBP_queuePacketTransmission(IDN_DATA, UBP_TxFlagIsRPC, (char *) &idnData, sizeof(IDNDataType));\n    delay(10);\n#ifdef DEBUG\n    if (success) Serial.println(\"IDN data packet queued successfully\");\n    else Serial.println(\"Failed to enqueue IDN data packet\");\n#endif\n    // put your main code here, to run repeatedly:\n    while (UBP_isBusy() == true) UBP_pump();\n\n#ifdef DEBUG\n    Serial.printf(\"IDN: %x\", idnData.deviceID[0]);\n    for (int i = 1; i < 13; i++) {\n      Serial.printf(\":%x\", idnData.deviceID[i]);\n    }\n    Serial.println(\"... done\");\n#endif\n\n\n    //--------- send Simblee into ultra low power mode ---------------------------------------------------\n\n    //#ifdef DEBUG\n    Serial.println(\"Sending Simblee/RFduino to sleep ...\");\n    //#endif\n    RFduino_ULPDelay(SLEEP_DURATION); //\n\n\n    //--------- send Simblee woke up again, now also wake up BM019 and repeat the loope cycle ------------\n\n#ifdef DEBUG\n    Serial.println(\"... Simblee/RFduino woke up again\");\n    Serial.println(\"Wake up CR95HF with wake up pulse...\");\n#endif\n    sendWakeupPulse(IRQ_PIN);  // Wake up BM019 (low pulse on IRQ_PIN)\n    readWakeUPEventRegister(SS_PIN, RXBuffer);\n    setupSPI();\n\n    delay(10);\n    SetProtocol_Command(); // ISO 15693 settings\n    delay(100);\n\n#ifdef DEBUG\n    Serial.println(\"... CR95HF woke up again. Receiving wake up response\");\n#endif\n  }\n}\n\n\n"
  },
  {
    "path": "LibreMonitorTests/BluetoothTestData.swift",
    "content": "//\n//  BluetoothTestData.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 29.01.17.\n//  Copyright © 2017 Uwe PetersenaString.append(\"All rights reserved.\n//\n// To test is weather these bytes are transferred and restored without any error.\n// Thus check, if after all transferal actions the result is the same\n\nimport Foundation\n\nstruct BluetoothTestData {\n    var sensorData = [[String]]()\n    \n    init()   {\n    }\n    static func data() -> [String] {\n        var sensorData = [String]()\n\n        // # ID: E0:07:A0:00:00:25:90:5E\n        // # Memory content: Sensor 1\n        var aString = String()\n        aString.append(\"73 C3 18 59 05 00 03 39\") // 0x00\n        aString.append(\"51 04 09 54 00 00 00 00\") // 0x01\n        aString.append(\"00 00 00 00 00 00 00 00\") // 0x02\n        aString.append(\"00 82 08 0A 11 00 C0 4A\") // 0x03\n        aString.append(\"65 00 0F 00 C0 46 25 80\") // 0x04\n        aString.append(\"0E 00 C0 4A 25 80 10 00\") // 0x05\n        aString.append(\"C0 4E 25 80 11 00 C0 4E\") // 0x06\n        aString.append(\"25 80 10 00 C0 52 65 00\") // 0x07\n        aString.append(\"0E 00 C0 52 25 80 10 00\") // 0x08\n        aString.append(\"C0 52 25 80 10 00 C0 3E\") // 0x09\n        aString.append(\"25 80 11 00 C0 42 25 80\") // 0x0a\n        aString.append(\"11 00 C0 42 25 80 11 00\") // 0x0b\n        aString.append(\"C0 42 25 80 11 00 C0 46\") // 0x0c\n        aString.append(\"25 80 11 00 C0 46 25 80\") // 0x0d\n        aString.append(\"11 00 C0 46 65 00 10 00\") // 0x0e\n        aString.append(\"C0 4A 65 00 00 00 C0 B6\") // 0x0f\n        aString.append(\"64 00 00 00 C0 CE 64 00\") // 0x10\n        aString.append(\"00 00 C0 E6 64 00 00 00\") // 0x11\n        aString.append(\"C0 FA 64 00 00 00 C0 0A\") // 0x12\n        aString.append(\"65 00 00 00 C0 12 65 00\") // 0x13\n        aString.append(\"00 00 C0 22 65 00 00 00\") // 0x14\n        aString.append(\"C0 2E 65 00 00 00 C0 3E\") // 0x15\n        aString.append(\"25 80 00 00 C0 52 65 00\") // 0x16\n        aString.append(\"00 00 C0 6E 26 80 00 00\") // 0x17\n        aString.append(\"C0 66 26 80 00 00 C0 5A\") // 0x18\n        aString.append(\"26 80 00 00 C0 52 26 80\") // 0x19\n        aString.append(\"00 00 C0 4A 26 80 00 00\") // 0x1a\n        aString.append(\"C0 42 26 80 00 00 C0 3E\") // 0x1b\n        aString.append(\"26 80 00 00 C0 36 26 80\") // 0x1c\n        aString.append(\"00 00 C0 2E 26 80 00 00\") // 0x1d\n        aString.append(\"C0 2E 26 80 00 00 C0 26\") // 0x1e\n        aString.append(\"26 80 00 00 C0 22 26 80\") // 0x1f\n        aString.append(\"00 00 C0 22 26 80 00 00\") // 0x20\n        aString.append(\"C0 22 26 80 00 00 C0 1E\") // 0x21\n        aString.append(\"26 80 00 00 C0 22 26 80\") // 0x22\n        aString.append(\"00 00 C0 22 26 80 00 00\") // 0x23\n        aString.append(\"C0 22 26 80 00 00 C0 72\") // 0x24\n        aString.append(\"24 80 00 00 C0 02 24 80\") // 0x25\n        aString.append(\"00 00 C0 5E 24 80 00 00\") // 0x26\n        aString.append(\"C0 96 64 00 09 54 00 00\") // 0x27\n        aString.append(\"D4 AE 00 01 15 04 39 51\") //\n        aString.append(\"14 07 96 80 5A 00 ED A6\") //\n        aString.append(\"0E 90 1A C8 04 D7 C8 69\") //\n        /*\n         aString.append(\"9E 42 21 83 F2 90 07 00\") //\n         aString.append(\"06 08 02 24 0C 43 17 3C\") //\n         aString.append(\"C2 43 08 08 B2 40 DF 00\") //\n         aString.append(\"08 08 D2 42 A2 F9 08 08\") //\n         aString.append(\"D2 42 A3 F9 08 08 0C 41\") //\n         aString.append(\"0C 53 92 12 90 1C 5C 93\") //\n         aString.append(\"03 20 A2 41 08 08 02 3C\") //\n         aString.append(\"B2 43 08 08 1C 43 21 53\") //\n         aString.append(\"30 41 0A 12 4A 4C 4C 93\") //\n         aString.append(\"0B 20 B2 40 50 CC 02 07\") //\n         aString.append(\"92 D3 00 07 B2 C0 00 02\") //\n         aString.append(\"00 07 A2 D2 00 07 02 3C\") //\n         aString.append(\"92 12 82 1C 32 D0 D8 00\") //\n         aString.append(\"E2 B3 C3 1C 09 28 E2 C3\") //\n         aString.append(\"C3 1C 4A 93 05 24 12 C3\") //\n         aString.append(\"12 10 A4 1C 12 11 A4 1C\") //\n         aString.append(\"3A 41 30 41 0A 12 0B 12\") //\n         aString.append(\"08 12 09 12 06 12 F2 90\") //\n         aString.append(\"07 00 06 08 68 20 B0 12\") //\n         aString.append(\"3A FB 61 20 92 12 78 1C\") //\n         aString.append(\"3A 40 FA F9 4C 43 8A 12\") //\n         aString.append(\"3B 40 84 1C 26 4B 38 40\") //\n         aString.append(\"B0 F9 39 40 A4 1C B2 90\") //\n         aString.append(\"00 20 A4 1C 09 2C 1F 43\") //\n         aString.append(\"B0 12 30 FB 3F 40 00 20\") //\n         aString.append(\"2F 89 82 4F A4 1C 06 3C\") //\n         aString.append(\"0F 43 B0 12 30 FB B2 50\") //\n         aString.append(\"00 E0 A4 1C 92 52 A4 1C\") //\n         aString.append(\"A4 1C 2F 49 7E 42 0D 43\") //\n         aString.append(\"0C 48 AB 12 1F 43 5E 43\") //\n         aString.append(\"3D 40 22 00 0C 48 AB 12\") //\n         aString.append(\"B2 90 00 01 A4 1C 08 28\") //\n         aString.append(\"7F 43 7E 42 0D 43 0C 48\") //\n         aString.append(\"AB 12 7C 40 34 00 29 3C\") //\n         aString.append(\"6C 42 8A 12 2F 49 3F F0\") //\n         aString.append(\"FF 07 82 4F A6 1C 1F 42\") //\n         aString.append(\"A6 1C 7E 40 0B 00 3D 40\") //\n         aString.append(\"16 00 0C 48 AB 12 7C 40\") //\n         aString.append(\"05 00 8A 12 2F 49 7E 40\") //\n         aString.append(\"0C 00 3D 40 28 00 0C 48\") //\n         aString.append(\"AB 12 7C 40 06 00 8A 12\") //\n         aString.append(\"2F 49 7E 40 0C 00 3D 40\") //\n         aString.append(\"34 00 0C 48 AB 12 B2 B0\") //\n         aString.append(\"10 00 22 01 06 2C 7C 40\") //\n         aString.append(\"28 00 92 12 8C 1C 0C 43\") //\n         aString.append(\"05 3C E2 C2 C3 1C 92 12\") //\n         aString.append(\"94 1C 1C 43 30 40 6C 5F\") //\n         aString.append(\"5E 43 3D 40 21 00 0C 48\") //\n         aString.append(\"00 46 C2 43 08 08 E2 D2\") //\n         aString.append(\"C3 1C 92 12 98 1C 4C 93\") //\n         aString.append(\"30 41 F2 90 07 00 06 08\") //\n         aString.append(\"02 24 0C 43 30 41 B0 12\") //\n         aString.append(\"3A FB 08 24 A2 43 DC F8\") //\n         aString.append(\"7C 40 28 00 92 12 8C 1C\") //\n         aString.append(\"0C 43 30 41 92 12 78 1C\") //\n         aString.append(\"92 D3 00 07 B2 40 4B D8\") //\n         aString.append(\"02 07 B2 C0 00 02 00 07\") //\n         aString.append(\"A2 D2 00 07 92 43 DC F8\") //\n         aString.append(\"32 D0 D8 00 E2 B3 C3 1C\") //\n         aString.append(\"05 28 E2 C3 C3 1C 92 42\") //\n         aString.append(\"A4 1C DE F8 5C 43 92 12\") //\n         aString.append(\"86 1C E2 C2 C3 1C 92 12\") //\n         aString.append(\"94 1C 1C 43 30 41 F2 90\") //\n         aString.append(\"07 00 06 08 02 24 0C 43\") //\n         aString.append(\"30 41 C2 43 08 08 E2 D2\") //\n         aString.append(\"C3 1C 92 12 72 1C 1C 43\") //\n         aString.append(\"30 41 0A 12 92 12 20 1C\") //\n         aString.append(\"4C 93 14 24 F2 90 05 00\") //\n         aString.append(\"0C 08 10 20 1D 42 06 08\") //\n         aString.append(\"5F 42 06 08 0D 93 07 20\") //\n         aString.append(\"7F 93 05 20 92 12 94 1C\") //\n         aString.append(\"C2 43 08 08 12 3C 7F 90\") //\n         aString.append(\"10 00 02 28 0C 43 0E 3C\") //\n         aString.append(\"C2 43 08 08 0C 43 07 3C\") //\n         aString.append(\"0E 4C 0E 5E 0A 4D 0A 5E\") //\n         aString.append(\"A2 4A 08 08 1C 53 0C 9F\") //\n         aString.append(\"F7 2B 1C 43 3A 41 30 41\") //\n         aString.append(\"0A 12 4A 4C B0 12 C8 5B\") //\n         aString.append(\"6A 92 10 20 7E 40 0B 00\") //\n         aString.append(\"3D 40 16 00 3C 40 B0 F9\") //\n         aString.append(\"92 12 4C 1C 82 4C A6 1C\") //\n         aString.append(\"92 52 A6 1C A6 1C 92 52\") //\n         aString.append(\"A6 1C A6 1C 3A 41 30 41\") //\n         aString.append(\"0E 43 1C 42 B6 F9 B0 12\") //\n         aString.append(\"DE 5E 1D 42 AA 1C 12 C3\") //\n         aString.append(\"0D 10 0D 11 0C 9D 02 2C\") //\n         aString.append(\"0D 8C 04 3C 0C 8D 0D 4C\") //\n         aString.append(\"3E 40 00 02 3D 90 00 02\") //\n         aString.append(\"02 28 3D 40 FF 01 5F 42\") //\n         aString.append(\"A8 F9 0F 9D 06 2C B2 D0\") //\n         aString.append(\"40 00 AE 1C F2 D0 40 00\") //\n         aString.append(\"C2 1C 0D DE 82 4D AA 1C\") //\n         aString.append(\"30 41 0A 12 0B 12 08 12\") //\n         aString.append(\"09 12 5B 42 A9 F9 48 43\") //\n         aString.append(\"C2 93 64 F8 09 34 F2 C0\") //\n         aString.append(\"80 00 64 F8 6B B2 01 28\") //\n         aString.append(\"58 43 4C 43 92 12 86 1C\") //\n         aString.append(\"59 42 64 F8 0A 3C 6A 93\") //\n         aString.append(\"04 20 B2 B0 00 02 00 08\") //\n         aString.append(\"04 28 7C 40 06 00 92 12\") //\n         aString.append(\"88 1C 1A 42 9E 01 4A 93\") //\n         aString.append(\"1F 24 4E 49 6E 83 7E 90\") //\n         aString.append(\"03 00 F7 2F 7A 90 10 00\") //\n         aString.append(\"02 20 58 B3 12 2C 4C 4A\") //\n         aString.append(\"7C 50 11 00 92 12 60 1C\") //\n         aString.append(\"5B B3 03 28 7A 90 06 00\") //\n         aString.append(\"E8 27 6B B3 03 28 7A 90\") //\n         aString.append(\"0E 00 E3 27 7A 90 10 00\") //\n         aString.append(\"D6 23 58 B3 DE 2F D9 3F\") //\n         aString.append(\"5E 42 64 F8 6E 83 7E 90\") //\n         aString.append(\"03 00 25 2C 92 12 96 1C\") //\n         aString.append(\"92 12 9A 1C 00 3C 3F 40\") //\n         aString.append(\"33 05 3F 53 FE 2F A2 B3\") //\n         aString.append(\"22 01 15 28 3F 40 4E C3\") //\n         aString.append(\"03 43 0B 43 3F 53 3B 63\") //\n         aString.append(\"FD 2F B2 B0 10 00 22 01\") //\n         aString.append(\"07 28 B2 B0 00 02 00 08\") //\n         aString.append(\"03 2C 92 12 70 1C 07 3C\") //\n         aString.append(\"7C 40 0A 00 02 3C 7C 40\") //\n         aString.append(\"0B 00 92 12 8C 1C 92 12\") //\n         aString.append(\"58 1C A2 D2 00 08 32 D2\") //\n         aString.append(\"30 40 6E 5F 30 41 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"FF FF 84 FD 25 00 9A FC\") //\n         aString.append(\"14 00 50 FC 19 00 20 FC\") //\n         aString.append(\"03 00 5F F5 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 AB AB 4A FB\") //\n         aString.append(\"E2 00 3C FA E1 00 AE FB\") //\n         aString.append(\"AB AB 2C 5A A4 00 CA FB\") //\n         aString.append(\"A3 00 56 5A A2 00 BA F9\") //\n         aString.append(\"A1 00 24 57 A0 00 AB AB\") //\n         aString.append(\"00 00 00 00 FF FF FF FF\") //\n         aString.append(\"20 00 71 62 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 AE 5C 00 00 A8 57\") //\n         aString.append(\"00 00 28 4E 68 45 00 00\") //\n         aString.append(\"DC 5F AE 5A 7A 5A DA 50\") //\n         */\n        sensorData.append(aString)\n        \n        // # ID: E0:07:A0:00:00:43:98:59\n        // # Memory content: Sensor 2\n        aString = String()\n        aString.append(\"E6 84 70 50 05 00 03 D9\") // 0x00\n        aString.append(\"50 04 A9 53 00 00 00 00\") // 0x01\n        aString.append(\"00 00 00 00 00 00 00 00\") // 0x02\n        aString.append(\"E3 2F 08 03 DA 01 C8 D0\") // 0x03\n        aString.append(\"D7 80 D6 01 C8 C4 D7 80\") // 0x04\n        aString.append(\"D0 01 C8 B8 17 81 CE 01\") // 0x05\n        aString.append(\"C8 B0 D7 80 C9 01 C8 A8\") // 0x06\n        aString.append(\"D7 80 C2 01 C8 A8 D7 80\") // 0x07\n        aString.append(\"BF 01 C8 A8 D7 80 BB 01\") // 0x08\n        aString.append(\"C8 AC D7 80 0D 02 C8 38\") // 0x09\n        aString.append(\"D8 80 03 02 C8 30 D8 80\") // 0x0a\n        aString.append(\"FE 01 C8 2C 18 81 FA 01\") // 0x0b\n        aString.append(\"88 1A D8 80 F0 01 C8 FC\") // 0x0c\n        aString.append(\"17 81 E9 01 C8 EC 17 81\") // 0x0d\n        aString.append(\"E5 01 C8 DC D7 80 DE 01\") // 0x0e\n        aString.append(\"C8 D8 D7 80 DA 02 C8 04\") // 0x0f\n        aString.append(\"18 81 61 02 C8 18 18 81\") // 0x10\n        aString.append(\"EF 01 C8 FC 17 81 72 01\") // 0x11\n        aString.append(\"C8 F4 D7 80 85 01 C8 D8\") // 0x12\n        aString.append(\"17 81 89 01 C8 B8 D7 80\") // 0x13\n        aString.append(\"92 01 C8 EC D7 80 AA 01\") // 0x14\n        aString.append(\"C8 DC D7 80 CB 01 C8 DC\") // 0x15\n        aString.append(\"17 81 DE 01 C8 F4 D7 80\") // 0x16\n        aString.append(\"04 02 C8 D0 D7 80 08 02\") // 0x17\n        aString.append(\"C8 18 D8 80 10 02 C8 C8\") // 0x18\n        aString.append(\"D7 80 25 02 C8 EC D7 80\") // 0x19\n        aString.append(\"02 03 C8 B4 D7 80 97 03\") // 0x1a\n        aString.append(\"C8 AC D7 80 0C 04 C8 AC\") // 0x1b\n        aString.append(\"D7 80 3D 04 C8 84 D7 80\") // 0x1c\n        aString.append(\"8B 04 C8 94 D7 80 A2 04\") // 0x1d\n        aString.append(\"C8 A0 D7 80 7F 04 C8 CC\") // 0x1e\n        aString.append(\"17 81 73 04 C8 A4 17 81\") // 0x1f\n        aString.append(\"6B 04 C8 9C D7 80 5E 04\") // 0x20\n        aString.append(\"C8 70 D7 80 47 04 C8 4C\") // 0x21\n        aString.append(\"D7 80 50 04 C8 DC 17 81\") // 0x22\n        aString.append(\"36 04 C8 08 D8 80 49 04\") // 0x23\n        aString.append(\"C8 FC 17 81 64 04 C8 18\") // 0x24\n        aString.append(\"18 81 5F 04 88 FA 17 81\") // 0x25\n        aString.append(\"D5 03 C8 04 18 81 54 03\") // 0x26\n        aString.append(\"C8 04 D8 80 A9 53 00 00\") // 0x27\n        aString.append(\"66 0F 00 01 BE 04 D9 50\") //\n        aString.append(\"14 07 96 80 5A 00 ED A6\") //\n        aString.append(\"12 78 1A C8 04 95 09 6C\") //\n        /*\n         aString.append(\"9E 42 21 83 F2 90 07 00\") //\n         aString.append(\"06 08 02 24 0C 43 17 3C\") //\n         aString.append(\"C2 43 08 08 B2 40 DF 00\") //\n         aString.append(\"08 08 D2 42 A2 F9 08 08\") //\n         aString.append(\"D2 42 A3 F9 08 08 0C 41\") //\n         aString.append(\"0C 53 92 12 90 1C 5C 93\") //\n         aString.append(\"03 20 A2 41 08 08 02 3C\") //\n         aString.append(\"B2 43 08 08 1C 43 21 53\") //\n         aString.append(\"30 41 0A 12 4A 4C 4C 93\") //\n         aString.append(\"0B 20 B2 40 50 CC 02 07\") //\n         aString.append(\"92 D3 00 07 B2 C0 00 02\") //\n         aString.append(\"00 07 A2 D2 00 07 02 3C\") //\n         aString.append(\"92 12 82 1C 32 D0 D8 00\") //\n         aString.append(\"E2 B3 C3 1C 09 28 E2 C3\") //\n         aString.append(\"C3 1C 4A 93 05 24 12 C3\") //\n         aString.append(\"12 10 A4 1C 12 11 A4 1C\") //\n         aString.append(\"3A 41 30 41 0A 12 0B 12\") //\n         aString.append(\"08 12 09 12 06 12 F2 90\") //\n         aString.append(\"07 00 06 08 68 20 B0 12\") //\n         aString.append(\"3A FB 61 20 92 12 78 1C\") //\n         aString.append(\"3A 40 FA F9 4C 43 8A 12\") //\n         aString.append(\"3B 40 84 1C 26 4B 38 40\") //\n         aString.append(\"B0 F9 39 40 A4 1C B2 90\") //\n         aString.append(\"00 20 A4 1C 09 2C 1F 43\") //\n         aString.append(\"B0 12 30 FB 3F 40 00 20\") //\n         aString.append(\"2F 89 82 4F A4 1C 06 3C\") //\n         aString.append(\"0F 43 B0 12 30 FB B2 50\") //\n         aString.append(\"00 E0 A4 1C 92 52 A4 1C\") //\n         aString.append(\"A4 1C 2F 49 7E 42 0D 43\") //\n         aString.append(\"0C 48 AB 12 1F 43 5E 43\") //\n         aString.append(\"3D 40 22 00 0C 48 AB 12\") //\n         aString.append(\"B2 90 00 01 A4 1C 08 28\") //\n         aString.append(\"7F 43 7E 42 0D 43 0C 48\") //\n         aString.append(\"AB 12 7C 40 34 00 29 3C\") //\n         aString.append(\"6C 42 8A 12 2F 49 3F F0\") //\n         aString.append(\"FF 07 82 4F A6 1C 1F 42\") //\n         aString.append(\"A6 1C 7E 40 0B 00 3D 40\") //\n         aString.append(\"16 00 0C 48 AB 12 7C 40\") //\n         aString.append(\"05 00 8A 12 2F 49 7E 40\") //\n         aString.append(\"0C 00 3D 40 28 00 0C 48\") //\n         aString.append(\"AB 12 7C 40 06 00 8A 12\") //\n         aString.append(\"2F 49 7E 40 0C 00 3D 40\") //\n         aString.append(\"34 00 0C 48 AB 12 B2 B0\") //\n         aString.append(\"10 00 22 01 06 2C 7C 40\") //\n         aString.append(\"28 00 92 12 8C 1C 0C 43\") //\n         aString.append(\"05 3C E2 C2 C3 1C 92 12\") //\n         aString.append(\"94 1C 1C 43 30 40 6C 5F\") //\n         aString.append(\"5E 43 3D 40 21 00 0C 48\") //\n         aString.append(\"00 46 C2 43 08 08 E2 D2\") //\n         aString.append(\"C3 1C 92 12 98 1C 4C 93\") //\n         aString.append(\"30 41 F2 90 07 00 06 08\") //\n         aString.append(\"02 24 0C 43 30 41 B0 12\") //\n         aString.append(\"3A FB 08 24 A2 43 DC F8\") //\n         aString.append(\"7C 40 28 00 92 12 8C 1C\") //\n         aString.append(\"0C 43 30 41 92 12 78 1C\") //\n         aString.append(\"92 D3 00 07 B2 40 4B D8\") //\n         aString.append(\"02 07 B2 C0 00 02 00 07\") //\n         aString.append(\"A2 D2 00 07 92 43 DC F8\") //\n         aString.append(\"32 D0 D8 00 E2 B3 C3 1C\") //\n         aString.append(\"05 28 E2 C3 C3 1C 92 42\") //\n         aString.append(\"A4 1C DE F8 5C 43 92 12\") //\n         aString.append(\"86 1C E2 C2 C3 1C 92 12\") //\n         aString.append(\"94 1C 1C 43 30 41 F2 90\") //\n         aString.append(\"07 00 06 08 02 24 0C 43\") //\n         aString.append(\"30 41 C2 43 08 08 E2 D2\") //\n         aString.append(\"C3 1C 92 12 72 1C 1C 43\") //\n         aString.append(\"30 41 0A 12 92 12 20 1C\") //\n         aString.append(\"4C 93 14 24 F2 90 05 00\") //\n         aString.append(\"0C 08 10 20 1D 42 06 08\") //\n         aString.append(\"5F 42 06 08 0D 93 07 20\") //\n         aString.append(\"7F 93 05 20 92 12 94 1C\") //\n         aString.append(\"C2 43 08 08 12 3C 7F 90\") //\n         aString.append(\"10 00 02 28 0C 43 0E 3C\") //\n         aString.append(\"C2 43 08 08 0C 43 07 3C\") //\n         aString.append(\"0E 4C 0E 5E 0A 4D 0A 5E\") //\n         aString.append(\"A2 4A 08 08 1C 53 0C 9F\") //\n         aString.append(\"F7 2B 1C 43 3A 41 30 41\") //\n         aString.append(\"0A 12 4A 4C B0 12 C8 5B\") //\n         aString.append(\"6A 92 10 20 7E 40 0B 00\") //\n         aString.append(\"3D 40 16 00 3C 40 B0 F9\") //\n         aString.append(\"92 12 4C 1C 82 4C A6 1C\") //\n         aString.append(\"92 52 A6 1C A6 1C 92 52\") //\n         aString.append(\"A6 1C A6 1C 3A 41 30 41\") //\n         aString.append(\"0E 43 1C 42 B6 F9 B0 12\") //\n         aString.append(\"DE 5E 1D 42 AA 1C 12 C3\") //\n         aString.append(\"0D 10 0D 11 0C 9D 02 2C\") //\n         aString.append(\"0D 8C 04 3C 0C 8D 0D 4C\") //\n         aString.append(\"3E 40 00 02 3D 90 00 02\") //\n         aString.append(\"02 28 3D 40 FF 01 5F 42\") //\n         aString.append(\"A8 F9 0F 9D 06 2C B2 D0\") //\n         aString.append(\"40 00 AE 1C F2 D0 40 00\") //\n         aString.append(\"C2 1C 0D DE 82 4D AA 1C\") //\n         aString.append(\"30 41 0A 12 0B 12 08 12\") //\n         aString.append(\"09 12 5B 42 A9 F9 48 43\") //\n         aString.append(\"C2 93 64 F8 09 34 F2 C0\") //\n         aString.append(\"80 00 64 F8 6B B2 01 28\") //\n         aString.append(\"58 43 4C 43 92 12 86 1C\") //\n         aString.append(\"59 42 64 F8 0A 3C 6A 93\") //\n         aString.append(\"04 20 B2 B0 00 02 00 08\") //\n         aString.append(\"04 28 7C 40 06 00 92 12\") //\n         aString.append(\"88 1C 1A 42 9E 01 4A 93\") //\n         aString.append(\"1F 24 4E 49 6E 83 7E 90\") //\n         aString.append(\"03 00 F7 2F 7A 90 10 00\") //\n         aString.append(\"02 20 58 B3 12 2C 4C 4A\") //\n         aString.append(\"7C 50 11 00 92 12 60 1C\") //\n         aString.append(\"5B B3 03 28 7A 90 06 00\") //\n         aString.append(\"E8 27 6B B3 03 28 7A 90\") //\n         aString.append(\"0E 00 E3 27 7A 90 10 00\") //\n         aString.append(\"D6 23 58 B3 DE 2F D9 3F\") //\n         aString.append(\"5E 42 64 F8 6E 83 7E 90\") //\n         aString.append(\"03 00 25 2C 92 12 96 1C\") //\n         aString.append(\"92 12 9A 1C 00 3C 3F 40\") //\n         aString.append(\"33 05 3F 53 FE 2F A2 B3\") //\n         aString.append(\"22 01 15 28 3F 40 4E C3\") //\n         aString.append(\"03 43 0B 43 3F 53 3B 63\") //\n         aString.append(\"FD 2F B2 B0 10 00 22 01\") //\n         aString.append(\"07 28 B2 B0 00 02 00 08\") //\n         aString.append(\"03 2C 92 12 70 1C 07 3C\") //\n         aString.append(\"7C 40 0A 00 02 3C 7C 40\") //\n         aString.append(\"0B 00 92 12 8C 1C 92 12\") //\n         aString.append(\"58 1C A2 D2 00 08 32 D2\") //\n         aString.append(\"30 40 6E 5F 30 41 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"FF FF 84 FD 25 00 9A FC\") //\n         aString.append(\"14 00 50 FC 19 00 20 FC\") //\n         aString.append(\"03 00 5F F5 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 AB AB 4A FB\") //\n         aString.append(\"E2 00 3C FA E1 00 AE FB\") //\n         aString.append(\"AB AB 2C 5A A4 00 CA FB\") //\n         aString.append(\"A3 00 56 5A A2 00 BA F9\") //\n         aString.append(\"A1 00 24 57 A0 00 AB AB\") //\n         aString.append(\"00 00 00 00 FF FF FF FF\") //\n         aString.append(\"20 00 71 62 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 AE 5C 00 00 A8 57\") //\n         aString.append(\"00 00 28 4E 68 45 00 00\") //\n         aString.append(\"DC 5F AE 5A 7A 5A DA 50\") //\n         */\n        sensorData.append(aString)\n        \n        // # ID: E0:07:A0:00:00:50:DE:AE\n        // # Memory content: Sensor 3\n        aString = String()\n        aString.append(\"78 13 88 53 05 00 03 7D\") // 0x00\n        aString.append(\"51 04 4D 54 00 00 00 00\") // 0x01\n        aString.append(\"00 00 00 00 00 00 00 00\") // 0x02\n        aString.append(\"1C FA 0C 0E 1A 00 C0 46\") // 0x03\n        aString.append(\"66 80 1C 00 C0 3E 66 80\") // 0x04\n        aString.append(\"1B 00 C0 36 66 80 1A 00\") // 0x05\n        aString.append(\"C0 2A 66 80 1B 00 C0 22\") // 0x06\n        aString.append(\"66 80 1B 00 C0 1E 66 80\") // 0x07\n        aString.append(\"19 00 C0 1A A6 80 1B 00\") // 0x08\n        aString.append(\"C0 16 66 80 1A 00 C0 1A\") // 0x09\n        aString.append(\"A6 80 1A 00 C0 1E A6 80\") // 0x0a\n        aString.append(\"1B 00 C0 22 66 80 1B 00\") // 0x0b\n        aString.append(\"C0 2A 66 80 1F 00 C0 5A\") // 0x0c\n        aString.append(\"66 80 1A 00 C0 52 66 80\") // 0x0d\n        aString.append(\"19 00 C0 4E 66 80 1C 00\") // 0x0e\n        aString.append(\"C0 4A 66 80 00 00 C8 26\") // 0x0f\n        aString.append(\"E0 80 00 00 C8 CA 1F 81\") // 0x10\n        aString.append(\"00 00 C8 6E 1F 81 00 00\") // 0x11\n        aString.append(\"C8 26 1F 81 00 00 C0 3A\") // 0x12\n        aString.append(\"A5 80 00 00 C0 02 67 80\") // 0x13\n        aString.append(\"00 00 C0 6E A7 80 00 00\") // 0x14\n        aString.append(\"C0 6A A7 80 00 00 C0 42\") // 0x15\n        aString.append(\"67 80 00 00 C0 4A A7 80\") // 0x16\n        aString.append(\"00 00 C0 2E A7 80 00 00\") // 0x17\n        aString.append(\"C0 F6 66 80 00 00 C8 96\") // 0x18\n        aString.append(\"66 80 00 00 C0 3E 66 80\") // 0x19\n        aString.append(\"CB 01 C8 0C 61 80 2B 89\") // 0x1a\n        aString.append(\"88 7E 53 00 00 80 B0 B6\") // 0x1b\n        aString.append(\"C2 86 1A 09 94 DE 84 80\") // 0x1c\n        aString.append(\"AC 02 C8 B8 47 00 21 01\") // 0x1d\n        aString.append(\"C8 C8 8B 00 A0 00 C8 A8\") // 0x1e\n        aString.append(\"8D 00 00 00 C0 26 5C 80\") // 0x1f\n        aString.append(\"00 00 C0 DE 64 80 00 00\") // 0x20\n        aString.append(\"C0 FA 66 80 00 00 C0 DE\") // 0x21\n        aString.append(\"67 80 00 00 C0 92 A8 80\") // 0x22\n        aString.append(\"00 00 C0 E2 A8 80 00 00\") // 0x23\n        aString.append(\"C0 1E A9 80 00 00 C8 F2\") // 0x24\n        aString.append(\"A8 80 00 00 C8 96 22 81\") // 0x25\n        aString.append(\"00 00 C8 0A 61 81 00 00\") // 0x26\n        aString.append(\"C8 7E 20 81 4D 54 00 00\") // 0x27\n        aString.append(\"6C 0C 00 01 D3 04 7D 51\") //\n        aString.append(\"14 07 96 80 5A 00 ED A6\") //\n        aString.append(\"14 76 1A C8 04 E4 39 6C\") //\n        /*\n         aString.append(\"9E 42 21 83 F2 90 07 00\") //\n         aString.append(\"06 08 02 24 0C 43 17 3C\") //\n         aString.append(\"C2 43 08 08 B2 40 DF 00\") //\n         aString.append(\"08 08 D2 42 A2 F9 08 08\") //\n         aString.append(\"D2 42 A3 F9 08 08 0C 41\") //\n         aString.append(\"0C 53 92 12 90 1C 5C 93\") //\n         aString.append(\"03 20 A2 41 08 08 02 3C\") //\n         aString.append(\"B2 43 08 08 1C 43 21 53\") //\n         aString.append(\"30 41 0A 12 4A 4C 4C 93\") //\n         aString.append(\"0B 20 B2 40 50 CC 02 07\") //\n         aString.append(\"92 D3 00 07 B2 C0 00 02\") //\n         aString.append(\"00 07 A2 D2 00 07 02 3C\") //\n         aString.append(\"92 12 82 1C 32 D0 D8 00\") //\n         aString.append(\"E2 B3 C3 1C 09 28 E2 C3\") //\n         aString.append(\"C3 1C 4A 93 05 24 12 C3\") //\n         aString.append(\"12 10 A4 1C 12 11 A4 1C\") //\n         aString.append(\"3A 41 30 41 0A 12 0B 12\") //\n         aString.append(\"08 12 09 12 06 12 F2 90\") //\n         aString.append(\"07 00 06 08 68 20 B0 12\") //\n         aString.append(\"3A FB 61 20 92 12 78 1C\") //\n         aString.append(\"3A 40 FA F9 4C 43 8A 12\") //\n         aString.append(\"3B 40 84 1C 26 4B 38 40\") //\n         aString.append(\"B0 F9 39 40 A4 1C B2 90\") //\n         aString.append(\"00 20 A4 1C 09 2C 1F 43\") //\n         aString.append(\"B0 12 30 FB 3F 40 00 20\") //\n         aString.append(\"2F 89 82 4F A4 1C 06 3C\") //\n         aString.append(\"0F 43 B0 12 30 FB B2 50\") //\n         aString.append(\"00 E0 A4 1C 92 52 A4 1C\") //\n         aString.append(\"A4 1C 2F 49 7E 42 0D 43\") //\n         aString.append(\"0C 48 AB 12 1F 43 5E 43\") //\n         aString.append(\"3D 40 22 00 0C 48 AB 12\") //\n         aString.append(\"B2 90 00 01 A4 1C 08 28\") //\n         aString.append(\"7F 43 7E 42 0D 43 0C 48\") //\n         aString.append(\"AB 12 7C 40 34 00 29 3C\") //\n         aString.append(\"6C 42 8A 12 2F 49 3F F0\") //\n         aString.append(\"FF 07 82 4F A6 1C 1F 42\") //\n         aString.append(\"A6 1C 7E 40 0B 00 3D 40\") //\n         aString.append(\"16 00 0C 48 AB 12 7C 40\") //\n         aString.append(\"05 00 8A 12 2F 49 7E 40\") //\n         aString.append(\"0C 00 3D 40 28 00 0C 48\") //\n         aString.append(\"AB 12 7C 40 06 00 8A 12\") //\n         aString.append(\"2F 49 7E 40 0C 00 3D 40\") //\n         aString.append(\"34 00 0C 48 AB 12 B2 B0\") //\n         aString.append(\"10 00 22 01 06 2C 7C 40\") //\n         aString.append(\"28 00 92 12 8C 1C 0C 43\") //\n         aString.append(\"05 3C E2 C2 C3 1C 92 12\") //\n         aString.append(\"94 1C 1C 43 30 40 6C 5F\") //\n         aString.append(\"5E 43 3D 40 21 00 0C 48\") //\n         aString.append(\"00 46 C2 43 08 08 E2 D2\") //\n         aString.append(\"C3 1C 92 12 98 1C 4C 93\") //\n         aString.append(\"30 41 F2 90 07 00 06 08\") //\n         aString.append(\"02 24 0C 43 30 41 B0 12\") //\n         aString.append(\"3A FB 08 24 A2 43 DC F8\") //\n         aString.append(\"7C 40 28 00 92 12 8C 1C\") //\n         aString.append(\"0C 43 30 41 92 12 78 1C\") //\n         aString.append(\"92 D3 00 07 B2 40 4B D8\") //\n         aString.append(\"02 07 B2 C0 00 02 00 07\") //\n         aString.append(\"A2 D2 00 07 92 43 DC F8\") //\n         aString.append(\"32 D0 D8 00 E2 B3 C3 1C\") //\n         aString.append(\"05 28 E2 C3 C3 1C 92 42\") //\n         aString.append(\"A4 1C DE F8 5C 43 92 12\") //\n         aString.append(\"86 1C E2 C2 C3 1C 92 12\") //\n         aString.append(\"94 1C 1C 43 30 41 F2 90\") //\n         aString.append(\"07 00 06 08 02 24 0C 43\") //\n         aString.append(\"30 41 C2 43 08 08 E2 D2\") //\n         aString.append(\"C3 1C 92 12 72 1C 1C 43\") //\n         aString.append(\"30 41 0A 12 92 12 20 1C\") //\n         aString.append(\"4C 93 14 24 F2 90 05 00\") //\n         aString.append(\"0C 08 10 20 1D 42 06 08\") //\n         aString.append(\"5F 42 06 08 0D 93 07 20\") //\n         aString.append(\"7F 93 05 20 92 12 94 1C\") //\n         aString.append(\"C2 43 08 08 12 3C 7F 90\") //\n         aString.append(\"10 00 02 28 0C 43 0E 3C\") //\n         aString.append(\"C2 43 08 08 0C 43 07 3C\") //\n         aString.append(\"0E 4C 0E 5E 0A 4D 0A 5E\") //\n         aString.append(\"A2 4A 08 08 1C 53 0C 9F\") //\n         aString.append(\"F7 2B 1C 43 3A 41 30 41\") //\n         aString.append(\"0A 12 4A 4C B0 12 C8 5B\") //\n         aString.append(\"6A 92 10 20 7E 40 0B 00\") //\n         aString.append(\"3D 40 16 00 3C 40 B0 F9\") //\n         aString.append(\"92 12 4C 1C 82 4C A6 1C\") //\n         aString.append(\"92 52 A6 1C A6 1C 92 52\") //\n         aString.append(\"A6 1C A6 1C 3A 41 30 41\") //\n         aString.append(\"0E 43 1C 42 B6 F9 B0 12\") //\n         aString.append(\"DE 5E 1D 42 AA 1C 12 C3\") //\n         aString.append(\"0D 10 0D 11 0C 9D 02 2C\") //\n         aString.append(\"0D 8C 04 3C 0C 8D 0D 4C\") //\n         aString.append(\"3E 40 00 02 3D 90 00 02\") //\n         aString.append(\"02 28 3D 40 FF 01 5F 42\") //\n         aString.append(\"A8 F9 0F 9D 06 2C B2 D0\") //\n         aString.append(\"40 00 AE 1C F2 D0 40 00\") //\n         aString.append(\"C2 1C 0D DE 82 4D AA 1C\") //\n         aString.append(\"30 41 0A 12 0B 12 08 12\") //\n         aString.append(\"09 12 5B 42 A9 F9 48 43\") //\n         aString.append(\"C2 93 64 F8 09 34 F2 C0\") //\n         aString.append(\"80 00 64 F8 6B B2 01 28\") //\n         aString.append(\"58 43 4C 43 92 12 86 1C\") //\n         aString.append(\"59 42 64 F8 0A 3C 6A 93\") //\n         aString.append(\"04 20 B2 B0 00 02 00 08\") //\n         aString.append(\"04 28 7C 40 06 00 92 12\") //\n         aString.append(\"88 1C 1A 42 9E 01 4A 93\") //\n         aString.append(\"1F 24 4E 49 6E 83 7E 90\") //\n         aString.append(\"03 00 F7 2F 7A 90 10 00\") //\n         aString.append(\"02 20 58 B3 12 2C 4C 4A\") //\n         aString.append(\"7C 50 11 00 92 12 60 1C\") //\n         aString.append(\"5B B3 03 28 7A 90 06 00\") //\n         aString.append(\"E8 27 6B B3 03 28 7A 90\") //\n         aString.append(\"0E 00 E3 27 7A 90 10 00\") //\n         aString.append(\"D6 23 58 B3 DE 2F D9 3F\") //\n         aString.append(\"5E 42 64 F8 6E 83 7E 90\") //\n         aString.append(\"03 00 25 2C 92 12 96 1C\") //\n         aString.append(\"92 12 9A 1C 00 3C 3F 40\") //\n         aString.append(\"33 05 3F 53 FE 2F A2 B3\") //\n         aString.append(\"22 01 15 28 3F 40 4E C3\") //\n         aString.append(\"03 43 0B 43 3F 53 3B 63\") //\n         aString.append(\"FD 2F B2 B0 10 00 22 01\") //\n         aString.append(\"07 28 B2 B0 00 02 00 08\") //\n         aString.append(\"03 2C 92 12 70 1C 07 3C\") //\n         aString.append(\"7C 40 0A 00 02 3C 7C 40\") //\n         aString.append(\"0B 00 92 12 8C 1C 92 12\") //\n         aString.append(\"58 1C A2 D2 00 08 32 D2\") //\n         aString.append(\"30 40 6E 5F 30 41 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"FF FF 84 FD 25 00 9A FC\") //\n         aString.append(\"14 00 50 FC 19 00 20 FC\") //\n         aString.append(\"03 00 5F F5 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 AB AB 4A FB\") //\n         aString.append(\"E2 00 3C FA E1 00 AE FB\") //\n         aString.append(\"AB AB 2C 5A A4 00 CA FB\") //\n         aString.append(\"A3 00 56 5A A2 00 BA F9\") //\n         aString.append(\"A1 00 24 57 A0 00 AB AB\") //\n         aString.append(\"00 00 00 00 FF FF FF FF\") //\n         aString.append(\"20 00 71 62 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 AE 5C 00 00 A8 57\") //\n         aString.append(\"00 00 28 4E 68 45 00 00\") //\n         aString.append(\"DC 5F AE 5A 7A 5A DA 50\") //\n         */\n        sensorData.append(aString)\n        \n        \n        // # ID: E0:07:A0:00:00:46:5C:54\n        // # Memory content: Sensor 4\n        aString = String()\n        aString.append(\"85 44 88 53 05 00 03 95\") // 0x00\n        aString.append(\"51 04 65 54 00 00 00 00\") // 0x01\n        aString.append(\"00 00 00 00 00 00 00 00\") // 0x02\n        aString.append(\"F5 D6 04 10 16 00 C0 4A\") // 0x03\n        aString.append(\"67 80 16 00 C0 46 A7 80\") // 0x04\n        aString.append(\"16 00 C0 46 A7 80 16 00\") // 0x05\n        aString.append(\"C0 46 A7 80 15 00 C0 4A\") // 0x06\n        aString.append(\"A7 80 16 00 C0 4A 67 80\") // 0x07\n        aString.append(\"15 00 C0 4A A7 80 16 00\") // 0x08\n        aString.append(\"C0 4A 67 80 16 00 C0 46\") // 0x09\n        aString.append(\"A7 80 16 00 C0 46 A7 80\") // 0x0a\n        aString.append(\"16 00 C0 46 A7 80 15 00\") // 0x0b\n        aString.append(\"C0 46 A7 80 15 00 C0 46\") // 0x0c\n        aString.append(\"A7 80 16 00 C0 46 67 80\") // 0x0d\n        aString.append(\"15 00 C0 46 67 80 16 00\") // 0x0e\n        aString.append(\"C0 46 67 80 00 00 C0 CE\") // 0x0f\n        aString.append(\"A7 80 00 00 C0 B6 A7 80\") // 0x10\n        aString.append(\"00 00 C0 BA A7 80 00 00\") // 0x11\n        aString.append(\"C0 BE A7 80 00 00 C0 BE\") // 0x12\n        aString.append(\"A7 80 00 00 C0 AA A7 80\") // 0x13\n        aString.append(\"00 00 C0 8E A7 80 00 00\") // 0x14\n        aString.append(\"C0 8A 67 80 00 00 C0 7E\") // 0x15\n        aString.append(\"A7 80 00 00 C0 72 A7 80\") // 0x16\n        aString.append(\"00 00 C0 66 A7 80 00 00\") // 0x17\n        aString.append(\"C0 5E 67 80 00 00 C0 56\") // 0x18\n        aString.append(\"A7 80 00 00 C0 4E A7 80\") // 0x19\n        aString.append(\"00 00 C0 4A 67 80 00 00\") // 0x1a\n        aString.append(\"C0 46 67 80 00 00 C0 CA\") // 0x1b\n        aString.append(\"A7 80 00 00 C0 C6 A7 80\") // 0x1c\n        aString.append(\"00 00 C0 C6 A7 80 00 00\") // 0x1d\n        aString.append(\"C0 C6 A7 80 00 00 C0 C6\") // 0x1e\n        aString.append(\"A7 80 00 00 C0 CA A7 80\") // 0x1f\n        aString.append(\"00 00 C0 CE A7 80 00 00\") // 0x20\n        aString.append(\"C0 CE A7 80 00 00 C0 D2\") // 0x21\n        aString.append(\"A7 80 00 00 C0 DA 67 80\") // 0x22\n        aString.append(\"00 00 C0 D6 A7 80 00 00\") // 0x23\n        aString.append(\"C0 CA A7 80 00 00 C0 CE\") // 0x24\n        aString.append(\"A7 80 00 00 C0 D2 A7 80\") // 0x25\n        aString.append(\"00 00 C0 D6 A7 80 00 00\") // 0x26\n        aString.append(\"C0 DA A7 80 65 54 00 00\") // 0x27\n        aString.append(\"D5 75 00 01 D3 04 95 51\") //\n        aString.append(\"14 07 96 80 5A 00 ED A6\") //\n        aString.append(\"12 9C 1A C8 04 A3 69 68\") //\n        /*\n         aString.append(\"9E 42 21 83 F2 90 07 00\") //\n         aString.append(\"06 08 02 24 0C 43 17 3C\") //\n         aString.append(\"C2 43 08 08 B2 40 DF 00\") //\n         aString.append(\"08 08 D2 42 A2 F9 08 08\") //\n         aString.append(\"D2 42 A3 F9 08 08 0C 41\") //\n         aString.append(\"0C 53 92 12 90 1C 5C 93\") //\n         aString.append(\"03 20 A2 41 08 08 02 3C\") //\n         aString.append(\"B2 43 08 08 1C 43 21 53\") //\n         aString.append(\"30 41 0A 12 4A 4C 4C 93\") //\n         aString.append(\"0B 20 B2 40 50 CC 02 07\") //\n         aString.append(\"92 D3 00 07 B2 C0 00 02\") //\n         aString.append(\"00 07 A2 D2 00 07 02 3C\") //\n         aString.append(\"92 12 82 1C 32 D0 D8 00\") //\n         aString.append(\"E2 B3 C3 1C 09 28 E2 C3\") //\n         aString.append(\"C3 1C 4A 93 05 24 12 C3\") //\n         aString.append(\"12 10 A4 1C 12 11 A4 1C\") //\n         aString.append(\"3A 41 30 41 0A 12 0B 12\") //\n         aString.append(\"08 12 09 12 06 12 F2 90\") //\n         aString.append(\"07 00 06 08 68 20 B0 12\") //\n         aString.append(\"3A FB 61 20 92 12 78 1C\") //\n         aString.append(\"3A 40 FA F9 4C 43 8A 12\") //\n         aString.append(\"3B 40 84 1C 26 4B 38 40\") //\n         aString.append(\"B0 F9 39 40 A4 1C B2 90\") //\n         aString.append(\"00 20 A4 1C 09 2C 1F 43\") //\n         aString.append(\"B0 12 30 FB 3F 40 00 20\") //\n         aString.append(\"2F 89 82 4F A4 1C 06 3C\") //\n         aString.append(\"0F 43 B0 12 30 FB B2 50\") //\n         aString.append(\"00 E0 A4 1C 92 52 A4 1C\") //\n         aString.append(\"A4 1C 2F 49 7E 42 0D 43\") //\n         aString.append(\"0C 48 AB 12 1F 43 5E 43\") //\n         aString.append(\"3D 40 22 00 0C 48 AB 12\") //\n         aString.append(\"B2 90 00 01 A4 1C 08 28\") //\n         aString.append(\"7F 43 7E 42 0D 43 0C 48\") //\n         aString.append(\"AB 12 7C 40 34 00 29 3C\") //\n         aString.append(\"6C 42 8A 12 2F 49 3F F0\") //\n         aString.append(\"FF 07 82 4F A6 1C 1F 42\") //\n         aString.append(\"A6 1C 7E 40 0B 00 3D 40\") //\n         aString.append(\"16 00 0C 48 AB 12 7C 40\") //\n         aString.append(\"05 00 8A 12 2F 49 7E 40\") //\n         aString.append(\"0C 00 3D 40 28 00 0C 48\") //\n         aString.append(\"AB 12 7C 40 06 00 8A 12\") //\n         aString.append(\"2F 49 7E 40 0C 00 3D 40\") //\n         aString.append(\"34 00 0C 48 AB 12 B2 B0\") //\n         aString.append(\"10 00 22 01 06 2C 7C 40\") //\n         aString.append(\"28 00 92 12 8C 1C 0C 43\") //\n         aString.append(\"05 3C E2 C2 C3 1C 92 12\") //\n         aString.append(\"94 1C 1C 43 30 40 6C 5F\") //\n         aString.append(\"5E 43 3D 40 21 00 0C 48\") //\n         aString.append(\"00 46 C2 43 08 08 E2 D2\") //\n         aString.append(\"C3 1C 92 12 98 1C 4C 93\") //\n         aString.append(\"30 41 F2 90 07 00 06 08\") //\n         aString.append(\"02 24 0C 43 30 41 B0 12\") //\n         aString.append(\"3A FB 08 24 A2 43 DC F8\") //\n         aString.append(\"7C 40 28 00 92 12 8C 1C\") //\n         aString.append(\"0C 43 30 41 92 12 78 1C\") //\n         aString.append(\"92 D3 00 07 B2 40 4B D8\") //\n         aString.append(\"02 07 B2 C0 00 02 00 07\") //\n         aString.append(\"A2 D2 00 07 92 43 DC F8\") //\n         aString.append(\"32 D0 D8 00 E2 B3 C3 1C\") //\n         aString.append(\"05 28 E2 C3 C3 1C 92 42\") //\n         aString.append(\"A4 1C DE F8 5C 43 92 12\") //\n         aString.append(\"86 1C E2 C2 C3 1C 92 12\") //\n         aString.append(\"94 1C 1C 43 30 41 F2 90\") //\n         aString.append(\"07 00 06 08 02 24 0C 43\") //\n         aString.append(\"30 41 C2 43 08 08 E2 D2\") //\n         aString.append(\"C3 1C 92 12 72 1C 1C 43\") //\n         aString.append(\"30 41 0A 12 92 12 20 1C\") //\n         aString.append(\"4C 93 14 24 F2 90 05 00\") //\n         aString.append(\"0C 08 10 20 1D 42 06 08\") //\n         aString.append(\"5F 42 06 08 0D 93 07 20\") //\n         aString.append(\"7F 93 05 20 92 12 94 1C\") //\n         aString.append(\"C2 43 08 08 12 3C 7F 90\") //\n         aString.append(\"10 00 02 28 0C 43 0E 3C\") //\n         aString.append(\"C2 43 08 08 0C 43 07 3C\") //\n         aString.append(\"0E 4C 0E 5E 0A 4D 0A 5E\") //\n         aString.append(\"A2 4A 08 08 1C 53 0C 9F\") //\n         aString.append(\"F7 2B 1C 43 3A 41 30 41\") //\n         aString.append(\"0A 12 4A 4C B0 12 C8 5B\") //\n         aString.append(\"6A 92 10 20 7E 40 0B 00\") //\n         aString.append(\"3D 40 16 00 3C 40 B0 F9\") //\n         aString.append(\"92 12 4C 1C 82 4C A6 1C\") //\n         aString.append(\"92 52 A6 1C A6 1C 92 52\") //\n         aString.append(\"A6 1C A6 1C 3A 41 30 41\") //\n         aString.append(\"0E 43 1C 42 B6 F9 B0 12\") //\n         aString.append(\"DE 5E 1D 42 AA 1C 12 C3\") //\n         aString.append(\"0D 10 0D 11 0C 9D 02 2C\") //\n         aString.append(\"0D 8C 04 3C 0C 8D 0D 4C\") //\n         aString.append(\"3E 40 00 02 3D 90 00 02\") //\n         aString.append(\"02 28 3D 40 FF 01 5F 42\") //\n         aString.append(\"A8 F9 0F 9D 06 2C B2 D0\") //\n         aString.append(\"40 00 AE 1C F2 D0 40 00\") //\n         aString.append(\"C2 1C 0D DE 82 4D AA 1C\") //\n         aString.append(\"30 41 0A 12 0B 12 08 12\") //\n         aString.append(\"09 12 5B 42 A9 F9 48 43\") //\n         aString.append(\"C2 93 64 F8 09 34 F2 C0\") //\n         aString.append(\"80 00 64 F8 6B B2 01 28\") //\n         aString.append(\"58 43 4C 43 92 12 86 1C\") //\n         aString.append(\"59 42 64 F8 0A 3C 6A 93\") //\n         aString.append(\"04 20 B2 B0 00 02 00 08\") //\n         aString.append(\"04 28 7C 40 06 00 92 12\") //\n         aString.append(\"88 1C 1A 42 9E 01 4A 93\") //\n         aString.append(\"1F 24 4E 49 6E 83 7E 90\") //\n         aString.append(\"03 00 F7 2F 7A 90 10 00\") //\n         aString.append(\"02 20 58 B3 12 2C 4C 4A\") //\n         aString.append(\"7C 50 11 00 92 12 60 1C\") //\n         aString.append(\"5B B3 03 28 7A 90 06 00\") //\n         aString.append(\"E8 27 6B B3 03 28 7A 90\") //\n         aString.append(\"0E 00 E3 27 7A 90 10 00\") //\n         aString.append(\"D6 23 58 B3 DE 2F D9 3F\") //\n         aString.append(\"5E 42 64 F8 6E 83 7E 90\") //\n         aString.append(\"03 00 25 2C 92 12 96 1C\") //\n         aString.append(\"92 12 9A 1C 00 3C 3F 40\") //\n         aString.append(\"33 05 3F 53 FE 2F A2 B3\") //\n         aString.append(\"22 01 15 28 3F 40 4E C3\") //\n         aString.append(\"03 43 0B 43 3F 53 3B 63\") //\n         aString.append(\"FD 2F B2 B0 10 00 22 01\") //\n         aString.append(\"07 28 B2 B0 00 02 00 08\") //\n         aString.append(\"03 2C 92 12 70 1C 07 3C\") //\n         aString.append(\"7C 40 0A 00 02 3C 7C 40\") //\n         aString.append(\"0B 00 92 12 8C 1C 92 12\") //\n         aString.append(\"58 1C A2 D2 00 08 32 D2\") //\n         aString.append(\"30 40 6E 5F 30 41 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"FF FF 84 FD 25 00 9A FC\") //\n         aString.append(\"14 00 50 FC 19 00 20 FC\") //\n         aString.append(\"03 00 5F F5 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 00 00 AB AB 4A FB\") //\n         aString.append(\"E2 00 3C FA E1 00 AE FB\") //\n         aString.append(\"AB AB 2C 5A A4 00 CA FB\") //\n         aString.append(\"A3 00 56 5A A2 00 BA F9\") //\n         aString.append(\"A1 00 24 57 A0 00 AB AB\") //\n         aString.append(\"00 00 00 00 FF FF FF FF\") //\n         aString.append(\"20 00 71 62 00 00 00 00\") //\n         aString.append(\"00 00 00 00 00 00 00 00\") //\n         aString.append(\"00 00 AE 5C 00 00 A8 57\") //\n         aString.append(\"00 00 28 4E 68 45 00 00\") //\n         aString.append(\"DC 5F AE 5A 7A 5A DA 50\") //\n         */\n//        sensorData.append(aString)\n        return sensorData\n\n    }\n}\n\n"
  },
  {
    "path": "LibreMonitorTests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "LibreMonitorTests/LibreMonitorTestSensorData.swift",
    "content": "//\n//  LibreMonitorTestSensorData.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 28.07.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\n\nimport XCTest\n//@testable import Pods_LibreMonitor\n@testable import LibreMonitor\n\nclass LibreMonitorTestSensorData: XCTestCase {\n    \n    // Adaptions for the c-code from the arduino part\n    typealias byte = UInt8\n    \n    // local properties for string slip Buffer content\n    var slipBufferPayloadData: Data = Data()\n    var slipBufferPayloadIdentifier: UInt16 = 0\n    var slipBufferTxFlags: UInt8 = 0\n    \n    \n    override func setUp() {\n        super.setUp()\n        // Put setup code here. This method is called before the invocation of each test method in the class.\n    }\n    \n    override func tearDown() {\n        // Put teardown code here. This method is called after the invocation of each test method in the class.\n        super.tearDown()\n    }\n    \n    func arrayOfValidTestInputs() -> [[UInt8]] {\n        \n        var testString2 =  \"FD 61 18 19 01 00 00 00\"  //  0 should return \"62 C2\", i.e. 25282 oder 49762 (with bytes not swapped)\n        testString2.append(\"00 00 00 00 00 00 00 00\") //  1\n        testString2.append(\"00 00 00 00 00 00 00 00\") //  2\n        testString2.append(\"62 C2 00 00 00 00 00 00\") //  3\n        testString2.append(\"00 00 00 00 00 00 00 00\") //  4\n        testString2.append(\"00 00 00 00 00 00 00 00\") //  5\n        testString2.append(\"00 00 00 00 00 00 00 00\") //  6\n        testString2.append(\"00 00 00 00 00 00 00 00\") //  7\n        testString2.append(\"00 00 00 00 00 00 00 00\") //  8\n        testString2.append(\"00 00 00 00 00 00 00 00\") //  9\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 10\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 11\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 12\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 13\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 14\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 15\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 16\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 17\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 18\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 19\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 20\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 21\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 22\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 23\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 24\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 25\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 26\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 27\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 28\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 29\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 30\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 31\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 32\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 33\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 34\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 35\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 36\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 37\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 38\n        testString2.append(\"00 00 00 00 00 00 00 00\") // 39\n        testString2.append(\"58 C7 00 01 15 04 96 50\") // 40\n        testString2.append(\"14 07 96 80 5A 00 ED A6\") // 41\n        testString2.append(\"12 13 1B C8 04 99 28 66\") // 42\n\n        testString2 = testString2.replacingOccurrences(of: \" \", with: \"\")\n        let bytes2 = stringToBytes(testString2)\n        \n        \n        var testString3 =  \"90 DC 18 19 03 00 00 00\"  //  0\n        testString3.append(\"00 00 00 00 00 00 00 00\") //  1\n        testString3.append(\"00 00 00 00 00 00 00 00\") //  2\n        testString3.append(\"E1 D7 06 03 FC 04 C8 24\") //  3\n        testString3.append(\"DA 80 F1 04 C8 30 9A 80\") //  4\n        testString3.append(\"E4 04 C8 24 9A 80 D4 04\") //  5\n        testString3.append(\"C8 10 5A 80 CB 04 C8 6C\") //  6\n        testString3.append(\"9A 80 C2 04 C8 78 DA 80\") //  7 \"C204C878DA80\" for trend test\n        testString3.append(\"2D 05 C8 18 D9 80 2B 05\") //  8\n        testString3.append(\"88 0E D9 81 33 05 C8 2C\") //  9\n        testString3.append(\"D9 80 31 05 C8 38 D9 80\") // 10\n        testString3.append(\"31 05 C8 28 D9 80 2E 05\") // 11\n        testString3.append(\"C8 34 D9 80 2B 05 C8 98\") // 12\n        testString3.append(\"99 80 22 05 C8 C0 99 80\") // 13\n        testString3.append(\"18 05 C8 00 9A 80 0A 05\") // 14\n        testString3.append(\"C8 08 9A 80 00 00 88 06\") // 15\n        testString3.append(\"98 80 55 05 C8 2C D9 80\") // 16\n        testString3.append(\"27 05 C8 98 99 80 00 00\") // 17 \"2705C8989980\" for history test\n        testString3.append(\"00 00 00 00 00 00 00 00\") // 18\n        testString3.append(\"00 00 00 00 00 00 00 00\") // 19\n        testString3.append(\"00 00 00 00 00 00 00 00\") // 20\n        testString3.append(\"00 00 00 00 00 00 00 00\") // 21\n        testString3.append(\"00 00 00 00 00 00 00 00\") // 22\n        testString3.append(\"00 00 00 00 00 00 00 00\") // 23\n        testString3.append(\"00 00 00 00 00 00 00 00\") // 24\n        testString3.append(\"00 00 00 00 00 00 00 00\") // 25\n        testString3.append(\"00 00 00 00 00 00 00 00\") // 26\n        testString3.append(\"00 00 00 00 00 00 00 00\") // 27\n        testString3.append(\"00 00 00 00 00 00 00 00\") // 28\n        testString3.append(\"00 00 00 00 00 00 00 00\") // 29\n        testString3.append(\"00 00 00 00 00 00 00 00\") // 30\n        testString3.append(\"00 00 00 00 00 00 00 00\") // 31\n        testString3.append(\"00 00 00 00 00 00 00 00\") // 32\n        testString3.append(\"00 00 00 00 00 00 00 00\") // 33\n        testString3.append(\"00 00 00 00 00 00 00 00\") // 34\n        testString3.append(\"00 00 00 00 00 00 00 00\") // 35\n        testString3.append(\"00 00 00 00 00 00 00 00\") // 36\n        testString3.append(\"00 00 00 00 00 00 00 00\") // 37\n        testString3.append(\"00 00 00 00 00 00 00 00\") // 38\n        testString3.append(\"00 00 00 00 37 00 00 00\") // 39\n        testString3.append(\"58 C7 00 01 15 04 96 50\") // 40\n        testString3.append(\"14 07 96 80 5A 00 ED A6\") // 41\n        testString3.append(\"12 13 1B C8 04 99 28 66\") // 42\n        testString3 = testString3.replacingOccurrences(of: \" \", with: \"\")\n        let bytes3 = stringToBytes(testString3)\n        \n        return [bytes2, bytes3]\n    }\n    \n    func testCrcTable() {\n        \n    }\n    \n    func testExample() {\n        \n        // Test valid crc and other data for the test cases\n        print(\"------- valid test cases for crc and other ------\")\n        let validTestCaseBytes = arrayOfValidTestInputs().last!\n        let date = Date()\n        if let sensorData = SensorData(bytes: validTestCaseBytes, date: date) {\n            print(sensorData)\n            print(\"Header validity: \" + String(sensorData.hasValidHeaderCRC))\n            print(\"Body validity:\" + String(sensorData.hasValidBodyCRC))\n            \n            XCTAssert(sensorData.hasValidHeaderCRC == true, \"Unvalid header crc\")\n            XCTAssert(sensorData.hasValidBodyCRC == true, \"Unvalid body crc\")\n            XCTAssert(sensorData.hasValidFooterCRC == true, \"Unvalid footer crc\")\n            \n            XCTAssert(sensorData.minutesSinceStart == 55, \"Wrong minutesSinceStart counter\")\n            XCTAssert(sensorData.nextTrendBlock == 6, \"Wrong next trend block\")\n            XCTAssert(sensorData.nextHistoryBlock == 3, \"Wrong next history block\")\n            XCTAssert(sensorData.date == date, \"Wrong date\")\n            XCTAssert(sensorData.state == .ready, \"Wrong sensor state\")\n            \n            // Test trend glucose measurement\n            let trendMeasurements = sensorData.trendMeasurements(0.0, slope: 0.1)\n            XCTAssert(trendMeasurements.count == 16, \"Wrong number of trend measurements\")\n            let byteStringInTrendMeasurement = trendMeasurements[0].byteString\n            let byteTrendStringAsReadFromSensor = \"C204C878DA80\"\n            XCTAssert(byteStringInTrendMeasurement == byteTrendStringAsReadFromSensor, \"Wrong byte string\") // \"[194, 4, 200, 120, 218, 128]\" or \"C204C878DA80\"\n            XCTAssert(trendMeasurements[0].date == date, \"Wrong date\")\n            XCTAssert(trendMeasurements[0].rawValue == 1218, \"Wrong raw value\")\n            XCTAssert((trendMeasurements[0].glucose - 121.8) < 0.001, \"Wrong glucose value\")\n            \n            // Test count and byte strings of history glucose measurement\n            let historyMeasurements = sensorData.historyMeasurements(0.0, slope: 0.1)\n            XCTAssert(historyMeasurements.count == 32, \"Wrong number of history measurements\")\n            let byteStringInHistoryMeasurement = historyMeasurements[0].byteString\n            let byteHIstoryStringAsReadFromSensor = \"2705C8989980\"\n            XCTAssert(byteStringInHistoryMeasurement == byteHIstoryStringAsReadFromSensor, \"Wrong byte string\") // \"[194, 4, 200, 120, 218, 128]\" or \"C204C878DA80\"\n            \n            \n            // Test dates of history glucose measurements. Date of most recent value must be 10 minutes behind and date of second most recent value must be 10 + 15 = 25 minutes behind\n            let tenMintues = 10 * 60\n            let twentyFiveMintues = 25 * 60\n            XCTAssert( Int(round(date.timeIntervalSince(historyMeasurements[0].date))) == tenMintues, \"Wrong history date, not 10 minutes apart\")\n            XCTAssert( Int(round(date.timeIntervalSince(historyMeasurements[1].date))) == twentyFiveMintues, \"Wrong history date, not 25 minutes apart\")\n\n            // Test raw values and glucose values of history measurements\n            XCTAssert(historyMeasurements[0].rawValue == 1319, \"Wrong raw value\")\n            XCTAssert((historyMeasurements[0].glucose - 131.9) < 0.001, \"Wrong glucose value\")\n\n        }\n        \n        // change data of body and ensure that crc is now different\n        print(\"------- invalid test cases for crc ------\")\n        var invalidTestCaseBytes = validTestCaseBytes\n        let endIndex = invalidTestCaseBytes.endIndex-1\n        invalidTestCaseBytes[endIndex] = invalidTestCaseBytes[endIndex] | 0xff  // change data such that crc will not match any more\n        if let sensorData = SensorData(bytes: invalidTestCaseBytes, date: Date()) {\n            print(sensorData)\n            print(\"Header validity: \" + String(sensorData.hasValidHeaderCRC))\n            \n            XCTAssertFalse(sensorData.hasValidFooterCRC == true, \"Error in footer crc\")\n        }\n    }\n    \n    \n    \n    func stringToBytes(_ theString: String) -> [UInt8] {\n        \n        let length = theString.lengthOfBytes(using: String.Encoding.utf8)\n        guard length % 2 == 0 else {\n            print(\"Error in \\(#function): String does not have an even number of characters and is thus not a valid string of pairs of characters where each pair represents a byte.\")\n            return [0]\n        }\n        \n        var theBytes = [UInt8]()\n        for index in stride(from: 0, to: length, by: 2) {\n            let aIndex = theString.characters.index(theString.startIndex, offsetBy: index)\n            let bIndex = theString.characters.index(theString.startIndex, offsetBy: index+2)\n            let range = aIndex..<bIndex\n//            let range = Range(start: aIndex, end: bIndex)\n            let string = String(theString.substring(with: range))\n            let aByte = UInt8(string!, radix: 16)\n            theBytes.append(aByte!)\n        }\n        return theBytes\n    }\n    \n}\n"
  },
  {
    "path": "LibreMonitorTests/LibreMonitorTests-Bridging-Header.h",
    "content": "//\n//  Use this file to import your target's public headers that you would like to expose to Swift.\n//\n#import \"NSData+CRC8.h\"\n#import \"NSData+SLIP.h\"\n#import \"constants.h\"\n#import \"data_types.h\"\n#import \"crc8.h\"\n#import \"libUBP.h\"\n"
  },
  {
    "path": "LibreMonitorTests/LibreMonitorTests.swift",
    "content": "//\n//  LibreMonitorTests.swift\n//  LibreMonitorTests\n//\n//  Created by Uwe Petersen on 09.10.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport XCTest\n@testable import LibreMonitor\n\nclass LibreMonitorTests: XCTestCase, SLIPBufferDelegate  {\n    // Adaptions for the c-code from the arduino part\n    typealias byte = UInt8\n    \n    // local properties for string slip Buffer content\n    var slipBufferPayloadData: Data = Data()\n    var slipBufferPayloadIdentifier: UInt16 = 0\n    var slipBufferTxFlags: UInt8 = 0\n    \n    \n    override func setUp() {\n        super.setUp()\n        // Put setup code here. This method is called before the invocation of each test method in the class.\n    }\n    \n    override func tearDown() {\n        // Put teardown code here. This method is called after the invocation of each test method in the class.\n        super.tearDown()\n    }\n    \n    func testExample() {\n        // This is an example of a functional test case.\n        // Use XCTAssert and related functions to verify your tests produce the correct results.\n        \n        XCTAssert(2 == 2, \"the message is it is false\")\n    }\n    \n    func testTransmission() {\n        // Test the crc calculation for some known cases of bytes\n        //\n        // Original data: <9c03c8c0 1a80>\n        // Excaped  data: <c0d20401 9c03c8db dc1a80cf c0> -> crc is cf as hex or -49 as Int (calculated without the c0 start and end byte)\n        // Original data: <0303c810 1980>\n        // Excaped  data: <c0d20401 0303c810 19801ec0> crc is 1e as hex or 30 as Int (calculated without the c0 start and end byte)\n        // unescaped: <06100148 02c8c859 0018a4> -> crc is -92 (as Int)\n        // escaped:   <c0c00610 014802c8 c8590018 a4c0>\n        //\n        // unescaped: <01200000 4e464320 4653324a 41535432 00000053>  crc is -> 83 as Int\n        // excaped:   <c0012000 004e4643 20465332 4a415354 32000000 53c0>\n        //\n        // unescaped: <06100100 00000000 0029d0>  -> crc is -48 as Int\n        // escaped:   <c0c00610 01000000 00000029 d0c0>\n        \n        let bytesArray: [[UInt8]] = [\n            [0xB0, 0x04, 0xC8, 0xB0, 0xD7, 0x00],\n            [0xCA, 0x02, 0xC8, 0x6C, 0x58, 0x01],\n            [0x9D, 0x02, 0xC8, 0x98, 0x97, 0x01],\n            [0x6B, 0x02, 0xC8, 0x38, 0x97, 0x00],\n            [0xCA, 0x02, 0xC8, 0x6C,   0x58, 0x01, 0x9C, 0x03, 0xC8, 0xC0,  0xDB, 0xDD, 0x1A, 0x80, 0x03, 0x03, 0xC8, 0x10,   0x19, 0x80, 0x01, 0x20, 0x00, 0x00,   0x4e, 0x46, 0x43, 0x20,   0x46, 0x53, 0x32, 0x4a,   0x41, 0x53, 0x54, 0x32,   0x00, 0x00, 0x00, 0x53],\n            [0xCA, 0x02, 0xC8, 0x6C,   0x58, 0x01, 0x9C, 0x03, 0xC8, 0xC0,   0xDB, 0xDD, 0xDC, 0x1A, 0x80, 0x03, 0x03, 0xC8, 0x10,   0x19, 0x80, 0x01, 0x20, 0x00, 0x00,   0x4e, 0x46, 0x43, 0x20,   0x46, 0x53, 0x32, 0x4a,   0x41, 0x53, 0x54, 0x32,   0x00, 0x00, 0x00, 0x53],\n            [0xCA, 0x02, 0xC8, 0x6C,   0x58, 0x01],\n            [0x9C, 0x03, 0xC8, 0xC0,   0x1A, 0x80],\n            [0x03, 0x03, 0xC8, 0x10,   0x19, 0x80],\n            [0x06, 0x10, 0x01, 0x48,   0x02, 0xc8, 0xc8, 0x59,   0x00, 0x18, 0xa4],\n            [0x01, 0x20, 0x00, 0x00,   0x4e, 0x46, 0x43, 0x20,   0x46, 0x53, 0x32, 0x4a,   0x41, 0x53, 0x54, 0x32,   0x00, 0x00, 0x00, 0x53],\n            [0x06, 0x10, 0x01, 0x00,   0x00, 0x00, 0x00, 0x00,   0x00, 0x29, 0xd0]\n        ]\n        \n        for bytes in bytesArray {\n            transmission(forPayload: bytes, packetIdentifier: UInt16(1234))\n        }\n\n        for testData in BluetoothTestData.data() {\n//            let range = testData.startIndex...testData.index(testData.startIndex, offsetBy: 244) // okay values on laat: 7; 201; 253; 255; not okay values:\n            let aString = testData.replacingOccurrences(of: \" \", with: \"\")\n            let bytes = stringToBytes(aString)\n            transmission(forPayload: bytes, packetIdentifier: UInt16(9999))\n        }\n        \n    }   \n    \n    // Delegate function for test purposes that receives the data (as received via bluetooth) and stores data in local properties\n    func slipBufferReceivedPayload(_ payloadData: Data, payloadIdentifier: UInt16, txFlags: UInt8) {\n        slipBufferPayloadData = payloadData\n        slipBufferPayloadIdentifier = payloadIdentifier\n        slipBufferTxFlags = txFlags\n        print(\"Payload is: \" + slipBufferPayloadData.debugDescription)\n    }\n\n    \n    \n    // Test complete transmission of a packet of bytes with SLIP, see https://de.wikipedia.org/wiki/Serial_Line_Internet_Protocol\n    func transmission(forPayload payload: [UInt8], packetIdentifier: UInt16) {\n        \n        // Connect simblee\n        SimbleeBLE_onConnect()\n        \n        // 1. escape the payload using SLIP\n        \n        let dataPayload =  Data(bytes: UnsafePointer<UInt8>(payload), count: payload.count)  // convert to NSData\n        \n        let count = dataPayload.count / MemoryLayout<Int8>.size\n        var cCharArray = [CChar](repeating: 0, count: count)          // c-char array, format to be transmitted\n        (dataPayload as NSData).getBytes(&cCharArray, length: count)                  // read into the c-char array\n        \n        // queue the packet and escape data if necessary according to SLIP, transmit and check for success\n        let success = UBP_queuePacketTransmission(packetIdentifier, UBP_TxFlagIsRPC, cCharArray, UInt16(payload.count))\n        XCTAssert(success, \"Failed to queue packet with SLIP\")\n        \n        // 2. get the escaped payload as transmitted from transmission buffer\n        \n        var txBuffer = [CChar](repeating: 0, count:440) /// Warning: This should not be hardcoded\n        var txBufferLength: Int32 = 0\n        getTxBuffer(&txBuffer, &txBufferLength)\n        //        let escapedDataPayload = Data(bytes: UnsafePointer<UInt8>(txBuffer), count: Int(txBufferLength))\n        let escapedDataPayload = Data(bytes: UnsafeRawPointer(txBuffer), count: Int(txBufferLength))\n        \n        print(\"Original data: \" + dataPayload.debugDescription)\n        print(\"Excaped  data: \" + escapedDataPayload.debugDescription)\n        \n        // 3. receive escaped data payload and unescape again. The unescaped data is stored in local properties\n        let slipBuffer = SLIPBuffer()\n        slipBuffer.delegate = self\n        slipBuffer.appendEscapedBytes(escapedDataPayload)\n        \n        XCTAssertEqual(slipBufferPayloadData, dataPayload, \"Transmitted and received payload are not equal\")\n        XCTAssertEqual(slipBufferPayloadIdentifier, packetIdentifier, \"Transmitted and received identifier are not equal\")\n        \n        // Disconnect simblee (resets the buffer)\n        SimbleeBLE_onDisconnect()\n        \n    }\n    \n\n    \n    \n    // MARK: crc test code\n    \n    func testCrc8() {\n        // Test the crc calculation for some known cases of bytes\n        //\n        // Original data: <9c03c8c0 1a80>\n        // Excaped  data: <c0d20401 9c03c8db dc1a80cf c0> -> crc is cf as hex or -49 as Int (calculated without the c0 start and end byte)\n        // Original data: <0303c810 1980>\n        // Excaped  data: <c0d20401 0303c810 19801ec0> crc is 1e as hex or 30 as Int (calculated without the c0 start and end byte)\n        //\n        // unescaped: <06100148 02c8c859 0018a4> -> crc is -92 (as Int)\n        // escaped:   <c0c00610 014802c8 c8590018 a4c0>\n        //\n        // unescaped: <01200000 4e464320 4653324a 41535432 00000053>  crc is -> 83 as Int\n        // excaped:   <c0012000 004e4643 20465332 4a415354 32000000 53c0>\n        //\n        // unescaped: <06100100 00000000 0029d0>  -> crc is -48 as Int\n        // escaped:   <c0c00610 01000000 00000029 d0c0>\n        \n        let bytesArray: [[UInt8]] = [\n            [0xd2, 0x04, 0x01, 0x9c,   0x03, 0xc8, 0xdb, 0xdc,   0x1a, 0x80, 0xcf],\n            [0xd2, 0x04, 0x01, 0x03,   0x03, 0xC8, 0x10, 0x19,   0x80, 0x1e],\n            [0x06, 0x10, 0x01, 0x48,   0x02, 0xc8, 0xc8, 0x59,   0x00, 0x18, 0xa4],\n            [0x01, 0x20, 0x00, 0x00,   0x4e, 0x46, 0x43, 0x20,   0x46, 0x53, 0x32, 0x4a,   0x41, 0x53, 0x54, 0x32,   0x00, 0x00, 0x00, 0x53],\n            [0x06, 0x10, 0x01, 0x00,   0x00, 0x00, 0x00, 0x00,   0x00, 0x29, 0xd0]\n        ]\n        \n        for bytes in bytesArray {\n            testCrc(forBytes: bytes)\n            testArduinoCrc(forBytes: bytes)\n        }\n    }\n    \n    func testArduinoCrc(forBytes bytes: [UInt8])  {\n        // Test an array of bytes, where the last byte contains the crc8 that should be calculated (this last byte is then the embedded crc8)\n        \n        var bytesToTransfer = bytes\n        let bytesToTransferLength = bytes.count - 1\n        \n        let calculatedCrc: UInt8 = CRC8(&bytesToTransfer, UInt16(bytesToTransferLength))\n        \n        let embeddedCrc = bytes[bytes.count-1]\n        \n        \n        print(String(format: \"Arduino crc calculated is 0x%2x and embecced ist 0x%2x\", arguments: [calculatedCrc, embeddedCrc]))\n        XCTAssert(embeddedCrc == calculatedCrc, \"Arduino Code: calculated and embedde crc do not match.\")\n    }\n    \n    func testCrc(forBytes bytes: [UInt8]) {\n        \n        // Last byte contains crc\n        let PacketChecksumLength = MemoryLayout<UInt8>.size\n        \n        // Convert bytes to NSData\n        let data = Data(bytes: UnsafePointer<UInt8>(bytes), count: bytes.count)\n        \n        // Extract embedded checksum from packet\n        var embeddedChecksumByte:Int8 = 0\n        (data as NSData).getBytes(&embeddedChecksumByte, range: NSMakeRange(data.count - PacketChecksumLength, PacketChecksumLength))\n        \n        // Calculate checksum over bytes, excluding the last byte which is the embedded checksum\n        let payload = Data(bytes: UnsafePointer<UInt8>(bytes), count: bytes.count - PacketChecksumLength)\n        let calculatedCrc8 = (payload as NSData).crc8Checksum()\n        \n        // Assert that they both are equal\n        print(String(format: \"Embedded crc8 is %d, calculated crc8 is %d\", arguments: [embeddedChecksumByte, calculatedCrc8]))\n        XCTAssert(embeddedChecksumByte == calculatedCrc8, \"the crc8 on nsdata is false\")\n    }\n    \n    \n    // MARK: example code for performance test\n    \n    func testPerformanceExample() {\n        // This is an example of a performance test case.\n        self.measure {\n            // Put the code you want to measure the time of here.\n        }\n    }\n    \n    \n    \n    \n    \n    \n    \n    func stringToBytes(_ theString: String) -> [UInt8] {\n        \n        let length = theString.lengthOfBytes(using: String.Encoding.utf8)\n        guard length % 2 == 0 else {\n            print(\"Error in \\(#function): String does not have an even number of characters and is thus not a valid string of pairs of characters where each pair represents a byte.\")\n            return [0]\n        }\n        \n        var theBytes = [UInt8]()\n        for index in stride(from: 0, to: length, by: 2) {\n            let aIndex = theString.characters.index(theString.startIndex, offsetBy: index)\n            let bIndex = theString.characters.index(theString.startIndex, offsetBy: index+2)\n            let range = aIndex..<bIndex\n            //            let range = Range(start: aIndex, end: bIndex)\n            let string = String(theString.substring(with: range))\n            let aByte = UInt8(string!, radix: 16)\n            theBytes.append(aByte!)\n        }\n        return theBytes\n    }\n    \n}\n"
  },
  {
    "path": "LibreMonitorTests/SimbleeCode/crc8.h",
    "content": "// LICENSES: [077915]\n// -----------------------------------\n// The contents of this file contains the aggregate of contributions\n//   covered under one or more licences. The full text of those licenses\n//   can be found in the \"LICENSES\" file at the top level of this project\n//   identified by the MD5 fingerprints listed above.\n//\n// Uwe Petersen: Modified version to test transmission part in iOS\n\n\n\n#import <Foundation/Foundation.h>\n\ntypedef uint8_t byte;\n\n\n//byte CRC8(void *data_in, byte number_of_bytes_to_read);\nbyte CRC8(void *data_in, uint16_t number_of_bytes_to_read); // fixed bug that made app crashed with data longer than 256 bytes\n"
  },
  {
    "path": "LibreMonitorTests/SimbleeCode/crc8.m",
    "content": "// LICENSES: [077915]\n// -----------------------------------\n// The contents of this file contains the aggregate of contributions\n//   covered under one or more licences. The full text of those licenses\n//   can be found in the \"LICENSES\" file at the top level of this project\n//   identified by the MD5 fingerprints listed above.\n//\n//\n// Uwe Petersen: Modified version to test transmission part in iOS\n\n\n#include \"crc8.h\"\n\n#define CRC8INIT  0x00\n#define CRC8POLY  0x18      // 0X18 = X^8+X^5+X^4+X^0\n\n//byte CRC8(void *bytes, byte number_of_bytes_to_read) {\nbyte CRC8(void *bytes, uint16_t number_of_bytes_to_read) {// fixed bug that made app crashed with data longer than 256 bytes\n    \n    byte *data_in = (byte*) bytes;\n    byte  crc;\n    uint16_t loop_count;\n    byte  bit_counter;\n    byte  data;\n    byte  feedback_bit;\n    \n    crc = CRC8INIT;\n    \n    for (loop_count = 0; loop_count != number_of_bytes_to_read; loop_count++)\n    {\n        data = data_in[loop_count];\n        \n        bit_counter = 8;\n        do {\n            feedback_bit = (crc ^ data) & 0x01;\n            \n            if ( feedback_bit == 0x01 ) {\n                crc = crc ^ CRC8POLY;\n            }\n            crc = (crc >> 1) & 0x7F;\n            if ( feedback_bit == 0x01 ) {\n                crc = crc | 0x80;\n            }\n            \n            data = data >> 1;\n            bit_counter--;\n            \n        } while (bit_counter > 0);\n    }\n    \n    return crc;\n}\n\n"
  },
  {
    "path": "LibreMonitorTests/SimbleeCode/libUBP.h",
    "content": "//\n// Uwe Petersen: Modified version to test transmission part in iOS\n\n#import <Foundation/Foundation.h>\n\ntypedef uint8_t byte;\n\n\n#ifndef libUBP_h\n#define libUBP_h\n#endif\n\n\ntypedef enum {\n    \n    UBP_TxFlagNone = 0 << 0,\n    UBP_TxFlagIsRPC = 1 << 0,\n    UBP_TxFlagRequiresACK = 1 << 1\n    \n} UBP_TxFlags;\n\n\n// Public\n\nvoid UBP_pump();\nbool UBP_queuePacketTransmission(unsigned short packetIdentifier, UBP_TxFlags txFlags, const char *packetBytes, unsigned short byteCount);\n\n//bool UBP_isBusy();\n\n// 2016-06-26: Needed for tests\nvoid getTxBuffer(char *txBuffer, int *txBufferLength);\nvoid SimbleeBLE_onConnect();\nvoid SimbleeBLE_onDisconnect();\n\n\n\n\n// Private\n\nvoid _UBP_pumpTxQueue();\n\n//void _UBP_ingestRxBytes(char *receivedBytes, int byteCount);\n\nint _UBP_makeEscapedCopy(const char *inputBuffer, unsigned short inputBufferLength, char *outputBuffer, unsigned short outputBufferLength);\n\nint _UBP_makeUnEscapedCopy(const char *inputBuffer, unsigned short inputBufferLength, char *outputBuffer);\n\nvoid _UBP_hostDisconnected();\n\n\n// To be implemented by end-user externally\n//extern void UBP_incomingChecksumFailed() __attribute__((weak));\n\n//extern void UBP_receivedPacket(unsigned short packetIdentifier, UBP_TxFlags txFlags, void *packetBuffer) __attribute__((weak));\n\n//extern void UBP_didAdvertise(bool start) __attribute__((weak));\n\n//extern void UBP_didConnect() __attribute__((weak));\n\n//extern void UBP_didDisconnect() __attribute__((weak));\n\n\n"
  },
  {
    "path": "LibreMonitorTests/SimbleeCode/libUBP.m",
    "content": "//\n// Uwe Petersen: Modified version to test transmission part in iOS\n\n#import \"libUBP.h\"\n#import \"crc8.h\"\n\n// Build-time configurations\n//#define BUFFER_LENGTH 64 // Uwe changed this on 2016-01-04\n//#define BUFFER_LENGTH 400 // Uwe changed this on 2016-07-24\n#define BUFFER_LENGTH 440 // Uwe changed this on 2016-12-25\n#define TX_CHUNK_SIZE 20\n#define PACKET_ID_SIZE 2\n\n// Serial Line IP (SLIP) escaping constants\n#define ESCAPE_BYTE 0xDB\n#define END_BYTE    0xC0\n#define ESCAPED_ESCAPE_BYTE 0xDD\n#define ESCAPED_END_BYTE    0xDC\nconst char escapeSequence_[1] = {ESCAPE_BYTE};\nconst char endSequence_[1] = {END_BYTE};\nconst char escapedEndSequence_[2] = {ESCAPE_BYTE, ESCAPED_END_BYTE};\nconst char escapedEscapeSequence_[2] = {ESCAPE_BYTE, ESCAPED_ESCAPE_BYTE};\n\n// Buffers\nchar ubpTxBuffer[BUFFER_LENGTH];\nint ubpTxBufferLength = 0;\nint ubpTxBufferSentByteCount = 0;\nchar ubpRxBuffer[BUFFER_LENGTH];\nint ubpRxBufferLength = 0;\nchar ubpUnescapedRxBufferBuffer[BUFFER_LENGTH];\nint ubpUnescapedRxBufferBufferLength = 0;\n\n// State Variables\nbool UBP_isTxPending = false;\nbool hostIsConnected = true;\n//bool hostIsConnected = false;\n\n// 2016-06-27: for testing purposes simulate simblee\nchar simbleeBuffer[BUFFER_LENGTH];\nint simbleeBufferLength = 0;\n\n/*\n// Functions\nbool UBP_isBusy() {\n    \n    return UBP_isTxPending;\n}\n */\nvoid UBP_pump() {\n    \n    _UBP_pumpTxQueue();\n}\n\n\nvoid _UBP_pumpTxQueue() {\n    \n    if (UBP_isTxPending) {\n        \n        char *nextByteToSend = ubpTxBuffer + ubpTxBufferSentByteCount;\n        \n        // Try sending the next chunk\n        if (ubpTxBufferSentByteCount < ubpTxBufferLength && hostIsConnected) {  // Haven't already sent all the bytes\n            \n            int retryRemainingCount = 1000;  // Limit the number of times we retry sending to avoid getting into an infinite loop\n            int remainingByteCount = ubpTxBufferLength - ubpTxBufferSentByteCount;\n            \n            if (remainingByteCount >= TX_CHUNK_SIZE) {  // Can fill the TX output buffer\n                \n                // Send is queued (the ble stack delays send to the start of the next tx window)\n                while (hostIsConnected && retryRemainingCount > 0) {\n                    retryRemainingCount--;\n                };\n                // 2016-06-27: This changed to the above to enable testing\n                // while ( SimbleeBLE.send(nextByteToSend, TX_CHUNK_SIZE) == false && hostIsConnected && retryRemainingCount > 0) {\n                //         retryRemainingCount--;\n                // };  // send() returns false if all tx buffers in use (can't enqueue, try again later)\n                \n                ubpTxBufferSentByteCount += TX_CHUNK_SIZE;\n                \n            } else {  // Only partial TX buffer remaining to send\n                \n                // Send is queued (the ble stack delays send to the start of the next tx window)\n                while ( hostIsConnected && retryRemainingCount > 0) {\n                    retryRemainingCount--;\n                };  // send() returns false if all tx buffers in use (can't enqueue, try again later)\n                // 2016-06-27: This changed to the above to enable testing\n                // while ( SimbleeBLE.send(nextByteToSend, remainingByteCount) == false && hostIsConnected && retryRemainingCount > 0) {\n                //     retryRemainingCount--;\n                // };  // send() returns false if all tx buffers in use (can't enqueue, try again later)\n                \n                ubpTxBufferSentByteCount += remainingByteCount;\n                \n                UBP_isTxPending = false;\n            }\n        }\n    }\n}\n/*\nvoid _UBP_ingestRxBytes(char *receivedBytes, int byteCount) {\n    \n    Serial.print(byteCount);\n    Serial.println(\" bytes receieved\");\n    \n    // NOTE: Assuming not called unless len > 0\n    \n    // Determine what to do with incoming fragment\n    if ( *receivedBytes == END_BYTE ) {  // Fragment has leading END byte, signals start of packet\n        \n        // Set fragment as the beginning of the reconstruction buffer\n        memcpy(ubpRxBuffer, receivedBytes, byteCount);\n        ubpRxBufferLength = byteCount;\n        \n    } else if (ubpRxBufferLength > 0) {  // Already have fragments in the reconstruction buffer\n        \n        // Append fragment to reconstruction buffer\n        memcpy(ubpRxBuffer + ubpRxBufferLength, receivedBytes, byteCount);\n        ubpRxBufferLength += byteCount;\n        \n    }\n    \n    \n    // Check RX buffer for trailing END byte\n    if ( *(ubpRxBuffer + ubpRxBufferLength - 1) == END_BYTE) {  // RX buffer ends with END byte, looks like packet is complete\n        \n        byte firstNonControlIndex = 1;\n        byte escapedDataLength = ubpRxBufferLength - 2;  // \"- 2\" for leading/trailing control chars\n        \n        // Un-escape the incoming payload\n        ubpUnescapedRxBufferBufferLength = _UBP_makeUnEscapedCopy(ubpRxBuffer + firstNonControlIndex, escapedDataLength, ubpUnescapedRxBufferBuffer);\n        byte payloadDataLength = ubpUnescapedRxBufferBufferLength - 1;  // -1 to account for checksum\n        \n        // Calculate checksum over payload, i.e. all bytes except for last checksum byte)\n        char calculatedChecksum = CRC8(ubpUnescapedRxBufferBuffer, payloadDataLength * sizeof(byte));\n        \n        // Extract embedded checksum value\n        char receivedChecksum = *(ubpUnescapedRxBufferBuffer + payloadDataLength);  // NOTE: Omitting '-1' because checksum byte comes just after payloadDataLength\n        \n        // Verify the checksum\n        if (calculatedChecksum == receivedChecksum) {\n            \n            unsigned short packetIdentifier = *(ubpUnescapedRxBufferBuffer);\n            UBP_TxFlags txFlags = (UBP_TxFlags) *(ubpUnescapedRxBufferBuffer + PACKET_ID_SIZE);\n            \n            if (UBP_receivedPacket) {\n                \n                void *packetBuffer = (ubpUnescapedRxBufferBuffer + PACKET_ID_SIZE + 1);  // skip <identifier length> + <tx flags length>\n                UBP_receivedPacket(packetIdentifier, txFlags, packetBuffer);\n            }\n            \n        } else {\n            \n            Serial.println(\"Incoming packet checksum invalid\");\n            \n            // Reset\n            ubpRxBufferLength = 0;\n            ubpUnescapedRxBufferBufferLength = 0;\n            \n            if (UBP_incomingChecksumFailed) {\n                \n                UBP_incomingChecksumFailed();\n            }\n        }\n        \n    }  // else haven't RX'd final fragment yet, keep waiting\n}\n*/\n\n// only needed to retreive the data for testing\nvoid getTxBuffer(char *txBuffer, int *txBufferLength) {\n    for (int i=0; i<ubpTxBufferLength; i++) {\n        txBuffer[i] = ubpTxBuffer[i];\n    }\n    *txBufferLength = ubpTxBufferLength;\n}\n\nbool UBP_queuePacketTransmission(unsigned short packetIdentifier, UBP_TxFlags txFlags, const char *packetBytes, unsigned short byteCount) {\n    \n    if (UBP_isTxPending) {  // Preexisting transmission still in progress\n        \n        // Serial.println(\"Could not queue packet because preexisting transmission is still in progress\");\n        return false;\n        \n    } else {  // Ready to queue a new transmission\n        \n        if (hostIsConnected == false) return ubpTxBuffer;\n        \n        ubpTxBufferLength = 0;\n        \n        // Start off with the END_BYTE as required for SLIP\n        ubpTxBuffer[0] = END_BYTE;\n        ubpTxBufferLength++;\n        \n        // Prepend the packet identifier\n        memcpy(ubpTxBuffer + ubpTxBufferLength, &packetIdentifier, sizeof(packetIdentifier));  // TODO: Escape the identifier\n        ubpTxBufferLength += sizeof(packetIdentifier);\n        \n        // Append the transmission flags\n        ubpTxBuffer[ubpTxBufferLength] = txFlags;\n        ubpTxBufferLength++;\n        \n        // Copy the escaped contents of packetBytes into the TX buffer following the packet identifier\n        int escapedByteCount = _UBP_makeEscapedCopy(packetBytes, byteCount, ubpTxBuffer + ubpTxBufferLength, BUFFER_LENGTH);\n        if (escapedByteCount != -1) {  // Escaping succeeded\n            \n            ubpTxBufferLength += escapedByteCount;\n            int payloadLength = ubpTxBufferLength - 1;  // Length so far minus leading END byte    //sizeof(packetIdentifier) + escapedByteCount;  // <identifier length> + <escaped content length>\n            \n            // Calculate and append checksum\n            byte checksumValue = CRC8(ubpTxBuffer + 1, payloadLength);  // Checksum over all payload bytes (minus the leading END byte, checksum, and trailing END byte)\n            *(ubpTxBuffer + ubpTxBufferLength) = checksumValue;\n            ubpTxBufferLength++;\n            \n            // Append trailing END byte\n            *(ubpTxBuffer + ubpTxBufferLength) = END_BYTE;\n            ubpTxBufferLength++;\n            \n            // Mark as ready to begin transmission\n            ubpTxBufferSentByteCount = 0;\n            UBP_isTxPending = true;\n            \n        } else {\n            \n            return false;  // Return false if we couldn't escape the content because it was going to overflow the output buffer\n        }\n    }\n    // 2016-06-27: this was missing in the original code\n    return true;\n}\n\nint _UBP_makeEscapedCopy(const char *inputBuffer, unsigned short inputBufferLength, char *outputBuffer, unsigned short outputBufferLength) {\n    \n    unsigned int bytesCopied = 0;\n    const char *inputBytes = inputBuffer;  // Cast here to avoid compiler warnings later\n    \n\n    // 2016-07-24: changed i from char to int to avoid buffer over flow that had happend for more numbers larger than 256\n    //for (char i = 0; i < inputBufferLength; i++) {  // For each byte to append\n    for (int i = 0; i < inputBufferLength; i++) {  // For each byte to append\n//        printf(\"i = %i\", (int) i);\n        \n        // Escape any control characters. Refer to Serial Line IP (SLIP) spec.\n        char aByte = *(inputBytes + i);\n        if (aByte ==  (char) ESCAPE_BYTE) {  // Escape an ESCAPE_BYTE\n//      if (aByte == ESCAPE_BYTE) {  // Escape an ESCAPE_BYTE\n            \n            if (bytesCopied + 1 >= outputBufferLength) return -1;  // Would¥ overflow destination buffer\n            else {\n                *(outputBuffer + bytesCopied++) = ESCAPE_BYTE;  // Write ESCAPE_BYTE to buffer and increment offset\n                *(outputBuffer + bytesCopied++) = ESCAPED_ESCAPE_BYTE;  // Write escaped ESCAPE_BYTE to buffer and increment offset\n            }\n            \n//        } else if (aByte == END_BYTE) {  // Escape an END_BYTE\n        } else if (aByte == (char) END_BYTE) {  // Escape an END_BYTE\n            \n            if (bytesCopied + 1 >= outputBufferLength) return -1;  // Would overflow destination buffer\n            else {\n                *(outputBuffer + bytesCopied++) = ESCAPE_BYTE;  // Write ESCAPE_BYTE to buffer and increment offset\n                *(outputBuffer + bytesCopied++) = ESCAPED_END_BYTE;  // Write escaped END_BYTE to buffer and increment offset\n            }\n            \n        } else {  // Not a control character\n            \n            if (bytesCopied >= outputBufferLength) return -1;  // Would overflow destination buffer\n            else *(outputBuffer + bytesCopied++) = aByte;  // Copy the unmolested byte to the buffer and increment offset\n        }\n    }\n    \n    return bytesCopied;\n}\n\n/*\n\nint _UBP_makeUnEscapedCopy(const char *inputBuffer, unsigned short inputBufferLength, char *outputBuffer) {\n    \n    bool done = false;\n    char * destinationBufferPtr = outputBuffer;\n    const char * sourceBufferPtr = inputBuffer;\n    \n    // UNESCAPE END Sequence_\n    while (!done && (sourceBufferPtr - inputBuffer) < inputBufferLength) {\n        \n        char * substringPtr = strstr(sourceBufferPtr, escapedEndSequence_);\n        if (substringPtr == NULL) done = true;\n        else {\n            \n            // Copy bytes between last-copied byte and next escape byte\n            char lengthToCopy = substringPtr - sourceBufferPtr;  // How many bytes between last byte copied and next escape byte\n            memcpy(destinationBufferPtr, sourceBufferPtr, lengthToCopy);\n            destinationBufferPtr += lengthToCopy;\n            sourceBufferPtr += lengthToCopy;\n            \n            // Replace escaped source sequence with unescaped version during copy, increment pointer\n            memcpy(destinationBufferPtr, endSequence_, sizeof(endSequence_));\n            destinationBufferPtr += sizeof(endSequence_);\n            \n            // Increment pointer past escaped end Sequence_\n            sourceBufferPtr += sizeof(escapedEndSequence_);\n        }\n    }\n    \n    // UNESCAPE ESCAPE SEQUENCE\n    done = false;\n    while (!done && (sourceBufferPtr - inputBuffer) < inputBufferLength) {\n        \n        char * substringPtr = strstr(sourceBufferPtr, escapedEscapeSequence_);\n        if (substringPtr == NULL) done = true;\n        else {\n            \n            // Copy bytes between last-copied byte and next escape byte\n            char lengthToCopy = substringPtr - sourceBufferPtr;  // How many bytes between last byte copied and next escape byte\n            memcpy(destinationBufferPtr, sourceBufferPtr, lengthToCopy);\n            destinationBufferPtr += lengthToCopy;\n            sourceBufferPtr += lengthToCopy;\n            \n            // Replace escaped source sequence with unescaped version during copy, increment pointer\n            memcpy(destinationBufferPtr, escapeSequence_, sizeof(escapeSequence_));\n            destinationBufferPtr += sizeof(escapeSequence_);\n            \n            // Increment pointer past escaped end Sequence_\n            sourceBufferPtr += sizeof(escapedEscapeSequence_);\n        }\n    }\n    \n    // COPY ANY TRAILING BYTES\n    char lengthToCopy = (inputBuffer + inputBufferLength) - sourceBufferPtr;  // How many bytes remain to be copied\n    memcpy(destinationBufferPtr, sourceBufferPtr, lengthToCopy);\n    destinationBufferPtr += lengthToCopy;\n    sourceBufferPtr += lengthToCopy;\n    \n    return (destinationBufferPtr - outputBuffer);  // Return the total number of bytes copied to the destination buffer\n}\n\n */\n\nvoid _UBP_hostDisconnected() {\n    \n    hostIsConnected = false;\n    \n    // Reset TX subsystem\n    UBP_isTxPending = false;\n    \n    // Reset RX subsystem\n    ubpRxBufferLength = 0;\n    \n    // Invoke user callback\n    // 2016-06-28: commentet out for testing\n//    if (UBP_didDisconnect) UBP_didDisconnect();\n}\n\n\n// RFduino EVENTS\n// ----------------------------------------------------\n//void SimbleeBLE_onAdvertisement(bool start) {\n//    \n//    if (UBP_didAdvertise) UBP_didAdvertise(start);\n//}\n//\nvoid SimbleeBLE_onConnect() {\n    \n    hostIsConnected = true;\n    \n    // 2016-06-29: uncommented and added for testing purposes\n    // if (UBP_didConnect) UBP_didConnect();\n    UBP_isTxPending = false;\n}\n\n//void SimbleeBLE_onReceive(char *data, int len) {\n//    \n//    _UBP_ingestRxBytes(data, len);\n//}\n\nvoid SimbleeBLE_onDisconnect() {\n    \n    _UBP_hostDisconnected();\n}\n\n\n"
  },
  {
    "path": "LibreMonitorTests/TransmissionTests.swift",
    "content": "//\n//  TransmissionTests.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 03.02.17.\n//  Copyright © 2017 Uwe Petersen. All rights reserved.\n//\n\nimport Foundation\n\nimport XCTest\n//@testable import Pods_LibreMonitor\n@testable import LibreMonitor\n\nclass TransmissionTests: XCTestCase {\n\n    \n    var testData = [[UInt8]]()\n    \n    override func setUp() {\n        super.setUp()\n        // Put setup code here. This method is called before the invocation of each test method in the class.\n        \n        \n        guard let dataAsString = BluetoothTestData.data().last else {\n            return\n        }\n        \n        let aString = dataAsString.replacingOccurrences(of: \" \", with: \"\")\n        let bytes = stringToBytes(aString)\n\n    }\n    \n    override func tearDown() {\n        // Put teardown code here. This method is called after the invocation of each test method in the class.\n        super.tearDown()\n    }\n    \n    \n    \n    func testTransmission() {\n        \n    }\n    \n    \n    \n    func stringToBytes(_ theString: String) -> [UInt8] {\n        \n        let length = theString.lengthOfBytes(using: String.Encoding.utf8)\n        guard length % 2 == 0 else {\n            print(\"Error in \\(#function): String does not have an even number of characters and is thus not a valid string of pairs of characters where each pair represents a byte.\")\n            return [0]\n        }\n        \n        var theBytes = [UInt8]()\n        for index in stride(from: 0, to: length, by: 2) {\n            let aIndex = theString.characters.index(theString.startIndex, offsetBy: index)\n            let bIndex = theString.characters.index(theString.startIndex, offsetBy: index+2)\n            let range = aIndex..<bIndex\n            //            let range = Range(start: aIndex, end: bIndex)\n            let string = String(theString.substring(with: range))\n            let aByte = UInt8(string!, radix: 16)\n            theBytes.append(aByte!)\n        }\n        return theBytes\n    }\n    \n\n}\n"
  },
  {
    "path": "LibreMonitorUITests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "LibreMonitorUITests/LibreMonitorUITests.swift",
    "content": "//\n//  LibreMonitorUITests.swift\n//  LibreMonitorUITests\n//\n//  Created by Uwe Petersen on 14.10.16.\n//  Copyright © 2016 Uwe Petersen. All rights reserved.\n//\n\nimport XCTest\n\nclass LibreMonitorUITests: XCTestCase {\n        \n    override func setUp() {\n        super.setUp()\n        \n        // Put setup code here. This method is called before the invocation of each test method in the class.\n        \n        // In UI tests it is usually best to stop immediately when a failure occurs.\n        continueAfterFailure = false\n        // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.\n        XCUIApplication().launch()\n\n        // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.\n    }\n    \n    override func tearDown() {\n        // Put teardown code here. This method is called after the invocation of each test method in the class.\n        super.tearDown()\n    }\n    \n    func testExample() {\n        // Use recording to get started writing UI tests.\n        // Use XCTAssert and related functions to verify your tests produce the correct results.\n    }\n    \n}\n"
  },
  {
    "path": "Podfile",
    "content": "# Uncomment this line to define a global platform for your project\n# platform :ios, '10.0'\n# Uncomment this line if you're using Swift\nuse_frameworks!\n\ntarget 'LibreMonitor' do\n#pod 'Charts' '~> 2.2.5'\n#pod 'Charts', :branch => 'Swift-3.0'\n#pod 'Charts', :git => 'https://github.com/danielgindi/Charts.git', :branch => 'Swift-3.0'\n#pod 'Charts', :git => 'https://github.com/danielgindi/Charts.git', :branch => 'Chart2.2.5-Swift3.0'\n#pod 'Charts', :git => 'https://github.com/danielgindi/Charts.git', :branch => 'master'\npod 'Charts'\n\nend\n\ntarget 'LibreMonitorTests' do\n\nend\n\ntarget 'LibreMonitorUITests' do\n\nend\n\n"
  },
  {
    "path": "README.md",
    "content": "# LibreMonitor - Monitor your Freestyle Libre\n\nLibreMonitor is a little DIY device that uses near field communication to read data from a Freestyle Libre sensor and transmit it via bluetooth low energy to an iPhone application. LibreMonitor scans the sensor every two minutes. It transfers all the 32 history values for the last eight hours and the 16 trend values for the current time and the last 15 minutes and displays them in a chart and in a table. \n\nBe aware that only the so called raw data is used and you have to choose slope and intercept yourself to have the application calculate useful glucose values. Values that mostly work fine for my sensors are 0.13 for slope and -20 for offset. Any other internal information such as from the temperature sensors is not yet fully understood and thus neglected.\n\nThis code is published so that others can contribute and help to improve it or use it to improve their own devices.\n\nLibreMonitor has no affiliation of any kind with Abbott. This is a DIY project for research purposes. The code provided here might provide wrong results. You will have to build your own device and are responsible for the results. Use at your own risk.  \n\n\n## What you need to build a LibreMonitor\n\n### 1. Buy some hardware\n\nParts needed for a LibreMonitor are\n\n* [BM019 NFC module](http://www.solutions-cubed.com/bm019/) capable of ISO/IEC 15693 commands. Possible sources are [Solutions Cubed LLC](http://www.solutions-cubed.com/bm019/), [Warbutech](http://www.warburtech.co.uk/products/modules/solutions.cubed.bm019.serial.to.nfc.converter/) or \n[Robotshop](http://www.robotshop.com/eu/en/serial-to-nfc-converter-module.html).\n* [Simblee](https://www.simblee.com) or [RFDuino](http://www.rfduino.com) and a corresponding USB Programming Shield. I recommend to get a startet kit. See their Webites for Distributors.\n* Lipo, e.g. [this one](http://www.exp-tech.de/polymer-lithium-ion-battery-110mah-5695) (100 mAh is fine for a full day).\n* Lipo charger (optional), e.g. [this](https://www.adafruit.com/product/1304) or [this](https://www.adafruit.com/products/1904) from adafruit. \n* Switch (optional but helpful if you mount a lipo charger).\n\n### 2. Do the wiring\n\nWire the parts as shown in the following diagram (courtesy to [libxMike](https://github.com/libxmike?tab=following)). \n\n\n<img src=\"https://cloud.githubusercontent.com/assets/10375483/19703622/c866a0d0-9b04-11e6-9471-8056324664b5.jpg\" width=\"500\">\n\n\nIt is suggested to mount and test everything on a breadboard before soldering the final device. Below are pictures of another LibreMonitor device without a lipo charger. As you can see, one can save a lot of space by cutting of the black part of the stacks for Pins GPIO2 to GPIO6, push them through the pin holes of the BM019 and then solder the parts together. Therefore you also have to cut off the stack pins on the other side, too. It is suggested to bend the black part of the other stacks by 90 degree. Thus, you can still plug in the USB Programming Shield (RFD22121) but save some space. \n\n\n<img src=\"https://cloud.githubusercontent.com/assets/10375483/19740419/e9ae9602-9bbe-11e6-98ad-f616d21ae129.jpeg\" width=\"300\">\n<img src=\"https://cloud.githubusercontent.com/assets/10375483/19740420/e9ce57d0-9bbe-11e6-8a48-0faff5641c39.jpeg\" width=\"300\">\n\n\n\nAnother device, this time with a lipo charger:\n\n\n<img src=\"https://cloud.githubusercontent.com/assets/10375483/19740504/2d73afbc-9bbf-11e6-8e18-ec32464d08ed.jpeg\" width=\"300\">\n<img src=\"https://cloud.githubusercontent.com/assets/10375483/19741238/30e8c438-9bc0-11e6-9f30-f5035daf4913.jpeg\" width=\"300\">\n\n\n### 3. Program your Simblee\n\nSimblee is IoT for connecting Everyone and Everything (IoT4EE).\nIt incorporates Mobile, Bluetooth® Smart, Mesh, Cloud and other forms of wireless connectivity.\n\nThe software to program the Simblee is standard Arduino code. It consists of LibreMonitor.ino and the library contained in LibreMonitorArduinoLibrary.zip. Refer to the [Simblee quick start guide](https://www.simblee.com/Simblee_Quickstart_Guide_v1.0.pdf) on the [Simblee website](https://www.simblee.com) for instructions on how to program the Simblee. If you wired your LibreMonitor as described above, don't forget to reconfigure the SPI pins of the Simblee in the variant.h file (see the wiring information in LibreMonitor.ino for more information on this)\n\n\n### 4. Build and run the LibreMonior iOS application\n\nThe iOS application requires Xcode 8, swift 3.0 and iOS 10. Download the Xcode project. Run [cocopoads](https://cocoapods.org) to install the [charts](https://github.com/danielgindi/Charts) library, needed for the blood sugar graph. Build the application and run it on the phone and start it. If you want to receive notifications for high or low glucose values and have a badge icon displayed, allow for the corresponding settings, when asked. Once the app is running set values for slope and offset (e.g. 0.13 and -20, press the corresponding row to get into the settings view). Connect to your Simblee by pressing \"connect\". Once the Simblee ist detected and connected the \"Simblee status\" should change to \"Notifying\" and be green. Place the LibreMonitor device above your Freestyle Libre and after no more than two minutes the data should be displayed or refreshed. See the screenshots below. \n\n\n<img src=\"https://cloud.githubusercontent.com/assets/10375483/19742181/19d18f24-9bc4-11e6-999d-449edba439b9.PNG\" width=\"300\">\n<img src=\"https://cloud.githubusercontent.com/assets/10375483/19742182/19f6b10a-9bc4-11e6-9c88-f850625fdbd4.PNG\" width=\"300\">\n\n\n<img src=\"https://cloud.githubusercontent.com/assets/10375483/19742183/19f9efbe-9bc4-11e6-81a4-9bed01c2f865.PNG\" width=\"300\">\n<img src=\"https://cloud.githubusercontent.com/assets/10375483/19742184/19fcf272-9bc4-11e6-8cd8-d02139f3616b.PNG\" width=\"300\">\n\n\n#### Some explanations \n\nThe \"Glucose\" row shows the current glucose value and two \"delta values\" that show how the glucose is about to develop (linear extrapolation for the next fifteen minutes). The first delta value is the difference of the current and the oldest minute-value, the delta value in braces is the difference of the current glucose value and the glucose value from 8 minutes ago, multiplied by two. The two \"prognosis\" glucose values are calculated by adding the delta values to the current glucose value. Glucose is calculated from the raw value as follows:\n\n\tglucose = raw * slope + offset\n\nThe \"Last 15 minutes\" and \"Last eight hours\" sections display the glucose values, corresponding date, the raw value, the 6 bytes of data as read from the Freestyle Libre sensor and some other test data. \n\n\n### General Troubleshooting\n\n* If a crc is wrong, most likely the device is not located near enough to the Freestyle Libre sensor.\n* If the data is not refreshed, disconnect and reconnect.\n* If the device cannot be connected, check whether bluetooth is switched on.\n\n\n## Suggested readings\n\n[Blog by Pierre Vandevenne](http://type1tennis.blogspot.de) with information on the internals of the Freestyle Libre and suggestions on how to choose slope and offset. Without his work all this would probably not have been possible.\n\n\n## Similar projects\n\n* [LimiTTer](https://github.com/JoernL/LimiTTer). Similar device, but data is sent to [xDrip+](https://github.com/jamorham/xDrip-plus), an Android app.\n* [Freestyle Libre Alarm](https://github.com/pimpimmi/LibreAlarm/wiki). Uses as Sony smart watch to read data from the Freestyle Libre and send it to an Android phone.\n* [Bluereader](https://www.startnext.com/bluereader) project by [Sandra Kessler](http://unendlichkeit.net/wordpress/) who got funding to build a small neat device. I intend to adapt this project to work with bluereader once the first devices are available.\n* [Android reader application](https://github.com/vicktor/FreeStyleLibre-NFC-Reader) by Viktor Bautista that was helpful at the beginning of this work.\n\n## Personal note\n\nAs of September 2018: I used different versions of the LibreMonitor and similar hardware (Marek’s Transmitter) based on Simblee or RFDuino since early 2016 up to March 2018 and liked it very much. When I started the project nothing similar was available. Meanwhile many other projects have evolved and also commercial hardware is available. Since March 2018 I have been using the [MiaoMiao](https://www.miaomiao.cool) hardware and I have to say that in my opinion it is much better than anything I had seen before. Thus I will no longer support the LibreMonitor hardware but only MiaoMiao hardware with the LibreMonitor iPhone application. So if you want to use the LibreMonitor with MiaoMiao, use the swift4 branch. If you choose to use the old LibreMonitor hardware, choose the old master branch.\n"
  },
  {
    "path": "libUBP RFduino.cpp",
    "content": "//\n// libUBP.cpp \n// C++ code\n// ----------------------------------\n// Developed with embedXcode+ \n// http://embedXcode.weebly.com\n//\n// Project \t\tBM019 Inventory\n//\n// Created by \tUwe Petersen, 02.01.16 14:13\n// \t\t\t\tUwe Petersen\n//\n// Copyright \t(c) Uwe Petersen, 2016\n// Licence\t\t<#license#>\n//\n// See \t\t\tlibUBP.h and ReadMe.txt for references\n//\n\n\n// Core library for code-sense - IDE-based\n#if defined(WIRING) // Wiring specific\n#   include \"Wiring.h\"\n#elif defined(MAPLE_IDE) // Maple specific\n#   include \"WProgram.h\"\n#elif defined(ROBOTIS) // Robotis specific\n#   include \"libpandora_types.h\"\n#   include \"pandora.h\"\n#elif defined(MPIDE) // chipKIT specific\n#   include \"WProgram.h\"\n#elif defined(DIGISPARK) // Digispark specific\n#   include \"Arduino.h\"\n#elif defined(ENERGIA) // LaunchPad specific\n#   include \"Energia.h\"\n#elif defined(LITTLEROBOTFRIENDS) // LittleRobotFriends specific\n#   include \"LRF.h\"\n#elif defined(MICRODUINO) // Microduino specific\n#   include \"Arduino.h\"\n#elif defined(TEENSYDUINO) // Teensy specific\n#   include \"Arduino.h\"\n#elif defined(REDBEARLAB) // RedBearLab specific\n#   include \"Arduino.h\"\n#elif defined(RFDUINO) // RFduino specific\n#   include \"Arduino.h\"\n#elif defined(SPARK) // Spark specific\n#   include \"application.h\"\n#elif defined(ARDUINO) // Arduino 1.0 and 1.5 specific\n#   include \"Arduino.h\"\n#else // error\n#   error Platform not defined\n#endif // end IDE\n\n// Code\n//#define SIMBLEE\n\n\n#include \"libUBP.h\"\n#include <Arduino.h>\n#include \"crc8.h\"\n\n// Choose Simblee or RFduino\n#ifdef SIMBLEE\n#include <SimbleeBLE.h>\n#else\n#include <RFduinoBLE.h>\n#endif\n\n// Build-time configurations\n//#define BUFFER_LENGTH 64\n//#define BUFFER_LENGTH 64 // Uwi changed this on 2016-01-04\n//#define BUFFER_LENGTH 400 // Uwi changed this on 2016-07-24\n#define BUFFER_LENGTH 430 // Uwi changed this on 2016-08-07\n#define TX_CHUNK_SIZE 20\n#define PACKET_ID_SIZE 2\n\n// Serial Line IP (SLIP) escaping constants\n#define ESCAPE_BYTE 0xDB\n#define END_BYTE    0xC0\n#define ESCAPED_ESCAPE_BYTE 0xDD\n#define ESCAPED_END_BYTE    0xDC\nconst char escapeSequence[1] = {ESCAPE_BYTE};\nconst char endSequence[1] = {END_BYTE};\nconst char escapedEndSequence[2] = {ESCAPE_BYTE, ESCAPED_END_BYTE};\nconst char escapedEscapeSequence[2] = {ESCAPE_BYTE, ESCAPED_ESCAPE_BYTE};\n\n// Buffers\nchar ubpTxBuffer[BUFFER_LENGTH];\nint ubpTxBufferLength = 0;\nint ubpTxBufferSentByteCount = 0;\nchar ubpRxBuffer[BUFFER_LENGTH];\nint ubpRxBufferLength = 0;\nchar ubpUnescapedRxBufferBuffer[BUFFER_LENGTH];\nint ubpUnescapedRxBufferBufferLength = 0;\n\n// State Variables\nbool UBP_isTxPending = false;\nbool hostIsConnected = false;\n\n// Functions\nbool UBP_isBusy() {\n    \n    return UBP_isTxPending;\n}\n\nvoid UBP_pump() {\n    \n    _UBP_pumpTxQueue();\n}\n\nvoid _UBP_pumpTxQueue() {\n    \n    if (UBP_isTxPending) {\n        \n        char *nextByteToSend = ubpTxBuffer + ubpTxBufferSentByteCount;\n        \n        // Try sending the next chunk\n        if (ubpTxBufferSentByteCount < ubpTxBufferLength && hostIsConnected) {  // Haven't already sent all the bytes\n            \n            int retryRemainingCount = 1000;  // Limit the number of times we retry sending to avoid getting into an infinite loop\n            int remainingByteCount = ubpTxBufferLength - ubpTxBufferSentByteCount;\n            \n            if (remainingByteCount >= TX_CHUNK_SIZE) {  // Can fill the TX output buffer\n                \n#ifdef SIMBLEE\n                // Send is queued (the ble stack delays send to the start of the next tx window)\n                while ( SimbleeBLE.send(nextByteToSend, TX_CHUNK_SIZE) == false && hostIsConnected && retryRemainingCount > 0) {\n#else\n                while ( RFduinoBLE.send(nextByteToSend, TX_CHUNK_SIZE) == false && hostIsConnected && retryRemainingCount > 0) {\n#endif\n                    retryRemainingCount--;\n                };  // send() returns false if all tx buffers in use (can't enqueue, try again later)\n                \n//                delay(20); // 2016-07-12: try to get fewer transfer errors using a small delay\n#ifdef DEBUG\n                Serial.printf(\"Sending the bytes\\n\");\n#endif\n                ubpTxBufferSentByteCount += TX_CHUNK_SIZE;\n                \n            } else {  // Only partial TX buffer remaining to send\n                \n                // Send is queued (the ble stack delays send to the start of the next tx window)\n#ifdef SIMBLEE\n                while ( SimbleeBLE.send(nextByteToSend, remainingByteCount) == false && hostIsConnected && retryRemainingCount > 0) {#\n#else\n                while ( RFduinoBLE.send(nextByteToSend, remainingByteCount) == false && hostIsConnected && retryRemainingCount > 0) {\n#endif\n                    retryRemainingCount--;\n                };  // send() returns false if all tx buffers in use (can't enqueue, try again later)\n                \n                ubpTxBufferSentByteCount += remainingByteCount;\n\n//                delay(20); // 2016-07-12: try to get fewer transfer errors using a small delay\n#ifdef DEBUG\n                Serial.printf(\"Sending the remaining bytes\\n\");\n#endif\n                UBP_isTxPending = false;\n            }\n        }\n    }\n}\n\nvoid _UBP_ingestRxBytes(char *receivedBytes, int byteCount) {\n    \n    Serial.print(byteCount);\n    Serial.println(\" bytes receieved\");\n    \n    // NOTE: Assuming not called unless len > 0\n    \n    // Determine what to do with incoming fragment\n    if ( *receivedBytes == END_BYTE ) {  // Fragment has leading END byte, signals start of packet\n        \n        // Set fragment as the beginning of the reconstruction buffer\n        memcpy(ubpRxBuffer, receivedBytes, byteCount);\n        ubpRxBufferLength = byteCount;\n        \n    } else if (ubpRxBufferLength > 0) {  // Already have fragments in the reconstruction buffer\n        \n        // Append fragment to reconstruction buffer\n        memcpy(ubpRxBuffer + ubpRxBufferLength, receivedBytes, byteCount);\n        ubpRxBufferLength += byteCount;\n        \n    }\n    \n    \n    // Check RX buffer for trailing END byte\n    if ( *(ubpRxBuffer + ubpRxBufferLength - 1) == END_BYTE) {  // RX buffer ends with END byte, looks like packet is complete\n        \n        byte firstNonControlIndex = 1;\n        byte escapedDataLength = ubpRxBufferLength - 2;  // \"- 2\" for leading/trailing control chars\n        \n        // Un-escape the incoming payload\n        ubpUnescapedRxBufferBufferLength = _UBP_makeUnEscapedCopy(ubpRxBuffer + firstNonControlIndex, escapedDataLength, ubpUnescapedRxBufferBuffer);\n        byte payloadDataLength = ubpUnescapedRxBufferBufferLength - 1;  // -1 to account for checksum\n        \n        // Calculate checksum over payload, i.e. all bytes except for last checksum byte)\n        char calculatedChecksum = CRC8(ubpUnescapedRxBufferBuffer, payloadDataLength * sizeof(byte));\n        \n        // Extract embedded checksum value\n        char receivedChecksum = *(ubpUnescapedRxBufferBuffer + payloadDataLength);  // NOTE: Omitting '-1' because checksum byte comes just after payloadDataLength\n        \n        // Verify the checksum\n        if (calculatedChecksum == receivedChecksum) {\n            \n            unsigned short packetIdentifier = *(ubpUnescapedRxBufferBuffer);\n            UBP_TxFlags txFlags = (UBP_TxFlags) *(ubpUnescapedRxBufferBuffer + PACKET_ID_SIZE);\n            \n            if (UBP_receivedPacket) {\n                \n                void *packetBuffer = (ubpUnescapedRxBufferBuffer + PACKET_ID_SIZE + 1);  // skip <identifier length> + <tx flags length>\n                UBP_receivedPacket(packetIdentifier, txFlags, packetBuffer);\n            }\n            \n        } else {\n            \n            Serial.println(\"Incoming packet checksum invalid\");\n            \n            // Reset\n            ubpRxBufferLength = 0;\n            ubpUnescapedRxBufferBufferLength = 0;\n            \n            if (UBP_incomingChecksumFailed) {\n                \n                UBP_incomingChecksumFailed();\n            }\n        }\n        \n    }  // else haven't RX'd final fragment yet, keep waiting\n}\n\nbool UBP_queuePacketTransmission(unsigned short packetIdentifier, UBP_TxFlags txFlags, const char *packetBytes, unsigned short byteCount) {\n    \n    if (UBP_isTxPending) {  // Preexisting transmission still in progress\n        \n#ifdef DEBUG\n        Serial.println(\"Could not queue packet because preexisting transmission is still in progress\");\n#endif\n        return false;\n        \n    } else {  // Ready to queue a new transmission\n        \n        if (hostIsConnected == false) {\n#ifdef DEBUG\n            Serial.println(\"Host not connected\");\n#endif\n            return false;\n        }\n        \n#ifdef DEBUG\n        Serial.println(\"ready to queue a new transmission\");\n#endif\n        ubpTxBufferLength = 0;\n        \n        // Start off with the END_BYTE as required for SLIP\n        ubpTxBuffer[0] = END_BYTE;\n        ubpTxBufferLength++;\n        \n        // Prepend the packet identifier\n        memcpy(ubpTxBuffer + ubpTxBufferLength, &packetIdentifier, sizeof(packetIdentifier));  // TODO: Escape the identifier\n        ubpTxBufferLength += sizeof(packetIdentifier);\n        \n        // Append the transmission flags\n        ubpTxBuffer[ubpTxBufferLength] = txFlags;\n        ubpTxBufferLength++;\n#ifdef DEBUG\n        Serial.println(\"appended the transmission flags\");\n#endif\n        \n        // Copy the escaped contents of packetBytes into the TX buffer following the packet identifier\n        int escapedByteCount = _UBP_makeEscapedCopy(packetBytes, byteCount, ubpTxBuffer + ubpTxBufferLength, BUFFER_LENGTH);\n#ifdef DEBUG\n        Serial.println(\"made escaped copy\");\n#endif\n        \n        if (escapedByteCount != -1) {  // Escaping succeeded\n            \n            ubpTxBufferLength += escapedByteCount;\n            int payloadLength = ubpTxBufferLength - 1;  // Length so far minus leading END byte    //sizeof(packetIdentifier) + escapedByteCount;  // <identifier length> + <escaped content length>\n            \n            // Calculate and append checksum\n            byte checksumValue = CRC8(ubpTxBuffer + 1, payloadLength);  // Checksum over all payload bytes (minus the leading END byte, checksum, and trailing END byte)\n            *(ubpTxBuffer + ubpTxBufferLength) = checksumValue;\n            ubpTxBufferLength++;\n            \n            // Append trailing END byte\n            *(ubpTxBuffer + ubpTxBufferLength) = END_BYTE;\n            ubpTxBufferLength++;\n            \n            // Mark as ready to begin transmission\n            ubpTxBufferSentByteCount = 0;\n            UBP_isTxPending = true;\n            \n        } else {\n            \n#ifdef DEBUG\n            Serial.println(\"Couldn't escape the content because it was going to overflow the output buffer\");\n#endif\n            return false;  // Return false if we couldn't escape the content because it was going to overflow the output buffer\n        }\n    }\n}\n\nint _UBP_makeEscapedCopy(const char *inputBuffer, unsigned short inputBufferLength, char *outputBuffer, unsigned short outputBufferLength) {\n    \n    unsigned int bytesCopied = 0;\n    const char *inputBytes = inputBuffer;  // Cast here to avoid compiler warnings later\n    \n    // 2016-07-24: changed i from char to int to avoid buffer over flow that had happend for more numbers larger than 256\n    //for (char i = 0; i < inputBufferLength; i++) {  // For each byte to append\n    for (int i = 0; i < inputBufferLength; i++) {  // For each byte to append\n        \n#ifdef DEBUG\n        Serial.printf(\"Input Buffer length is %d and i = %d\\n\", inputBufferLength, i);\n#endif\n        // Escape any control characters. Refer to Serial Line IP (SLIP) spec.\n        char aByte = *(inputBytes + i);\n        if (aByte == ESCAPE_BYTE) {  // Escape an ESCAPE_BYTE\n            \n#ifdef DEBUG\n            Serial.printf(\"%d:%x ESC\\n\", bytesCopied, aByte);\n#endif\n            if (bytesCopied + 1 >= outputBufferLength) return -1;  // Would overflow destination buffer\n            else {\n                *(outputBuffer + bytesCopied++) = ESCAPE_BYTE;  // Write ESCAPE_BYTE to buffer and increment offset\n                *(outputBuffer + bytesCopied++) = ESCAPED_ESCAPE_BYTE;  // Write escaped ESCAPE_BYTE to buffer and increment offset\n            }\n            \n        } else if (aByte == END_BYTE) {  // Escape an END_BYTE\n            \n#ifdef DEBUG\n            Serial.printf(\"%d:%x END\\n\", bytesCopied, aByte);\n#endif\n            if (bytesCopied + 1 >= outputBufferLength) return -1;  // Would overflow destination buffer\n            else {\n                *(outputBuffer + bytesCopied++) = ESCAPE_BYTE;  // Write ESCAPE_BYTE to buffer and increment offset\n                *(outputBuffer + bytesCopied++) = ESCAPED_END_BYTE;  // Write escaped END_BYTE to buffer and increment offset\n            }\n            \n        } else {  // Not a control character\n            \n#ifdef DEBUG\n            Serial.printf(\"%d:%x\\n\", bytesCopied, aByte);\n#endif\n            if (bytesCopied >= outputBufferLength) return -1;  // Would overflow destination buffer\n            else *(outputBuffer + bytesCopied++) = aByte;  // Copy the unmolested byte to the buffer and increment offset\n        }\n    }\n    \n    return bytesCopied;\n}\n\nint _UBP_makeUnEscapedCopy(const char *inputBuffer, unsigned short inputBufferLength, char *outputBuffer) {\n    \n    bool done = false;\n    char * destinationBufferPtr = outputBuffer;\n    const char * sourceBufferPtr = inputBuffer;\n    \n    // UNESCAPE END SEQUENCE\n    while (!done && (sourceBufferPtr - inputBuffer) < inputBufferLength) {\n        \n        char * substringPtr = strstr(sourceBufferPtr, escapedEndSequence);\n        if (substringPtr == NULL) done = true;\n        else {\n            \n            // Copy bytes between last-copied byte and next escape byte\n            char lengthToCopy = substringPtr - sourceBufferPtr;  // How many bytes between last byte copied and next escape byte\n            memcpy(destinationBufferPtr, sourceBufferPtr, lengthToCopy);\n            destinationBufferPtr += lengthToCopy;\n            sourceBufferPtr += lengthToCopy;\n            \n            // Replace escaped source sequence with unescaped version during copy, increment pointer\n            memcpy(destinationBufferPtr, endSequence, sizeof(endSequence));\n            destinationBufferPtr += sizeof(endSequence);\n            \n            // Increment pointer past escaped end sequence\n            sourceBufferPtr += sizeof(escapedEndSequence);\n        }\n    }\n    \n    // UNESCAPE ESCAPE SEQUENCE\n    done = false;\n    while (!done && (sourceBufferPtr - inputBuffer) < inputBufferLength) {\n        \n        char * substringPtr = strstr(sourceBufferPtr, escapedEscapeSequence);\n        if (substringPtr == NULL) done = true;\n        else {\n            \n            // Copy bytes between last-copied byte and next escape byte\n            char lengthToCopy = substringPtr - sourceBufferPtr;  // How many bytes between last byte copied and next escape byte\n            memcpy(destinationBufferPtr, sourceBufferPtr, lengthToCopy);\n            destinationBufferPtr += lengthToCopy;\n            sourceBufferPtr += lengthToCopy;\n            \n            // Replace escaped source sequence with unescaped version during copy, increment pointer\n            memcpy(destinationBufferPtr, escapeSequence, sizeof(escapeSequence));\n            destinationBufferPtr += sizeof(escapeSequence);\n            \n            // Increment pointer past escaped end sequence\n            sourceBufferPtr += sizeof(escapedEscapeSequence);\n        }\n    }\n    \n    // COPY ANY TRAILING BYTES\n    char lengthToCopy = (inputBuffer + inputBufferLength) - sourceBufferPtr;  // How many bytes remain to be copied\n    memcpy(destinationBufferPtr, sourceBufferPtr, lengthToCopy);\n    destinationBufferPtr += lengthToCopy;\n    sourceBufferPtr += lengthToCopy;\n    \n    return (destinationBufferPtr - outputBuffer);  // Return the total number of bytes copied to the destination buffer\n}\n\nvoid _UBP_hostDisconnected() {\n    \n    hostIsConnected = false;\n    \n    // Reset TX subsystem\n    UBP_isTxPending = false;\n    \n    // Reset RX subsystem\n    ubpRxBufferLength = 0;\n    \n    // Invoke user callback\n    if (UBP_didDisconnect) UBP_didDisconnect();\n}\n\n\n// Simblee/RFduino EVENTS\n// ----------------------------------------------------\n#ifdef SIMBLEE\nvoid SimbleeBLE_onAdvertisement(bool start) {\n    if (UBP_didAdvertise) UBP_didAdvertise(start);\n}\nvoid SimbleeBLE_onConnect() {\n    hostIsConnected = true;\n    if (UBP_didConnect) UBP_didConnect();\n}\n        \nvoid SimbleeBLE_onReceive(char *data, int len) {\n    _UBP_ingestRxBytes(data, len);\n}\n        \nvoid SimbleeBLE_onDisconnect() {\n    _UBP_hostDisconnected();\n}\n#else\nvoid RFduinoBLE_onAdvertisement(bool start) {\n    if (UBP_didAdvertise) UBP_didAdvertise(start);\n}\n\nvoid RFduinoBLE_onConnect() {\n    hostIsConnected = true;\n    if (UBP_didConnect) UBP_didConnect();\n}\n\nvoid RFduinoBLE_onReceive(char *data, int len) {\n    _UBP_ingestRxBytes(data, len);\n}\n\nvoid RFduinoBLE_onDisconnect() {\n    _UBP_hostDisconnected();\n}\n#endif\n"
  }
]