diff --git a/app/app.iml b/app/app.iml
deleted file mode 100644
index f36de1906719a71a357c1f627683fe377dc6f4ae..0000000000000000000000000000000000000000
--- a/app/app.iml
+++ /dev/null
@@ -1,154 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="640gAndroidUploader" external.system.module.version="0.4.0-SNAPSHOT" type="JAVA_MODULE" version="4">
-  <component name="FacetManager">
-    <facet type="android-gradle" name="Android-Gradle">
-      <configuration>
-        <option name="GRADLE_PROJECT_PATH" value=":app" />
-      </configuration>
-    </facet>
-    <facet type="android" name="Android">
-      <configuration>
-        <option name="SELECTED_BUILD_VARIANT" value="debug" />
-        <option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
-        <option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
-        <option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
-        <afterSyncTasks>
-          <task>generateDebugSources</task>
-        </afterSyncTasks>
-        <option name="ALLOW_USER_CONFIGURATION" value="false" />
-        <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
-        <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
-        <option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
-        <option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
-      </configuration>
-    </facet>
-  </component>
-  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
-    <output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
-    <output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
-    <exclude-output />
-    <content url="file://$MODULE_DIR$">
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/fabric/res/debug" type="java-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
-      <sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
-      <sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
-      <sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
-      <sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
-      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/jni" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
-      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
-      <sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
-      <sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
-      <sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
-      <sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/animated-vector-drawable/23.4.0/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.4.0/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/design/23.4.0/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/recyclerview-v7/23.4.0/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/23.4.0/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-vector-drawable/23.4.0/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.bugfender.sdk/android/0.4.4/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.crashlytics.sdk.android/answers/1.3.10/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.crashlytics.sdk.android/beta/1.2.2/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.crashlytics.sdk.android/crashlytics-core/2.3.14/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.crashlytics.sdk.android/crashlytics/2.6.5/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.getkeepsafe.relinker/relinker/1.2.1/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.github.PhilJay/MPAndroidChart-Realm/v1.1.0/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.mikepenz/fastadapter/1.5.2/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.mikepenz/google-material-typeface/2.2.0.1.original/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.mikepenz/iconics-core/2.6.0/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.mikepenz/materialdrawer/5.2.9/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.mikepenz/materialize/0.8.8/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/io.fabric.sdk.android/fabric/1.3.14/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/io.realm/realm-android-library/1.0.0/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/uk.co.chrisjenx/calligraphy/2.2.0/jars" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
-      <excludeFolder url="file://$MODULE_DIR$/build/outputs" />
-    </content>
-    <orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" />
-    <orderEntry type="sourceFolder" forTests="false" />
-    <orderEntry type="library" exported="" name="okio-1.8.0" level="project" />
-    <orderEntry type="library" exported="" name="support-annotations-23.4.0" level="project" />
-    <orderEntry type="library" exported="" name="google-material-typeface-2.2.0.1.original" level="project" />
-    <orderEntry type="library" exported="" name="okhttp-2.4.0" level="project" />
-    <orderEntry type="library" exported="" name="relinker-1.2.1" level="project" />
-    <orderEntry type="library" exported="" name="retrofit-1.9.0" level="project" />
-    <orderEntry type="library" exported="" name="realm-annotations-1.0.0" level="project" />
-    <orderEntry type="library" exported="" name="crashlytics-core-2.3.14" level="project" />
-    <orderEntry type="library" exported="" name="animated-vector-drawable-23.4.0" level="project" />
-    <orderEntry type="library" exported="" name="commons-lang3-3.4" level="project" />
-    <orderEntry type="library" exported="" name="support-v4-23.4.0" level="project" />
-    <orderEntry type="library" exported="" name="recyclerview-v7-23.4.0" level="project" />
-    <orderEntry type="library" exported="" name="slf4j-api-1.7.2" level="project" />
-    <orderEntry type="library" exported="" name="support-vector-drawable-23.4.0" level="project" />
-    <orderEntry type="library" exported="" name="materialize-0.8.8" level="project" />
-    <orderEntry type="library" exported="" name="realm-android-library-1.0.0" level="project" />
-    <orderEntry type="library" exported="" name="appcompat-v7-23.4.0" level="project" />
-    <orderEntry type="library" exported="" name="design-23.4.0" level="project" />
-    <orderEntry type="library" exported="" name="android-0.4.4" level="project" />
-    <orderEntry type="library" exported="" name="fabric-1.3.14" level="project" />
-    <orderEntry type="library" exported="" name="MPAndroidChart-v3.0.0-beta1" level="project" />
-    <orderEntry type="library" exported="" name="crashlytics-2.6.5" level="project" />
-    <orderEntry type="library" exported="" name="beta-1.2.2" level="project" />
-    <orderEntry type="library" exported="" name="fastadapter-1.5.2" level="project" />
-    <orderEntry type="library" exported="" name="gson-2.7" level="project" />
-    <orderEntry type="library" exported="" name="retrofit-2.1.0" level="project" />
-    <orderEntry type="library" exported="" name="converter-gson-2.1.0" level="project" />
-    <orderEntry type="library" exported="" name="answers-1.3.10" level="project" />
-    <orderEntry type="library" exported="" name="materialdrawer-5.2.9" level="project" />
-    <orderEntry type="library" exported="" name="MPAndroidChart-Realm-v1.1.0" level="project" />
-    <orderEntry type="library" exported="" name="calligraphy-2.2.0" level="project" />
-    <orderEntry type="library" exported="" name="okhttp-3.3.0" level="project" />
-    <orderEntry type="library" exported="" name="iconics-core-2.6.0" level="project" />
-    <orderEntry type="library" exported="" name="org.apache.http.legacy-android-23" level="project" />
-  </component>
-</module>
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index c7dfac638564444c54e3883d8761adceb53b9263..321863d615cb36775b630d58e4edd1721a5f7a06 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,3 +1,5 @@
+import org.ajoberstar.grgit.Grgit
+
 buildscript {
     repositories {
         maven { url 'https://maven.fabric.io/public' }
@@ -5,7 +7,8 @@ buildscript {
 
     dependencies {
         classpath 'io.fabric.tools:gradle:1.21.6'
-        classpath 'io.realm:realm-gradle-plugin:1.1.0'
+        classpath 'io.realm:realm-gradle-plugin:1.1.1'
+        classpath 'org.ajoberstar:grgit:1.5.0'
     }
 }
 plugins {
@@ -23,8 +26,25 @@ apply plugin: 'io.fabric'
 apply plugin: 'realm-android'
 
 def gitVersion() {
-    def process = ['sh', '-c', 'git tag -l | grep -c ".*" -'].execute().text.trim()
-    return process.toInteger() + 1
+    // current dir is <your proj>/app, so it's likely that all your git repo files are in the dir
+    // above.
+    ext.repo = Grgit.open(project.file('..'))
+
+    // should result in the same value as running
+    // git tag -l | wc -l or git tag -l | grep -c ".*" -
+    def numOfTags = ext.repo.tag.list().size()
+    return numOfTags
+}
+
+def gitCommitId() {
+    //def process = ['sh', '-c', 'git tag -l | grep -c ".*" -'].execute().text.trim()
+    //return process.toInteger() + 1
+    //return 42
+    // current dir is <your proj>/app, so it's likely that all your git repo files are in the dir
+    // above.
+    ext.repo = Grgit.open(project.file('..'))
+
+    return ext.repo.log().first().id.substring(0, 7)
 }
 
 def getBugfenderApiKey() {
@@ -47,7 +67,7 @@ android {
         applicationId "info.nightscout.android"
         minSdkVersion 14
         targetSdkVersion 23
-        versionName project.properties['version']
+        versionName project.properties['version'] + "/" + gitCommitId()
         versionCode gitVersion()
         buildConfigField "String", "BUGFENDER_API_KEY", getBugfenderApiKey()
     }
@@ -134,7 +154,7 @@ dependencies {
     compile 'org.apache.commons:commons-lang3:3.4'
     compile 'com.mikepenz:google-material-typeface:2.2.0.1.original@aar'
     compile 'uk.co.chrisjenx:calligraphy:2.2.0'
-    compile 'com.bugfender.sdk:android:0.4.4'
+    compile 'com.bugfender.sdk:android:0.6.2'
     compile 'com.github.PhilJay:MPAndroidChart:v3.0.0-beta1'
     compile 'com.github.PhilJay:MPAndroidChart-Realm:v1.1.0@aar'
     compile 'com.android.support:support-v4:23.4.0'
diff --git a/app/gradle.properties b/app/gradle.properties
index 0db303f3a5e5d10435a82acd862bec04bc146452..1dd0e26d2b59d84aa9b32ab72e3c5b99065efabe 100644
--- a/app/gradle.properties
+++ b/app/gradle.properties
@@ -1 +1 @@
-version=0.4.0-SNAPSHOT
+version=0.5.0-SNAPSHOT
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 398c27edf0eb1986f7012659700f3f14e2f49a61..80e56888d3b01828035953934ed4cb6cb4d761ef 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -18,6 +18,9 @@
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.USB_PERMISSION" />
 
+    <!-- allow to disable battery optimization -->
+    <uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
+
     <application
         android:name=".UploaderApplication"
         android:allowBackup="true"
@@ -26,6 +29,7 @@
         android:supportsRtl="true"
         android:theme="@style/AppTheme">
 
+
         <!-- I have set screenOrientation to "portrait" to avoid the restart of AsyncTasks when you rotate the phone -->
         <activity
             android:name=".medtronic.MainActivity"
@@ -64,24 +68,27 @@
             android:label="@string/title_activity_login"
             android:theme="@style/SettingsTheme" />
 
+        <activity android:name=".medtronic.StatusActivity" />
+
         <service
             android:name=".upload.nightscout.NightscoutUploadIntentService"
             android:icon="@drawable/ic_launcher" />
-
+        <service
+            android:name=".xdrip_plus.XDripPlusUploadIntentService"
+            android:icon="@drawable/ic_launcher" />
         <service
             android:name=".medtronic.service.MedtronicCnlIntentService"
             android:icon="@drawable/ic_launcher" />
 
-        <activity android:name=".medtronic.StatusActivity" />
-
         <receiver android:name=".medtronic.service.MedtronicCnlAlarmReceiver" />
         <receiver android:name=".upload.nightscout.NightscoutUploadReceiver" />
+        <receiver android:name=".xdrip_plus.XDripPlusUploadReceiver" />
 
 
         <receiver android:name=".medtronic.service.MedtronicCnlAlarmReceiver"></receiver>
         <meta-data
             android:name="io.fabric.ApiKey"
-            android:value="FABRIC_API_KEY_VALUE" />
+            android:value="aa26e770bd4f7480eed7cabb63a84363ecd12009" />
     </application>
 
 </manifest>
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/android/medtronic/GetHmacAndKeyActivity.java b/app/src/main/java/info/nightscout/android/medtronic/GetHmacAndKeyActivity.java
index d2f50fa2b184934da6ae12a9cfbda2351113a9f9..c487d9382984b303e6292afeb7f05fec42790870 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/GetHmacAndKeyActivity.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/GetHmacAndKeyActivity.java
@@ -62,20 +62,8 @@ import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper;
  */
 public class GetHmacAndKeyActivity extends AppCompatActivity implements LoaderCallbacks<Cursor> {
 
-    /**
-     * Keep track of the login task to ensure we can cancel it if requested.
-     */
-    // TODO - Replace with Rx.Java
-    private GetHmacAndKey mHmacAndKeyTask = null;
-
     // UI references.
-    private EditText mUsernameView;
-    private EditText mPasswordView;
-    private EditText mHostnameView;
-    private View mProgressView;
-    private View mLoginFormView;
     private TextView mRegisteredStickView;
-    private MenuItem mLoginMenuItem;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -83,35 +71,8 @@ public class GetHmacAndKeyActivity extends AppCompatActivity implements LoaderCa
         setContentView(R.layout.activity_login);
 
         getSupportActionBar().setDisplayHomeAsUpEnabled(true);
-        getSupportActionBar().setTitle("Register USB");
-
-        // Set up the login form.
-        mUsernameView = (EditText) findViewById(R.id.username);
-
-        mPasswordView = (EditText) findViewById(R.id.password);
-        mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
-            @Override
-            public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
-                if (id == EditorInfo.IME_ACTION_DONE) {
-                    attemptLogin();
-                    return true;
-                }
-                return false;
-            }
-        });
-
-        mHostnameView = (EditText) findViewById(R.id.hostname);
-        mHostnameView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
-            @Override
-            public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
-                attemptLogin();
-                return true;
-            }
-        });
+        getSupportActionBar().setTitle("Registered Devices");
 
