Full Code of UPetersen/LibreMonitor for AI

master 275b833a216b cached
73 files
460.9 KB
128.6k tokens
25 symbols
1 requests
Download .txt
Showing preview only (487K chars total). Download the full file or copy to clipboard to get everything.
Repository: UPetersen/LibreMonitor
Branch: master
Commit: 275b833a216b
Files: 73
Total size: 460.9 KB

Directory structure:
gitextract_hx6qj96v/

├── LICENSE.md
├── LibreMonitor/
│   ├── AppDelegate.swift
│   ├── Assets.xcassets/
│   │   └── AppIcon.appiconset/
│   │       └── Contents.json
│   ├── Base.lproj/
│   │   └── LaunchScreen.storyboard
│   ├── BloodGlucose+CoreDataClass.swift
│   ├── BloodGlucose+CoreDataProperties.swift
│   ├── Bluetooth/
│   │   ├── Data_types+Extensions.swift
│   │   ├── NSData+CRC8.h
│   │   ├── NSData+CRC8.m
│   │   ├── NSData+SLIP.h
│   │   ├── NSData+SLIP.m
│   │   ├── SLIPBuffer.swift
│   │   ├── SimbleeManager.swift
│   │   ├── constants.h
│   │   └── data_types.h
│   ├── HeaderData+CoreDataClass.swift
│   ├── HeaderData+CoreDataProperties.swift
│   ├── Info.plist
│   ├── LibreMonitor-Bridging-Header.h
│   ├── LibreMonitor.entitlements
│   ├── LibreMonitor.xcdatamodeld/
│   │   ├── .xccurrentversion
│   │   └── LibreMonitor.xcdatamodel/
│   │       └── contents
│   ├── LibreMonitorUITests-Bridging-Header.h
│   ├── Main.storyboard
│   ├── Model/
│   │   ├── CRC.swift
│   │   ├── LibreSensor.swift
│   │   ├── Measurement.swift
│   │   ├── SensorData.swift
│   │   └── SensorState.swift
│   ├── ModelCoreData/
│   │   ├── BloodGlucose+CoreDataClass.swift
│   │   ├── BloodGlucose+CoreDataProperties.swift
│   │   ├── CoreDataStack.swift
│   │   ├── HeaderData+CoreDataClass.swift
│   │   ├── HeaderData+CoreDataProperties.swift
│   │   ├── Reader+CoreDataClass.swift
│   │   ├── Reader+CoreDataProperties.swift
│   │   ├── Sensor+CoreDataClass.swift
│   │   └── Sensor+CoreDataProperties.swift
│   ├── Reader+CoreDataClass.swift
│   ├── Reader+CoreDataProperties.swift
│   ├── Sensor+CoreDataClass.swift
│   ├── Sensor+CoreDataProperties.swift
│   ├── SimbleeCode/
│   │   ├── crc8.h
│   │   ├── crc8.m
│   │   ├── libUBP.h
│   │   └── libUBP.m
│   ├── ViewControllers/
│   │   ├── AdjustmentsTableViewController.swift
│   │   └── BloodSugarTableViewController.swift
│   └── Views/
│       ├── BloodSugarGraphView.swift
│       └── BloodSugarGraphViewTableViewCell.swift
├── LibreMonitor.ino
├── LibreMonitor.xcodeproj/
│   ├── project.pbxproj
│   ├── project.xcworkspace/
│   │   └── contents.xcworkspacedata
│   └── xcuserdata/
│       └── Uwe.xcuserdatad/
│           └── xcschemes/
│               ├── LibreMonitor.xcscheme
│               └── xcschememanagement.plist
├── LibreMonitor.xcworkspace/
│   ├── contents.xcworkspacedata
│   └── xcuserdata/
│       └── Uwe.xcuserdatad/
│           └── xcdebugger/
│               └── Breakpoints_v2.xcbkptlist
├── LibreMonitorRFduino.ino
├── LibreMonitorTests/
│   ├── BluetoothTestData.swift
│   ├── Info.plist
│   ├── LibreMonitorTestSensorData.swift
│   ├── LibreMonitorTests-Bridging-Header.h
│   ├── LibreMonitorTests.swift
│   ├── SimbleeCode/
│   │   ├── crc8.h
│   │   ├── crc8.m
│   │   ├── libUBP.h
│   │   └── libUBP.m
│   └── TransmissionTests.swift
├── LibreMonitorUITests/
│   ├── Info.plist
│   └── LibreMonitorUITests.swift
├── Podfile
├── README.md
└── libUBP RFduino.cpp

================================================
FILE CONTENTS
================================================

================================================
FILE: LICENSE.md
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "{}"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright {yyyy} {name of copyright owner}

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: LibreMonitor/AppDelegate.swift
================================================
//
//  AppDelegate.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 14.10.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import UIKit
import CoreBluetooth
import UserNotifications

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDelegate {

    var window: UIWindow?
    var coreDataStack = CoreDataStack()


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
     
        
        // Allow local notifications for iOS 10
        let center = UNUserNotificationCenter.current()
        let options: UNAuthorizationOptions = [.alert, .badge, .sound]
        center.requestAuthorization(options: options) { (granted, error) in
            if granted {
//                application.registerForRemoteNotifications()
            }
        }
        
        // Do not show a badge icon value unless data has been received
        UIApplication.shared.applicationIconBadgeNumber = 0 // hide badge number
   
        
        // Override point for customization after application launch.
//        let splitViewController = self.window!.rootViewController as! UISplitViewController
//        let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UINavigationController
//        navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem
//        splitViewController.delegate = self
//
//        let masterNavigationController = splitViewController.viewControllers[0] as! UINavigationController
//        let controller = masterNavigationController.topViewController as! MasterViewController
//        controller.managedObjectContext = self.persistentContainer.viewContext
        
        print("In didFinishLaunchingWithOptions")
        
        let tabBarController = self.window?.rootViewController as! UITabBarController
        
        if let childViewControllers = tabBarController.viewControllers {
            
            for childViewController in childViewControllers where childViewController is UINavigationController {
                let navigationController = childViewController as! UINavigationController
                let bloodSugarTableViewController = navigationController.topViewController as! BloodSugarTableViewController
                
                // Set core data stack in view controller
                bloodSugarTableViewController.coreDataStack = coreDataStack
            }
        }
        
        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
        // 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.
        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
        print("In applicationWillResignActive")
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        // 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.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
        print("In applicationDidEnterBackground")
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // 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.
        print("In applicationWillEnterForeground")
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // 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.
        print("In applicationDidBecomeActive")
    }

    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        // Saves changes in the application's managed object context before the application terminates.
        print("In applicationWillTerminate")
        //        self.saveContext()
        coreDataStack.saveContext()
    }

//    // MARK: - Split view
//
//    func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool {
//        guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false }
//        guard let topAsDetailController = secondaryAsNavController.topViewController as? DetailViewController else { return false }
//        if topAsDetailController.detailItem == nil {
//            // Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
//            return true
//        }
//        return false
//    }
//    // MARK: - Core Data stack
//
//    lazy var persistentContainer: NSPersistentContainer = {
//        /*
//         The persistent container for the application. This implementation
//         creates and returns a container, having loaded 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.
//        */
//        let container = NSPersistentContainer(name: "LibreMonitor")
//        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
//            if let error = error as NSError? {
//                // Replace this implementation with code to handle the error appropriately.
//                // 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.
//                 
//                /*
//                 Typical reasons for an error here include:
//                 * The parent directory does not exist, cannot be created, or disallows writing.
//                 * The persistent store is not accessible, due to permissions or data protection when the device is locked.
//                 * The device is out of space.
//                 * The store could not be migrated to the current model version.
//                 Check the error message to determine what the actual problem was.
//                 */
//                fatalError("Unresolved error \(error), \(error.userInfo)")
//            }
//        })
//        return container
//    }()
//
//    // MARK: - Core Data Saving support
//
//    func saveContext () {
//        let context = persistentContainer.viewContext
//        if context.hasChanges {
//            do {
//                try context.save()
//            } catch {
//                // Replace this implementation with code to handle the error appropriately.
//                // 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.
//                let nserror = error as NSError
//                fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
//            }
//        }
//    }

}



================================================
FILE: LibreMonitor/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "iphone",
      "size" : "20x20",
      "scale" : "2x"
    },
    {
      "idiom" : "iphone",
      "size" : "20x20",
      "scale" : "3x"
    },
    {
      "idiom" : "iphone",
      "size" : "29x29",
      "scale" : "2x"
    },
    {
      "idiom" : "iphone",
      "size" : "29x29",
      "scale" : "3x"
    },
    {
      "idiom" : "iphone",
      "size" : "40x40",
      "scale" : "2x"
    },
    {
      "idiom" : "iphone",
      "size" : "40x40",
      "scale" : "3x"
    },
    {
      "idiom" : "iphone",
      "size" : "60x60",
      "scale" : "2x"
    },
    {
      "idiom" : "iphone",
      "size" : "60x60",
      "scale" : "3x"
    },
    {
      "idiom" : "ipad",
      "size" : "20x20",
      "scale" : "1x"
    },
    {
      "idiom" : "ipad",
      "size" : "20x20",
      "scale" : "2x"
    },
    {
      "idiom" : "ipad",
      "size" : "29x29",
      "scale" : "1x"
    },
    {
      "idiom" : "ipad",
      "size" : "29x29",
      "scale" : "2x"
    },
    {
      "idiom" : "ipad",
      "size" : "40x40",
      "scale" : "1x"
    },
    {
      "idiom" : "ipad",
      "size" : "40x40",
      "scale" : "2x"
    },
    {
      "idiom" : "ipad",
      "size" : "76x76",
      "scale" : "1x"
    },
    {
      "idiom" : "ipad",
      "size" : "76x76",
      "scale" : "2x"
    },
    {
      "idiom" : "ipad",
      "size" : "83.5x83.5",
      "scale" : "2x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: LibreMonitor/Base.lproj/LaunchScreen.storyboard
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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">
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11106"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--View Controller-->
        <scene sceneID="EHf-IW-A2E">
            <objects>
                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
                        <viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                    </view>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="53" y="375"/>
        </scene>
    </scenes>
</document>


================================================
FILE: LibreMonitor/BloodGlucose+CoreDataClass.swift
================================================
//
//  BloodGlucose+CoreDataClass.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 14.10.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation
import CoreData


public class BloodGlucose: NSManagedObject {

}


================================================
FILE: LibreMonitor/BloodGlucose+CoreDataProperties.swift
================================================
//
//  BloodGlucose+CoreDataProperties.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 14.10.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation
import CoreData 

extension BloodGlucose {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<BloodGlucose> {
        return NSFetchRequest<BloodGlucose>(entityName: "BloodGlucose");
    }

    @NSManaged public var bytes: String?
    @NSManaged public var date: NSDate?
    @NSManaged public var dateString: String?
    @NSManaged public var id: Int32
    @NSManaged public var type: Int16
    @NSManaged public var value: Double
    @NSManaged public var sensor: Sensor?

}


================================================
FILE: LibreMonitor/Bluetooth/Data_types+Extensions.swift
================================================
//
//  Data_types+Extensions.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 15.05.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation

extension IDNDataType {
    
    func deviceIDString() -> String {
        
        var _self = self  // make a copy of self to be able to access it via a pointer (does not work on self itself)
        
        // Extrakt device ID by creating an array from the tuple
        
        let deviceIDString = withUnsafePointer(to: &_self.deviceID, { (ptr) -> String? in
            
            let uint8Ptr = unsafeBitCast(ptr, to: UnsafePointer<UInt8>.self)
            
            var deviceIDString: String = String(format: "%02X", arguments: [uint8Ptr[0]])
            for index in 1...12 {
                deviceIDString += String(format: ":%02X", arguments: [uint8Ptr[index]])
            }
            return deviceIDString
        })
        
        print(deviceIDString!)
        
        return deviceIDString ?? "no device id"
    }
}


extension SystemInformationDataType {
    
    func uidString() -> String {
        
        var _self = self  // make a copy of self to be able to access it via a pointer (does not work on self itself)
        
        // Extrakt UID by creating an array from the tuple
        
        let uidString = withUnsafePointer(to: &_self.uid, { (ptr) -> String? in
            
            let uint8Ptr = unsafeBitCast(ptr, to: UnsafePointer<UInt8>.self)
            
            var uidString: String = String(format: "%02X", arguments: [uint8Ptr[0]])
            for index in 1...7 {
                uidString += String(format: "%02X", arguments: [uint8Ptr[index]])
//                uidString += String(format: ":%02X", arguments: [uint8Ptr[index]])
            }
            return uidString
        })
        
        print(uidString!)
        
        return uidString ?? "no uid"
    }
}


//extension RawDataType {
//    func byteString() -> String {
//        
//        var _self = self  // make a copy of self to be able to access it via a pointer (does not work on self itself)
//        
//        // Extrakt UID by creating an array from the tuple
//        
//        let byteString = withUnsafePointer(&_self.bytes, { (ptr) -> String? in
//            
//            let uint8Ptr = unsafeBitCast(ptr, UnsafePointer<UInt8>.self)
//            
//            var byteString: String = String(format: "%02X", arguments: [uint8Ptr[0]])
//            for index in 1...5 {
//                byteString += String(format: "%02X", arguments: [uint8Ptr[index]])
//                //                uidString += String(format: ":%02X", arguments: [uint8Ptr[index]])
//            }
//            return byteString
//        })
//        
//        print(byteString!)
//        
//        return byteString ?? "no bytes"
//    }
//}



================================================
FILE: LibreMonitor/Bluetooth/NSData+CRC8.h
================================================
//
//  NSData+CRC8.h
//  Bluetooth LE Test
//
//  Created by Chas Conway on 12/11/13.
//  Copyright (c) 2013 Chas Conway. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface NSData (CRC8)

- (signed char)CRC8Checksum;

//+ (signed char)CRC8ChecksumFromBuffer:(signed char *)dataBuffer bytesToRead:(signed char)bytesToRead;
+ (signed char)CRC8ChecksumFromBuffer:(signed char *)dataBuffer bytesToRead:(uint16_t)bytesToRead; // changed to uint16_t by Uwi on 2016-12-26

@end


================================================
FILE: LibreMonitor/Bluetooth/NSData+CRC8.m
================================================
//
//  NSData+CRC8.m
//  Bluetooth LE Test
//
//  Created by Chas Conway on 12/11/13.
//  Copyright (c) 2013 Chas Conway. All rights reserved.
//

#import "NSData+CRC8.h"

#define CRC8INIT  0x00
#define CRC8POLY  0x18              //0X18 = X^8+X^5+X^4+X^0

@implementation NSData (CRC8)

- (signed char)CRC8Checksum {
	
	signed char *buffer = malloc(self.length);
	[self getBytes:buffer length:self.length];
	return [NSData CRC8ChecksumFromBuffer:buffer bytesToRead:self.length];
}

//+ (signed char)CRC8ChecksumFromBuffer:(signed char *)dataBuffer bytesToRead:(signed char)bytesToRead {
+ (signed char)CRC8ChecksumFromBuffer:(signed char *)dataBuffer bytesToRead:(uint16_t)bytesToRead {  // changed to uint16_t by Uwi on 2016-12-26
	
    signed char  crc;
    uint16_t loop_count;
    signed char  bit_counter;
    signed char  data;
    signed char  feedback_bit;
    
    crc = CRC8INIT;
    
    for (loop_count = 0; loop_count != bytesToRead; loop_count++)
    {
        data = dataBuffer[loop_count];
        
        bit_counter = 8;
        do {
            feedback_bit = (crc ^ data) & 0x01;
            
            if ( feedback_bit == 0x01 ) {
                crc = crc ^ CRC8POLY;
            }
            crc = (crc >> 1) & 0x7F;
            if ( feedback_bit == 0x01 ) {
                crc = crc | 0x80;
            }
            
            data = data >> 1;
            bit_counter--;
            
        } while (bit_counter > 0);
    }
    
    return crc;
}

@end


================================================
FILE: LibreMonitor/Bluetooth/NSData+SLIP.h
================================================
//
//  NSData+SLIP.h
//  Arduino Greenhouse
//
//  Created by Chas Conway on 5/23/14.
//  Copyright (c) 2014 Chas Conway. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface NSData (SLIP)

- (NSIndexSet *)indexesOfEndBytes;
- (NSData *)unescapedData;

- (BOOL)beginsWithEndByte;
- (BOOL)endsWithEndByte;

@end


================================================
FILE: LibreMonitor/Bluetooth/NSData+SLIP.m
================================================
//
//  NSData+SLIP.m
//  Arduino Greenhouse
//
//  Created by Chas Conway on 5/23/14.
//  Copyright (c) 2014 Chas Conway. All rights reserved.
//
//  Modified by Uwe Petersen

#import "NSData+SLIP.h"

// Serial Line IP (SLIP) escaping constants
#define ESCAPE_BYTE 0xDB
#define END_BYTE    0xC0
#define ESCAPED_ESCAPE_BYTE 0xDD
#define ESCAPED_END_BYTE    0xDC
const uint8_t escapeSequence[1] = {ESCAPE_BYTE};
const uint8_t endSequence[1] = {END_BYTE};
const uint8_t escapedEndSequence[2] = {ESCAPE_BYTE, ESCAPED_END_BYTE};
const uint8_t escapedEscapeSequence[2] = {ESCAPE_BYTE, ESCAPED_ESCAPE_BYTE};

@implementation NSData (SLIP)

- (NSIndexSet *)indexesOfEndBytes {
	
	__block NSMutableIndexSet *endByteIndices = [NSMutableIndexSet new];
	
	[self enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
		
		for (NSInteger i = byteRange.location; i < (byteRange.location + byteRange.length); i++) {  // For each byte in the range
			
			uint8_t aByte = *((uint8_t *)bytes + i);
			if (aByte == END_BYTE) [endByteIndices addIndex:i];
		}
	}];
	
	return endByteIndices;
}

- (NSData *)unescapedData {
	
	NSMutableData *outputData = [[NSMutableData alloc] initWithData:self];

	BOOL done = NO;
    NSUInteger notYetUnescaped = 0; // 2016-06-30, Uwe Petersen:
	while (!done) {  // Search for escaped END bytes
	
        // 2016-06-30, Uwe Petersen:
        NSRange resultRange = [outputData rangeOfData:[NSData dataWithBytes:escapedEndSequence length:2] options:0 range:NSMakeRange(notYetUnescaped, outputData.length - notYetUnescaped)];
//        NSRange resultRange = [outputData rangeOfData:[NSData dataWithBytes:escapedEndSequence length:2] options:0 range:NSMakeRange(0, outputData.length)];
		if (resultRange.location != NSNotFound) {  // Found an occurance
			
			// Replace that escaped occurance with the unescaped value
			[outputData replaceBytesInRange:resultRange withBytes:endSequence length:1];
            notYetUnescaped = resultRange.location + 1; // 2016-06-30, Uwe Petersen
		
		} else {  // Didn't find any more occurances, so exit while loop
			
			done = YES;
		}
	}
	
	done = NO;
    notYetUnescaped = 0; // 2016-06-30, Uwe Petersen
	while (!done) {  // Search for escaped ESCAPE bytes
		
        // 2016-06-30, Uwe Petersen:
        NSRange resultRange = [outputData rangeOfData:[NSData dataWithBytes:escapedEscapeSequence length:2] options:0 range:NSMakeRange(notYetUnescaped, outputData.length - notYetUnescaped)];
//        NSRange resultRange = [outputData rangeOfData:[NSData dataWithBytes:escapedEscapeSequence length:2] options:0 range:NSMakeRange(0, outputData.length)];
		if (resultRange.location != NSNotFound) {  // Found an occurance
			
			// Replace that escaped occurance with the unescaped value
			[outputData replaceBytesInRange:resultRange withBytes:escapeSequence length:1];
            notYetUnescaped = resultRange.location + 1; // 2016-06-30, Uwe Petersen

			
		} else {  // Didn't find any more occurances, so exit while loop
			
			done = YES;
		}
	}
	
	return [NSData dataWithData:outputData];
}

- (BOOL)beginsWithEndByte {
	
	NSIndexSet *endByteIndices = [self indexesOfEndBytes];
	return [endByteIndices containsIndex:0];
}

- (BOOL)endsWithEndByte {
	
	NSIndexSet *endByteIndices = [self indexesOfEndBytes];
	return [endByteIndices containsIndex:(self.length - 1)];
}

@end


================================================
FILE: LibreMonitor/Bluetooth/SLIPBuffer.swift
================================================
//
//  SLIPBuffer.swift
//  UBA-Demo
//
//  Created by Chas Conway on 2/4/15.
//  Copyright (c) 2015 Chas Conway. All rights reserved.
//
//  Modified by Uwe Petersen

import Foundation

let PacketIdentifierLength = MemoryLayout<UInt16>.size
let PacketFlagsLength = MemoryLayout<UInt8>.size
let PacketChecksumLength = MemoryLayout<UInt8>.size

protocol SLIPBufferDelegate {
	
	func slipBufferReceivedPayload(_ payloadData: Data, payloadIdentifier: UInt16, txFlags: UInt8)
}


class SLIPBuffer {

    var rxBuffer = Data()
	var delegate:SLIPBufferDelegate?
	
	/// 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.
	///
    /// The bytes that are appended are escaped bytes according to the serial line internet protocol (SLIP). SLIP works as follows:
    /// - A transmission packet (the payload data) is appended by a special "END" byte, which distinguishes the datagram boundaries in the byte stream.
    /// - If the END byte occurs in the payload data to be sent, the two byte sequence [ESC, ESC_END] is sent instead.
    /// - If the ESC byte occurs in the payload data to be sent, the two byte sequence [ESC, ESC_ESC] is sent instead.
    /// - 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)
    ///
    /// The special bytes used by SLIP are:
    /// - 0xC0 ... END     -> Frame End (and Frame Beginning in this realization)
    /// - 0xDB ... ESC     -> Frame Escape
    /// - 0xDC ... ESC_END -> Transposed Frame END
    /// - 0xDD ... ESC_ESC -> Transposed Frame ESC
    ///
    /// Reference: https://en.m.wikipedia.org/wiki/Serial_Line_Internet_Protocol
    ///
	/// - parameter escapedData: data with escape bytes to be appended to the buffer
	func appendEscapedBytes(_ escapedData: Data) {
		
		rxBuffer.append(escapedData)
		scanRxBufferForFrames()
	}
	
	
    /// 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. 
    ///
    /// Extracting the payload means the following steps: 
    /// - Extract the payload from the SLIP frame:
    ///   - Remove the END byte at the beginning and at the end of the frame.
    ///   - 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. 
    /// - Check CRC and remove the rcr bytes:
    ///   - 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.
    /// - If the CRCs are equal, a delegate method is called with the payload data (with the one appended CRC byte removed).
    ///
    /// The serial line internet protocol (SLIP) works as follows:
    /// - A transmission packet (the payload data) is appended by a special "END" byte, which distinguishes the datagram boundaries in the byte stream.
    /// - If the END byte occurs in the payload data to be sent, the two byte sequence [ESC, ESC_END] is sent instead.
    /// - If the ESC byte occurs in the payload data to be sent, the two byte sequence [ESC, ESC_ESC] is sent instead.
    /// - 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)
    ///
    /// The special bytes used by SLIP are:
    /// - 0xC0 ... END     -> Frame End (and Frame Beginning in this realization)
    /// - 0xDB ... ESC     -> Frame Escape
    /// - 0xDC ... ESC_END -> Transposed Frame END
    /// - 0xDD ... ESC_ESC -> Transposed Frame ESC
    ///
    /// Reference: https://en.m.wikipedia.org/wiki/Serial_Line_Internet_Protocol
    ///
    func scanRxBufferForFrames() {
        
        // get indices of all END bytes
        // TODO: idexesOfEndBytes is an Objective-C-extension of NSData. Reprogram this in Swift for data type "Data"
        guard let endByteIndices = NSData.init(data: rxBuffer).indexesOfEndBytes() else {
            return
        }

        // 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]
		var previousEndByteIndex = NSNotFound
        for endByteIndex in endByteIndices {
            
            print(String(endByteIndex.description) as Any)
            
            if (previousEndByteIndex != NSNotFound) {
                
                if endByteIndex - previousEndByteIndex > 2 {  // Contains at least one byte and checksum byte
                    
                    print("Identified a potential SLIP frame")
                    
                    print(self.rxBuffer.debugDescription)
                    
                    // Extact the frame (END byte at beginning and end are aleady removed)
                    let escapedPacket = self.rxBuffer.subdata(in: Range((previousEndByteIndex + 1)..<endByteIndex))
                    
                    // Decode the packet (undo SLIP)
                    self.decodeSLIPPacket(escapedPacket)
                    
                } else {
                    
                    print("Ignoring improbable SLIP frame")
                }
            }
            previousEndByteIndex = endByteIndex
        }
    
		// Remove byte in buffer up to, but not including, the previous END byte, i.e. cut of everything before the beginning of the frame.
		if previousEndByteIndex != NSNotFound {
            rxBuffer.removeSubrange(0..<previousEndByteIndex)
        }
    }
	
	/// Decode the escape packet.
	///
    /// 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.
    ///
	/// - parameter escapedPacket: packet that still contains ESC and END bytes (as they were needed for the serial line internet protocol)
	func decodeSLIPPacket(_ escapedPacket:Data) {
		
		// Remove SLIP escaping
        guard let unescapedPacket = (escapedPacket as NSData).unescaped() else {
            return
        }
		
		// Extract embedded checksum from packet
        var embeddedChecksumByte:UInt8 = 0
        unescapedPacket.copyBytes(to: &embeddedChecksumByte, from: Range((unescapedPacket.count - PacketChecksumLength)..<unescapedPacket.count))
        
        
        // 2016-07-30, Uwe Petersen: get unescaped packet without checksum
        let unescapedPacketWithoutChecksum = unescapedPacket.subdata(in: Range(0..<(unescapedPacket.count-PacketChecksumLength)))
		
        // Calculate checksum on payload bytes (2016-06-30, Uwe Petersen: seems to be an error to calculate on unescaped packet. Changed to escaped packet)
        let checksummedData = escapedPacket.subdata(in: Range(0..<escapedPacket.count - PacketChecksumLength))
        let calculatedChecksum = (checksummedData as NSData).crc8Checksum()
        
        if UInt8(bitPattern: calculatedChecksum) == embeddedChecksumByte { // crc is calulated as Int8 and thus has to be converted to UInt8
			
			if let aDelegate = delegate {
				
				// Extract payload and payload ID. (2016-06-30, Uwe Petersen: seems to be an error to calculate on unescaped packet. Changed to escaped packet)
				var identifier: UInt16 = 0;
                let _ = unescapedPacketWithoutChecksum.copyBytes(to: UnsafeMutableBufferPointer(start: &identifier, count: 1), from: Range(0..<PacketIdentifierLength))
				
                
                // 2016-06-30, Uwe Petersen: seems to be an error to calculate on unescaped packet. Changed to escaped packet
                var txFlags: UInt8 = 0;
                unescapedPacketWithoutChecksum.copyBytes(to: &txFlags, from: Range((PacketIdentifierLength-1)..<(PacketIdentifierLength-1+PacketFlagsLength)))
                
                let payloadData = unescapedPacketWithoutChecksum.subdata(in: Range( (PacketIdentifierLength + PacketFlagsLength)..<unescapedPacketWithoutChecksum.count ))
				
				// Notify delegate with payloadData 
				aDelegate.slipBufferReceivedPayload(payloadData, payloadIdentifier: identifier, txFlags: txFlags)
			}
			
		} else {

            print("SLIP frame failed checksum")
        }
	}
}


================================================
FILE: LibreMonitor/Bluetooth/SimbleeManager.swift
================================================
//
//  SimbleeManager.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 23.04.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//
//  How does the Simblee work?
//
//    1.) Services
///       The Simblee has only one service. By convention the service UUID is set to "2220" (this 
//        could be changed in the arduino code any time):
//
//        Service:
//        "<CBService: 0x14c72a810, isPrimary = YES, UUID = 2220>"
//
//    2.) Characteristics
//        Simble provides three Characteristics: one read and two write characteristics. This is
//        a "hard coded" feature of the simblee and cannot be changed. The debugDescription 
//        of these three characteristics is as follows:
//
//        a) Read Characteristic:
//               "<CBCharacteristic: 0x14c7664e0, UUID = 2221, properties = 0x12, value = (null), notifying = NO>"
//           ... with properties:
//              __C.CBCharacteristicProperties(rawValue: 18)
//              Broadcast:                            [false]
//              Read:                                 [true]
//              WriteWithoutResponse:                 [false]
//              Write:                                [false]
//              Notify:                               [true]
//              Indicate:                             [false]
//              AuthenticatedSignedWrites:            [false]
//              ExtendedProperties:                   [false]
//              NotifyEncryptionRequired:             [false]
//              BroaIndicateEncryptionRequireddcast:  [false]
//
//        b) First Write Characteristic:
//              "<CBCharacteristic: 0x14c766620, UUID = 2222, properties = 0xC, value = (null), notifying = NO>"
//           ... with properties:
//              __C.CBCharacteristicProperties(rawValue: 12)
//              Broadcast:                            [false]
//              Read:                                 [false]
//              WriteWithoutResponse:                 [true]
//              Write:                                [true]
//              Notify:                               [false]
//              Indicate:                             [false]
//              AuthenticatedSignedWrites:            [false]
//              ExtendedProperties:                   [false]
//              NotifyEncryptionRequired:             [false]
//              BroaIndicateEncryptionRequireddcast:  [false]
//
//        c) Second Write Characteristic:
//              "<CBCharacteristic: 0x14c766720, UUID = 2223, properties = 0xC, value = (null), notifying = NO>"
//           ... with properties:
//              __C.CBCharacteristicProperties(rawValue: 12)
//              Broadcast:                            [false]
//              Read:                                 [false]
//              WriteWithoutResponse:                 [true]
//              Write:                                [true]
//              Notify:                               [false]
//              Indicate:                             [false]
//              AuthenticatedSignedWrites:            [false]
//              ExtendedProperties:                   [false]
//              NotifyEncryptionRequired:             [false]
//              BroaIndicateEncryptionRequireddcast:  [false]
//
//   3.) Further information on Simblee services and characteristics can be found on
//       http://forum.rfduino.com/index.php?topic=1066.15
//

import Foundation
import UIKit
import CoreBluetooth


public enum SimbleeManagerState: String {
    case Unassigned = "Unassigned"
    case Scanning = "Scanning"
    case Disconnected = "Disconnected"
    case DisconnectedManually = "Disconnected manually"
    case Connecting = "Connecting"
    case Connected = "Connected"
    case Notifying = "Notifying"
}

protocol SimbleeManagerDelegate {
    func simbleeManagerPeripheralStateChanged(_ state:SimbleeManagerState)
    func simbleeManagerReceivedMessage(_ messageIdentifier:UInt16, txFlags:UInt8, payloadData:Data)
}

class SimbleeManager: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate, SLIPBufferDelegate {
    
    // MARK: - Properties
    var centralManager: CBCentralManager!
    var peripheral: CBPeripheral?
    var slipBuffer = SLIPBuffer()
    
    fileprivate let serviceUUIDs:[CBUUID]? = [CBUUID(string: "2220")]
    
    var BLEScanDuration = 3.0
    
    var delegate: SimbleeManagerDelegate? {
        didSet {
            // Help delegate initialize by sending current state directly after delegate assignment
            delegate?.simbleeManagerPeripheralStateChanged(state)
        }
    }
    
    var state: SimbleeManagerState = .Unassigned {
        didSet {
            // Help delegate initialize by sending current state directly after delegate assignment
            delegate?.simbleeManagerPeripheralStateChanged(state)
        }
    }
    
    // MARK: - Mehods
    
    override init() {
        super.init()
        centralManager = CBCentralManager(delegate: self, queue: nil, options: nil)
        slipBuffer.delegate = self
    }
    
    func scanForSimblee() {
        if centralManager.state == .poweredOn {
            print ("Start scanning for Simblee")
            centralManager.scanForPeripherals(withServices: serviceUUIDs, options: nil)
            state = .Scanning
        }
    }
    
    func connect() {
        if let peripheral = peripheral {
            peripheral.delegate = self
            centralManager.stopScan()
            centralManager.connect(peripheral, options: nil)
            state = .Connecting        }
    }
    
    func disconnectManually() {
        switch state {
        case .Connected, .Connecting, .Notifying:
            state = .DisconnectedManually  // to avoid reconnect in didDisconnetPeripheral
            centralManager.cancelPeripheralConnection(peripheral!)
        default:
            break
        }
//        if state == .Connected || peripheral?.state == .Connecting {
//            centralManager.cancelPeripheralConnection(peripheral!)
//        }
    }
    
    
    // MARK: - CBCentralManagerDelegate
    
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        print("centralManagerDidUpdateState")
        // TODO: maybe handle the case of bluetooth beeing switched of (and sometimes later) on again here by stopping and restarting scanning
    }
    
    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
        print("didDiscoverPeripheral with name \(peripheral.name)")
        
        self.peripheral = peripheral
        connect()
    }
    
    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
        print("didConnectPeripheral")
        state = .Connected
        // Discover all Services. This might be helpful if writing is needed some time
        peripheral.discoverServices(nil)
    }
    
    func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
        print("didFailToConnectPeripheral")
        state = .Disconnected
    }
    
    func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
        print("didDisconnectPeripheral")
        switch state {
        case .DisconnectedManually:
            state = .Disconnected
        default:
            state = .Disconnected
            scanForSimblee()
        }
        // Keep this code in case you want it some later time: it is used for reconnection only in background mode
//        state = .Disconnected
//        // Start scanning, if disconnection occurred in background mode
//        if UIApplication.sharedApplication().applicationState == .Background ||
//            UIApplication.sharedApplication().applicationState == .Inactive {
//            scanForSimblee()
//        }
    }
    
    
    // MARK: - CBPeripheralDelegate
    
    
    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
    
        print("didDiscoverServices")
        if let services = peripheral.services {
            print("Discovered services on RFduino");
            for service in services {
                peripheral.discoverCharacteristics(nil, for: service)
//                print("Service: ")
//                debugPrint(service.debugDescription)
            }
        }
    }
    
    
    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {

        print("didDiscoverCharacteristicsForService");
        if let error = error {
            print("An error occured: \(error.localizedDescription)")
        }

        if let characteristics = service.characteristics {
            for characteristic in characteristics {
//                print("Characteristic: ")
//                debugPrint(characteristic.debugDescription)
//                print("... with properties: ")
//                debugPrint(characteristic.properties)
//                print("Broadcast:                           ", [characteristic.properties.contains(.Broadcast)])
//                print("Read:                                ", [characteristic.properties.contains(.Read)])
//                print("WriteWithoutResponse:                ", [characteristic.properties.contains(.WriteWithoutResponse)])
//                print("Write:                               ", [characteristic.properties.contains(.Write)])
//                print("Notify:                              ", [characteristic.properties.contains(.Notify)])
//                print("Indicate:                            ", [characteristic.properties.contains(.Indicate)])
//                print("AuthenticatedSignedWrites:           ", [characteristic.properties.contains(.AuthenticatedSignedWrites )])
//                print("ExtendedProperties:                  ", [characteristic.properties.contains(.ExtendedProperties)])
//                print("NotifyEncryptionRequired:            ", [characteristic.properties.contains(.NotifyEncryptionRequired)])
//                print("BroaIndicateEncryptionRequireddcast: ", [characteristic.properties.contains(.IndicateEncryptionRequired)])
                
                // Choose the notifiying characteristic and Register to be notified whenever the simblee transmits
                if (characteristic.properties.intersection(.notify)) == .notify {
                    peripheral.setNotifyValue(true, for: characteristic)
                }
            }
        } else {
            print("Discovered characteristics on RFduino, but no characteristics listed. There must be some error.");
        }
    }

    
    func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
        print("didUpdateNotificationStateForCharacteristic")
        if let error = error {
            print("An error occured: \(error.localizedDescription)")
        }
        state = .Notifying
    }
    
    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
        print("didUpdateValueForCharacteristic")
        if let error = error {
            print("Characteristic update error = \(error.localizedDescription)")
        } else {
            if let value = characteristic.value {
                slipBuffer.appendEscapedBytes(value)
            }
        }
    }
    
    
    // MARK: - SLIPBufferDelegate
    
    
    func slipBufferReceivedPayload(_ payloadData: Data, payloadIdentifier: UInt16, txFlags: UInt8) {
        
        // Inform delegate
        if let delegate = delegate {
            delegate.simbleeManagerReceivedMessage(payloadIdentifier, txFlags: txFlags, payloadData: payloadData)
        }
    }
    

}





