-
-        mLoginFormView = findViewById(R.id.login_form);
-        mProgressView = findViewById(R.id.login_progress);
         mRegisteredStickView = (TextView) findViewById(R.id.registered_usb_devices);
 
         showRegisteredSticks();
@@ -119,21 +80,12 @@ public class GetHmacAndKeyActivity extends AppCompatActivity implements LoaderCa
 
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
-        MenuInflater inflater = getMenuInflater();
-        inflater.inflate(R.menu.menu_register_usb, menu);
-
-        mLoginMenuItem = menu.findItem(R.id.action_menu_login);
-        mLoginMenuItem.setIcon(new IconicsDrawable(this, GoogleMaterial.Icon.gmd_cloud_download).color(Color.WHITE).actionBar());
-
         return true;
     }
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
-            case R.id.action_menu_login:
-                attemptLogin();
-                break;
             case android.R.id.home:
                 finish();
                 break;
@@ -146,103 +98,13 @@ public class GetHmacAndKeyActivity extends AppCompatActivity implements LoaderCa
         super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));
     }
 
-    /**
-     * Attempts to sign in or register the account specified by the login form.
-     * If there are form errors (invalid username, missing fields, etc.), the
-     * errors are presented and no actual login attempt is made.
-     */
-    private void attemptLogin() {
-        if (mHmacAndKeyTask != null || !checkOnline("Please connect to the Internet", "You must be online to register your USB stick.")) {
-            return;
-        }
-
-        // Reset errors.
-        mUsernameView.setError(null);
-        mPasswordView.setError(null);
-        mHostnameView.setError(null);
-
-        // Store values at the time of the login attempt.
-        String username = mUsernameView.getText().toString();
-        String password = mPasswordView.getText().toString();
-        String hostname = mHostnameView.getText().toString();
-
-        boolean cancel = false;
-        View focusView = null;
-
-        // Check for a valid password, if the user entered one.
-        if (TextUtils.isEmpty(password)) {
-            mPasswordView.setError(getString(R.string.error_invalid_password));
-            focusView = mPasswordView;
-            cancel = true;
-        }
-
-        // Check for a valid username address.
-        if (TextUtils.isEmpty(username)) {
-            mUsernameView.setError(getString(R.string.error_field_required));
-            focusView = mUsernameView;
-            cancel = true;
-        }
-
-        // Check for a  carelink server hostname (this is optional for a user to define)
-        if (TextUtils.isEmpty(hostname)) {
-            hostname = getString(R.string.server_hostname); // default
-        }
-
-        if (cancel) {
-            // There was an error; don't attempt login and focus the first
-            // form field with an error.
-            focusView.requestFocus();
-        } else {
-            // Show a progress spinner, and kick off a background task to
-            // perform the user login attempt.
-            showProgress(true);
-            mHmacAndKeyTask = new GetHmacAndKey(username, password, hostname);
-            mHmacAndKeyTask.execute((Void) null);
-        }
-    }
-
-    /**
-     * Shows the progress UI and hides the login form.
-     */
-    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
-    private void showProgress(final boolean show) {
-        // On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
-        // for very easy animations. If available, use these APIs to fade-in
-        // the progress spinner.
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
-            int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);
-
-            mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
-            mLoginFormView.animate().setDuration(shortAnimTime).alpha(
-                    show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
-                }
-            });
-
-            mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
-            mProgressView.animate().setDuration(shortAnimTime).alpha(
-                    show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
-                }
-            });
-        } else {
-            // The ViewPropertyAnimator APIs are not available, so simply show
-            // and hide the relevant UI components.
-            mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
-            mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
-        }
-    }
 
     private void showRegisteredSticks() {
         Realm realm = Realm.getDefaultInstance();
 
         RealmResults<ContourNextLinkInfo> results = realm.where(ContourNextLinkInfo.class).findAll();
 
-        String deviceTableHtml = "<big><b>Registered Devices</b></big><br/>";
+        String deviceTableHtml = "";
 
         for (ContourNextLinkInfo info : results) {
             String longSerial = info.getSerialNumber();
@@ -254,29 +116,6 @@ public class GetHmacAndKeyActivity extends AppCompatActivity implements LoaderCa
         mRegisteredStickView.setText(Html.fromHtml(deviceTableHtml));
     }
 
-    private boolean checkOnline(String title, String message) {
-        ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
-        NetworkInfo netInfo = cm.getActiveNetworkInfo();
-
-        boolean isOnline = (netInfo != null && netInfo.isConnectedOrConnecting());
-
-        if (!isOnline) {
-            new AlertDialog.Builder(this, R.style.AppTheme)
-                    .setTitle(title)
-                    .setMessage(message)
-                    .setCancelable(false)
-                    .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
-                        public void onClick(DialogInterface dialog, int which) {
-                            dialog.dismiss();
-                        }
-                    })
-                    .setIcon(android.R.drawable.ic_dialog_alert)
-                    .show();
-        }
-
-        return isOnline;
-    }
-
     @Override
     public Loader<Cursor> onCreateLoader(int id, Bundle args) {
         return null;
@@ -290,129 +129,5 @@ public class GetHmacAndKeyActivity extends AppCompatActivity implements LoaderCa
     public void onLoaderReset(Loader<Cursor> loader) {
     }
 
-    /**
-     * Represents an asynchronous login/registration task used to authenticate
-     * the user.
-     */
-    public class GetHmacAndKey extends AsyncTask<Void, Void, Boolean> {
-
-        private final String mUsername;
-        private final String mPassword;
-        private final String mHostname;
-
-        // Note: if AsyncTask declaration can be located and changed,
-        // then we can pass status to onPostExecute() in return value
-        // from doInBackground()
-        // and not have to store it this way.
-        private String mStatus = "success";
-
-        GetHmacAndKey(String username, String password, String hostname) {
-            mUsername = username;
-            mPassword = password;
-            mHostname = hostname;
-        }
-
-        @Override
-        protected Boolean doInBackground(final Void... params) {
-            HttpResponse response;
-            try {
-                DefaultHttpClient client = new DefaultHttpClient();
-                HttpPost loginPost = new HttpPost(mHostname + "/patient/j_security_check");
-                List<NameValuePair> nameValuePairs = new ArrayList<>();
-                nameValuePairs.add(new BasicNameValuePair("j_username", mUsername));
-                nameValuePairs.add(new BasicNameValuePair("j_password", mPassword));
-                nameValuePairs.add(new BasicNameValuePair("j_character_encoding", "UTF-8"));
-                loginPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8"));
-                response = client.execute(loginPost);
-
-                if (response.getStatusLine().getStatusCode() == 200) {
-                    // Get the HMAC/keys for every serial we have seen
-                    Realm realm = Realm.getDefaultInstance();
-
-                    RealmResults<ContourNextLinkInfo> results = realm.where(ContourNextLinkInfo.class).findAll();
-                    for (ContourNextLinkInfo info : results) {
-                        String longSerial = info.getSerialNumber();
-
-                        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
-                        ObjectOutputStream hmacRequest = new ObjectOutputStream(buffer);
-                        hmacRequest.writeInt(0x1c);
-                        hmacRequest.writeObject(longSerial.replaceAll("\\d+-", ""));
-
-                        HttpPost hmacPost = new HttpPost(mHostname + "/patient/secure/SnapshotServer/");
-                        hmacPost.setEntity(new ByteArrayEntity(buffer.toByteArray()));
-                        hmacPost.setHeader("Content-type", "application/octet-stream");
-                        response = client.execute(hmacPost);
-
-                        ByteArrayInputStream inputBuffer = new ByteArrayInputStream(EntityUtils.toByteArray(response.getEntity()));
-                        ObjectInputStream hmacResponse = new ObjectInputStream(inputBuffer);
-                        byte[] hmacBytes = (byte[]) hmacResponse.readObject();
-                        ArrayUtils.reverse(hmacBytes);
-                        String hmac = MessageUtils.byteArrayToHexString(hmacBytes);
-
-                        buffer.reset();
-                        inputBuffer.reset();
-
-                        ObjectOutputStream keyRequest = new ObjectOutputStream(buffer);
-                        keyRequest.writeInt(0x1f);
-                        keyRequest.writeObject(longSerial);
-
-                        HttpPost keyPost = new HttpPost(mHostname + "/patient/secure/SnapshotServer/");
-                        keyPost.setEntity(new ByteArrayEntity(buffer.toByteArray()));
-                        keyPost.setHeader("Content-type", "application/octet-stream");
-                        response = client.execute(keyPost);
-
-                        inputBuffer = new ByteArrayInputStream(EntityUtils.toByteArray(response.getEntity()));
-                        ObjectInputStream keyResponse = new ObjectInputStream(inputBuffer);
-                        keyResponse.readInt(); // Throw away the first int. Not sure what it does
-                        String key = MessageUtils.byteArrayToHexString((byte[]) keyResponse.readObject());
-
-                        realm.beginTransaction();
-                        info.setHmac(hmac);
-                        info.setKey(key);
-                        realm.commitTransaction();
-                    }
-
-                    return true;
-                }
-
-            } catch (ClientProtocolException e) {
-                mStatus = getString(R.string.error_client_protocol_exception);
-                return false;
-            } catch (IOException e) {
-                mStatus = getString(R.string.error_io_exception);
-                return false;
-            } catch (ClassNotFoundException e) {
-                mStatus = getString(R.string.error_class_not_found_exception);
-                return false;
-            }
-
-            mStatus = getString(R.string.error_http_response) + "http response: " + response.getStatusLine();
-
-            return false;
-        }
-
-        @Override
-        protected void onPostExecute(final Boolean success) {
-            mHmacAndKeyTask = null;
-
-            if (success) {
-                showRegisteredSticks();
-                mLoginMenuItem.setVisible(false);
-                mLoginFormView.setVisibility(View.GONE);
-                mProgressView.setVisibility(View.GONE);
-                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
-                imm.hideSoftInputFromWindow(mLoginFormView.getWindowToken(), 0);
-            } else {
-                showProgress(false);
-                mPasswordView.setError(mStatus);
-                mPasswordView.requestFocus();
-            }
-        }
-
-        @Override
-        protected void onCancelled() {
-            mHmacAndKeyTask = null;
-            showProgress(false);
-        }
-    }
 }
+
diff --git a/app/src/main/java/info/nightscout/android/medtronic/MainActivity.java b/app/src/main/java/info/nightscout/android/medtronic/MainActivity.java
index 6905665497f5f23e3f18498ffd4eff166fbbf795..d1249934460aebef1968d8ab832c1dcdbb04f5f3 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/MainActivity.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/MainActivity.java
@@ -3,6 +3,7 @@ package info.nightscout.android.medtronic;
 import android.app.AlarmManager;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -12,11 +13,14 @@ import android.content.SharedPreferences;
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbManager;
+import android.net.Uri;
 import android.os.BatteryManager;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.SystemClock;
+import android.os.PowerManager;
 import android.preference.PreferenceManager;
+import android.provider.Settings;
 import android.support.v4.app.TaskStackBuilder;
 import android.support.v4.content.LocalBroadcastManager;
 import android.support.v7.app.AlertDialog;
@@ -107,6 +111,28 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
             stopCgmService();
         }
 
+        // Disable battery optimization to avoid missing values on 6.0+
+        // taken from https://github.com/NightscoutFoundation/xDrip/blob/master/app/src/main/java/com/eveningoutpost/dexdrip/Home.java#L277L298
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            final String packageName = getPackageName();
+            //Log.d(TAG, "Maybe ignoring battery optimization");
+            final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
+            if (!pm.isIgnoringBatteryOptimizations(packageName)) {
+                Log.d(TAG, "Requesting ignore battery optimization");
+                try {
+                    // ignoring battery optimizations required for constant connection
+                    // to peripheral device - eg CGM transmitter.
+                    final Intent intent = new Intent();
+                    intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
+                    intent.setData(Uri.parse("package:" + packageName));
+                    startActivity(intent);
+                } catch (ActivityNotFoundException e) {
+                    Log.d(TAG, "Device does not appear to support battery optimization whitelisting!");
+                }
+            }
+        }
+
         LocalBroadcastManager.getInstance(this).registerReceiver(
                 statusMessageReceiver,
                 new IntentFilter(MedtronicCnlIntentService.Constants.ACTION_STATUS_MESSAGE));
@@ -149,7 +175,7 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
                 .withIcon(GoogleMaterial.Icon.gmd_settings)
                 .withSelectable(false);
         final PrimaryDrawerItem itemRegisterUsb = new PrimaryDrawerItem()
-                .withName("Register Contour Next Link")
+                .withName("Registered Devices")
                 .withIcon(GoogleMaterial.Icon.gmd_usb)
                 .withSelectable(false);
         final PrimaryDrawerItem itemStopCollecting = new PrimaryDrawerItem()