================================================
FILE: LibreMonitor/Bluetooth/constants.h
================================================
// 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

#define ALL_BYTES 0x1007   //
#define IDN_DATA 0x2001    //
#define SYSTEM_INFORMATION_DATA 0x2002  //
#define BATTERY_DATA 0x2005     //



================================================
FILE: LibreMonitor/Bluetooth/data_types.h
================================================
// Data types for data to be transfered
// Need a struct with one variable and the packed attribute to make this an array in swift (in a simple way


// Battery
typedef struct  __attribute__((packed)) {
    float voltage;
    float temperature;
} BatteryDataType;


/// System information command response
/// @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
/// @param resultCode 0x80 if no error
/// @param responseFlags
/// @param infoFlags bit 0 is set to 1 in case of error
/// @param errorCode error code
/// @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.
typedef struct  __attribute__((packed)) {
    uint8_t uid[8];
    uint8_t resultCode;
    uint8_t responseFlags;
    uint8_t infoFlags;
    uint8_t errorCode;
} SystemInformationDataType;


/// IDN command response, which is the device ID
/// @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
/// @param resultCode 0x00 if no error
/// @param deiceID 13 bytes containing the device ID.
typedef struct  __attribute__((packed)) {
    uint8_t resultCode;
    uint8_t deviceID[13];
    uint8_t romCRC[2];
} IDNDataType;


/// The first 344 bytes of data as read from FRAM of the Freestyle Libre Sensor
/// @detail Contains 24 byes of header, 296 bytes of body with blood sugar data
/// and 24 bytes of footer
/// @param bytes 344 bytes containing the the raw data
typedef struct  __attribute__((packed)) {
    uint8_t allBytes[344];
} AllBytesDataType;



================================================
FILE: LibreMonitor/HeaderData+CoreDataClass.swift
================================================
//
//  HeaderData+CoreDataClass.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 14.10.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation
import CoreData

@objc(HeaderData)
public class HeaderData: NSManagedObject {

}


================================================
FILE: LibreMonitor/HeaderData+CoreDataProperties.swift
================================================
//
//  HeaderData+CoreDataProperties.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 14.10.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation
import CoreData


extension HeaderData {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<HeaderData> {
        return NSFetchRequest<HeaderData>(entityName: "HeaderData");
    }

    @NSManaged public var bytes: String?
    @NSManaged public var date: NSDate?

}


================================================
FILE: LibreMonitor/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleDevelopmentRegion</key>
	<string>en</string>
	<key>CFBundleExecutable</key>
	<string>$(EXECUTABLE_NAME)</string>
	<key>CFBundleIdentifier</key>
	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>$(PRODUCT_NAME)</string>
	<key>CFBundlePackageType</key>
	<string>APPL</string>
	<key>CFBundleShortVersionString</key>
	<string>1.0</string>
	<key>CFBundleVersion</key>
	<string>1</string>
	<key>LSRequiresIPhoneOS</key>
	<true/>
	<key>UIBackgroundModes</key>
	<array>
		<string>bluetooth-central</string>
	</array>
	<key>UIFileSharingEnabled</key>
	<true/>
	<key>UILaunchStoryboardName</key>
	<string>LaunchScreen</string>
	<key>UIMainStoryboardFile</key>
	<string>Main</string>
	<key>UIRequiredDeviceCapabilities</key>
	<array>
		<string>armv7</string>
		<string>healthkit</string>
	</array>
	<key>UIStatusBarTintParameters</key>
	<dict>
		<key>UINavigationBar</key>
		<dict>
			<key>Style</key>
			<string>UIBarStyleDefault</string>
			<key>Translucent</key>
			<false/>
		</dict>
	</dict>
	<key>UISupportedInterfaceOrientations</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationLandscapeLeft</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
	</array>
	<key>UISupportedInterfaceOrientations~ipad</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationPortraitUpsideDown</string>
		<string>UIInterfaceOrientationLandscapeLeft</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
	</array>
</dict>
</plist>


================================================
FILE: LibreMonitor/LibreMonitor-Bridging-Header.h
================================================
//
//  Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "NSData+CRC8.h"
#import "NSData+SLIP.h"
#import "constants.h"
#import "data_types.h"



================================================
FILE: LibreMonitor/LibreMonitor.entitlements
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>com.apple.developer.healthkit</key>
	<true/>
</dict>
</plist>


================================================
FILE: LibreMonitor/LibreMonitor.xcdatamodeld/.xccurrentversion
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>_XCCurrentVersionName</key>
	<string>LibreMonitor.xcdatamodel</string>
</dict>
</plist>


================================================
FILE: LibreMonitor/LibreMonitor.xcdatamodeld/LibreMonitor.xcdatamodel/contents
================================================
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1" systemVersion="11A491" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
    <entity name="Event" representedClassName="Event" codeGenerationType="class">
        <attribute name="timestamp" optional="YES" attributeType="Date"/>
    </entity>
    <elements>
        <element name="Event" positionX="261" positionY="189" width="128" height="60"/>
    </elements>
    <entity name="BloodGlucose" representedClassName=".BloodGlucose" syncable="YES">
        <attribute name="bytes" optional="YES" attributeType="String" syncable="YES"/>
        <attribute name="date" optional="YES" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
        <attribute name="dateString" optional="YES" attributeType="String" syncable="YES"/>
        <attribute name="id" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES" syncable="YES"/>
        <attribute name="type" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES" syncable="YES"/>
        <attribute name="value" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES" indexed="YES" syncable="YES"/>
        <relationship name="sensor" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Sensor" inverseName="bloodGlucose" inverseEntity="Sensor" syncable="YES"/>
    </entity>
    <entity name="HeaderData" representedClassName="HeaderData" syncable="YES">
        <attribute name="bytes" optional="YES" attributeType="String" syncable="YES"/>
        <attribute name="date" optional="YES" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
    </entity>
    <entity name="Reader" representedClassName=".Reader" syncable="YES">
        <attribute name="batteryVoltage" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES" syncable="YES"/>
        <attribute name="temperature" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES" syncable="YES"/>
        <attribute name="uid" optional="YES" attributeType="String" syncable="YES"/>
    </entity>
    <entity name="Sensor" representedClassName=".Sensor" syncable="YES">
        <attribute name="lastScanDate" optional="YES" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
        <attribute name="minutesSinceStart" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES" syncable="YES"/>
        <attribute name="startDate" optional="YES" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
        <attribute name="uid" optional="YES" attributeType="String" syncable="YES"/>
        <relationship name="bloodGlucose" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="BloodGlucose" inverseName="sensor" inverseEntity="BloodGlucose" syncable="YES"/>
    </entity>
    <elements>
        <element name="Event" positionX="207" positionY="-135" width="128" height="58"/>
        <element name="BloodGlucose" positionX="43" positionY="81" width="128" height="148"/>
        <element name="HeaderData" positionX="189" positionY="-18" width="128" height="75"/>
        <element name="Reader" positionX="288" positionY="261" width="128" height="88"/>
        <element name="Sensor" positionX="261" positionY="84" width="128" height="118"/>
    </elements>
</model>

================================================
FILE: LibreMonitor/LibreMonitorUITests-Bridging-Header.h
================================================
//
//  Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "NSData+CRC8.h"
#import "NSData+SLIP.h"
#import "constants.h"
#import "data_types.h"


================================================
FILE: LibreMonitor/Main.storyboard
================================================
<?xml version="1.0" encoding="UTF-8"?>
<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">
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11161"/>
        <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--Blood Sugar Table View Controller-->
        <scene sceneID="ImT-lg-bzr">
            <objects>
                <tableViewController modalPresentationStyle="overFullScreen" id="50o-9a-5MG" customClass="BloodSugarTableViewController" customModule="LibreMonitor" customModuleProvider="target" sceneMemberID="viewController">
                    <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">
                        <rect key="frame" x="0.0" y="64" width="375" height="554"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <prototypes>
                            <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">
                                <rect key="frame" x="0.0" y="28" width="375" height="44"/>
                                <autoresizingMask key="autoresizingMask"/>
                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KSA-Qo-0iw" id="f3z-vb-S0d">
                                    <frame key="frameInset" width="375" height="43.5"/>
                                    <autoresizingMask key="autoresizingMask"/>
                                    <subviews>
                                        <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="geB-0N-HCr">
                                            <frame key="frameInset" minX="15" minY="15" width="91" height="14.5"/>
                                            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                                            <fontDescription key="fontDescription" type="system" pointSize="12"/>
                                            <color key="textColor" red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                            <nil key="highlightedColor"/>
                                        </label>
                                        <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Detail" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="7Ok-y7-eKF">
                                            <frame key="frameInset" minX="112" minY="15" width="33" height="14.5"/>
                                            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                                            <fontDescription key="fontDescription" type="system" pointSize="12"/>
                                            <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                            <nil key="highlightedColor"/>
                                        </label>
                                    </subviews>
                                </tableViewCellContentView>
                            </tableViewCell>
                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="BloodSugarGraphTableViewCell" rowHeight="331" id="jdB-cO-2dn" customClass="BloodSugarGraphViewTableViewCell" customModule="LibreMonitor" customModuleProvider="target">
                                <rect key="frame" x="0.0" y="72" width="375" height="331"/>
                                <autoresizingMask key="autoresizingMask"/>
                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="jdB-cO-2dn" id="g5L-6G-F7W">
                                    <frame key="frameInset" width="375" height="330.5"/>
                                    <autoresizingMask key="autoresizingMask"/>
                                    <subviews>
                                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="U1C-fo-eIu" customClass="BloodSugarGraphView" customModule="LibreMonitor" customModuleProvider="target">
                                            <color key="backgroundColor" red="0.97488003280000002" green="0.63108614230000004" blue="0.54087663860000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                            <color key="tintColor" red="0.21386732429999999" green="1" blue="0.15152120020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                        </view>
                                    </subviews>
                                    <constraints>
                                        <constraint firstItem="U1C-fo-eIu" firstAttribute="width" secondItem="g5L-6G-F7W" secondAttribute="width" id="IJa-Mw-X6T"/>
                                        <constraint firstItem="U1C-fo-eIu" firstAttribute="height" secondItem="g5L-6G-F7W" secondAttribute="height" id="Kzb-7c-cLU"/>
                                        <constraint firstItem="U1C-fo-eIu" firstAttribute="centerY" secondItem="g5L-6G-F7W" secondAttribute="centerY" id="T67-rZ-fMN"/>
                                        <constraint firstItem="U1C-fo-eIu" firstAttribute="centerX" secondItem="g5L-6G-F7W" secondAttribute="centerX" id="c4W-Lb-viC"/>
                                    </constraints>
                                </tableViewCellContentView>
                                <connections>
                                    <outlet property="barChartView" destination="U1C-fo-eIu" id="yRf-2P-7bE"/>
                                    <outlet property="lineChartView" destination="U1C-fo-eIu" id="iPw-k8-YjO"/>
                                </connections>
                            </tableViewCell>
                        </prototypes>
                        <connections>
                            <outlet property="dataSource" destination="50o-9a-5MG" id="Yga-5N-Ao6"/>
                            <outlet property="delegate" destination="50o-9a-5MG" id="f68-gz-v0t"/>
                        </connections>
                    </tableView>
                    <extendedEdge key="edgesForExtendedLayout"/>
                    <navigationItem key="navigationItem" id="LSU-c9-uSa"/>
                    <refreshControl key="refreshControl" opaque="NO" multipleTouchEnabled="YES" contentMode="center" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" id="ES1-fl-YYX">
                        <rect key="frame" x="0.0" y="0.0" width="1000" height="1000"/>
                        <autoresizingMask key="autoresizingMask"/>
                        <attributedString key="attributedTitle">
                            <fragment content="Aktualisierung alle zwei Minuten im Status &quot;Notifying&quot;.">
                                <attributes>
                                    <font key="NSFont" metaFont="smallSystem"/>
                                    <paragraphStyle key="NSParagraphStyle" alignment="center" lineBreakMode="wordWrapping" baseWritingDirection="natural" lineHeightMultiple="1" tighteningFactorForTruncation="0.0"/>
                                </attributes>
                            </fragment>
                        </attributedString>
                        <connections>
                            <action selector="doRefresh:" destination="50o-9a-5MG" eventType="valueChanged" id="dGD-br-dHx"/>
                        </connections>
                    </refreshControl>
                    <connections>
                        <segue destination="RRb-Vb-fEk" kind="showDetail" identifier="ChangeBloodGlucoseAdjustments" id="rkq-Eh-apj"/>
                    </connections>
                </tableViewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="rfD-Rn-XvB" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="1239" y="1000"/>
        </scene>
        <!--Adjustments Table View Controller-->
        <scene sceneID="KrO-eT-0KU">
            <objects>
                <tableViewController id="p1I-y2-sJ2" customClass="AdjustmentsTableViewController" customModule="LibreMonitor" customModuleProvider="target" sceneMemberID="viewController">
                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="6ty-D7-GsN">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <sections>
                            <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">
                                <cells>
                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="KhQ-e7-kta">
                                        <rect key="frame" x="0.0" y="119.5" width="375" height="44"/>
                                        <autoresizingMask key="autoresizingMask"/>
                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KhQ-e7-kta" id="1J4-j6-1aL">
                                            <frame key="frameInset" width="375" height="43.5"/>
                                            <autoresizingMask key="autoresizingMask"/>
                                            <subviews>
                                                <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">
                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                                    <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                                    <nil key="highlightedColor"/>
                                                </label>
                                                <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">
                                                    <constraints>
                                                        <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="120" id="KIY-lx-ceo"/>
                                                    </constraints>
                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                                    <textInputTraits key="textInputTraits" keyboardType="numbersAndPunctuation"/>
                                                </textField>
                                            </subviews>
                                            <constraints>
                                                <constraint firstItem="6rr-p0-qrk" firstAttribute="baseline" secondItem="XaO-BA-G9S" secondAttribute="baseline" id="K1Q-va-Zzy"/>
                                                <constraint firstItem="6rr-p0-qrk" firstAttribute="trailing" secondItem="1J4-j6-1aL" secondAttribute="trailingMargin" id="gJb-g7-heD"/>
                                                <constraint firstItem="XaO-BA-G9S" firstAttribute="leading" secondItem="1J4-j6-1aL" secondAttribute="leadingMargin" constant="10" id="pgd-Lb-eVi"/>
                                                <constraint firstItem="6rr-p0-qrk" firstAttribute="top" secondItem="1J4-j6-1aL" secondAttribute="topMargin" id="z9w-uj-8jJ"/>
                                            </constraints>
                                        </tableViewCellContentView>
                                    </tableViewCell>
                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="OHa-VS-zrB">
                                        <rect key="frame" x="0.0" y="163.5" width="375" height="44"/>
                                        <autoresizingMask key="autoresizingMask"/>
                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="OHa-VS-zrB" id="JqF-JX-s9v">
                                            <frame key="frameInset" width="375" height="43.5"/>
                                            <autoresizingMask key="autoresizingMask"/>
                                            <subviews>
                                                <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">
                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                                    <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                                    <nil key="highlightedColor"/>
                                                </label>
                                                <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">
                                                    <constraints>
                                                        <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="120" id="sjq-Sh-ISQ"/>
                                                    </constraints>
                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                                    <textInputTraits key="textInputTraits" keyboardType="numbersAndPunctuation"/>
                                                </textField>
                                            </subviews>
                                            <constraints>
                                                <constraint firstItem="zNa-Ly-leh" firstAttribute="leading" secondItem="JqF-JX-s9v" secondAttribute="leadingMargin" constant="10" id="7gb-Gc-QoT"/>
                                                <constraint firstItem="zNa-Ly-leh" firstAttribute="centerY" secondItem="JqF-JX-s9v" secondAttribute="centerY" id="AcC-oz-nwR"/>
                                                <constraint firstItem="f1a-bL-AF1" firstAttribute="centerY" secondItem="zNa-Ly-leh" secondAttribute="centerY" id="qXh-Hq-0XW"/>
                                                <constraint firstItem="f1a-bL-AF1" firstAttribute="trailing" secondItem="JqF-JX-s9v" secondAttribute="trailingMargin" id="zYl-eK-blb"/>
                                            </constraints>
                                        </tableViewCellContentView>
                                    </tableViewCell>
                                </cells>
                            </tableViewSection>
                        </sections>
                        <connections>
                            <outlet property="dataSource" destination="p1I-y2-sJ2" id="iFC-8a-rKQ"/>
                            <outlet property="delegate" destination="p1I-y2-sJ2" id="4G7-sw-9L9"/>
                        </connections>
                    </tableView>
                    <navigationItem key="navigationItem" id="V9s-LS-E01"/>
                    <connections>
                        <outlet property="offsetTextField" destination="6rr-p0-qrk" id="MdT-ZU-Xrt"/>
                        <outlet property="slopeTextField" destination="f1a-bL-AF1" id="01j-ZC-4f6"/>
                    </connections>
                </tableViewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="g2J-9j-6dp" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="2829" y="1000"/>
        </scene>
        <!--Grafik-->
        <scene sceneID="ItB-yR-jGL">
            <objects>
                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="Aqc-Zr-wxr" sceneMemberID="viewController">
                    <tabBarItem key="tabBarItem" title="Grafik" id="m5f-C6-Iyo"/>
                    <toolbarItems/>
                    <navigationBar key="navigationBar" contentMode="scaleToFill" id="D5j-St-ijw">
                        <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
                        <autoresizingMask key="autoresizingMask"/>
                    </navigationBar>
                    <nil name="viewControllers"/>
                    <connections>
                        <segue destination="50o-9a-5MG" kind="relationship" relationship="rootViewController" id="mac-75-ac4"/>
                    </connections>
                </navigationController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="6xi-6N-6sh" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="442" y="1000"/>
        </scene>
        <!--Tab Bar Controller-->
        <scene sceneID="eSi-nN-T7n">
            <objects>
                <tabBarController automaticallyAdjustsScrollViewInsets="NO" id="W2V-7Y-4OF" sceneMemberID="viewController">
                    <toolbarItems/>
                    <tabBar key="tabBar" contentMode="scaleToFill" id="NAN-gf-Fb0">
                        <rect key="frame" x="0.0" y="0.0" width="1000" height="1000"/>
                        <autoresizingMask key="autoresizingMask"/>
                        <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
                    </tabBar>
                    <connections>
                        <segue destination="Aqc-Zr-wxr" kind="relationship" relationship="viewControllers" id="qst-Qa-KIQ"/>
                        <segue destination="XyS-H7-wRd" kind="relationship" relationship="viewControllers" id="dZb-aa-FZd"/>
                    </connections>
                </tabBarController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="iJp-75-dO7" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="-370" y="1000"/>
        </scene>
        <!--Acknowledgements-->
        <scene sceneID="Fu4-Xg-VqK">
            <objects>
                <viewController title="Acknowledgements" id="XyS-H7-wRd" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="Cl1-q4-umi"/>
                        <viewControllerLayoutGuide type="bottom" id="4UX-Pj-Oe1"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="za1-0o-Q3C">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" editable="NO" usesAttributedText="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wh2-vh-DhE">
                                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                <attributedString key="attributedText">
                                    <fragment>
                                        <string key="content">The following sets forth attribution notices for third party software that may be contained in portions of this product.

---
The following software or parts of it may be included in this product: </string>
                                        <attributes>
                                            <font key="NSFont" metaFont="system" size="10"/>
                                            <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
                                        </attributes>
                                    </fragment>
                                    <fragment>
                                        <string key="content" base64-UTF8="YES">
Cg
</string>
                                        <attributes>
                                            <font key="NSFont" size="10" name="HelveticaNeue"/>
                                            <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
                                        </attributes>
                                    </fragment>
                                    <fragment>
                                        <string key="content" base64-UTF8="YES">
Cg
</string>
                                        <attributes>
                                            <font key="NSFont" size="10" name="HelveticaNeue"/>
                                            <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
                                                <tabStops>
                                                    <textTab alignment="left" location="28">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="56">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="84">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="112">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="140">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="168">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="196">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="224">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="252">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="280">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="308">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="336">
                                                        <options/>
                                                    </textTab>
                                                </tabStops>
                                            </paragraphStyle>
                                        </attributes>
                                    </fragment>
                                    <fragment content="CryptoSwift">
                                        <attributes>
                                            <font key="NSFont" size="12" name=".AppleSystemUIFont"/>
                                            <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
                                        </attributes>
                                    </fragment>
                                    <fragment>
                                        <string key="content" base64-UTF8="YES">
Cg
</string>
                                        <attributes>
                                            <font key="NSFont" size="10" name="HelveticaNeue"/>
                                            <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
                                        </attributes>
                                    </fragment>
                                    <fragment>
                                        <string key="content" base64-UTF8="YES">
Cg
</string>
                                        <attributes>
                                            <font key="NSFont" size="10" name="HelveticaNeue"/>
                                            <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
                                                <tabStops>
                                                    <textTab alignment="left" location="28">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="56">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="84">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="112">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="140">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="168">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="196">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="224">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="252">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="280">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="308">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="336">
                                                        <options/>
                                                    </textTab>
                                                </tabStops>
                                            </paragraphStyle>
                                        </attributes>
                                    </fragment>
                                    <fragment>
                                        <mutableString key="content">see https://github.com/krzyzanowskim/CryptoSwift

Copyright (C) 2014 Marcin Krzyżanowski &lt;marcin.krzyzanowski@gmail.com&gt;
This software is provided 'as-is', without any express or implied warranty. 

In no event will the authors be held liable for any damages arising from the use of this software. 

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

- 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.
- Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
- This notice may not be removed or altered from any source or binary distribution.


---
The following software or parts of it may be included in this product: </mutableString>
                                        <attributes>
                                            <font key="NSFont" metaFont="system" size="10"/>
                                            <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
                                        </attributes>
                                    </fragment>
                                    <fragment>
                                        <string key="content" base64-UTF8="YES">
Cg
</string>
                                        <attributes>
                                            <font key="NSFont" size="10" name="HelveticaNeue"/>
                                            <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
                                        </attributes>
                                    </fragment>
                                    <fragment>
                                        <string key="content" base64-UTF8="YES">
Cg
</string>
                                        <attributes>
                                            <font key="NSFont" size="10" name="HelveticaNeue"/>
                                            <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
                                                <tabStops>
                                                    <textTab alignment="left" location="28">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="56">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="84">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="112">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="140">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="168">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="196">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="224">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="252">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="280">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="308">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="336">
                                                        <options/>
                                                    </textTab>
                                                </tabStops>
                                            </paragraphStyle>
                                        </attributes>
                                    </fragment>
                                    <fragment content="RFduinoUBP">
                                        <attributes>
                                            <font key="NSFont" size="12" name=".SFNSText"/>
                                            <font key="NSOriginalFont" size="12" name=".SFNSText"/>
                                            <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
                                        </attributes>
                                    </fragment>
                                    <fragment>
                                        <string key="content" base64-UTF8="YES">
Cg
</string>
                                        <attributes>
                                            <font key="NSFont" size="10" name="HelveticaNeue"/>
                                            <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
                                        </attributes>
                                    </fragment>
                                    <fragment>
                                        <string key="content" base64-UTF8="YES">
Cg
</string>
                                        <attributes>
                                            <font key="NSFont" size="10" name="HelveticaNeue"/>
                                            <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
                                                <tabStops>
                                                    <textTab alignment="left" location="28">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="56">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="84">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="112">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="140">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="168">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="196">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="224">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="252">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="280">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="308">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="336">
                                                        <options/>
                                                    </textTab>
                                                </tabStops>
                                            </paragraphStyle>
                                        </attributes>
                                    </fragment>
                                    <fragment>
                                        <mutableString key="content">see https://github.com/cconway/RFduinoUBP

The MIT License (MIT)

Copyright (c) 2015 cconway

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. ---
The following software or parts of it may be included in this product: RFduinoUBP, see https://github.com/cconway/RFduinoUBP


---
The following software or parts of it may be included in this product: </mutableString>
                                        <attributes>
                                            <font key="NSFont" metaFont="system" size="10"/>
                                            <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
                                        </attributes>
                                    </fragment>
                                    <fragment>
                                        <string key="content" base64-UTF8="YES">
Cg
</string>
                                        <attributes>
                                            <font key="NSFont" size="10" name="HelveticaNeue"/>
                                            <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
                                        </attributes>
                                    </fragment>
                                    <fragment>
                                        <string key="content" base64-UTF8="YES">
Cg
</string>
                                        <attributes>
                                            <font key="NSFont" size="10" name="HelveticaNeue"/>
                                            <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
                                                <tabStops>
                                                    <textTab alignment="left" location="28">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="56">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="84">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="112">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="140">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="168">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="196">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="224">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="252">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="280">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="308">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="336">
                                                        <options/>
                                                    </textTab>
                                                </tabStops>
                                            </paragraphStyle>
                                        </attributes>
                                    </fragment>
                                    <fragment content="Charts">
                                        <attributes>
                                            <font key="NSFont" size="12" name=".AppleSystemUIFont"/>
                                            <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
                                        </attributes>
                                    </fragment>
                                    <fragment>
                                        <string key="content" base64-UTF8="YES">
Cg
</string>
                                        <attributes>
                                            <font key="NSFont" size="10" name="HelveticaNeue"/>
                                            <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
                                        </attributes>
                                    </fragment>
                                    <fragment>
                                        <string key="content" base64-UTF8="YES">
Cg
</string>
                                        <attributes>
                                            <font key="NSFont" size="10" name="HelveticaNeue"/>
                                            <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
                                                <tabStops>
                                                    <textTab alignment="left" location="28">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="56">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="84">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="112">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="140">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="168">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="196">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="224">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="252">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="280">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="308">
                                                        <options/>
                                                    </textTab>
                                                    <textTab alignment="left" location="336">
                                                        <options/>
                                                    </textTab>
                                                </tabStops>
                                            </paragraphStyle>
                                        </attributes>
                                    </fragment>
                                    <fragment>
                                        <mutableString key="content">see hhttps://github.com/danielgindi/Charts

  Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "{}"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright {yyyy} {name of copyright owner}

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

</mutableString>
                                        <attributes>
                                            <font key="NSFont" metaFont="system" size="10"/>
                                            <paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
                                        </attributes>
                                    </fragment>
                                </attributedString>
                                <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
                            </textView>
                        </subviews>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                        <constraints>
                            <constraint firstItem="wh2-vh-DhE" firstAttribute="width" secondItem="za1-0o-Q3C" secondAttribute="width" id="00F-ce-7sG"/>
                            <constraint firstItem="wh2-vh-DhE" firstAttribute="top" secondItem="Cl1-q4-umi" secondAttribute="bottom" constant="8" symbolic="YES" id="dqZ-N9-a7w"/>
                            <constraint firstItem="wh2-vh-DhE" firstAttribute="centerX" secondItem="za1-0o-Q3C" secondAttribute="centerX" id="dxA-Vz-5Lr"/>
                            <constraint firstItem="wh2-vh-DhE" firstAttribute="height" secondItem="za1-0o-Q3C" secondAttribute="height" id="e5W-L2-DD4"/>
                        </constraints>
                    </view>
                    <tabBarItem key="tabBarItem" title="Aknwoledgements" id="cqu-02-OO6"/>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="KsD-cc-ZmE" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="410" y="1751"/>
        </scene>
        <!--Navigation Controller-->
        <scene sceneID="PcD-8F-rWp">
            <objects>
                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="RRb-Vb-fEk" sceneMemberID="viewController">
                    <toolbarItems/>
                    <navigationBar key="navigationBar" contentMode="scaleToFill" id="TeE-cz-f4e">
                        <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
                        <autoresizingMask key="autoresizingMask"/>
                    </navigationBar>
                    <nil name="viewControllers"/>
                    <connections>
                        <segue destination="p1I-y2-sJ2" kind="relationship" relationship="rootViewController" id="8ew-YJ-gwy"/>
                    </connections>
                </navigationController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="eNH-XW-Zjn" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="2031" y="1000"/>
        </scene>
    </scenes>
</document>


================================================
FILE: LibreMonitor/Model/CRC.swift
================================================
//
//  CRC.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 26.07.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//
//
//  Part of this code is taken from
//  CRC.swift
//  CryptoSwift
//
//  Created by Marcin Krzyzanowski on 25/08/14.
//  Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
//

import Foundation

final class Crc {
    /// Table of precalculated crc16 values
    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]




    /// Calculates crc16. Taken from https://github.com/krzyzanowskim/CryptoSwift with modifications (reversing and byte swapping) to adjust for crc as used by Freestyle Libre
    ///
    /// - parameter message: Array of bytes for which the crc is to be calculated
    /// - parameter seed:    seed for crc
    ///
    /// - returns: crc16
    static func crc16(_ message:[UInt8], seed: UInt16? = nil) -> UInt16 {
        var crc: UInt16 = seed != nil ? seed! : 0x0000
        
        // calculate crc
        for chunk in BytesSequence(chunkSize: 256, data: message) {
            for b in chunk {
                crc = (crc >> 8) ^ crc16table[Int((crc ^ UInt16(b)) & 0xFF)]
            }
        }
        
        // reverse the bits (modification by Uwe Petersen, 2016-06-059
        var reverseCrc = UInt16(0)
        for _ in 0..<16 {
            reverseCrc = reverseCrc << 1 | crc & 1
            crc >>= 1
        }
        
        // swap bytes and return (modification by Uwe Petersen, 2016-06-059
        return reverseCrc.byteSwapped
    }


    /// Checks crc for an array of bytes.
    ///
    /// 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.
    ///
    /// - parameter bytes: Array of bytes with a crc in the first two bytes
    ///
    /// - returns: true if crc is valid
    static func hasValidCrc16InFirstTwoBytes(_ bytes: [UInt8]) -> Bool {
        
        print(Array(bytes.dropFirst(2)))
        let calculatedCrc = Crc.crc16(Array(bytes.dropFirst(2)), seed: 0xffff)
        let enclosedCrc =  (UInt16(bytes[0]) << 8) | UInt16(bytes[1])
        
//        print(String(format: "Calculated crc is %X and enclosed crc is %x", arguments: [calculatedCrc, enclosedCrc]))
        
        return calculatedCrc == enclosedCrc
    }
    
}

/// Struct BytesSequence, taken from https://github.com/krzyzanowskim/CryptoSwift
struct BytesSequence: Sequence {
    let chunkSize: Int
    let data: Array<UInt8>
    
    func makeIterator() -> AnyIterator<ArraySlice<UInt8>> {
        
        var offset:Int = 0
        
        return AnyIterator {
            let end = Swift.min(self.chunkSize, self.data.count - offset)
            let result = self.data[offset..<offset + end]
            offset += result.count
            return !result.isEmpty ? result : nil
        }
    }
}


================================================
FILE: LibreMonitor/Model/LibreSensor.swift
================================================
//
//  LibreSensor.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 15.05.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation

class LibreSensor {
    
    var uid: String
    
    lazy var serialNumber: String = {
        
        // The serial number of the sensor can be derived from its uid.
        //
        // The numbers an letters of the serial number are coded a compressed scheme that uses only 32 numbers and letters,
        // by omitting the letters B, I, O and S. This information is stored in consecutive units of five bits.
        //
        // The encding thus is as follows:
        //   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
        //   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
        //
        // Example:
        //    Uid is E0 07 A0 00 00 25 90 5E, and the corresponding serial number is "0M00009DHCR"
        //           \   / \              /
        //            -+-   -----+--------
        //             |         |
        //             |         +-- This part encodes the serial number, see below
        //             +-- Standard first two bytes, where 0x07 is the code for "Texas Instruments Tag-it™", see https://en.wikipedia.org/wiki/ISO/IEC_15693
        //
        //   1.) Convert the part without E007, i.e. A0 00 00 25 90 5E to binary representation
        //
        //            A    0     0    0     0    0     2    5     9    0     5    E
        //          1010 0000  0000 0000  0000 0000  0010 0101  1001 0000  0101 1110
        //
        //   2.) Split this binary array in units of five bits length from the beginning and pad with two zeros at the end and
        //       calculate the corresponding integer and retreive the corresponding char from the table above
        //
        //     +--  1010 0000  0000 0000  0000 0000  0010 0101  1001 0000  0101 1110   + 00
        //     |
        //     +->  10100 00000 00000 00000 00000 01001 01100 10000 01011 11000
        //            |     |     |     |     |     |     |     |     |     |
        //            |     |     |     |     |     |     |     |     |     +- = 24 -> "R"
        //            |     |     |     |     |     |     |     |     +------- = 11 -> "C"
        //            |     |     |     |     |     |     |     +------------- = 16 -> "H"
        //            |     |     |     |     |     |     +------------------- = 12 -> "D"
        //            |     |     |     |     |     +------------------------- =  9 -> "9"
        //            |     |     |     |     +------------------------------- =  0 -> "0"
        //            |     |     |     +------------------------------------- =  0 -> "0"
        //            |     |     +------------------------------------------- =  0 -> "0"
        //            |     +------------------------------------------------- =  0 -> "0"
        //            +------------------------------------------------------- = 20 -> "M"
        //
        //   3.) Prepend "0" at the beginning an thus receive "0M00009DHCR"
        
        
        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"]
        let uidString = self.uid.substring(from: self.uid.characters.index(self.uid.startIndex, offsetBy: 4)) // "E007A0000025905E" -> "A0000025905E"
        
        var serialNumber = ""
        
        guard uidString.lengthOfBytes(using: String.Encoding.ascii) == 12,
            let uidAsInt = Int(uidString, radix: 16) // "A0000025905E"  -> 175921862905950
            else {return ""}
        
        let uidAsBinaryString = String(uidAsInt, radix: 2) + "00"  // -> "10100000000000000000000000100101100100000101111000"
        let length = uidAsBinaryString.lengthOfBytes(using: String.Encoding.ascii)
        
        for index in stride(from: 0, to: length, by: 5) {
            if index + 4 < length {
                let startIndex = uidAsBinaryString.startIndex
                let leftIndex = uidAsBinaryString.index(startIndex, offsetBy: index)
                let rightIndex = uidAsBinaryString.index(startIndex, offsetBy: index+5)
                let range = leftIndex..<rightIndex
                let fiveBits = uidAsBinaryString.substring(with: range)
                
                if let theInt = Int(fiveBits, radix: 2) , theInt >= 0 && theInt < lookupTable.count {
                    serialNumber += lookupTable[theInt] // "10100" -> 20 -> "M"
                }
            }
        }
        serialNumber = "0" + serialNumber  // "M00009DHCR" -> "0M00009DHCR"
        return serialNumber
    }()
    