@@ -246,8 +272,8 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
     private boolean hasDetectedCnl() {
         if (mRealm.where(ContourNextLinkInfo.class).count() == 0) {
             new AlertDialog.Builder(this, R.style.AppTheme)
-                    .setTitle("Contour Next Link not detected")
-                    .setMessage("To register a Contour Next Link you must first plug it in.")
+                    .setTitle("No registered Contour Next Link devices")
+                    .setMessage("To register a Contour Next Link you must first plug it in, and get a reading from the pump.")
                     .setCancelable(false)
                     .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                         public void onClick(DialogInterface dialog, int which) {
@@ -266,7 +292,6 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
         UsbDevice cnlDevice = UsbHidDriver.getUsbDevice(usbManager, MedtronicCnlIntentService.USB_VID, MedtronicCnlIntentService.USB_PID);
 
         return !(usbManager != null && cnlDevice != null && !usbManager.hasPermission(cnlDevice));
-
     }
 
     private void waitForUsbPermission() {
@@ -305,7 +330,7 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
     }
 
     private void startCgmService() {
-        startCgmService(System.currentTimeMillis());
+        startCgmService(System.currentTimeMillis() + 1000);
     }
 
     private void startCgmService(long initialPoll) {
@@ -524,8 +549,6 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
     private class RefreshDisplayRunnable implements Runnable {
         @Override
         public void run() {
-            Log.d(TAG, "NOW " + new Date(System.currentTimeMillis()).toString());
-
             // UI elements - TODO do these need to be members?
             TextView textViewBg = (TextView) findViewById(R.id.textview_bg);
             TextView textViewBgTime = (TextView) findViewById(R.id.textview_bg_time);
@@ -630,11 +653,9 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
                 return;
             }
 
-            long nextPoll = pumpStatusData.getEventDate().getTime() + MedtronicCnlIntentService.POLL_GRACE_PERIOD_MS + MedtronicCnlIntentService.POLL_PERIOD_MS;
+            long nextPoll = pumpStatusData.getEventDate().getTime() + pumpStatusData.getPumpTimeOffset()
+                    + MedtronicCnlIntentService.POLL_GRACE_PERIOD_MS + MedtronicCnlIntentService.POLL_PERIOD_MS;
             startCgmService(nextPoll);
-            Log.d(TAG, "Local time " + new Date());
-            Log.d(TAG, "Last event was " + new Date(pumpStatusData.getEventDate().getTime()));
-            Log.d(TAG, "Next Poll at " + new Date(nextPoll).toString());
 
             // Delete invalid or old records from Realm
             // TODO - show an error message if the valid records haven't been uploaded
diff --git a/app/src/main/java/info/nightscout/android/medtronic/MedtronicCNLSession.java b/app/src/main/java/info/nightscout/android/medtronic/MedtronicCNLSession.java
deleted file mode 100644
index 6c1ac2f55a6295cb70d7ada74b9825bd6755926f..0000000000000000000000000000000000000000
--- a/app/src/main/java/info/nightscout/android/medtronic/MedtronicCNLSession.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package info.nightscout.android.medtronic;
-
-/**
- * Created by lgoedhart on 26/03/2016.
- */
-public class MedtronicCNLSession {
-    private byte[] HMAC;
-    private byte[] key;
-
-    private long linkMAC;
-    private long pumpMAC;
-
-    private byte radioChannel;
-    private int bayerSequenceNumber = 1;
-    private int medtronicSequenceNumber = 1;
-
-    public byte[] getHMAC() {
-        return HMAC;
-    }
-
-    public byte[] getKey() {
-        return key;
-    }
-    public byte[] getIV() {
-        byte[] iv = new byte[key.length];
-        System.arraycopy(key,0,iv,0,key.length);
-        iv[0] = radioChannel;
-        return iv;
-    }
-
-    public long getLinkMAC() {
-        return linkMAC;
-    }
-
-    public void setLinkMAC( long linkMAC ) {
-        this.linkMAC = linkMAC;
-    }
-
-    public long getPumpMAC() {
-        return pumpMAC;
-    }
-
-    public void setPumpMAC( long pumpMAC ) {
-        this.pumpMAC = pumpMAC;
-    }
-
-    public int getBayerSequenceNumber() {
-        return bayerSequenceNumber;
-    }
-
-    public int getMedtronicSequenceNumber() {
-        return medtronicSequenceNumber;
-    }
-
-    public byte getRadioChannel() {
-        return radioChannel;
-    }
-
-    public void incrBayerSequenceNumber() {
-        bayerSequenceNumber++;
-    }
-
-    public void incrMedtronicSequenceNumber() {
-        medtronicSequenceNumber++;
-    }
-
-    public void setRadioChannel(byte radioChannel) {
-        this.radioChannel = radioChannel;
-    }
-
-    public void setHMAC( byte[] hmac ) {
-        this.HMAC = hmac;
-    }
-
-    public void setKey( byte[] key ) {
-        this.key = key;
-    }
-}
diff --git a/app/src/main/java/info/nightscout/android/medtronic/MedtronicCNLReader.java b/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlReader.java
similarity index 94%
rename from app/src/main/java/info/nightscout/android/medtronic/MedtronicCNLReader.java
rename to app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlReader.java
index 505f6414814beaee557686a4cb9d194848767da7..6dd908f0dd3f57b8d8c585d51690eaee4b82df5b 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/MedtronicCNLReader.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlReader.java
@@ -9,6 +9,7 @@ import java.io.IOException;
 import java.math.BigDecimal;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
@@ -36,6 +37,7 @@ import info.nightscout.android.medtronic.message.PumpStatusResponseMessage;
 import info.nightscout.android.medtronic.message.PumpTimeRequestMessage;
 import info.nightscout.android.medtronic.message.PumpTimeResponseMessage;
 import info.nightscout.android.medtronic.message.ReadInfoResponseMessage;
+import info.nightscout.android.medtronic.message.RequestLinkKeyResponseMessage;
 import info.nightscout.android.medtronic.message.UnexpectedMessageException;
 import info.nightscout.android.model.medtronicNg.PumpStatusEvent;
 import info.nightscout.android.utils.HexDump;
@@ -43,9 +45,9 @@ import info.nightscout.android.utils.HexDump;
 /**
  * Created by lgoedhart on 24/03/2016.
  */
-public class MedtronicCNLReader implements ContourNextLinkMessageHandler {
+public class MedtronicCnlReader implements ContourNextLinkMessageHandler {
 
-    private static final String TAG = MedtronicCNLReader.class.getSimpleName();
+    private static final String TAG = MedtronicCnlReader.class.getSimpleName();
 
     private static final int USB_BLOCKSIZE = 64;
     private static final int READ_TIMEOUT_MS = 5000;
@@ -54,11 +56,11 @@ public class MedtronicCNLReader implements ContourNextLinkMessageHandler {
     private static final byte[] RADIO_CHANNELS = {0x14, 0x11, 0x0e, 0x17, 0x1a};
     private UsbHidDriver mDevice;
 
-    private MedtronicCNLSession mPumpSession = new MedtronicCNLSession();
+    private MedtronicCnlSession mPumpSession = new MedtronicCnlSession();
 
     private String mStickSerial = null;
 
-    public MedtronicCNLReader(UsbHidDriver device) {
+    public MedtronicCnlReader(UsbHidDriver device) {
         mDevice = device;
     }
 
@@ -87,7 +89,7 @@ public class MedtronicCNLReader implements ContourNextLinkMessageHandler {
         return mStickSerial;
     }
 
-    public MedtronicCNLSession getPumpSession() {
+    public MedtronicCnlSession getPumpSession() {
         return mPumpSession;
     }
 
@@ -238,7 +240,7 @@ public class MedtronicCNLReader implements ContourNextLinkMessageHandler {
         Log.d(TAG, "Finished enterPasshtroughMode");
     }
 
-    public void openConnection() throws IOException, TimeoutException {
+    public void openConnection() throws IOException, TimeoutException, NoSuchAlgorithmException {
         Log.d(TAG, "Begin openConnection");
         new ContourNextLinkBinaryMessage(ContourNextLinkBinaryMessage.CommandType.OPEN_CONNECTION, mPumpSession, mPumpSession.getHMAC()).send(this);
         // FIXME - We need to care what the response message is - wrong MAC and all that
@@ -264,6 +266,24 @@ public class MedtronicCNLReader implements ContourNextLinkMessageHandler {
         Log.d(TAG, String.format("Finished requestReadInfo. linkMAC = '%d', pumpMAC = '%d", linkMAC, pumpMAC));
     }
 
+    public void requestLinkKey() throws IOException, TimeoutException, EncryptionException, ChecksumException {
+        Log.d(TAG, "Begin requestLinkKey");
+        new ContourNextLinkBinaryMessage(ContourNextLinkBinaryMessage.CommandType.REQUEST_LINK_KEY, mPumpSession, null).send(this);
+
+        ContourNextLinkMessage response = RequestLinkKeyResponseMessage.fromBytes(mPumpSession, readMessage());
+
+        // FIXME - this needs to go into RequestLinkKeyResponseMessage
+        ByteBuffer infoBuffer = ByteBuffer.allocate(55);
+        infoBuffer.order(ByteOrder.BIG_ENDIAN);
+        infoBuffer.put(response.encode(), 0x21, 55);
+
+        byte[] packedLinkKey = infoBuffer.array();
+
+        this.getPumpSession().setPackedLinkKey(packedLinkKey);
+
+        Log.d(TAG, String.format("Finished requestLinkKey. linkKey = '%s'", this.getPumpSession().getKey()));
+    }
+
     public byte negotiateChannel(byte lastRadioChannel) throws IOException, ChecksumException, TimeoutException {
         ArrayList<Byte> radioChannels = new ArrayList<>(Arrays.asList(ArrayUtils.toObject(RADIO_CHANNELS)));
 
diff --git a/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlSession.java b/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlSession.java
new file mode 100644
index 0000000000000000000000000000000000000000..215e7f3e6174163da35db8824c928d87f5d454bb
--- /dev/null
+++ b/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlSession.java
@@ -0,0 +1,130 @@
+package info.nightscout.android.medtronic;
+
+import org.apache.commons.lang3.ArrayUtils;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * Created by lgoedhart on 26/03/2016.
+ */
+public class MedtronicCnlSession {
+    private static final String HMAC_PADDING = "A4BD6CED9A42602564F413123";
+
+    private byte[] HMAC;
+    private byte[] key;
+
+    private String stickSerial;
+
+    private long linkMAC;
+    private long pumpMAC;
+
+    private byte radioChannel;
+    private int bayerSequenceNumber = 1;
+    private int medtronicSequenceNumber = 1;
+
+    /*public byte[] getHMAC() {
+        return HMAC;
+    }*/
+
+    public byte[] getHMAC() throws NoSuchAlgorithmException {
+        String shortSerial = this.stickSerial.replaceAll("\\d+-", "");
+        byte[] message = (shortSerial + HMAC_PADDING).getBytes();
+        byte[] numArray;
+
+        MessageDigest instance = MessageDigest.getInstance("SHA-256");
+        instance.update(message);
+
+        numArray = instance.digest();
+        ArrayUtils.reverse(numArray);
+
+        return numArray;
+    }
+
+    public byte[] getKey() {
+        return key;
+    }
+
+    public byte[] getIV() {
+        byte[] iv = new byte[key.length];
+        System.arraycopy(key, 0, iv, 0, key.length);
+        iv[0] = radioChannel;
+        return iv;
+    }
+
+    public long getLinkMAC() {
+        return linkMAC;
+    }
+
+    public void setLinkMAC(long linkMAC) {
+        this.linkMAC = linkMAC;
+    }
+
+    public long getPumpMAC() {
+        return pumpMAC;
+    }
+
+    public void setPumpMAC(long pumpMAC) {
+        this.pumpMAC = pumpMAC;
+    }
+
+    public int getBayerSequenceNumber() {
+        return bayerSequenceNumber;
+    }
+
+    public int getMedtronicSequenceNumber() {
+        return medtronicSequenceNumber;
+    }
+
+    public byte getRadioChannel() {
+        return radioChannel;
+    }
+
+    public void incrBayerSequenceNumber() {
+        bayerSequenceNumber++;
+    }
+
+    public void incrMedtronicSequenceNumber() {
+        medtronicSequenceNumber++;
+    }
+
+    public void setRadioChannel(byte radioChannel) {
+        this.radioChannel = radioChannel;
+    }
+
+    public void setHMAC(byte[] hmac) {
+        this.HMAC = hmac;
+    }
+
+    public void setKey(byte[] key) {
+        this.key = key;
+    }
+
+    public void setPackedLinkKey(byte[] packedLinkKey) {
+        this.key = new byte[16];
+
+        int pos = this.stickSerial.charAt(this.stickSerial.length() - 1) & 7;
+
+        for (int i = 0; i < this.key.length; i++) {
+            if ((packedLinkKey[pos + 1] & 1) == 1) {
+                this.key[i] = (byte) ~packedLinkKey[pos];
+            } else {
+                this.key[i] = packedLinkKey[pos];
+            }
+
+            if (((packedLinkKey[pos + 1] >> 1) & 1) == 0) {
+                pos += 3;
+            } else {
+                pos += 2;
+            }
+        }
+    }
+
+    public String getStickSerial() {
+        return stickSerial;
+    }
+
+    public void setStickSerial(String stickSerial) {
+        this.stickSerial = stickSerial;
+    }
+}
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/BeginEHSMMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/BeginEHSMMessage.java
index ed1c7d8f18c7cc61920428de4ec47ed5f6a1dc91..e2ee643a1a0d9f7de0a0c566c6d2d147ad6e3e19 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/message/BeginEHSMMessage.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/BeginEHSMMessage.java
@@ -1,12 +1,12 @@
 package info.nightscout.android.medtronic.message;
 
-import info.nightscout.android.medtronic.MedtronicCNLSession;
+import info.nightscout.android.medtronic.MedtronicCnlSession;
 
 /**
  * Created by lgoedhart on 26/03/2016.
  */
 public class BeginEHSMMessage extends MedtronicSendMessage {
-    public BeginEHSMMessage(MedtronicCNLSession pumpSession) throws EncryptionException {
+    public BeginEHSMMessage(MedtronicCnlSession pumpSession) throws EncryptionException {
         super(SendMessageType.BEGIN_EHSM_SESSION, pumpSession, buildPayload());
     }
 
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/ChannelNegotiateMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/ChannelNegotiateMessage.java
index cce33d28ea977c9f978269c0d1938bb189e0cff2..eda3ce6f6f514f3045396216dc658b65e825e5fc 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/message/ChannelNegotiateMessage.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/ChannelNegotiateMessage.java
@@ -1,6 +1,6 @@
 package info.nightscout.android.medtronic.message;
 
-import info.nightscout.android.medtronic.MedtronicCNLSession;
+import info.nightscout.android.medtronic.MedtronicCnlSession;
 
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
@@ -9,11 +9,11 @@ import java.nio.ByteOrder;
  * Created by lgoedhart on 26/03/2016.
  */
 public class ChannelNegotiateMessage extends MedtronicMessage {
-    public ChannelNegotiateMessage(MedtronicCNLSession pumpSession) {
+    public ChannelNegotiateMessage(MedtronicCnlSession pumpSession) {
         super(CommandType.SEND_MESSAGE, CommandAction.CHANNEL_NEGOTIATE, pumpSession, buildPayload(pumpSession));
     }
 
-    protected static byte[] buildPayload( MedtronicCNLSession pumpSession ) {
+    protected static byte[] buildPayload( MedtronicCnlSession pumpSession ) {
         ByteBuffer payload = ByteBuffer.allocate(26);
         payload.order(ByteOrder.LITTLE_ENDIAN);
         // The MedtronicMessage sequence number is always sent as 1 for this message,
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkBinaryMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkBinaryMessage.java
index 33eda925bd298ff4079372cf0189bfc82c1e1d83..95e94baa56ef73718e3db0d2d13e272f8b48a058 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkBinaryMessage.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkBinaryMessage.java
@@ -1,6 +1,6 @@
 package info.nightscout.android.medtronic.message;
 
-import info.nightscout.android.medtronic.MedtronicCNLSession;
+import info.nightscout.android.medtronic.MedtronicCnlSession;
 
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
@@ -34,13 +34,17 @@ public class ContourNextLinkBinaryMessage extends ContourNextLinkMessage{
         CommandType(int commandType) {
             value = (byte) commandType;
         }
+
+        public int getValue() {
+            return value;
+        }
     }
 
-    public ContourNextLinkBinaryMessage(CommandType commandType, MedtronicCNLSession pumpSession, byte[] payload) {
+    public ContourNextLinkBinaryMessage(CommandType commandType, MedtronicCnlSession pumpSession, byte[] payload) {
         super(buildPayload(commandType, pumpSession, payload));
     }
 
-    protected static byte[] buildPayload(CommandType commandType, MedtronicCNLSession pumpSession, byte[] payload) {
+    protected static byte[] buildPayload(CommandType commandType, MedtronicCnlSession pumpSession, byte[] payload) {
         int payloadLength = payload == null ? 0 : payload.length;
 
         ByteBuffer payloadBuffer = ByteBuffer.allocate( ENVELOPE_SIZE + payloadLength );
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/EndEHSMMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/EndEHSMMessage.java
index fe1adae580d34b37306f8a7ed30d536bff49448b..0364110375aec3d9c5f6b9c940f500d363758e4f 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/message/EndEHSMMessage.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/EndEHSMMessage.java
@@ -1,12 +1,12 @@
 package info.nightscout.android.medtronic.message;
 
-import info.nightscout.android.medtronic.MedtronicCNLSession;
+import info.nightscout.android.medtronic.MedtronicCnlSession;
 
 /**
  * Created by lgoedhart on 26/03/2016.
  */
 public class EndEHSMMessage extends MedtronicSendMessage {
-    public EndEHSMMessage(MedtronicCNLSession pumpSession) throws EncryptionException {
+    public EndEHSMMessage(MedtronicCnlSession pumpSession) throws EncryptionException {
         super(SendMessageType.END_EHSM_SESSION, pumpSession, buildPayload());
     }
 
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicMessage.java
index aed8d129f378cd16c779c13f83b3d0c857ccce81..25588505ab2e817307d0428108a0e2bb98ef4eb7 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicMessage.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicMessage.java
@@ -1,6 +1,6 @@
 package info.nightscout.android.medtronic.message;
 
-import info.nightscout.android.medtronic.MedtronicCNLSession;
+import info.nightscout.android.medtronic.MedtronicCnlSession;
 
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
@@ -29,7 +29,7 @@ public class MedtronicMessage extends ContourNextLinkBinaryMessage {
         }
     }
 
-    protected MedtronicMessage(CommandType commandType, CommandAction commandAction, MedtronicCNLSession pumpSession, byte[] payload) {
+    protected MedtronicMessage(CommandType commandType, CommandAction commandAction, MedtronicCnlSession pumpSession, byte[] payload) {
         super(commandType, pumpSession, buildPayload(commandAction, payload));
     }
 
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicReceiveMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicReceiveMessage.java
index 63d854a6e12871c1a6fae098011f5ecfb120dbb3..c2f4a7d58cf10d70925e3d2ab15e3358a4ff3a3f 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicReceiveMessage.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicReceiveMessage.java
@@ -1,6 +1,6 @@
 package info.nightscout.android.medtronic.message;
 
-import info.nightscout.android.medtronic.MedtronicCNLSession;
+import info.nightscout.android.medtronic.MedtronicCnlSession;
 
 import java.nio.ByteBuffer;
 
@@ -12,7 +12,7 @@ public class MedtronicReceiveMessage extends MedtronicMessage {
     static int ENCRYPTED_ENVELOPE_SIZE = 3;
     static int CRC_SIZE = 2;
 
-    protected MedtronicReceiveMessage(CommandType commandType, CommandAction commandAction, MedtronicCNLSession pumpSession, byte[] payload) {
+    protected MedtronicReceiveMessage(CommandType commandType, CommandAction commandAction, MedtronicCnlSession pumpSession, byte[] payload) {
         super(commandType, commandAction, pumpSession, payload);
     }
 
@@ -38,14 +38,17 @@ public class MedtronicReceiveMessage extends MedtronicMessage {
      * | byte receiveSequenceNumber | BE short receiveMessageType | byte[] Payload bytes | BE short CCITT CRC |
      * +----------------------------+-----------------------------+----------------------+--------------------+
      */
-    public static ContourNextLinkMessage fromBytes(MedtronicCNLSession pumpSession, byte[] bytes) throws ChecksumException, EncryptionException {
+    public static ContourNextLinkMessage fromBytes(MedtronicCnlSession pumpSession, byte[] bytes) throws ChecksumException, EncryptionException {
         // TODO - turn this into a factory
         ContourNextLinkMessage message = MedtronicMessage.fromBytes(bytes);
 
         // TODO - Validate the message, inner CCITT, serial numbers, etc
 
         // If there's not 57 bytes, then we got back a bad message. Not sure how to process these yet.
-        if( bytes.length >= 57 ) {
+        // Also, READ_INFO and REQUEST_LINK_KEY are not encrypted
+        if (bytes.length >= 57 &&
+                (bytes[18] != CommandType.READ_INFO.getValue()) &&
+                (bytes[18] != CommandType.REQUEST_LINK_KEY_RESPONSE.getValue())) {
             // Replace the encrypted bytes by their decrypted equivalent (same block size)
             byte encryptedPayloadSize = bytes[56];
 
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicSendMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicSendMessage.java
index 4d099d8e59d831d04bf6d50789813d2cc6118393..7bba4ded16da96428fd056f5b985ce821ee9e63e 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicSendMessage.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicSendMessage.java
@@ -1,6 +1,6 @@
 package info.nightscout.android.medtronic.message;
 
-import info.nightscout.android.medtronic.MedtronicCNLSession;
+import info.nightscout.android.medtronic.MedtronicCnlSession;
 
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
@@ -28,7 +28,7 @@ public class MedtronicSendMessage extends MedtronicMessage {
         }
     }
 
-    protected MedtronicSendMessage(SendMessageType sendMessageType, MedtronicCNLSession pumpSession, byte[] payload) throws EncryptionException {
+    protected MedtronicSendMessage(SendMessageType sendMessageType, MedtronicCnlSession pumpSession, byte[] payload) throws EncryptionException {
         super(CommandType.SEND_MESSAGE, CommandAction.PUMP_REQUEST, pumpSession, buildPayload(sendMessageType, pumpSession, payload));
     }
 
@@ -43,7 +43,7 @@ public class MedtronicSendMessage extends MedtronicMessage {
      * | byte sendSequenceNumber | BE short sendMessageType | byte[] Payload bytes | BE short CCITT CRC |
      * +-------------------------+----------------------+----------------------+--------------------+
      */
-    protected static byte[] buildPayload(SendMessageType sendMessageType, MedtronicCNLSession pumpSession, byte[] payload) throws EncryptionException {
+    protected static byte[] buildPayload(SendMessageType sendMessageType, MedtronicCnlSession pumpSession, byte[] payload) throws EncryptionException {
         byte payloadLength = (byte) (payload == null ? 0 : payload.length);
 
         ByteBuffer sendPayloadBuffer = ByteBuffer.allocate(ENCRYPTED_ENVELOPE_SIZE + payloadLength + CRC_SIZE);
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/PumpBasalPatternRequestMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/PumpBasalPatternRequestMessage.java
index c1aefefde92979edb4dcd3df29c91d14855a1131..d31eb36a229654efedd6b9849fac749c1b748254 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/message/PumpBasalPatternRequestMessage.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/PumpBasalPatternRequestMessage.java
@@ -1,12 +1,12 @@
 package info.nightscout.android.medtronic.message;
 
-import info.nightscout.android.medtronic.MedtronicCNLSession;
+import info.nightscout.android.medtronic.MedtronicCnlSession;
 
 /**
  * Created by lgoedhart on 26/03/2016.
  */
 public class PumpBasalPatternRequestMessage extends MedtronicSendMessage {
-    public PumpBasalPatternRequestMessage(MedtronicCNLSession pumpSession) throws EncryptionException {
+    public PumpBasalPatternRequestMessage(MedtronicCnlSession pumpSession) throws EncryptionException {
         super(SendMessageType.READ_BASAL_PATTERN_REQUEST, pumpSession, null);
     }
 }
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/PumpBasalPatternResponseMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/PumpBasalPatternResponseMessage.java
index 7aee86799f4e3bb61c72c492820472971ac78267..d4b4ef97d55422a5d5be2a5179879569a59cfcad 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/message/PumpBasalPatternResponseMessage.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/PumpBasalPatternResponseMessage.java
@@ -1,16 +1,16 @@
 package info.nightscout.android.medtronic.message;
 
-import info.nightscout.android.medtronic.MedtronicCNLSession;
+import info.nightscout.android.medtronic.MedtronicCnlSession;
 
 /**
  * Created by lgoedhart on 27/03/2016.
  */
 public class PumpBasalPatternResponseMessage extends MedtronicReceiveMessage {
-    protected PumpBasalPatternResponseMessage(CommandType commandType, CommandAction commandAction, MedtronicCNLSession pumpSession, byte[] payload) {
+    protected PumpBasalPatternResponseMessage(CommandType commandType, CommandAction commandAction, MedtronicCnlSession pumpSession, byte[] payload) {
         super(commandType, commandAction, pumpSession, payload);
     }
 
-    public static ContourNextLinkMessage fromBytes(MedtronicCNLSession pumpSession, byte[] bytes) throws ChecksumException, EncryptionException {
+    public static ContourNextLinkMessage fromBytes(MedtronicCnlSession pumpSession, byte[] bytes) throws ChecksumException, EncryptionException {
         // TODO - turn this into a factory
         ContourNextLinkMessage message = MedtronicReceiveMessage.fromBytes(pumpSession, bytes);
 
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusRequestMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusRequestMessage.java
index aba4dc62d0db5aea298fa4fcc8160b3e7162185a..1162bfe139ca65e06fe1eb95571f1ff67520f78c 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusRequestMessage.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusRequestMessage.java
@@ -1,12 +1,12 @@
 package info.nightscout.android.medtronic.message;
 
-import info.nightscout.android.medtronic.MedtronicCNLSession;
+import info.nightscout.android.medtronic.MedtronicCnlSession;
 
 /**
  * Created by lgoedhart on 26/03/2016.
  */
 public class PumpStatusRequestMessage extends MedtronicSendMessage {
-    public PumpStatusRequestMessage(MedtronicCNLSession pumpSession) throws EncryptionException {
+    public PumpStatusRequestMessage(MedtronicCnlSession pumpSession) throws EncryptionException {
         super(SendMessageType.READ_PUMP_STATUS_REQUEST, pumpSession, null);
     }
 }
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusResponseMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusResponseMessage.java
index bbd3c3b63c916c6ee20439a83dbc70223d54bf8a..06e9a0f3357d2456f64a5eb7c84ac3218d1e35ee 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusResponseMessage.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusResponseMessage.java
@@ -1,16 +1,16 @@
 package info.nightscout.android.medtronic.message;
 
-import info.nightscout.android.medtronic.MedtronicCNLSession;
+import info.nightscout.android.medtronic.MedtronicCnlSession;
 
 /**
  * Created by lgoedhart on 27/03/2016.
  */
 public class PumpStatusResponseMessage extends MedtronicReceiveMessage {
-    protected PumpStatusResponseMessage(CommandType commandType, CommandAction commandAction, MedtronicCNLSession pumpSession, byte[] payload) {
+    protected PumpStatusResponseMessage(CommandType commandType, CommandAction commandAction, MedtronicCnlSession pumpSession, byte[] payload) {
         super(commandType, commandAction, pumpSession, payload);
     }
 
-    public static ContourNextLinkMessage fromBytes(MedtronicCNLSession pumpSession, byte[] bytes) throws ChecksumException, EncryptionException {
+    public static ContourNextLinkMessage fromBytes(MedtronicCnlSession pumpSession, byte[] bytes) throws ChecksumException, EncryptionException {
         // TODO - turn this into a factory
         ContourNextLinkMessage message = MedtronicReceiveMessage.fromBytes(pumpSession, bytes);
 
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/PumpTimeRequestMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/PumpTimeRequestMessage.java
index 97fb82065755fe04806bb1862ea38940c8f1c40d..89305b0a9b3873d3ec4079eeacebf8d740443ffe 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/message/PumpTimeRequestMessage.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/PumpTimeRequestMessage.java
@@ -1,12 +1,12 @@
 package info.nightscout.android.medtronic.message;
 
-import info.nightscout.android.medtronic.MedtronicCNLSession;
+import info.nightscout.android.medtronic.MedtronicCnlSession;
 
 /**
  * Created by lgoedhart on 26/03/2016.
  */
 public class PumpTimeRequestMessage extends MedtronicSendMessage {
-    public PumpTimeRequestMessage(MedtronicCNLSession pumpSession) throws EncryptionException {
+    public PumpTimeRequestMessage(MedtronicCnlSession pumpSession) throws EncryptionException {
         super(SendMessageType.TIME_REQUEST, pumpSession, null);
     }
 }
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/PumpTimeResponseMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/PumpTimeResponseMessage.java
index 940f9afa38015f6bb9dc185fdd84a28baf4d1a8e..3437dd69c65e9adfe188966ea14cbc1a6f8afb18 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/message/PumpTimeResponseMessage.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/PumpTimeResponseMessage.java
@@ -1,16 +1,16 @@
 package info.nightscout.android.medtronic.message;
 
-import info.nightscout.android.medtronic.MedtronicCNLSession;
+import info.nightscout.android.medtronic.MedtronicCnlSession;
 
 /**
  * Created by lgoedhart on 27/03/2016.
  */
 public class PumpTimeResponseMessage extends MedtronicReceiveMessage {
-    protected PumpTimeResponseMessage(CommandType commandType, CommandAction commandAction, MedtronicCNLSession pumpSession, byte[] payload) {
+    protected PumpTimeResponseMessage(CommandType commandType, CommandAction commandAction, MedtronicCnlSession pumpSession, byte[] payload) {
         super(commandType, commandAction, pumpSession, payload);
     }
 
-    public static ContourNextLinkMessage fromBytes(MedtronicCNLSession pumpSession, byte[] bytes) throws ChecksumException, EncryptionException {
+    public static ContourNextLinkMessage fromBytes(MedtronicCnlSession pumpSession, byte[] bytes) throws ChecksumException, EncryptionException {
         // TODO - turn this into a factory
         ContourNextLinkMessage message = MedtronicReceiveMessage.fromBytes(pumpSession, bytes);
 
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/ReadInfoResponseMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/ReadInfoResponseMessage.java
index 980392929a454a5cd841d74de46f5e46b7669aef..68aab2df7977d4235e1c445b4b8ac0692d16e88b 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/message/ReadInfoResponseMessage.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/ReadInfoResponseMessage.java
@@ -1,16 +1,16 @@
 package info.nightscout.android.medtronic.message;
 
-import info.nightscout.android.medtronic.MedtronicCNLSession;
+import info.nightscout.android.medtronic.MedtronicCnlSession;
 
 /**
  * Created by lgoedhart on 10/05/2016.
  */
 public class ReadInfoResponseMessage extends MedtronicReceiveMessage {
-    protected ReadInfoResponseMessage(CommandType commandType, CommandAction commandAction, MedtronicCNLSession pumpSession, byte[] payload) {
+    protected ReadInfoResponseMessage(CommandType commandType, CommandAction commandAction, MedtronicCnlSession pumpSession, byte[] payload) {
         super(commandType, commandAction, pumpSession, payload);
     }
 
-    public static ContourNextLinkMessage fromBytes(MedtronicCNLSession pumpSession, byte[] bytes) throws ChecksumException, EncryptionException {
+    public static ContourNextLinkMessage fromBytes(MedtronicCnlSession pumpSession, byte[] bytes) throws ChecksumException, EncryptionException {
         // TODO - turn this into a factory
         ContourNextLinkMessage message = MedtronicReceiveMessage.fromBytes(pumpSession, bytes);
 
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/RequestLinkKeyResponseMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/RequestLinkKeyResponseMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..423e40fb8ab61296fc9c26995837a56932715a7e
--- /dev/null
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/RequestLinkKeyResponseMessage.java
@@ -0,0 +1,21 @@
+package info.nightscout.android.medtronic.message;
+
+import info.nightscout.android.medtronic.MedtronicCnlSession;
+
+/**
+ * Created by lgoedhart on 10/05/2016.
+ */
+public class RequestLinkKeyResponseMessage extends MedtronicReceiveMessage {
+    protected RequestLinkKeyResponseMessage(CommandType commandType, CommandAction commandAction, MedtronicCnlSession pumpSession, byte[] payload) {
+        super(commandType, commandAction, pumpSession, payload);
+    }
+
+    public static ContourNextLinkMessage fromBytes(MedtronicCnlSession pumpSession, byte[] bytes) throws ChecksumException, EncryptionException {
+        // TODO - turn this into a factory
+        ContourNextLinkMessage message = MedtronicReceiveMessage.fromBytes(pumpSession, bytes);
+
+        // TODO - Validate the MessageType
+
+        return message;
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlAlarmReceiver.java b/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlAlarmReceiver.java
index a0af992a915f00cd4c9ca02e5d240b3371f5ba2a..49e648c68cc37df7ca643e632c9c76b1457b32f0 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlAlarmReceiver.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlAlarmReceiver.java
@@ -4,6 +4,7 @@ import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
+import android.os.Build;
 import android.support.v4.content.WakefulBroadcastReceiver;
 import android.util.Log;
 
@@ -16,8 +17,8 @@ public class MedtronicCnlAlarmReceiver extends WakefulBroadcastReceiver {
     private static final String TAG = MedtronicCnlAlarmReceiver.class.getSimpleName();
     private static final int ALARM_ID = 102; // Alarm id
 
-    private static PendingIntent pi = null;
-    private static AlarmManager am = null;
+    private static PendingIntent pendingIntent = null;
+    private static AlarmManager alarmManager = null;
 
     @Override
     public void onReceive(final Context context, Intent intent) {
@@ -31,9 +32,9 @@ public class MedtronicCnlAlarmReceiver extends WakefulBroadcastReceiver {
     public void setContext(Context context) {
         cancelAlarm();
 
-        am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+        alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
         Intent intent = new Intent(context, MedtronicCnlAlarmReceiver.class);
-        pi = PendingIntent.getBroadcast(context, ALARM_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+        pendingIntent = PendingIntent.getBroadcast(context, ALARM_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
     }
 
     // Setting the alarm in 15 seconds from now
@@ -43,7 +44,7 @@ public class MedtronicCnlAlarmReceiver extends WakefulBroadcastReceiver {
 
     // Setting the alarm to call onRecieve
     public void setAlarm(long millis) {
-        if (am == null || pi == null)
+        if (alarmManager == null || pendingIntent == null)
             return;
 
         cancelAlarm();
@@ -53,7 +54,12 @@ public class MedtronicCnlAlarmReceiver extends WakefulBroadcastReceiver {
             millis = System.currentTimeMillis();
 
         Log.d(TAG, "AlarmManager set to fire   at " + new Date(millis));
-        am.setExact(AlarmManager.RTC_WAKEUP, millis, pi);
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            alarmManager.setAlarmClock(new AlarmManager.AlarmClockInfo(millis, null), pendingIntent);
+        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+            alarmManager.setExact(AlarmManager.RTC_WAKEUP, millis, pendingIntent);
+        } else
+            alarmManager.set(AlarmManager.RTC_WAKEUP, millis, pendingIntent);
     }
 
     // restarting the alarm after MedtronicCnlIntentService.POLL_PERIOD_MS from now
@@ -63,10 +69,10 @@ public class MedtronicCnlAlarmReceiver extends WakefulBroadcastReceiver {
 
     // Cancel the alarm.
     public void cancelAlarm() {
-        if (am == null || pi == null)
+        if (alarmManager == null || pendingIntent == null)
             return;
 
-        am.cancel(pi);
+        alarmManager.cancel(pendingIntent);
     }
 
 }
diff --git a/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java b/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java
index 1a1f246f4f3e4cd643b14ee0c4cf1b3e9484f6e7..b958a2c3ac004079815a46121313dc9e74cf097a 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java
@@ -5,21 +5,26 @@ import android.app.IntentService;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbManager;
+import android.os.Build;
+import android.preference.PreferenceManager;
 import android.support.v4.app.NotificationManagerCompat;
 import android.support.v4.content.LocalBroadcastManager;
 import android.util.Log;
 
 import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
 import java.util.Date;
 import java.util.Locale;
 import java.util.concurrent.TimeoutException;
 
+import info.nightscout.android.R;
 import info.nightscout.android.USB.UsbHidDriver;
 import info.nightscout.android.medtronic.MainActivity;
-import info.nightscout.android.medtronic.MedtronicCNLReader;
+import info.nightscout.android.medtronic.MedtronicCnlReader;
 import info.nightscout.android.medtronic.message.ChecksumException;
 import info.nightscout.android.medtronic.message.EncryptionException;
 import info.nightscout.android.medtronic.message.MessageUtils;
@@ -28,6 +33,7 @@ import info.nightscout.android.model.medtronicNg.ContourNextLinkInfo;
 import info.nightscout.android.model.medtronicNg.PumpInfo;
 import info.nightscout.android.model.medtronicNg.PumpStatusEvent;
 import info.nightscout.android.upload.nightscout.NightscoutUploadReceiver;
+import info.nightscout.android.xdrip_plus.XDripPlusUploadReceiver;
 import io.realm.Realm;
 import io.realm.RealmResults;
 
@@ -128,7 +134,7 @@ public class MedtronicCnlIntentService extends IntentService {
             return;
         }
 
-        MedtronicCNLReader cnlReader = new MedtronicCNLReader(mHidDevice);
+        MedtronicCnlReader cnlReader = new MedtronicCnlReader(mHidDevice);
 
         Realm realm = Realm.getDefaultInstance();
         realm.beginTransaction();
@@ -152,22 +158,7 @@ public class MedtronicCnlIntentService extends IntentService {
                 info = realm.copyToRealm(info);
             }
 
-            String hmac = info.getHmac();
-            String key = info.getKey();
-
-            if (hmac == null || key == null) {
-                // Must commit the transaction before we send the Registration activation message
-                realm.commitTransaction();
-
-                sendMessage(Constants.ACTION_USB_REGISTER);
-                realm.close();
-                MedtronicCnlAlarmReceiver.completeWakefulIntent(intent);
-                // TODO - throw, don't return
-                return;
-            }
-
-            cnlReader.getPumpSession().setHMAC(MessageUtils.hexStringToByteArray(hmac));
-            cnlReader.getPumpSession().setKey(MessageUtils.hexStringToByteArray(key));
+            cnlReader.getPumpSession().setStickSerial(info.getSerialNumber());
 
             cnlReader.enterControlMode();
 
@@ -176,6 +167,17 @@ public class MedtronicCnlIntentService extends IntentService {
                 cnlReader.openConnection();
                 cnlReader.requestReadInfo();
 
+                String key = info.getKey();
+
+                if (key == null) {
+                    cnlReader.requestLinkKey();
+
+                    info.setKey(MessageUtils.byteArrayToHexString(cnlReader.getPumpSession().getKey()));
+                    key = info.getKey();
+                }
+
+                cnlReader.getPumpSession().setKey(MessageUtils.hexStringToByteArray(key));
+
                 long pumpMAC = cnlReader.getPumpSession().getPumpMAC();
                 Log.i(TAG, "PumpInfo MAC: " + (pumpMAC & 0xffffff));
                 MainActivity.setActivePumpMac(pumpMAC);
@@ -209,8 +211,10 @@ public class MedtronicCnlIntentService extends IntentService {
 
                     long pumpTime = cnlReader.getPumpTime().getTime();
                     long pumpOffset = pumpTime - System.currentTimeMillis();
+                    Log.d(TAG, "Time offset between pump and device: " + pumpOffset + " millis.");
 
                     // TODO - send ACTION to MainActivity to show offset between pump and uploader.
+                    pumpRecord.setPumpTimeOffset(pumpOffset);
                     pumpRecord.setPumpDate(new Date(pumpTime - pumpOffset));
                     cnlReader.getPumpStatus(pumpRecord, pumpOffset);
                     activePump.getPumpHistory().add(pumpRecord);
@@ -243,6 +247,9 @@ public class MedtronicCnlIntentService extends IntentService {
             } catch (UnexpectedMessageException e) {
                 Log.e(TAG, "Unexpected Message", e);
                 sendStatus("Communication Error: " + e.getMessage());
+            } catch (NoSuchAlgorithmException e) {
+                Log.e(TAG, "Could not determine CNL HMAC", e);
+                sendStatus("Error connecting to Contour Next Link: Hashing error.");
             } finally {
                 //TODO : 05.11.2016 has the close to be here?
                 cnlReader.closeConnection();
@@ -274,17 +281,39 @@ public class MedtronicCnlIntentService extends IntentService {
             }
 
             // TODO - set status if offline or Nightscout not reachable
+            sendToXDrip();
             uploadToNightscout();
             MedtronicCnlAlarmReceiver.completeWakefulIntent(intent);
         }
     }
 
+    // reliable wake alarm manager wake up for all android versions
+    public static void wakeUpIntent(Context context, long wakeTime, PendingIntent pendingIntent) {
+        final AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, wakeTime, pendingIntent);
+        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+            alarm.setExact(AlarmManager.RTC_WAKEUP, wakeTime, pendingIntent);
+        } else
+            alarm.set(AlarmManager.RTC_WAKEUP, wakeTime, pendingIntent);
+    }
+
+    private void sendToXDrip() {
+        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+        if (prefs.getBoolean(getString(R.string.preference_enable_xdrip_plus), false)) {
+            final Intent receiverIntent = new Intent(this, XDripPlusUploadReceiver.class);
+            final long timestamp = System.currentTimeMillis() + 500L;
+            final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, (int) timestamp, receiverIntent, PendingIntent.FLAG_ONE_SHOT);
+            Log.d(TAG, "Scheduling xDrip+ send");
+            wakeUpIntent(getApplicationContext(), timestamp, pendingIntent);
+        }
+    }
+
     private void uploadToNightscout() {
-        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
         Intent receiverIntent = new Intent(this, NightscoutUploadReceiver.class);
         final long timestamp = System.currentTimeMillis() + 1000L;
-        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, (int)timestamp, receiverIntent, PendingIntent.FLAG_ONE_SHOT);
-        alarmManager.set(AlarmManager.RTC_WAKEUP, timestamp, pendingIntent);
+        final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, (int) timestamp, receiverIntent, PendingIntent.FLAG_ONE_SHOT);
+        wakeUpIntent(getApplicationContext(), timestamp, pendingIntent);
     }
 
     private boolean hasUsbHostFeature() {
diff --git a/app/src/main/java/info/nightscout/android/model/medtronicNg/ContourNextLinkInfo.java b/app/src/main/java/info/nightscout/android/model/medtronicNg/ContourNextLinkInfo.java
index 404d801c8250aaa33c13ca53e58b0d9f0e852a05..9b054671a3580a5c5e142405e89d8ea52147e100 100644
--- a/app/src/main/java/info/nightscout/android/model/medtronicNg/ContourNextLinkInfo.java
+++ b/app/src/main/java/info/nightscout/android/model/medtronicNg/ContourNextLinkInfo.java
@@ -9,7 +9,6 @@ import io.realm.annotations.PrimaryKey;
 public class ContourNextLinkInfo extends RealmObject {
     @PrimaryKey
     private String serialNumber;
-    private String hmac;
     private String key;
 
     public String getSerialNumber() {
@@ -20,14 +19,6 @@ public class ContourNextLinkInfo extends RealmObject {
         this.serialNumber = serialNumber;
     }
 
-    public String getHmac() {
-        return hmac;
-    }
-
-    public void setHmac(String hmac) {
-        this.hmac = hmac;
-    }
-
     public String getKey() {
         return key;
     }
diff --git a/app/src/main/java/info/nightscout/android/model/medtronicNg/PumpStatusEvent.java b/app/src/main/java/info/nightscout/android/model/medtronicNg/PumpStatusEvent.java
index 496a85bacbf51966917c3c7463feed8a2d99ab43..ab95d50f6d346d506d3a6f03a992e53cfaa00804 100644
--- a/app/src/main/java/info/nightscout/android/model/medtronicNg/PumpStatusEvent.java
+++ b/app/src/main/java/info/nightscout/android/model/medtronicNg/PumpStatusEvent.java
@@ -3,6 +3,7 @@ package info.nightscout.android.model.medtronicNg;
 import java.util.Date;
 
 import io.realm.RealmObject;
+import io.realm.annotations.Ignore;
 import io.realm.annotations.Index;
 
 /**
@@ -38,6 +39,9 @@ public class PumpStatusEvent extends RealmObject {
     private boolean recentBolusWizard; // Whether a bolus wizard has been run recently
     private int bolusWizardBGL; // in mg/dL. 0 means no recent bolus wizard reading.
 
+    @Ignore
+    private long pumpTimeOffset; // millis the pump is ahead
+
     @Index
     private boolean uploaded = false;
 
@@ -249,6 +253,14 @@ public class PumpStatusEvent extends RealmObject {
         this.recentBolusWizard = recentBolusWizard;
     }
 
+    public long getPumpTimeOffset() {
+        return pumpTimeOffset;
+    }
+
+    public void setPumpTimeOffset(long pumpTimeOffset) {
+        this.pumpTimeOffset = pumpTimeOffset;
+    }
+
     public enum CGM_TREND {
         NONE,
         DOUBLE_UP,
diff --git a/app/src/main/java/info/nightscout/android/settings/SettingsFragment.java b/app/src/main/java/info/nightscout/android/settings/SettingsFragment.java
index e070ac229cd308a3e7f82ae50528aa789bfcbb21..7519a5c7f75cc4e177012ca37b2ec08d272d0b8a 100644
--- a/app/src/main/java/info/nightscout/android/settings/SettingsFragment.java
+++ b/app/src/main/java/info/nightscout/android/settings/SettingsFragment.java
@@ -10,13 +10,7 @@ import android.preference.Preference;
 import android.preference.PreferenceCategory;
 import android.preference.PreferenceFragment;
 
-import java.io.IOException;
-
 import info.nightscout.android.R;
-import info.nightscout.android.upload.nightscout.NightscoutApi;
-import retrofit2.Call;
-import retrofit2.Retrofit;
-import retrofit2.converter.gson.GsonConverterFactory;
 
 public class SettingsFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener {
 
diff --git a/app/src/main/java/info/nightscout/android/upload/nightscout/NightScoutApi.java b/app/src/main/java/info/nightscout/android/upload/nightscout/NightscoutApi.java
similarity index 100%
rename from app/src/main/java/info/nightscout/android/upload/nightscout/NightScoutApi.java
rename to app/src/main/java/info/nightscout/android/upload/nightscout/NightscoutApi.java
diff --git a/app/src/main/java/info/nightscout/android/upload/nightscout/NightscoutUploadIntentService.java b/app/src/main/java/info/nightscout/android/upload/nightscout/NightscoutUploadIntentService.java
index 3fcefde12a486c2e2b5d71f48634cd60d1058fac..6ac7129878dfdcf45118b3f1f4cf83538766de24 100644
--- a/app/src/main/java/info/nightscout/android/upload/nightscout/NightscoutUploadIntentService.java
+++ b/app/src/main/java/info/nightscout/android/upload/nightscout/NightscoutUploadIntentService.java
@@ -10,6 +10,8 @@ import android.preference.PreferenceManager;
 import android.support.v4.content.LocalBroadcastManager;
 import android.util.Log;
 
+import org.apache.http.HttpResponse;
+import org.apache.http.StatusLine;
 import org.apache.http.client.ResponseHandler;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.StringEntity;
@@ -31,7 +33,6 @@ import java.util.regex.Pattern;
 
 import info.nightscout.android.R;
 import info.nightscout.android.medtronic.MainActivity;
-import info.nightscout.android.medtronic.service.MedtronicCnlIntentService;
 import info.nightscout.android.model.medtronicNg.PumpStatusEvent;
 import info.nightscout.android.upload.nightscout.serializer.EntriesSerializer;
 import io.realm.Realm;
@@ -170,22 +171,22 @@ public class NightscoutUploadIntentService extends IntentService {
                 addMbgEntry(entriesBody, record);
             }
 
-            uploadToNightscout(new URL(baseURL + "/entries"), secret, entriesBody);
+            boolean isUploaded = uploadToNightscout(new URL(baseURL + "/entries"), secret, entriesBody);
 
-            for(int i = 0; i < devicestatusBody.length(); i++) {
-                uploadToNightscout(new URL(baseURL + "/devicestatus"), secret, devicestatusBody.getJSONObject(i));
+            for(int i = 0; isUploaded && i < devicestatusBody.length(); i++) {
+                isUploaded &= uploadToNightscout(new URL(baseURL + "/devicestatus"), secret, devicestatusBody.getJSONObject(i));
             }
 
-            // Yay! We uploaded. Tell Realm
-            // FIXME - check the upload succeeded!
-            mRealm.beginTransaction();
-
-            for (PumpStatusEvent updateRecord : records) {
-                updateRecord.setUploaded(true);
+            if (isUploaded) {
+                // Yay! We uploaded. Tell Realm
+                // FIXME - check the upload succeeded!
+                mRealm.beginTransaction();
+                for (PumpStatusEvent updateRecord : records) {
+                    updateRecord.setUploaded(true);
+                }
+                mRealm.commitTransaction();
             }
 
-            mRealm.commitTransaction();
-
         } catch (Exception e) {
             Log.e(TAG, "Unable to post data", e);
         }
@@ -237,6 +238,7 @@ public class NightscoutUploadIntentService extends IntentService {
             httpclient.execute(post, responseHandler);
         } catch (Exception e) {
             Log.w(TAG, "Unable to post data to: '" + post.getURI().toString() + "'", e);
+            return false;
         }
 
         return true;
@@ -256,11 +258,22 @@ public class NightscoutUploadIntentService extends IntentService {
         iob.put("timestamp", record.getPumpDate());
         iob.put("bolusiob", record.getActiveInsulin());
 
+        JSONObject status = new JSONObject();
+        if (record.isBolusing()) {
+            status.put("bolusing", true);
+        } else if (record.isSuspended()) {
+            status.put("suspended", true);
+        } else {
+            status.put("status", "normal");
+        }
+
         JSONObject battery = new JSONObject();
         battery.put("percent", record.getBatteryPercentage());
 
         pumpInfo.put("iob", iob);
         pumpInfo.put("battery", battery);
+        pumpInfo.put("status", status);
+
         json.put("pump", pumpInfo);
         String jsonString = json.toString();
         Log.i(TAG, "Device Status JSON: " + jsonString);
diff --git a/app/src/main/java/info/nightscout/android/xdrip_plus/XDripPlusUploadIntentService.java b/app/src/main/java/info/nightscout/android/xdrip_plus/XDripPlusUploadIntentService.java
new file mode 100644
index 0000000000000000000000000000000000000000..6cc1a6f91b54362685926b06cb6f9072b78704bd
--- /dev/null
+++ b/app/src/main/java/info/nightscout/android/xdrip_plus/XDripPlusUploadIntentService.java
@@ -0,0 +1,171 @@
+package info.nightscout.android.xdrip_plus;
+
+import android.app.IntentService;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.support.v4.content.LocalBroadcastManager;
+import android.util.Log;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.List;
+import java.util.Locale;
+
+import info.nightscout.android.medtronic.MainActivity;
+import info.nightscout.android.model.medtronicNg.PumpStatusEvent;
+import info.nightscout.android.upload.nightscout.serializer.EntriesSerializer;
+import io.realm.Realm;
+import io.realm.RealmResults;
+import io.realm.Sort;
+
+/**
+ * Created by jamorham on 17/11/2016.
+ */
+
+
+public class XDripPlusUploadIntentService extends IntentService {
+
+    private static final String TAG = XDripPlusUploadIntentService.class.getSimpleName();
+    private static final SimpleDateFormat ISO8601_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault());
+    Context mContext;
+    private Realm mRealm;
+
+    public XDripPlusUploadIntentService() {
+        super(XDripPlusUploadIntentService.class.getName());
+    }
+
+    // status unused
+    protected void sendStatus(String message) {
+        Intent localIntent =
+                new Intent(info.nightscout.android.xdrip_plus.XDripPlusUploadIntentService.Constants.ACTION_STATUS_MESSAGE)
+                        .putExtra(info.nightscout.android.xdrip_plus.XDripPlusUploadIntentService.Constants.EXTENDED_DATA, message);
+        LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        Log.i(TAG, "onCreate called");
+        mContext = this.getBaseContext();
+    }
+
+    @Override
+    protected void onHandleIntent(Intent intent) {
+        Log.d(TAG, "onHandleIntent called");
+        mRealm = Realm.getDefaultInstance();
+
+        RealmResults<PumpStatusEvent> all_records = mRealm
+                .where(PumpStatusEvent.class)
+                .notEqualTo("sgv", 0)
+                .findAllSorted("eventDate", Sort.DESCENDING);
+
+        // get the most recent record and send that
+        if (all_records.size() > 0) {
+            List<PumpStatusEvent> records = all_records.subList(0, 1);
+            doXDripUpload(records);
+        }
+        XDripPlusUploadReceiver.completeWakefulIntent(intent);
+    }
+
+    private void doXDripUpload(List<PumpStatusEvent> records) {
+        try {
+
+            final JSONArray devicestatusBody = new JSONArray();
+            final JSONArray entriesBody = new JSONArray();
+
+            for (PumpStatusEvent record : records) {
+                addDeviceStatus(devicestatusBody, record);
+                addSgvEntry(entriesBody, record);
+                addMbgEntry(entriesBody, record);
+            }
+
+            if (entriesBody.length() > 0) sendBundle(mContext, "add", "entries", entriesBody);
+            if (devicestatusBody.length() > 0)
+                sendBundle(mContext, "add", "devicestatus", devicestatusBody);
+
+        } catch (Exception e) {
+            Log.e(TAG, "Unable to send bundle: " + e);
+        }
+    }
+
+    private void sendBundle(Context context, String action, String collection, JSONArray json) {
+        final Bundle bundle = new Bundle();
+        bundle.putString("action", action);
+        bundle.putString("collection", collection);
+        bundle.putString("data", json.toString());
+        final Intent intent = new Intent(Constants.XDRIP_PLUS_NS_EMULATOR);
+        intent.putExtras(bundle).addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
+        context.sendBroadcast(intent);
+        List<ResolveInfo> receivers = context.getPackageManager().queryBroadcastReceivers(intent, 0);
+        if (receivers.size() < 1) {
+            Log.e(TAG, "No receivers");
+        } else Log.e(TAG, receivers.size() + " receivers");
+    }
+
+
+    private void addDeviceStatus(JSONArray devicestatusArray, PumpStatusEvent record) throws Exception {
+        JSONObject json = new JSONObject();
+        json.put("uploaderBattery", MainActivity.batLevel);
+        json.put("device", record.getDeviceName());
+        json.put("created_at", ISO8601_DATE_FORMAT.format(record.getPumpDate()));
+
+        JSONObject pumpInfo = new JSONObject();
+        pumpInfo.put("clock", ISO8601_DATE_FORMAT.format(record.getPumpDate()));
+        pumpInfo.put("reservoir", new BigDecimal(record.getReservoirAmount()).setScale(3, BigDecimal.ROUND_HALF_UP));
+
+        JSONObject iob = new JSONObject();
+        iob.put("timestamp", record.getPumpDate());
+        iob.put("bolusiob", record.getActiveInsulin());
+
+        JSONObject battery = new JSONObject();
+        battery.put("percent", record.getBatteryPercentage());
+
+        pumpInfo.put("iob", iob);
+        pumpInfo.put("battery", battery);
+        json.put("pump", pumpInfo);
+        //String jsonString = json.toString();
+
+        devicestatusArray.put(json);
+    }
+
+    private void addSgvEntry(JSONArray entriesArray, PumpStatusEvent pumpRecord) throws Exception {
+        JSONObject json = new JSONObject();
+        // TODO replace with Retrofit/EntriesSerializer
+        json.put("sgv", pumpRecord.getSgv());
+        json.put("direction", EntriesSerializer.getDirectionString(pumpRecord.getCgmTrend()));
+        json.put("device", pumpRecord.getDeviceName());
+        json.put("type", "sgv");
+        json.put("date", pumpRecord.getEventDate().getTime());
+        json.put("dateString", pumpRecord.getEventDate());
+
+        entriesArray.put(json);
+    }
+
+    private void addMbgEntry(JSONArray entriesArray, PumpStatusEvent pumpRecord) throws Exception {
+        if (pumpRecord.hasRecentBolusWizard()) {
+            JSONObject json = new JSONObject();
+
+            // TODO replace with Retrofit/EntriesSerializer
+            json.put("type", "mbg");
+            json.put("mbg", pumpRecord.getBolusWizardBGL());
+            json.put("device", pumpRecord.getDeviceName());
+            json.put("date", pumpRecord.getEventDate().getTime());
+            json.put("dateString", pumpRecord.getEventDate());
+
+            entriesArray.put(json);
+        }
+    }
+
+
+    public final class Constants {
+        public static final String ACTION_STATUS_MESSAGE = "info.nightscout.android.xdrip_plus.STATUS_MESSAGE";
+        public static final String EXTENDED_DATA = "info.nightscout.android.xdrip_plus.DATA";
+        private static final String XDRIP_PLUS_NS_EMULATOR = "com.eveningoutpost.dexdrip.NS_EMULATOR";
+    }
+}
diff --git a/app/src/main/java/info/nightscout/android/xdrip_plus/XDripPlusUploadReceiver.java b/app/src/main/java/info/nightscout/android/xdrip_plus/XDripPlusUploadReceiver.java
new file mode 100644
index 0000000000000000000000000000000000000000..734cd34d65542d827f26d5b81290ccb42023db47
--- /dev/null
+++ b/app/src/main/java/info/nightscout/android/xdrip_plus/XDripPlusUploadReceiver.java
@@ -0,0 +1,22 @@
+package info.nightscout.android.xdrip_plus;
+
+import android.content.Context;
+import android.content.Intent;
+import android.support.v4.content.WakefulBroadcastReceiver;
+import android.util.Log;
+
+
+/**
+ * Created by jamorham on 17/11/2016.
+ */
+public class XDripPlusUploadReceiver extends WakefulBroadcastReceiver {
+    private static final String TAG = XDripPlusUploadReceiver.class.getSimpleName();
+
+    @Override
+    public void onReceive(final Context context, Intent intent) {
+        // Start the IntentService
+        Log.d(TAG, "Received broadcast message");
+        Intent service = new Intent(context, XDripPlusUploadIntentService.class);
+        startWakefulService(context, service);
+    }
+}
diff --git a/app/src/main/res/drawable/drawer_header.jpg b/app/src/main/res/drawable/drawer_header.jpg
index e3f8ab881ebc761afbfdad7ae6b554adb658d83a..251abd5c8a8ee193ef484393a966c891c8f5478a 100644
Binary files a/app/src/main/res/drawable/drawer_header.jpg and b/app/src/main/res/drawable/drawer_header.jpg differ
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
index 462badee54883bc0f801bacf05107482d57e99b6..84cc07b2b8603da6a558869fe53fa029ae140bcd 100644
--- a/app/src/main/res/layout/activity_login.xml
+++ b/app/src/main/res/layout/activity_login.xml
@@ -11,13 +11,6 @@
     tools:context=".medtronic.GetHmacAndKeyActivity">
 
     <!-- Login progress -->
-    <ProgressBar
-        android:id="@+id/login_progress"
-        style="?android:attr/progressBarStyleLarge"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginBottom="8dp"
-        android:visibility="gone"/>
 
     <ScrollView
         android:layout_width="match_parent"
@@ -28,62 +21,10 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content">
 
-            <LinearLayout
-                android:id="@+id/login_form"
+            <TextView
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:orientation="vertical">
-
-                <TextView
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:textAppearance="?android:attr/textAppearanceMedium"
-                    android:text="@string/prompt_carelink_username_password" />
-
-                <AutoCompleteTextView
-                    android:id="@+id/username"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:hint="@string/prompt_username"
-                    android:inputType="text"
-                    android:imeOptions="actionNext"
-                    android:maxLines="1"
-                    android:singleLine="true"/>
-
-                <EditText
-                    android:id="@+id/password"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:hint="@string/prompt_password"
-                    android:imeActionId="@+id/login"
-                    android:imeActionLabel="@string/action_sign_in_short"
-                    android:imeOptions="actionDone|actionUnspecified"
-                    android:inputType="textPassword"
-                    android:maxLines="1"
-                    android:singleLine="true"/>
-
-                <AutoCompleteTextView
-                    android:id="@+id/hostname"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:hint="Carelink hostname (optional)"
-                    android:imeOptions="actionDone"
-                    android:inputType="text"
-                    android:maxLines="1"/>
-
-
-            </LinearLayout>
-
-            <LinearLayout
-                android:orientation="horizontal"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent">
-
-                <TextView
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:id="@+id/registered_usb_devices" />
-            </LinearLayout>
+                android:id="@+id/registered_usb_devices" />
 
         </LinearLayout>
     </ScrollView>
diff --git a/app/src/main/res/menu/menu_register_usb.xml b/app/src/main/res/menu/menu_register_usb.xml
deleted file mode 100644
index 81a6c5646903e8d5f192edbd9d651e4b025c70dc..0000000000000000000000000000000000000000
--- a/app/src/main/res/menu/menu_register_usb.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto">
-    <item android:id="@+id/action_menu_login"
-        android:title="Login"
-        android:orderInCategory="100"
-        app:showAsAction="always"
-        />
-</menu>
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 00a255b85ec633800300f0bd6f93fbc4b81ae25c..89751b6c042dc6aca1482597467d1d6cfffab63f 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -35,7 +35,7 @@
     <string name="preference_api_secret">API SECRET</string>
     <string name="prompt_carelink_username_password">Please enter your CareLink details.\nThey will not be stored.</string>
     <string name="close">Close</string>
-    <string name="register_contour_next_link">Register Contour Next Link</string>
+    <string name="register_contour_next_link">Registered Devices</string>
     <string name="preferences_enable_crashlytics">prefs_enable_crashlytics</string>
     <string name="preferences_enable_answers">prefs_enable_answers</string>
     <string name="preferences_enable_remote_logcat">prefs_enable_remote_logcat</string>
@@ -46,6 +46,7 @@
     <string name="button_text_start_uploading_data">Start Uploading CGM Data</string>
     <string name="preference_eula_accepted">IUNDERSTAND</string>
     <string name="preference_enable_rest_upload">EnableRESTUpload</string>
+    <string name="preference_enable_xdrip_plus">EnablexDripPlusUpload</string>
     <string name="error_msg_api_secret_length">API Secret must be 12 characters or longer.</string>
     <string name="text_unit_mmolxl">mmol/L</string>
     <string name="text_unit_mgxdl">mg/dL</string>
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 8a8fb08d3852284649d8428d84e72fac42c4d557..9e6793c85ec60101ef37b053d3af5d9caefd74b1 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -39,6 +39,10 @@
             android:dialogTitle="Enter your Nightscout API secret"
             android:key="@string/preference_api_secret"
             android:title="API Secret"/>
+        <CheckBoxPreference
+            android:key="@string/preference_enable_xdrip_plus"
+            android:summary="Enable local broadcast of data to xDrip+"
+            android:title="Send to xDrip+"/>
     </PreferenceCategory>
     <PreferenceCategory android:title="Disclaimer">
         <SwitchPreference
diff --git a/build.gradle b/build.gradle
index 04964d2ceed4f5f07ac9cb13fce761e51603eaeb..9da42b0b994170c75de5ee547bfabc0007cf8dd7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,7 +5,7 @@ buildscript {
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.2.2'
+        classpath 'com.android.tools.build:gradle:2.2.3'
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files
         classpath "io.realm:realm-gradle-plugin:1.0.0"