    lazy var prettyUid: String = {
        
        var prettyUid = self.uid
        let length = self.uid.lengthOfBytes(using: String.Encoding.ascii)
        for index in stride(from: 2, to: length, by: 2).reversed() {
            prettyUid.insert(Character(":"), at: prettyUid.characters.index(prettyUid.startIndex, offsetBy: index))
        }
        return prettyUid
    }()
    
    
    init(withUID uid: String) {
        self.uid = uid
    }
    
}


================================================
FILE: LibreMonitor/Model/Measurement.swift
================================================
//
//  Measurement.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 25.08.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation


/// Structure for one glucose measurement including value, date and raw data bytes
struct Measurement {
    /// The date for this measurement
    let date: Date
    /// The bytes as read from the sensor. All data is derived from this \"raw data"
    let bytes: [UInt8]
    /// The bytes as String
    let byteString: String
    /// The raw value as read from the sensor
    let rawValue: Int
    /// slope to calculate glucose from raw value in (mg/dl)/raw
    let slope: Double
    /// glucose offset to be added in mg/dl
    let offset: Double
    /// The glucose value in mg/dl
    let glucose: Double
    /// Initialize a new glucose measurement
    ///
    /// - parameter bytes:  raw data bytes as read from the sensor
    /// - parameter slope:  slope to calculate glucose from raw value in (mg/dl)/raw
    /// - parameter offset: glucose offset to be added in mg/dl
    /// - parameter date:   date of the measurement
    ///
    /// - returns: Measurement
    init(bytes: [UInt8], slope: Double = 0.1, offset: Double = 0.0, date: Date) {
        self.bytes = bytes
        self.byteString = bytes.reduce("", {$0 + String(format: "%02X", arguments: [$1])})
        self.rawValue = (Int(bytes[1]) << 8) & 0x0F00 + Int(bytes[0])
        self.slope = slope
        self.offset = offset
        self.glucose = offset + slope * Double(rawValue)
        self.date = date
    }
    var description: String {
        return String("Glucose: \(glucose) (mg/dl), date:  \(date), slope: \(slope), offset: \(offset),rawValue: \(rawValue), bytes: \(bytes)" )
    }
}


================================================
FILE: LibreMonitor/Model/SensorData.swift
================================================
//
//  SensorData
//  LibreMonitor
//
//  Created by Uwe Petersen on 26.07.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation


/// Structure for data from Freestyle Libre sensor
/// To be initialized with the bytes as read via nfc. Provides all derived data.
struct SensorData {
    
    /// 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)
    let numberOfBytes = 344 // Header and body and footer of Freestyle Libre data (i.e. 40 blocks of 8 bytes)
    /// Array of 344 bytes as read via nfc
    let bytes: [UInt8]
    /// Subarray of 24 header bytes
    let header: [UInt8]
    /// Subarray of 296 body bytes
    let body: [UInt8]
    /// Subarray of 24 footer bytes
    let footer: [UInt8]
    /// Date when data was read from sensor
    let date: Date
    /// Minutes (approx) since start of sensor
    let minutesSinceStart: Int
    /// Index on the next block of trend data that the sensor will measure and store
    let nextTrendBlock: Int
    /// Index on the next block of history data that the sensor will create from trend data and store
    let nextHistoryBlock: Int
    /// true if the header crc, stored in the first two bytes, is equal to the calculated crc
    var hasValidHeaderCRC: Bool {
        return Crc.hasValidCrc16InFirstTwoBytes(header)
    }
    /// true if the body crc, stored in the first two bytes, is equal to the calculated crc
    var hasValidBodyCRC: Bool {
        return Crc.hasValidCrc16InFirstTwoBytes(body)
    }
    /// true if the footer crc, stored in the first two bytes, is equal to the calculated crc
    var hasValidFooterCRC: Bool {
        return Crc.hasValidCrc16InFirstTwoBytes(footer)
    }
    
    /// Sensor state (ready, failure, starting etc.)
    var state: SensorState {
        switch header[4] {
        case 01:
            return SensorState.notYetStarted
        case 02:
            return SensorState.starting
        case 03:
            return SensorState.ready
        case 04:
            return SensorState.expired
        case 05:
            return SensorState.shutdown
        case 06:
            return SensorState.failure
        default:
            return SensorState.unknown
        }
    }
    
    
    init?(bytes: [UInt8], date: Date = Date()) {
        guard bytes.count == numberOfBytes else {
            return nil
        }
        self.bytes = bytes
        self.date = date
        
        let headerRange =   0..<24   //  24 bytes, i.e.  3 blocks a 8 bytes
        let bodyRange   =  24..<320  // 296 bytes, i.e. 37 blocks a 8 bytes
        let footerRange = 320..<344  //  24 bytes, i.e.  3 blocks a 8 bytes
        
        self.header = Array(bytes[headerRange])
        self.body   = Array(bytes[bodyRange])
        self.footer = Array(bytes[footerRange])
        
        self.nextTrendBlock = Int(body[2])
        self.nextHistoryBlock = Int(body[3])
        self.minutesSinceStart = Int(body[293]) << 8 + Int(body[292])
    }

    
    /// Get array of 16 trend glucose measurements. 
    /// 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.
    ///
    /// - parameter offset: offset in mg/dl that is added
    /// - parameter slope:  slope in (mg/dl)/ raw
    ///
    /// - returns: Array of Measurements
    func trendMeasurements(_ offset: Double = 0.0, slope: Double = 0.1) -> [Measurement] {
        var measurements = [Measurement]()
        
        // 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.
        for blockIndex in 0...15 {
            
            var index = 4 + (nextTrendBlock - 1 - blockIndex) * 6 // runs backwards
            if index < 4 {
                index = index + 96 // if end of ring buffer is reached shift to beginning of ring buffer
            }
            
            let range = index..<index+6
            let measurementBytes = Array(body[range])
            let measurementDate = date.addingTimeInterval(Double(-60 * blockIndex))
            
            let measurement = Measurement(bytes: measurementBytes, slope: slope, offset: offset, date: measurementDate)
            
            measurements.append(measurement)
        }
        return measurements
    }
    
    
    /// Get array of 32 history glucose measurements. 
    /// 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, ... .
    ///
    /// - parameter offset: offset in mg/dl that is added
    /// - parameter slope:  slope in (mg/dl)/ raw
    ///
    /// - returns: Array of Measurements
    func historyMeasurements(_ offset: Double = 0.0, slope: Double = 0.1) -> [Measurement] {
      
        let mostRecentHistoryDate = date.addingTimeInterval( 60.0 * -Double( (minutesSinceStart - 3) % 15 + 3 ) )
        var measurements = [Measurement]()
        // 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.
        for blockIndex in 0..<32 {
            
            var index = 100 + (nextHistoryBlock - 1 - blockIndex) * 6 // runs backwards
            if index < 100 {
                index = index + 192 // if end of ring buffer is reached shift to beginning of ring buffer
            }
            
            let range = index..<index+6
            let measurementBytes = Array(body[range])
            let measurementDate = mostRecentHistoryDate.addingTimeInterval(Double(-900 * blockIndex)) // 900 = 60 * 15
            
            let measurement = Measurement(bytes: measurementBytes, slope: slope, offset: offset, date: measurementDate)
            
            measurements.append(measurement)
        }
        return measurements
    }
    

}





================================================
FILE: LibreMonitor/Model/SensorState.swift
================================================
//
//  SensorState.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 31.07.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation

/// State of the freestyle libre sensor
///
/// - notYetStarted: 0x01 sensor not yet started
/// - starting:      0x02 sensor is in the starting phase
/// - ready:         0x03 sensor is ready, i.e. in normal operation mode
/// - stateFour:     0x04 state with yet unknown meaning
/// - expired:       0x05 sensor is expired
/// - failure:       0x06 sensor has an error
/// - unknown:       any other state
enum SensorState {
    case notYetStarted
    case starting
    case ready
    case expired
    case shutdown
    case failure
    case unknown
    
    init(){
        self = .unknown
    }
    
    var description: String {
        switch self {
        case .notYetStarted:
            return "Sensor not yet startet"
        case .starting:
            return "Sensor in starting phase"
        case .ready:
            return "Sensor is ready"
        case .expired:
            return "Sensor is expired"
        case .shutdown:
            return "Sensor is shut down"
        case .failure:
            return "Sensor has failure"
        default:
            return "Unknown sensor state"
        }
    }
}


================================================
FILE: LibreMonitor/ModelCoreData/BloodGlucose+CoreDataClass.swift
================================================
//
//  BloodGlucose+CoreDataClass.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 09.10.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation
import CoreData


public class BloodGlucose: NSManagedObject {

}


================================================
FILE: LibreMonitor/ModelCoreData/BloodGlucose+CoreDataProperties.swift
================================================
//
//  BloodGlucose+CoreDataProperties.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 09.10.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation
import CoreData

extension BloodGlucose {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<BloodGlucose> {
        return NSFetchRequest<BloodGlucose>(entityName: "BloodGlucose");
    }

    @NSManaged public var bytes: String?
    @NSManaged public var dateString: String?
    @NSManaged public var id: Int32
    @NSManaged public var type: Int16
    @NSManaged public var value: Double
    @NSManaged public var date: NSDate?
    @NSManaged public var sensor: Sensor?

}


================================================
FILE: LibreMonitor/ModelCoreData/CoreDataStack.swift
================================================
//
//  CoreDataStack.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 13.04.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation
import UIKit
import CoreData

class CoreDataStack: NSObject {
    
//    var managedObjectContext: NSManagedObjectContext
    
    override init() {
    }
//    override init() {
//        
//        // This resource is the same name as your xcdatamodeld contained in your project.
//        guard let modelURL = NSBundle.mainBundle().URLForResource("DataModel", withExtension:"momd") else {
//            fatalError("Error loading model from bundle")
//        }
//        
//        // 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.
//        guard let mom = NSManagedObjectModel(contentsOfURL: modelURL) else {
//            fatalError("Error initializing mom from: \(modelURL)")
//        }
//        
//        let psc = NSPersistentStoreCoordinator(managedObjectModel: mom)
//        
//        managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
//        managedObjectContext.persistentStoreCoordinator = psc
//        
//        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
//            let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
//            let docURL = urls[urls.endIndex-1]
//            /* The directory the application uses to store the Core Data store file.
//             This code uses a file named "DataModel.sqlite" in the application's documents directory.
//             */
//            let storeURL = docURL.URLByAppendingPathComponent("DataModel.sqlite")
//            do {
//                try psc.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: nil)
//            } catch {
//                fatalError("Error migrating store: \(error)")
//            }
//        }
//    }
    
    
    lazy var applicationDocumentsDirectory: URL = {
        // 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.
        var urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        return urls[urls.count-1]
    }()
    
    lazy var managedObjectModel: NSManagedObjectModel = {
        // 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.
        let modelURL = Bundle.main.url(forResource: "LibreMonitor", withExtension: "momd")!
        return NSManagedObjectModel(contentsOf: modelURL)!
    }()
    
    lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
        // 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.
        // Create the coordinator and store
        let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
        let url = self.applicationDocumentsDirectory.appendingPathComponent("SingleViewCoreData.sqlite")
        var failureReason = "There was an error creating or loading the application's saved data."
        do {
            try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: nil)
        } catch {
            // Report any error we got.
            var dict = [String: AnyObject]()
            dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data" as AnyObject?
            dict[NSLocalizedFailureReasonErrorKey] = failureReason as AnyObject?
            
            dict[NSUnderlyingErrorKey] = error as NSError
            let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
            // Replace this with code to handle the error appropriately.
            // 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.
            NSLog("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
            abort()
        }
        
        return coordinator
    }()
    
    lazy var managedObjectContext: NSManagedObjectContext = {
        // 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.
        let coordinator = self.persistentStoreCoordinator
        var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
        managedObjectContext.persistentStoreCoordinator = coordinator
        return managedObjectContext
    }()
    
    // MARK: - Core Data Saving support
    
    func saveContext () {
        if managedObjectContext.hasChanges {
            do {
                try managedObjectContext.save()
            } catch {
                // Replace this implementation with code to handle the error appropriately.
                // 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.
                let nserror = error as NSError
                NSLog("Unresolved error \(nserror), \(nserror.userInfo)")
                abort()
            }
        }
    }
    
}


================================================
FILE: LibreMonitor/ModelCoreData/HeaderData+CoreDataClass.swift
================================================
//
//  HeaderData+CoreDataClass.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 09.10.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation
import CoreData

@objc(HeaderData)
public class HeaderData: NSManagedObject {

}


================================================
FILE: LibreMonitor/ModelCoreData/HeaderData+CoreDataProperties.swift
================================================
//
//  HeaderData+CoreDataProperties.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 09.10.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation
import CoreData


extension HeaderData {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<HeaderData> {
        return NSFetchRequest<HeaderData>(entityName: "HeaderData");
    }

    @NSManaged public var bytes: String?
    @NSManaged public var date: NSDate?

}


================================================
FILE: LibreMonitor/ModelCoreData/Reader+CoreDataClass.swift
================================================
//
//  Reader+CoreDataClass.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 09.10.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation
import CoreData


public class Reader: NSManagedObject {

}


================================================
FILE: LibreMonitor/ModelCoreData/Reader+CoreDataProperties.swift
================================================
//
//  Reader+CoreDataProperties.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 09.10.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation
import CoreData


extension Reader {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Reader> {
        return NSFetchRequest<Reader>(entityName: "Reader");
    }

    @NSManaged public var batteryVoltage: Double
    @NSManaged public var temperature: Double
    @NSManaged public var uid: String?

}


================================================
FILE: LibreMonitor/ModelCoreData/Sensor+CoreDataClass.swift
================================================
//
//  Sensor+CoreDataClass.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 09.10.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation
import CoreData


public class Sensor: NSManagedObject {

}


================================================
FILE: LibreMonitor/ModelCoreData/Sensor+CoreDataProperties.swift
================================================
//
//  Sensor+CoreDataProperties.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 09.10.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation
import CoreData

extension Sensor {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Sensor> {
        return NSFetchRequest<Sensor>(entityName: "Sensor");
    }

    @NSManaged public var startDate: NSDate?
    @NSManaged public var uid: String?
    @NSManaged public var lastScanDate: NSDate?
    @NSManaged public var minutesSinceStart: Int32
    @NSManaged public var bloodGlucose: NSSet?

}

// MARK: Generated accessors for bloodGlucose
extension Sensor {

    @objc(addBloodGlucoseObject:)
    @NSManaged public func addToBloodGlucose(_ value: BloodGlucose)

    @objc(removeBloodGlucoseObject:)
    @NSManaged public func removeFromBloodGlucose(_ value: BloodGlucose)

    @objc(addBloodGlucose:)
    @NSManaged public func addToBloodGlucose(_ values: NSSet)

    @objc(removeBloodGlucose:)
    @NSManaged public func removeFromBloodGlucose(_ values: NSSet)

}


================================================
FILE: LibreMonitor/Reader+CoreDataClass.swift
================================================
//
//  Reader+CoreDataClass.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 14.10.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation
import CoreData


public class Reader: NSManagedObject {

}


================================================
FILE: LibreMonitor/Reader+CoreDataProperties.swift
================================================
//
//  Reader+CoreDataProperties.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 14.10.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation
import CoreData


extension Reader {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Reader> {
        return NSFetchRequest<Reader>(entityName: "Reader");
    }

    @NSManaged public var batteryVoltage: Double
    @NSManaged public var temperature: Double
    @NSManaged public var uid: String?

}


================================================
FILE: LibreMonitor/Sensor+CoreDataClass.swift
================================================
//
//  Sensor+CoreDataClass.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 14.10.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation
import CoreData


public class Sensor: NSManagedObject {

}


================================================
FILE: LibreMonitor/Sensor+CoreDataProperties.swift
================================================
//
//  Sensor+CoreDataProperties.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 14.10.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation
import CoreData 

extension Sensor {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Sensor> {
        return NSFetchRequest<Sensor>(entityName: "Sensor");
    }

    @NSManaged public var lastScanDate: NSDate?
    @NSManaged public var minutesSinceStart: Int32
    @NSManaged public var startDate: NSDate?
    @NSManaged public var uid: String?
    @NSManaged public var bloodGlucose: NSSet?

}

// MARK: Generated accessors for bloodGlucose
extension Sensor {

    @objc(addBloodGlucoseObject:)
    @NSManaged public func addToBloodGlucose(_ value: BloodGlucose)

    @objc(removeBloodGlucoseObject:)
    @NSManaged public func removeFromBloodGlucose(_ value: BloodGlucose)

    @objc(addBloodGlucose:)
    @NSManaged public func addToBloodGlucose(_ values: NSSet)

    @objc(removeBloodGlucose:)
    @NSManaged public func removeFromBloodGlucose(_ values: NSSet)

}


================================================
FILE: LibreMonitor/SimbleeCode/crc8.h
================================================
// LICENSES: [077915]
// -----------------------------------
// The contents of this file contains the aggregate of contributions
//   covered under one or more licences. The full text of those licenses
//   can be found in the "LICENSES" file at the top level of this project
//   identified by the MD5 fingerprints listed above.
//
// Uwe Petersen: Modified version to test transmission part in iOS



#import <Foundation/Foundation.h>

typedef uint8_t byte;


byte CRC8(void *data_in, byte number_of_bytes_to_read);


================================================
FILE: LibreMonitor/SimbleeCode/crc8.m
================================================
// LICENSES: [077915]
// -----------------------------------
// The contents of this file contains the aggregate of contributions
//   covered under one or more licences. The full text of those licenses
//   can be found in the "LICENSES" file at the top level of this project
//   identified by the MD5 fingerprints listed above.
//
//
// Uwe Petersen: Modified version to test transmission part in iOS


#include "crc8.h"

#define CRC8INIT  0x00
#define CRC8POLY  0x18      // 0X18 = X^8+X^5+X^4+X^0

byte CRC8(void *bytes, byte number_of_bytes_to_read) {
    
    byte *data_in = (byte*) bytes;
    byte  crc;
    uint16_t loop_count;
    byte  bit_counter;
    byte  data;
    byte  feedback_bit;
    
    crc = CRC8INIT;
    
    for (loop_count = 0; loop_count != number_of_bytes_to_read; loop_count++)
    {
        data = data_in[loop_count];
        
        bit_counter = 8;
        do {
            feedback_bit = (crc ^ data) & 0x01;
            
            if ( feedback_bit == 0x01 ) {
                crc = crc ^ CRC8POLY;
            }
            crc = (crc >> 1) & 0x7F;
            if ( feedback_bit == 0x01 ) {
                crc = crc | 0x80;
            }
            
            data = data >> 1;
            bit_counter--;
            
        } while (bit_counter > 0);
    }
    
    return crc;
}



================================================
FILE: LibreMonitor/SimbleeCode/libUBP.h
================================================
//
// Uwe Petersen: Modified version to test transmission part in iOS

#import <Foundation/Foundation.h>

typedef uint8_t byte;


#ifndef libUBP_h
#define libUBP_h
#endif


typedef enum {
    
    UBP_TxFlagNone = 0 << 0,
    UBP_TxFlagIsRPC = 1 << 0,
    UBP_TxFlagRequiresACK = 1 << 1
    
} UBP_TxFlags;


// Public

void UBP_pump();
bool UBP_queuePacketTransmission(unsigned short packetIdentifier, UBP_TxFlags txFlags, const char *packetBytes, unsigned short byteCount);

//bool UBP_isBusy();

// 2016-06-26: Needed for tests
void getTxBuffer(char *txBuffer, int *txBufferLength);
void SimbleeBLE_onConnect();
void SimbleeBLE_onDisconnect();




// Private

void _UBP_pumpTxQueue();

//void _UBP_ingestRxBytes(char *receivedBytes, int byteCount);

int _UBP_makeEscapedCopy(const char *inputBuffer, unsigned short inputBufferLength, char *outputBuffer, unsigned short outputBufferLength);

int _UBP_makeUnEscapedCopy(const char *inputBuffer, unsigned short inputBufferLength, char *outputBuffer);

void _UBP_hostDisconnected();


// To be implemented by end-user externally
//extern void UBP_incomingChecksumFailed() __attribute__((weak));

//extern void UBP_receivedPacket(unsigned short packetIdentifier, UBP_TxFlags txFlags, void *packetBuffer) __attribute__((weak));

//extern void UBP_didAdvertise(bool start) __attribute__((weak));

//extern void UBP_didConnect() __attribute__((weak));

//extern void UBP_didDisconnect() __attribute__((weak));




================================================
FILE: LibreMonitor/SimbleeCode/libUBP.m
================================================
//
// Uwe Petersen: Modified version to test transmission part in iOS

#import "libUBP.h"
#import "crc8.h"

// Build-time configurations
//#define BUFFER_LENGTH 64 // Uwe changed this on 2016-01-04
#define BUFFER_LENGTH 400 // Uwe changed this on 2016-07-24
#define TX_CHUNK_SIZE 20
#define PACKET_ID_SIZE 2

// Serial Line IP (SLIP) escaping constants
#define ESCAPE_BYTE 0xDB
#define END_BYTE    0xC0
#define ESCAPED_ESCAPE_BYTE 0xDD
#define ESCAPED_END_BYTE    0xDC
const char escapeSequence_[1] = {ESCAPE_BYTE};
const char endSequence_[1] = {END_BYTE};
const char escapedEndSequence_[2] = {ESCAPE_BYTE, ESCAPED_END_BYTE};
const char escapedEscapeSequence_[2] = {ESCAPE_BYTE, ESCAPED_ESCAPE_BYTE};

// Buffers
char ubpTxBuffer[BUFFER_LENGTH];
int ubpTxBufferLength = 0;
int ubpTxBufferSentByteCount = 0;
char ubpRxBuffer[BUFFER_LENGTH];
int ubpRxBufferLength = 0;
char ubpUnescapedRxBufferBuffer[BUFFER_LENGTH];
int ubpUnescapedRxBufferBufferLength = 0;

// State Variables
bool UBP_isTxPending = false;
bool hostIsConnected = true;
//bool hostIsConnected = false;

// 2016-06-27: for testing purposes simulate simblee
char simbleeBuffer[BUFFER_LENGTH];
int simbleeBufferLength = 0;

/*
// Functions
bool UBP_isBusy() {
    
    return UBP_isTxPending;
}
 */
void UBP_pump() {
    
    _UBP_pumpTxQueue();
}


void _UBP_pumpTxQueue() {
    
    if (UBP_isTxPending) {
        
        char *nextByteToSend = ubpTxBuffer + ubpTxBufferSentByteCount;
        
        // Try sending the next chunk
        if (ubpTxBufferSentByteCount < ubpTxBufferLength && hostIsConnected) {  // Haven't already sent all the bytes
            
            int retryRemainingCount = 1000;  // Limit the number of times we retry sending to avoid getting into an infinite loop
            int remainingByteCount = ubpTxBufferLength - ubpTxBufferSentByteCount;
            
            if (remainingByteCount >= TX_CHUNK_SIZE) {  // Can fill the TX output buffer
                
                // Send is queued (the ble stack delays send to the start of the next tx window)
                while (hostIsConnected && retryRemainingCount > 0) {
                    retryRemainingCount--;
                };
                // 2016-06-27: This changed to the above to enable testing
                // while ( SimbleeBLE.send(nextByteToSend, TX_CHUNK_SIZE) == false && hostIsConnected && retryRemainingCount > 0) {
                //         retryRemainingCount--;
                // };  // send() returns false if all tx buffers in use (can't enqueue, try again later)
                
                ubpTxBufferSentByteCount += TX_CHUNK_SIZE;
                
            } else {  // Only partial TX buffer remaining to send
                
                // Send is queued (the ble stack delays send to the start of the next tx window)
                while ( hostIsConnected && retryRemainingCount > 0) {
                    retryRemainingCount--;
                };  // send() returns false if all tx buffers in use (can't enqueue, try again later)
                // 2016-06-27: This changed to the above to enable testing
                // while ( SimbleeBLE.send(nextByteToSend, remainingByteCount) == false && hostIsConnected && retryRemainingCount > 0) {
                //     retryRemainingCount--;
                // };  // send() returns false if all tx buffers in use (can't enqueue, try again later)
                
                ubpTxBufferSentByteCount += remainingByteCount;
                
                UBP_isTxPending = false;
            }
        }
    }
}
/*
void _UBP_ingestRxBytes(char *receivedBytes, int byteCount) {
    
    Serial.print(byteCount);
    Serial.println(" bytes receieved");
    
    // NOTE: Assuming not called unless len > 0
    
    // Determine what to do with incoming fragment
    if ( *receivedBytes == END_BYTE ) {  // Fragment has leading END byte, signals start of packet
        
        // Set fragment as the beginning of the reconstruction buffer
        memcpy(ubpRxBuffer, receivedBytes, byteCount);
        ubpRxBufferLength = byteCount;
        
    } else if (ubpRxBufferLength > 0) {  // Already have fragments in the reconstruction buffer
        
        // Append fragment to reconstruction buffer
        memcpy(ubpRxBuffer + ubpRxBufferLength, receivedBytes, byteCount);
        ubpRxBufferLength += byteCount;
        
    }
    
    
    // Check RX buffer for trailing END byte
    if ( *(ubpRxBuffer + ubpRxBufferLength - 1) == END_BYTE) {  // RX buffer ends with END byte, looks like packet is complete
        
        byte firstNonControlIndex = 1;
        byte escapedDataLength = ubpRxBufferLength - 2;  // "- 2" for leading/trailing control chars
        
        // Un-escape the incoming payload
        ubpUnescapedRxBufferBufferLength = _UBP_makeUnEscapedCopy(ubpRxBuffer + firstNonControlIndex, escapedDataLength, ubpUnescapedRxBufferBuffer);
        byte payloadDataLength = ubpUnescapedRxBufferBufferLength - 1;  // -1 to account for checksum
        
        // Calculate checksum over payload, i.e. all bytes except for last checksum byte)
        char calculatedChecksum = CRC8(ubpUnescapedRxBufferBuffer, payloadDataLength * sizeof(byte));
        
        // Extract embedded checksum value
        char receivedChecksum = *(ubpUnescapedRxBufferBuffer + payloadDataLength);  // NOTE: Omitting '-1' because checksum byte comes just after payloadDataLength
        
        // Verify the checksum
        if (calculatedChecksum == receivedChecksum) {
            
            unsigned short packetIdentifier = *(ubpUnescapedRxBufferBuffer);
            UBP_TxFlags txFlags = (UBP_TxFlags) *(ubpUnescapedRxBufferBuffer + PACKET_ID_SIZE);
            
            if (UBP_receivedPacket) {
                
                void *packetBuffer = (ubpUnescapedRxBufferBuffer + PACKET_ID_SIZE + 1);  // skip <identifier length> + <tx flags length>
                UBP_receivedPacket(packetIdentifier, txFlags, packetBuffer);
            }
            
        } else {
            
            Serial.println("Incoming packet checksum invalid");
            
            // Reset
            ubpRxBufferLength = 0;
            ubpUnescapedRxBufferBufferLength = 0;
            
            if (UBP_incomingChecksumFailed) {
                
                UBP_incomingChecksumFailed();
            }
        }
        
    }  // else haven't RX'd final fragment yet, keep waiting
}
*/

// only needed to retreive the data for testing
void getTxBuffer(char *txBuffer, int *txBufferLength) {
    for (int i=0; i<ubpTxBufferLength; i++) {
        txBuffer[i] = ubpTxBuffer[i];
    }
    *txBufferLength = ubpTxBufferLength;
}

bool UBP_queuePacketTransmission(unsigned short packetIdentifier, UBP_TxFlags txFlags, const char *packetBytes, unsigned short byteCount) {
    
    if (UBP_isTxPending) {  // Preexisting transmission still in progress
        
        // Serial.println("Could not queue packet because preexisting transmission is still in progress");
        return false;
        
    } else {  // Ready to queue a new transmission
        
        if (hostIsConnected == false) return ubpTxBuffer;
        
        ubpTxBufferLength = 0;
        
        // Start off with the END_BYTE as required for SLIP
        ubpTxBuffer[0] = END_BYTE;
        ubpTxBufferLength++;
        
        // Prepend the packet identifier
        memcpy(ubpTxBuffer + ubpTxBufferLength, &packetIdentifier, sizeof(packetIdentifier));  // TODO: Escape the identifier
        ubpTxBufferLength += sizeof(packetIdentifier);
        
        // Append the transmission flags
        ubpTxBuffer[ubpTxBufferLength] = txFlags;
        ubpTxBufferLength++;
        
        // Copy the escaped contents of packetBytes into the TX buffer following the packet identifier
        int escapedByteCount = _UBP_makeEscapedCopy(packetBytes, byteCount, ubpTxBuffer + ubpTxBufferLength, BUFFER_LENGTH);
        if (escapedByteCount != -1) {  // Escaping succeeded
            
            ubpTxBufferLength += escapedByteCount;
            int payloadLength = ubpTxBufferLength - 1;  // Length so far minus leading END byte    //sizeof(packetIdentifier) + escapedByteCount;  // <identifier length> + <escaped content length>
            
            // Calculate and append checksum
            byte checksumValue = CRC8(ubpTxBuffer + 1, payloadLength);  // Checksum over all payload bytes (minus the leading END byte, checksum, and trailing END byte)
            *(ubpTxBuffer + ubpTxBufferLength) = checksumValue;
            ubpTxBufferLength++;
            
            // Append trailing END byte
            *(ubpTxBuffer + ubpTxBufferLength) = END_BYTE;
            ubpTxBufferLength++;
            
            // Mark as ready to begin transmission
            ubpTxBufferSentByteCount = 0;
            UBP_isTxPending = true;
            
        } else {
            
            return false;  // Return false if we couldn't escape the content because it was going to overflow the output buffer
        }
    }
    // FIXME: 2016-06-27: this was missing in the original code
    return true;
}

int _UBP_makeEscapedCopy(const char *inputBuffer, unsigned short inputBufferLength, char *outputBuffer, unsigned short outputBufferLength) {
    
    unsigned int bytesCopied = 0;
    const char *inputBytes = inputBuffer;  // Cast here to avoid compiler warnings later
    
    for (char i = 0; i < inputBufferLength; i++) {  // For each byte to append
        
        // Escape any control characters. Refer to Serial Line IP (SLIP) spec.
        char aByte = *(inputBytes + i);
        if (aByte ==  (char) ESCAPE_BYTE) {  // Escape an ESCAPE_BYTE
//      if (aByte == ESCAPE_BYTE) {  // Escape an ESCAPE_BYTE
            
            if (bytesCopied + 1 >= outputBufferLength) return -1;  // Would¥ overflow destination buffer
            else {
                *(outputBuffer + bytesCopied++) = ESCAPE_BYTE;  // Write ESCAPE_BYTE to buffer and increment offset
                *(outputBuffer + bytesCopied++) = ESCAPED_ESCAPE_BYTE;  // Write escaped ESCAPE_BYTE to buffer and increment offset
            }
            
//        } else if (aByte == END_BYTE) {  // Escape an END_BYTE
        } else if (aByte == (char) END_BYTE) {  // Escape an END_BYTE
            
            if (bytesCopied + 1 >= outputBufferLength) return -1;  // Would overflow destination buffer
            else {
                *(outputBuffer + bytesCopied++) = ESCAPE_BYTE;  // Write ESCAPE_BYTE to buffer and increment offset
                *(outputBuffer + bytesCopied++) = ESCAPED_END_BYTE;  // Write escaped END_BYTE to buffer and increment offset
            }
            
        } else {  // Not a control character
            
            if (bytesCopied >= outputBufferLength) return -1;  // Would overflow destination buffer
            else *(outputBuffer + bytesCopied++) = aByte;  // Copy the unmolested byte to the buffer and increment offset
        }
    }
    
    return bytesCopied;
}

/*

int _UBP_makeUnEscapedCopy(const char *inputBuffer, unsigned short inputBufferLength, char *outputBuffer) {
    
    bool done = false;
    char * destinationBufferPtr = outputBuffer;
    const char * sourceBufferPtr = inputBuffer;
    
    // UNESCAPE END Sequence_
    while (!done && (sourceBufferPtr - inputBuffer) < inputBufferLength) {
        
        char * substringPtr = strstr(sourceBufferPtr, escapedEndSequence_);
        if (substringPtr == NULL) done = true;
        else {
            
            // Copy bytes between last-copied byte and next escape byte
            char lengthToCopy = substringPtr - sourceBufferPtr;  // How many bytes between last byte copied and next escape byte
            memcpy(destinationBufferPtr, sourceBufferPtr, lengthToCopy);
            destinationBufferPtr += lengthToCopy;
            sourceBufferPtr += lengthToCopy;
            
            // Replace escaped source sequence with unescaped version during copy, increment pointer
            memcpy(destinationBufferPtr, endSequence_, sizeof(endSequence_));
            destinationBufferPtr += sizeof(endSequence_);
            
            // Increment pointer past escaped end Sequence_
            sourceBufferPtr += sizeof(escapedEndSequence_);
        }
    }
    
    // UNESCAPE ESCAPE SEQUENCE
    done = false;
    while (!done && (sourceBufferPtr - inputBuffer) < inputBufferLength) {
        
        char * substringPtr = strstr(sourceBufferPtr, escapedEscapeSequence_);
        if (substringPtr == NULL) done = true;
        else {
            
            // Copy bytes between last-copied byte and next escape byte
            char lengthToCopy = substringPtr - sourceBufferPtr;  // How many bytes between last byte copied and next escape byte
            memcpy(destinationBufferPtr, sourceBufferPtr, lengthToCopy);
            destinationBufferPtr += lengthToCopy;
            sourceBufferPtr += lengthToCopy;
            
            // Replace escaped source sequence with unescaped version during copy, increment pointer
            memcpy(destinationBufferPtr, escapeSequence_, sizeof(escapeSequence_));
            destinationBufferPtr += sizeof(escapeSequence_);
            
            // Increment pointer past escaped end Sequence_
            sourceBufferPtr += sizeof(escapedEscapeSequence_);
        }
    }
    
    // COPY ANY TRAILING BYTES
    char lengthToCopy = (inputBuffer + inputBufferLength) - sourceBufferPtr;  // How many bytes remain to be copied
    memcpy(destinationBufferPtr, sourceBufferPtr, lengthToCopy);
    destinationBufferPtr += lengthToCopy;
    sourceBufferPtr += lengthToCopy;
    
    return (destinationBufferPtr - outputBuffer);  // Return the total number of bytes copied to the destination buffer
}

 */

void _UBP_hostDisconnected() {
    
    hostIsConnected = false;
    
    // Reset TX subsystem
    UBP_isTxPending = false;
    
    // Reset RX subsystem
    ubpRxBufferLength = 0;
    
    // Invoke user callback
    // 2016-06-28: commentet out for testing
//    if (UBP_didDisconnect) UBP_didDisconnect();
}


// RFduino EVENTS
// ----------------------------------------------------
//void SimbleeBLE_onAdvertisement(bool start) {
//    
//    if (UBP_didAdvertise) UBP_didAdvertise(start);
//}
//
void SimbleeBLE_onConnect() {
    
    hostIsConnected = true;
    
    // 2016-06-29: uncommented and added for testing purposes
    // if (UBP_didConnect) UBP_didConnect();
    UBP_isTxPending = false;
}

//void SimbleeBLE_onReceive(char *data, int len) {
//    
//    _UBP_ingestRxBytes(data, len);
//}

void SimbleeBLE_onDisconnect() {
    
    _UBP_hostDisconnected();
}




================================================
FILE: LibreMonitor/ViewControllers/AdjustmentsTableViewController.swift
================================================
//
//  AdjustmentsTableViewController.swift
//  LibreMonitor
//
//  Created by Uwe Petersen on 27.05.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation
import UIKit

class AdjustmentsTableViewController: UITableViewController, UITextFieldDelegate {
    

    let numberFormatter = NumberFormatter()
    
    @IBOutlet weak var offsetTextField: UITextField!
    @IBOutlet weak var slopeTextField: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        numberFormatter.numberStyle = .decimal
        offsetTextField.delegate = self // for handling return key
        slopeTextField.delegate = self
        
        let bloodGlucoseOffset = UserDefaults.standard.double(forKey: "bloodGlucoseOffset")
        let bloodGlucoseSlope = UserDefaults.standard.double(forKey: "bloodGlucoseSlope")
        
        offsetTextField.text = numberFormatter.string(from: NSNumber(value: bloodGlucoseOffset))
        slopeTextField.text = numberFormatter.string(from: NSNumber(value: bloodGlucoseSlope))
                
        self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(AdjustmentsTableViewController.didTapSaveButton))
        self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .undo, target: self, action: #selector(AdjustmentsTableViewController.didTapUndoButton))
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        checkInputForTextField(textField)
        return true
    }
    
    
    func didTapSaveButton() {
        checkInputForTextField(offsetTextField)
        checkInputForTextField(slopeTextField)
    }
    
    func checkInputForTextField(_ textField: UITextField) {
        guard let aNumber = numberFormatter.number(from: textField.text!) else {
            displayAlertForTextField(textField)
            return
        }
        
        switch textField {
        case offsetTextField:
            let bloodGlucoseOffset = Double(aNumber)
            UserDefaults.standard.set(bloodGlucoseOffset, forKey: "bloodGlucoseOffset")
        case slopeTextField:
            let bloodGlucoseSlope = Double(aNumber)
            UserDefaults.standard.set(bloodGlucoseSlope, forKey: "bloodGlucoseSlope")
        default:
            fatalError("Fatal Error in \(#file): textField not handled in switch case")
            break
        }
        
        // update table view
        NotificationCenter.default.post(name: Notification.Name(rawValue: "updateBloodSugarTableViewController"), object: self)
        
        resignFirstResponder()
        navigationController?.dismiss(animated: true, completion: nil)
    }
    
    func didTapUndoButton() {
        resignFirstResponder()
        navigationController?.dismiss(animated: true, completion: nil)
    }
    
    func displayAlertForTextField(_ textField: UITextField) {
        let message = String(format: "\"\(textField.text!)\" ist kein gültiger Wert, bitte korrigieren.", [])
        let alertController = UIAlertController(title: "Ungültige Eingabe", message: message, preferredStyle: .alert)
        let defaultAction = UIAlertAction(title: "OK", style: .default, handler: nil)
        alertController.addAction(defaultAction)
        
        present(alertController, animated: true, completion: nil)
    }
}


================================================
FILE: LibreMonitor/ViewControllers/BloodSugarTableViewController.swift
================================================
//
//  TableViewController.swift
//
//  Created by Uwe Petersen on 01.02.16.
//  Copyright © 2016 Uwe Petersen. All rights reserved.
//

import Foundation

import UIKit
import CoreBluetooth
import CoreData
import UserNotifications


class BloodSugarTableViewController: UITableViewController, SimbleeManagerDelegate {
    
    var coreDataStack = CoreDataStack()
    var simbleeManager = SimbleeManager()
    
    var sensorData: SensorData?
    var trendMeasurements: [Measurement]?
    var historyMeasurements: [Measurement]?
    var batteryVoltage = 0.0
    
    var bloodGlucoseOffset: Double!
    var bloodGlucoseSlope: Double!
    var sensor: LibreSensor?
    

    var deviceID = "-"
    var temperatureString = "_"
    
    var timeInMinutesSinceStartOfSensor = 0
    var timeOfLastScan = Date()
    var transmissionDuration = TimeInterval()
    var timeOfTransmissionStart = Date()
    
    
    var dateFormatter = DateFormatter()
    var timeFormatter = DateFormatter()
    
    var notificationTimer = Timer()
    var showNotification = true
    
    
    /// Enum for the sections of this table view
    fileprivate enum Section: Int {
        case connectionData, generalData, graph, trendData, historyData
        /// Count of enum cases (has to be adjusted to this/each very enum)
        /// Source: http://stackoverflow.com/questions/27094878/how-do-i-get-the-count-of-a-swift-enum
        static let count: Int = {
            var max: Int = 0
            while let _ = Section(rawValue: max) { max += 1 }
            return max
        }()
    }
    
    
    @IBAction func doRefresh(_ sender: UIRefreshControl) {
        sender.endRefreshing()
        tableView.reloadData()
    }
    
    // MARK: - View Controller life ciycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        // self.navigationItem.leftBarButtonItem = self.editButtonItem()
        simbleeManager.delegate = self
        self.title = "LibreMonitor"
        
        let connectButtonTitle = connectButtonTitleForState(simbleeManager.state)
        let conncectButton = UIBarButtonItem(title: connectButtonTitle, style: .plain, target: self, action: #selector(BloodSugarTableViewController.didTapConnectButton))
        self.navigationItem.rightBarButtonItem = conncectButton
        
        bloodGlucoseOffset = UserDefaults.standard.double(forKey: "bloodGlucoseOffset")
        bloodGlucoseSlope = UserDefaults.standard.double(forKey: "bloodGlucoseSlope")
        if bloodGlucoseSlope <= 0.00001 {
            bloodGlucoseSlope = 1.0
            UserDefaults.standard.set(bloodGlucoseSlope, forKey: "bloodGlucoseSlope")
        }
        
        
        dateFormatter.dateFormat = "yyyy-MM-dd"
        timeFormatter.dateFormat = "HH:mm:ss"
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        bloodGlucoseOffset = UserDefaults.standard.double(forKey: "bloodGlucoseOffset")
        bloodGlucoseSlope = UserDefaults.standard.double(forKey: "bloodGlucoseSlope")
        
        // Notification for updating table view after application did become active again
        NotificationCenter.default.addObserver(self, selector: #selector(BloodSugarTableViewController.updateTableView), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil)
        // Notification for updating table view after having changed the offset and/of slope
        NotificationCenter.default.addObserver(self, selector: #selector(BloodSugarTableViewController.updateTableView), name: NSNotification.Name(rawValue: "updateBloodSugarTableViewController"), object: nil)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil)
        super.viewWillDisappear(true)
    }
    
    
    func didTapConnectButton() {
        switch (simbleeManager.state) {
        case .Unassigned:
            simbleeManager.scanForSimblee()
        case .Scanning:
            simbleeManager.centralManager.stopScan()
            simbleeManager.state = .Disconnected
        case .Connected, .Connecting, .Notifying:
            simbleeManager.disconnectManually()
        case .Disconnected, .DisconnectedManually:
            simbleeManager.connect()
        }
    }
    
    
    func updateTableView() {
        self.tableView.reloadData()
    }
    

    // MARK: - Table View
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        return Section.count
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        switch Section(rawValue: section)! {
        case .connectionData: return 3
        case .generalData: return 7
        case .graph: return 1
        case .trendData: return 16
        case .historyData: return 32
        }
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        if (indexPath as NSIndexPath).section == 2 {
            
            // Draw graph
            let cell = tableView.dequeueReusableCell(withIdentifier: "BloodSugarGraphTableViewCell", for: indexPath)
            guard let theCell = cell as? BloodSugarGraphViewTableViewCell else {return cell}

            if let trendMeasurements = trendMeasurements, let historyMeasurements = historyMeasurements {
                theCell.lineChartView.trendMeasurements = trendMeasurements
                theCell.lineChartView.historyMeasurements = historyMeasurements
                theCell.lineChartView.setGlucoseCharts(trendMeasurements, historyMeasurements: historyMeasurements)
                theCell.setNeedsDisplay()
                theCell.lineChartView.setNeedsDisplay()
            }
            return theCell
        } else {
            let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
            self.configureCell(cell, atIndexPath: indexPath)
            return cell
        }
    }
    
    override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        // Return false if you do not want the specified item to be editable.
        return true
    }
    
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if (indexPath as NSIndexPath).section == 0 && (indexPath as NSIndexPath).row == 0 {
            didTapConnectButton()
        } else if (indexPath as NSIndexPath).section == 0 && (indexPath as NSIndexPath).row == 2 {
            // ChangeBloodGlucoseAdjustments
            performSegue(withIdentifier: "ChangeBloodGlucoseAdjustments", sender: self)
        }
    }
    
    
    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        switch section {
        case 0: return "Connection"
        case 1: return "General data"
        case 2:
            let seconds = (NSDate() as NSDate).timeIntervalSince(timeOfLastScan).truncatingRemainder(dividingBy: 60.0)
            let minutes = (Date().timeIntervalSince(timeOfLastScan) - seconds) / 60.0
            return String(format: "Graph from %2.0f:%02.0f minutes ago", arguments: [minutes, seconds])
        case 3: return "Last 15 minutes"
        case 4: return "Last eight hours"
        case 5: return "Neue Letzte 15 Minuten"
        case 6: return "Neue Letzte 8 Stunden"
        default: return nil
        }
    }
    
    
    func configureCell(_ cell: UITableViewCell, atIndexPath indexPath: IndexPath) {
        cell.backgroundColor = UIColor.white
        cell.detailTextLabel?.textColor = UIColor.black
        cell.accessoryType = .none
        
        switch Section(rawValue: (indexPath as NSIndexPath).section)! {
        case .connectionData:
            switch (indexPath as NSIndexPath).row {
            case 0:
                cell.textLabel?.text = "Simblee status"
                cell.detailTextLabel?.text = simbleeManager.state.rawValue
                cell.backgroundColor = colorForConnectionState()
            case 1:
                cell.textLabel?.text = "Last scan:"
                if let sennsorData = sensorData {
                    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])
                    
                    if Date().timeIntervalSince(sennsorData.date as Date) > 240.0 {
                        cell.backgroundColor = UIColor.red
                    }
                }
            case 2:
                cell.textLabel?.text = "Offset / Slope:"
                cell.detailTextLabel?.text = String(format: "%.0f mg/dl, %.4f", arguments: [bloodGlucoseOffset, bloodGlucoseSlope])
                cell.accessoryType = .disclosureIndicator
            default: break
            }
        case .generalData:
            switch (indexPath as NSIndexPath).row {
            case 0:
                cell.textLabel?.text = "BM019 ID"
                cell.detailTextLabel?.text = deviceID
            case 1:
                var crcString = String()
                var color = UIColor()
                if let sensorData = sensorData {
                    crcString += ", crcs: \(sensorData.hasValidHeaderCRC), \(sensorData.hasValidBodyCRC), \(sensorData.hasValidFooterCRC)"
                    color = colorForSensorState( (sensorData.hasValidHeaderCRC && sensorData.hasValidBodyCRC && sensorData.hasValidFooterCRC) )
                } else {
                    crcString = ", nil"
                    color = UIColor.lightGray
                }
                cell.textLabel?.text = "Sensor SN"
                if let sensor = sensor {
                    cell.detailTextLabel?.text =  sensor.serialNumber + crcString // + " (" + sensor.prettyUid  + ")"
                } else {
                    cell.detailTextLabel?.text = ""
                }
                cell.backgroundColor = color
                
                
            case 2:
                cell.textLabel?.text = "Environment"
                cell.detailTextLabel?.text = String(format: "%3.1f V", arguments: [batteryVoltage]) + ", " + temperatureString
                if batteryVoltage < 3.0 {
                    cell.backgroundColor = UIColor.orange
                }
            case 3:
                cell.textLabel?.text = "Blocks"
                if let sennsorData = sensorData {
                    cell.detailTextLabel?.text = "Trend: \(sennsorData.nextTrendBlock), history: \(sennsorData.nextHistoryBlock), minutes: \(sennsorData.minutesSinceStart)"
                }
            case 4:
                cell.textLabel?.text = "Glucose"
                
                if let trendMeasurements = trendMeasurements {
                    let currentGlucose = trendMeasurements[0].glucose
                    let longDelta = currentGlucose - trendMeasurements[15].glucose
                    let shortDelta = (currentGlucose - trendMeasurements[8].glucose) * 2.0 * 16.0/15.0
                    let longPrediction = currentGlucose + longDelta
                    let shortPrediction = currentGlucose + shortDelta
                    cell.detailTextLabel?.text = String(format: "%0.0f, Delta: %0.0f (%0.0f), Prognosis: %0.0f (%0.0f)", arguments: [currentGlucose, longDelta, shortDelta, longPrediction, shortPrediction])
                    if longPrediction < 70.0 || shortPrediction < 70.0 || longPrediction > 180.0 || shortPrediction > 180.0 || (
Download .txt
gitextract_hx6qj96v/

├── LICENSE.md
├── LibreMonitor/
│   ├── AppDelegate.swift
│   ├── Assets.xcassets/
│   │   └── AppIcon.appiconset/
│   │       └── Contents.json
│   ├── Base.lproj/
│   │   └── LaunchScreen.storyboard
│   ├── BloodGlucose+CoreDataClass.swift
│   ├── BloodGlucose+CoreDataProperties.swift
│   ├── Bluetooth/
│   │   ├── Data_types+Extensions.swift
│   │   ├── NSData+CRC8.h
│   │   ├── NSData+CRC8.m
│   │   ├── NSData+SLIP.h
│   │   ├── NSData+SLIP.m
│   │   ├── SLIPBuffer.swift
│   │   ├── SimbleeManager.swift
│   │   ├── constants.h
│   │   └── data_types.h
│   ├── HeaderData+CoreDataClass.swift
│   ├── HeaderData+CoreDataProperties.swift
│   ├── Info.plist
│   ├── LibreMonitor-Bridging-Header.h
│   ├── LibreMonitor.entitlements
│   ├── LibreMonitor.xcdatamodeld/
│   │   ├── .xccurrentversion
│   │   └── LibreMonitor.xcdatamodel/
│   │       └── contents
│   ├── LibreMonitorUITests-Bridging-Header.h
│   ├── Main.storyboard
│   ├── Model/
│   │   ├── CRC.swift
│   │   ├── LibreSensor.swift
│   │   ├── Measurement.swift
│   │   ├── SensorData.swift
│   │   └── SensorState.swift
│   ├── ModelCoreData/
│   │   ├── BloodGlucose+CoreDataClass.swift
│   │   ├── BloodGlucose+CoreDataProperties.swift
│   │   ├── CoreDataStack.swift
│   │   ├── HeaderData+CoreDataClass.swift
│   │   ├── HeaderData+CoreDataProperties.swift
│   │   ├── Reader+CoreDataClass.swift
│   │   ├── Reader+CoreDataProperties.swift
│   │   ├── Sensor+CoreDataClass.swift
│   │   └── Sensor+CoreDataProperties.swift
│   ├── Reader+CoreDataClass.swift
│   ├── Reader+CoreDataProperties.swift
│   ├── Sensor+CoreDataClass.swift
│   ├── Sensor+CoreDataProperties.swift
│   ├── SimbleeCode/
│   │   ├── crc8.h
│   │   ├── crc8.m
│   │   ├── libUBP.h
│   │   └── libUBP.m
│   ├── ViewControllers/
│   │   ├── AdjustmentsTableViewController.swift
│   │   └── BloodSugarTableViewController.swift
│   └── Views/
│       ├── BloodSugarGraphView.swift
│       └── BloodSugarGraphViewTableViewCell.swift
├── LibreMonitor.ino
├── LibreMonitor.xcodeproj/
│   ├── project.pbxproj
│   ├── project.xcworkspace/
│   │   └── contents.xcworkspacedata
│   └── xcuserdata/
│       └── Uwe.xcuserdatad/
│           └── xcschemes/
│               ├── LibreMonitor.xcscheme
│               └── xcschememanagement.plist
├── LibreMonitor.xcworkspace/
│   ├── contents.xcworkspacedata
│   └── xcuserdata/
│       └── Uwe.xcuserdatad/
│           └── xcdebugger/
│               └── Breakpoints_v2.xcbkptlist
├── LibreMonitorRFduino.ino
├── LibreMonitorTests/
│   ├── BluetoothTestData.swift
│   ├── Info.plist
│   ├── LibreMonitorTestSensorData.swift
│   ├── LibreMonitorTests-Bridging-Header.h
│   ├── LibreMonitorTests.swift
│   ├── SimbleeCode/
│   │   ├── crc8.h
│   │   ├── crc8.m
│   │   ├── libUBP.h
│   │   └── libUBP.m
│   └── TransmissionTests.swift
├── LibreMonitorUITests/
│   ├── Info.plist
│   └── LibreMonitorUITests.swift
├── Podfile
├── README.md
└── libUBP RFduino.cpp
Download .txt
SYMBOL INDEX (25 symbols across 6 files)

FILE: LibreMonitor/Bluetooth/data_types.h
  type BatteryDataType (line 6) | typedef struct  __attribute__((packed)) {
  type SystemInformationDataType (line 19) | typedef struct  __attribute__((packed)) {
  type IDNDataType (line 32) | typedef struct  __attribute__((packed)) {
  type AllBytesDataType (line 43) | typedef struct  __attribute__((packed)) {

FILE: LibreMonitor/SimbleeCode/crc8.h
  type byte (line 14) | typedef uint8_t byte;

FILE: LibreMonitor/SimbleeCode/libUBP.h
  type byte (line 6) | typedef uint8_t byte;
  type UBP_TxFlags (line 14) | typedef enum {

FILE: LibreMonitorTests/SimbleeCode/crc8.h
  type byte (line 14) | typedef uint8_t byte;

FILE: LibreMonitorTests/SimbleeCode/libUBP.h
  type byte (line 6) | typedef uint8_t byte;
  type UBP_TxFlags (line 14) | typedef enum {

FILE: libUBP RFduino.cpp
  function UBP_isBusy (line 99) | bool UBP_isBusy() {
  function UBP_pump (line 104) | void UBP_pump() {
  function _UBP_ingestRxBytes (line 161) | void _UBP_ingestRxBytes(char *receivedBytes, int byteCount) {
  function UBP_queuePacketTransmission (line 229) | bool UBP_queuePacketTransmission(unsigned short packetIdentifier, UBP_Tx...
  function _UBP_makeEscapedCopy (line 301) | int _UBP_makeEscapedCopy(const char *inputBuffer, unsigned short inputBu...
  function _UBP_makeUnEscapedCopy (line 350) | int _UBP_makeUnEscapedCopy(const char *inputBuffer, unsigned short input...
  function _UBP_hostDisconnected (line 410) | void _UBP_hostDisconnected() {
  function SimbleeBLE_onAdvertisement (line 428) | void SimbleeBLE_onAdvertisement(bool start) {
  function SimbleeBLE_onConnect (line 431) | void SimbleeBLE_onConnect() {
  function SimbleeBLE_onReceive (line 436) | void SimbleeBLE_onReceive(char *data, int len) {
  function SimbleeBLE_onDisconnect (line 440) | void SimbleeBLE_onDisconnect() {
  function RFduinoBLE_onAdvertisement (line 444) | void RFduinoBLE_onAdvertisement(bool start) {
  function RFduinoBLE_onConnect (line 448) | void RFduinoBLE_onConnect() {
  function RFduinoBLE_onReceive (line 453) | void RFduinoBLE_onReceive(char *data, int len) {
  function RFduinoBLE_onDisconnect (line 457) | void RFduinoBLE_onDisconnect() {
Condensed preview — 73 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (498K chars).
[
  {
    "path": "LICENSE.md",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "LibreMonitor/AppDelegate.swift",
    "chars": 7832,
    "preview": "//\n//  AppDelegate.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 14.10.16.\n//  Copyright © 2016 Uwe Petersen."
  },
  {
    "path": "LibreMonitor/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "chars": 1495,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\""
  },
  {
    "path": "LibreMonitor/Base.lproj/LaunchScreen.storyboard",
    "chars": 1740,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
  },
  {
    "path": "LibreMonitor/BloodGlucose+CoreDataClass.swift",
    "chars": 245,
    "preview": "//\n//  BloodGlucose+CoreDataClass.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 14.10.16.\n//  Copyright © 201"
  },
  {
    "path": "LibreMonitor/BloodGlucose+CoreDataProperties.swift",
    "chars": 674,
    "preview": "//\n//  BloodGlucose+CoreDataProperties.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 14.10.16.\n//  Copyright "
  },
  {
    "path": "LibreMonitor/Bluetooth/Data_types+Extensions.swift",
    "chars": 2856,
    "preview": "//\n//  Data_types+Extensions.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 15.05.16.\n//  Copyright © 2016 Uwe"
  },
  {
    "path": "LibreMonitor/Bluetooth/NSData+CRC8.h",
    "chars": 491,
    "preview": "//\n//  NSData+CRC8.h\n//  Bluetooth LE Test\n//\n//  Created by Chas Conway on 12/11/13.\n//  Copyright (c) 2013 Chas Conway"
  },
  {
    "path": "LibreMonitor/Bluetooth/NSData+CRC8.m",
    "chars": 1489,
    "preview": "//\n//  NSData+CRC8.m\n//  Bluetooth LE Test\n//\n//  Created by Chas Conway on 12/11/13.\n//  Copyright (c) 2013 Chas Conway"
  },
  {
    "path": "LibreMonitor/Bluetooth/NSData+SLIP.h",
    "chars": 329,
    "preview": "//\n//  NSData+SLIP.h\n//  Arduino Greenhouse\n//\n//  Created by Chas Conway on 5/23/14.\n//  Copyright (c) 2014 Chas Conway"
  },
  {
    "path": "LibreMonitor/Bluetooth/NSData+SLIP.m",
    "chars": 3357,
    "preview": "//\n//  NSData+SLIP.m\n//  Arduino Greenhouse\n//\n//  Created by Chas Conway on 5/23/14.\n//  Copyright (c) 2014 Chas Conway"
  },
  {
    "path": "LibreMonitor/Bluetooth/SLIPBuffer.swift",
    "chars": 8673,
    "preview": "//\n//  SLIPBuffer.swift\n//  UBA-Demo\n//\n//  Created by Chas Conway on 2/4/15.\n//  Copyright (c) 2015 Chas Conway. All ri"
  },
  {
    "path": "LibreMonitor/Bluetooth/SimbleeManager.swift",
    "chars": 11940,
    "preview": "//\n//  SimbleeManager.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 23.04.16.\n//  Copyright © 2016 Uwe Peters"
  },
  {
    "path": "LibreMonitor/Bluetooth/constants.h",
    "chars": 359,
    "preview": "// Define unique identifiers for each data packet here. This identifier is transfered together with the data and can be "
  },
  {
    "path": "LibreMonitor/Bluetooth/data_types.h",
    "chars": 1883,
    "preview": "// Data types for data to be transfered\n// Need a struct with one variable and the packed attribute to make this an arra"
  },
  {
    "path": "LibreMonitor/HeaderData+CoreDataClass.swift",
    "chars": 258,
    "preview": "//\n//  HeaderData+CoreDataClass.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 14.10.16.\n//  Copyright © 2016 "
  },
  {
    "path": "LibreMonitor/HeaderData+CoreDataProperties.swift",
    "chars": 462,
    "preview": "//\n//  HeaderData+CoreDataProperties.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 14.10.16.\n//  Copyright © "
  },
  {
    "path": "LibreMonitor/Info.plist",
    "chars": 1798,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "LibreMonitor/LibreMonitor-Bridging-Header.h",
    "chars": 197,
    "preview": "//\n//  Use this file to import your target's public headers that you would like to expose to Swift.\n//\n#import \"NSData+C"
  },
  {
    "path": "LibreMonitor/LibreMonitor.entitlements",
    "chars": 239,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "LibreMonitor/LibreMonitor.xcdatamodeld/.xccurrentversion",
    "chars": 265,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "LibreMonitor/LibreMonitor.xcdatamodeld/LibreMonitor.xcdatamodel/contents",
    "chars": 3552,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<model type=\"com.apple.IDECoreDataModeler.DataModel\" documentVer"
  },
  {
    "path": "LibreMonitor/LibreMonitorUITests-Bridging-Header.h",
    "chars": 196,
    "preview": "//\n//  Use this file to import your target's public headers that you would like to expose to Swift.\n//\n#import \"NSData+C"
  },
  {
    "path": "LibreMonitor/Main.storyboard",
    "chars": 67395,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
  },
  {
    "path": "LibreMonitor/Model/CRC.swift",
    "chars": 4617,
    "preview": "//\n//  CRC.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 26.07.16.\n//  Copyright © 2016 Uwe Petersen. All rig"
  },
  {
    "path": "LibreMonitor/Model/LibreSensor.swift",
    "chars": 5245,
    "preview": "//\n//  LibreSensor.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 15.05.16.\n//  Copyright © 2016 Uwe Petersen."
  },
  {
    "path": "LibreMonitor/Model/Measurement.swift",
    "chars": 1728,
    "preview": "//\n//  Measurement.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 25.08.16.\n//  Copyright © 2016 Uwe Petersen."
  },
  {
    "path": "LibreMonitor/Model/SensorData.swift",
    "chars": 6163,
    "preview": "//\n//  SensorData\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 26.07.16.\n//  Copyright © 2016 Uwe Petersen. All ri"
  },
  {
    "path": "LibreMonitor/Model/SensorState.swift",
    "chars": 1289,
    "preview": "//\n//  SensorState.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 31.07.16.\n//  Copyright © 2016 Uwe Petersen."
  },
  {
    "path": "LibreMonitor/ModelCoreData/BloodGlucose+CoreDataClass.swift",
    "chars": 245,
    "preview": "//\n//  BloodGlucose+CoreDataClass.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 09.10.16.\n//  Copyright © 201"
  },
  {
    "path": "LibreMonitor/ModelCoreData/BloodGlucose+CoreDataProperties.swift",
    "chars": 673,
    "preview": "//\n//  BloodGlucose+CoreDataProperties.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 09.10.16.\n//  Copyright "
  },
  {
    "path": "LibreMonitor/ModelCoreData/CoreDataStack.swift",
    "chars": 5840,
    "preview": "//\n//  CoreDataStack.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 13.04.16.\n//  Copyright © 2016 Uwe Peterse"
  },
  {
    "path": "LibreMonitor/ModelCoreData/HeaderData+CoreDataClass.swift",
    "chars": 258,
    "preview": "//\n//  HeaderData+CoreDataClass.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 09.10.16.\n//  Copyright © 2016 "
  },
  {
    "path": "LibreMonitor/ModelCoreData/HeaderData+CoreDataProperties.swift",
    "chars": 462,
    "preview": "//\n//  HeaderData+CoreDataProperties.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 09.10.16.\n//  Copyright © "
  },
  {
    "path": "LibreMonitor/ModelCoreData/Reader+CoreDataClass.swift",
    "chars": 233,
    "preview": "//\n//  Reader+CoreDataClass.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 09.10.16.\n//  Copyright © 2016 Uwe "
  },
  {
    "path": "LibreMonitor/ModelCoreData/Reader+CoreDataProperties.swift",
    "chars": 495,
    "preview": "//\n//  Reader+CoreDataProperties.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 09.10.16.\n//  Copyright © 2016"
  },
  {
    "path": "LibreMonitor/ModelCoreData/Sensor+CoreDataClass.swift",
    "chars": 233,
    "preview": "//\n//  Sensor+CoreDataClass.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 09.10.16.\n//  Copyright © 2016 Uwe "
  },
  {
    "path": "LibreMonitor/ModelCoreData/Sensor+CoreDataProperties.swift",
    "chars": 1063,
    "preview": "//\n//  Sensor+CoreDataProperties.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 09.10.16.\n//  Copyright © 2016"
  },
  {
    "path": "LibreMonitor/Reader+CoreDataClass.swift",
    "chars": 233,
    "preview": "//\n//  Reader+CoreDataClass.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 14.10.16.\n//  Copyright © 2016 Uwe "
  },
  {
    "path": "LibreMonitor/Reader+CoreDataProperties.swift",
    "chars": 495,
    "preview": "//\n//  Reader+CoreDataProperties.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 14.10.16.\n//  Copyright © 2016"
  },
  {
    "path": "LibreMonitor/Sensor+CoreDataClass.swift",
    "chars": 233,
    "preview": "//\n//  Sensor+CoreDataClass.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 14.10.16.\n//  Copyright © 2016 Uwe "
  },
  {
    "path": "LibreMonitor/Sensor+CoreDataProperties.swift",
    "chars": 1064,
    "preview": "//\n//  Sensor+CoreDataProperties.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 14.10.16.\n//  Copyright © 2016"
  },
  {
    "path": "LibreMonitor/SimbleeCode/crc8.h",
    "chars": 519,
    "preview": "// LICENSES: [077915]\n// -----------------------------------\n// The contents of this file contains the aggregate of cont"
  },
  {
    "path": "LibreMonitor/SimbleeCode/crc8.m",
    "chars": 1328,
    "preview": "// LICENSES: [077915]\n// -----------------------------------\n// The contents of this file contains the aggregate of cont"
  },
  {
    "path": "LibreMonitor/SimbleeCode/libUBP.h",
    "chars": 1457,
    "preview": "//\n// Uwe Petersen: Modified version to test transmission part in iOS\n\n#import <Foundation/Foundation.h>\n\ntypedef uint8_"
  },
  {
    "path": "LibreMonitor/SimbleeCode/libUBP.m",
    "chars": 14711,
    "preview": "//\n// Uwe Petersen: Modified version to test transmission part in iOS\n\n#import \"libUBP.h\"\n#import \"crc8.h\"\n\n// Build-tim"
  },
  {
    "path": "LibreMonitor/ViewControllers/AdjustmentsTableViewController.swift",
    "chars": 3374,
    "preview": "//\n//  AdjustmentsTableViewController.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 27.05.16.\n//  Copyright ©"
  },
  {
    "path": "LibreMonitor/ViewControllers/BloodSugarTableViewController.swift",
    "chars": 28538,
    "preview": "//\n//  TableViewController.swift\n//\n//  Created by Uwe Petersen on 01.02.16.\n//  Copyright © 2016 Uwe Petersen. All righ"
  },
  {
    "path": "LibreMonitor/Views/BloodSugarGraphView.swift",
    "chars": 6087,
    "preview": "//\n//  BloodSugarGraphView.swift\n//\n//  Created by Uwe Petersen on 23.03.16.\n//\n//  Blood sugar data ranges from time of"
  },
  {
    "path": "LibreMonitor/Views/BloodSugarGraphViewTableViewCell.swift",
    "chars": 650,
    "preview": "//\n//  BloodSugarGraphViewTableViewCell.swift\n//\n//  Created by Uwe Petersen on 23.03.16.\n//\n\nimport Foundation\nimport U"
  },
  {
    "path": "LibreMonitor.ino",
    "chars": 30615,
    "preview": "///\n///   LibreMonitor\n/// \n///   Copyright (c) 2015 Uwe Petersen, all right reserved\n///\n///   Wiring connections:\n///\n"
  },
  {
    "path": "LibreMonitor.xcodeproj/project.pbxproj",
    "chars": 50855,
    "preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
  },
  {
    "path": "LibreMonitor.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "chars": 157,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:LibreMonitor.xc"
  },
  {
    "path": "LibreMonitor.xcodeproj/xcuserdata/Uwe.xcuserdatad/xcschemes/LibreMonitor.xcscheme",
    "chars": 4257,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0820\"\n   version = \"1.3\">\n   <BuildAction\n      "
  },
  {
    "path": "LibreMonitor.xcodeproj/xcuserdata/Uwe.xcuserdatad/xcschemes/xcschememanagement.plist",
    "chars": 664,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "LibreMonitor.xcworkspace/contents.xcworkspacedata",
    "chars": 230,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"group:LibreMonitor.x"
  },
  {
    "path": "LibreMonitor.xcworkspace/xcuserdata/Uwe.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist",
    "chars": 8231,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Bucket\n   type = \"0\"\n   version = \"2.0\">\n   <Breakpoints>\n      <BreakpointProxy"
  },
  {
    "path": "LibreMonitorRFduino.ino",
    "chars": 33251,
    "preview": "//#include <RFduinoBLE.h>\n\n///\n///   LibreMonitor\n/// \n///   Copyright (c) 2015 Uwe Petersen, all right reserved\n///\n///"
  },
  {
    "path": "LibreMonitorTests/BluetoothTestData.swift",
    "chars": 54564,
    "preview": "//\n//  BluetoothTestData.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 29.01.17.\n//  Copyright © 2017 Uwe Pet"
  },
  {
    "path": "LibreMonitorTests/Info.plist",
    "chars": 680,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "LibreMonitorTests/LibreMonitorTestSensorData.swift",
    "chars": 11719,
    "preview": "//\n//  LibreMonitorTestSensorData.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 28.07.16.\n//  Copyright © 201"
  },
  {
    "path": "LibreMonitorTests/LibreMonitorTests-Bridging-Header.h",
    "chars": 232,
    "preview": "//\n//  Use this file to import your target's public headers that you would like to expose to Swift.\n//\n#import \"NSData+C"
  },
  {
    "path": "LibreMonitorTests/LibreMonitorTests.swift",
    "chars": 11306,
    "preview": "//\n//  LibreMonitorTests.swift\n//  LibreMonitorTests\n//\n//  Created by Uwe Petersen on 09.10.16.\n//  Copyright © 2016 Uw"
  },
  {
    "path": "LibreMonitorTests/SimbleeCode/crc8.h",
    "chars": 648,
    "preview": "// LICENSES: [077915]\n// -----------------------------------\n// The contents of this file contains the aggregate of cont"
  },
  {
    "path": "LibreMonitorTests/SimbleeCode/crc8.m",
    "chars": 1455,
    "preview": "// LICENSES: [077915]\n// -----------------------------------\n// The contents of this file contains the aggregate of cont"
  },
  {
    "path": "LibreMonitorTests/SimbleeCode/libUBP.h",
    "chars": 1457,
    "preview": "//\n// Uwe Petersen: Modified version to test transmission part in iOS\n\n#import <Foundation/Foundation.h>\n\ntypedef uint8_"
  },
  {
    "path": "LibreMonitorTests/SimbleeCode/libUBP.m",
    "chars": 15006,
    "preview": "//\n// Uwe Petersen: Modified version to test transmission part in iOS\n\n#import \"libUBP.h\"\n#import \"crc8.h\"\n\n// Build-tim"
  },
  {
    "path": "LibreMonitorTests/TransmissionTests.swift",
    "chars": 1987,
    "preview": "//\n//  TransmissionTests.swift\n//  LibreMonitor\n//\n//  Created by Uwe Petersen on 03.02.17.\n//  Copyright © 2017 Uwe Pet"
  },
  {
    "path": "LibreMonitorUITests/Info.plist",
    "chars": 680,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "LibreMonitorUITests/LibreMonitorUITests.swift",
    "chars": 1259,
    "preview": "//\n//  LibreMonitorUITests.swift\n//  LibreMonitorUITests\n//\n//  Created by Uwe Petersen on 14.10.16.\n//  Copyright © 201"
  },
  {
    "path": "Podfile",
    "chars": 613,
    "preview": "# Uncomment this line to define a global platform for your project\n# platform :ios, '10.0'\n# Uncomment this line if you'"
  },
  {
    "path": "README.md",
    "chars": 8734,
    "preview": "# LibreMonitor - Monitor your Freestyle Libre\n\nLibreMonitor is a little DIY device that uses near field communication to"
  },
  {
    "path": "libUBP RFduino.cpp",
    "chars": 17023,
    "preview": "//\n// libUBP.cpp \n// C++ code\n// ----------------------------------\n// Developed with embedXcode+ \n// http://embedXcode."
  }
]

About this extraction

This page contains the full source code of the UPetersen/LibreMonitor GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 73 files (460.9 KB), approximately 128.6k tokens, and a symbol index with 25 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!