diff --git a/app/build.gradle b/app/build.gradle
index 742d781f311bc64d8087b7db300892313e22c6af..22026ff2431f6f1adbbadb1c698a7d798c73a8cf 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -145,7 +145,7 @@ release {
 
 dependencies {
     compile files('libs/slf4j-api-1.7.2.jar')
-    compile('com.crashlytics.sdk.android:crashlytics:2.6.5@aar') {
+    compile('com.crashlytics.sdk.android:crashlytics:2.6.6@aar') {
         transitive = true;
     }
     compile('com.mikepenz:materialdrawer:5.2.9@aar') {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 2ea896197d19abb365b6bbd2baaa8357cdd3692d..82d30493197be0106b2cf30795d7fed79e1ec57d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -31,11 +31,13 @@
 
 
         <!-- I have set screenOrientation to "portrait" to avoid the restart of AsyncTasks when you rotate the phone -->
+        <!-- configChanges="uiMode" added to avoid restart of AsyncTasks when phone is plugged into charger/dock (for phones that can do usb otg & charging simultaneously -->
         <activity
             android:name=".medtronic.MainActivity"
             android:icon="@drawable/ic_launcher"
             android:label="@string/app_name"
             android:launchMode="singleTask"
+            android:configChanges="uiMode"
             android:screenOrientation="portrait">
 
             <intent-filter android:icon="@drawable/ic_launcher">
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 681f50ee06f600d809b4b987fb57f55366ffcebc..220ba9f2db5213d998fd4ca935afdcc7a39418c5 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/MainActivity.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/MainActivity.java
@@ -58,6 +58,7 @@ import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
 import java.text.DateFormat;
 import java.text.DecimalFormat;
 import java.text.NumberFormat;
+import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.Locale;
 import java.util.Queue;
@@ -94,8 +95,12 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
     private boolean hasZoomedChart = false;
 
     private NumberFormat sgvFormatter;
-    private boolean mmolxl;
-    private boolean mmolxlDecimals;
+    private static boolean mmolxl;
+    private static boolean mmolxlDecimals;
+
+    public static long timeLastGoodSGV = 0;
+    public static short pumpBattery = 0;
+    public static int countUnavailableSGV = 0;
 
     boolean mEnableCgmService = true;
     SharedPreferences prefs = null;
@@ -139,6 +144,20 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
         return nextPoll;
     }
 
+    public static String strFormatSGV(float sgvValue) {
+        if (mmolxl) {
+            NumberFormat sgvFormatter;
+            if (mmolxlDecimals) {
+                sgvFormatter = new DecimalFormat("0.00");
+            } else {
+                sgvFormatter = new DecimalFormat("0.0");
+            }
+            return sgvFormatter.format(sgvValue / MMOLXLFACTOR);
+        } else {
+            return String.valueOf(sgvValue);
+        }
+    }
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         Log.i(TAG, "onCreate called");
@@ -332,17 +351,14 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
         mChart.getGridLabelRenderer().setHumanRounding(false);
 
         mChart.getGridLabelRenderer().setLabelFormatter(new DefaultLabelFormatter() {
-            DateFormat mFormat = DateFormat.getTimeInstance(DateFormat.SHORT);
+            DateFormat mFormat = new SimpleDateFormat("HH:mm");  // 24 hour format forced to fix label overlap
+
             @Override
             public String formatLabel(double value, boolean isValueX) {
                 if (isValueX) {
                     return mFormat.format(new Date((long) value));
                 } else {
-                    if (mmolxl) {
-                        return sgvFormatter.format(value / MMOLXLFACTOR);
-                    } else {
                         return sgvFormatter.format(value);
-                    }
                 }
             }}
         );
@@ -617,7 +633,8 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
 
                         lastQueryTS = pump.getLastQueryTS();
 
-                        startCgmService(MainActivity.getNextPoll(pumpStatusData));
+// >>>>> note: prototype smart poll handling added to cnl intent
+//                        startCgmService(MainActivity.getNextPoll(pumpStatusData));
 
                         // Delete invalid or old records from Realm
                         // TODO - show an error message if the valid records haven't been uploaded
@@ -640,7 +657,10 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
                         }
 
                         // TODO - handle isOffline in NightscoutUploadIntentService?
-                        uploadCgmData();
+
+ // >>>>> check this out as it's uploading before cnl comms finishes and may cause occasional channel changes due to wifi noise - cnl intent handles ns upload trigger after all comms finish
+ //                       uploadCgmData();
+
                         refreshDisplay();
                     }
                 });
@@ -685,7 +705,7 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
             }
         }
 
-        private Queue<StatusMessage> messages = new ArrayBlockingQueue<>(10);
+        private Queue<StatusMessage> messages = new ArrayBlockingQueue<>(400);
 
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -693,7 +713,7 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
             Log.i(TAG, "Message Receiver: " + message);
 
             synchronized (messages) {
-                while (messages.size() > 8) {
+                while (messages.size() > 398) {
                     messages.poll();
                 }
                 messages.add(new StatusMessage(message));
@@ -802,6 +822,9 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
         }
 
         private void updateChart(RealmResults<PumpStatusEvent> results) {
+
+            mChart.getGridLabelRenderer().setNumHorizontalLabels(6);
+
             int size = results.size();
             if (size == 0) {
                 final long now = System.currentTimeMillis(),
@@ -832,9 +855,9 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
                 int sgv = pumpStatus.getSgv();
 
                 if (mmolxl) {
-                    entries[pos++] = new DataPoint(pumpStatus.getEventDate(), pumpStatus.getSgv() / MMOLXLFACTOR);
+                    entries[pos++] = new DataPoint(pumpStatus.getEventDate(), (float) pumpStatus.getSgv() / MMOLXLFACTOR);
                 } else {
-                    entries[pos++] = new DataPoint(pumpStatus.getEventDate(), pumpStatus.getSgv());
+                    entries[pos++] = new DataPoint(pumpStatus.getEventDate(), (float) pumpStatus.getSgv());
                 }
             }
 
@@ -860,11 +883,7 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
                         double sgv = dataPoint.getY();
 
                         StringBuilder sb = new StringBuilder(mFormat.format(new Date((long) dataPoint.getX())) + ": ");
-                        if (mmolxl) {
-                            sb.append(sgvFormatter.format(sgv / MMOLXLFACTOR));
-                        } else {
-                            sb.append(sgvFormatter.format(sgv));
-                        }
+                        sb.append(sgvFormatter.format(sgv));
                         Toast.makeText(getBaseContext(), sb.toString(), Toast.LENGTH_SHORT).show();
                     }
                 });
@@ -873,11 +892,11 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
                     @Override
                     public void draw(Canvas canvas, Paint paint, float x, float y, DataPointInterface dataPoint) {
                         double sgv = dataPoint.getY();
-                        if (sgv < 80)
+                        if (sgv < (mmolxl?4.5:80))
                             paint.setColor(Color.RED);
-                        else if (sgv <= 180)
+                        else if (sgv <= (mmolxl?10:180))
                             paint.setColor(Color.GREEN);
-                        else if (sgv <= 260)
+                        else if (sgv <= (mmolxl?14:260))
                             paint.setColor(Color.YELLOW);
                         else
                             paint.setColor(Color.RED);
diff --git a/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlReader.java b/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlReader.java
index 7efd3ef64e16fd2a735bb172950a83c2be3de732..6763c82d683bcd7daf32ba61f95294216a4a2a70 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlReader.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlReader.java
@@ -9,7 +9,6 @@ import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
-import java.util.Locale;
 import java.util.concurrent.TimeoutException;
 
 import info.nightscout.android.USB.UsbHidDriver;
@@ -51,6 +50,8 @@ public class MedtronicCnlReader {
     private MedtronicCnlSession mPumpSession = new MedtronicCnlSession();
     private String mStickSerial = null;
 
+    private static final int SLEEP_MS = 500;
+
     public MedtronicCnlReader(UsbHidDriver device) {
         mDevice = device;
     }
@@ -78,9 +79,9 @@ public class MedtronicCnlReader {
             doRetry = false;
             try {
                 new ContourNextLinkCommandMessage(ContourNextLinkCommandMessage.ASCII.NAK)
-                        .send(mDevice, 500).checkControlMessage(ContourNextLinkCommandMessage.ASCII.EOT);
+                        .send(mDevice, SLEEP_MS).checkControlMessage(ContourNextLinkCommandMessage.ASCII.EOT);
                 new ContourNextLinkCommandMessage(ContourNextLinkCommandMessage.ASCII.ENQ)
-                        .send(mDevice, 500).checkControlMessage(ContourNextLinkCommandMessage.ASCII.ACK);
+                        .send(mDevice, SLEEP_MS).checkControlMessage(ContourNextLinkCommandMessage.ASCII.ACK);
             } catch (UnexpectedMessageException e2) {
                 try {
                     new ContourNextLinkCommandMessage(ContourNextLinkCommandMessage.ASCII.EOT).send(mDevice);
@@ -95,11 +96,11 @@ public class MedtronicCnlReader {
     public void enterPassthroughMode() throws IOException, TimeoutException, UnexpectedMessageException, ChecksumException, EncryptionException {
         Log.d(TAG, "Begin enterPasshtroughMode");
         new ContourNextLinkCommandMessage("W|")
-                .send(mDevice, 500).checkControlMessage(ContourNextLinkCommandMessage.ASCII.ACK);
+                .send(mDevice, SLEEP_MS).checkControlMessage(ContourNextLinkCommandMessage.ASCII.ACK);
         new ContourNextLinkCommandMessage("Q|")
-                .send(mDevice, 500).checkControlMessage(ContourNextLinkCommandMessage.ASCII.ACK);
+                .send(mDevice, SLEEP_MS).checkControlMessage(ContourNextLinkCommandMessage.ASCII.ACK);
         new ContourNextLinkCommandMessage("1|")
-                .send(mDevice, 500).checkControlMessage(ContourNextLinkCommandMessage.ASCII.ACK);
+                .send(mDevice, SLEEP_MS).checkControlMessage(ContourNextLinkCommandMessage.ASCII.ACK);
         Log.d(TAG, "Finished enterPasshtroughMode");
     }
 
@@ -150,9 +151,11 @@ public class MedtronicCnlReader {
             ChannelNegotiateResponseMessage response = new ChannelNegotiateRequestMessage(mPumpSession).send(mDevice);
 
             if (response.getRadioChannel() == mPumpSession.getRadioChannel()) {
+                mPumpSession.setRadioRSSI(response.getRadioRSSI());
                 break;
             } else {
                 mPumpSession.setRadioChannel((byte)0);
+                mPumpSession.setRadioRSSI((byte)0);
             }
         }
 
@@ -168,7 +171,17 @@ public class MedtronicCnlReader {
 
     public Date getPumpTime() throws EncryptionException, IOException, ChecksumException, TimeoutException, UnexpectedMessageException {
         Log.d(TAG, "Begin getPumpTime");
-        // FIXME - throw if not in EHSM mode (add a state machine)
+
+        // CNL<-->PUMP comms can have occasional short lived noise causing errors, retrying once catches this
+        try {
+            PumpTimeResponseMessage response = new PumpTimeRequestMessage(mPumpSession).send(mDevice);
+            Log.d(TAG, "Finished getPumpTime with date " + response.getPumpTime());
+            return response.getPumpTime();
+        } catch (UnexpectedMessageException e) {
+            Log.e(TAG, "Unexpected Message", e);
+        } catch (TimeoutException e) {
+            Log.e(TAG, "Timeout communicating with the Contour Next Link.", e);
+        }
 
         PumpTimeResponseMessage response = new PumpTimeRequestMessage(mPumpSession).send(mDevice);
 
@@ -179,7 +192,18 @@ public class MedtronicCnlReader {
     public PumpStatusEvent updatePumpStatus(PumpStatusEvent pumpRecord) throws IOException, EncryptionException, ChecksumException, TimeoutException, UnexpectedMessageException {
         Log.d(TAG, "Begin updatePumpStatus");
 
-        // FIXME - throw if not in EHSM mode (add a state machine)
+        // CNL<-->PUMP comms can have occasional short lived noise causing errors, retrying once catches this
+        try {
+            PumpStatusResponseMessage response = new PumpStatusRequestMessage(mPumpSession).send(mDevice);
+            response.updatePumpRecord(pumpRecord);
+            Log.d(TAG, "Finished updatePumpStatus");
+            return pumpRecord;
+        } catch (UnexpectedMessageException e) {
+            Log.e(TAG, "Unexpected Message", e);
+        } catch (TimeoutException e) {
+            Log.e(TAG, "Timeout communicating with the Contour Next Link.", e);
+        }
+
         PumpStatusResponseMessage response = new PumpStatusRequestMessage(mPumpSession).send(mDevice);
         response.updatePumpRecord(pumpRecord);
 
@@ -222,18 +246,18 @@ public class MedtronicCnlReader {
     public void endPassthroughMode() throws IOException, TimeoutException, UnexpectedMessageException, ChecksumException, EncryptionException {
         Log.d(TAG, "Begin endPassthroughMode");
         new ContourNextLinkCommandMessage("W|")
-                .send(mDevice, 500).checkControlMessage(ContourNextLinkCommandMessage.ASCII.ACK);
+                .send(mDevice, SLEEP_MS).checkControlMessage(ContourNextLinkCommandMessage.ASCII.ACK);
         new ContourNextLinkCommandMessage("Q|")
-                .send(mDevice, 500).checkControlMessage(ContourNextLinkCommandMessage.ASCII.ACK);
+                .send(mDevice, SLEEP_MS).checkControlMessage(ContourNextLinkCommandMessage.ASCII.ACK);
         new ContourNextLinkCommandMessage("0|")
-                .send(mDevice, 500).checkControlMessage(ContourNextLinkCommandMessage.ASCII.ACK);
+                .send(mDevice, SLEEP_MS).checkControlMessage(ContourNextLinkCommandMessage.ASCII.ACK);
         Log.d(TAG, "Finished endPassthroughMode");
     }
 
     public void endControlMode() throws IOException, TimeoutException, UnexpectedMessageException, ChecksumException, EncryptionException {
         Log.d(TAG, "Begin endControlMode");
         new ContourNextLinkCommandMessage(ContourNextLinkCommandMessage.ASCII.EOT)
-                .send(mDevice, 500).checkControlMessage(ContourNextLinkCommandMessage.ASCII.ENQ);
+                .send(mDevice, SLEEP_MS).checkControlMessage(ContourNextLinkCommandMessage.ASCII.ENQ);
         Log.d(TAG, "Finished endControlMode");
     }
 }
diff --git a/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlSession.java b/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlSession.java
index b5d96589c39013cbba4acf9a29c219dd9adfd65e..9c7952f3803a8a17437d51345a26be47dec1d092 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlSession.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlSession.java
@@ -20,6 +20,8 @@ public class MedtronicCnlSession {
     private long pumpMAC;
 
     private byte radioChannel;
+    private byte radioRSSI;
+
     private int bayerSequenceNumber = 1;
     private int medtronicSequenceNumber = 1;
 
@@ -80,6 +82,14 @@ public class MedtronicCnlSession {
         return radioChannel;
     }
 
+    public byte getRadioRSSI() {
+        return radioRSSI;
+    }
+
+    public int getRadioRSSIpercentage() {
+        return (((int) radioRSSI & 0x00FF) * 100) / 0xA8;
+    }
+
     public void incrBayerSequenceNumber() {
         bayerSequenceNumber++;
     }
@@ -92,6 +102,10 @@ public class MedtronicCnlSession {
         this.radioChannel = radioChannel;
     }
 
+    public void setRadioRSSI(byte radioRSSI) {
+        this.radioRSSI = radioRSSI;
+    }
+
     public void setHMAC(byte[] hmac) {
         this.HMAC = hmac;
     }
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/ChannelNegotiateResponseMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/ChannelNegotiateResponseMessage.java
index 67f8d9beba4495cc760b07748f9141a576b66ee5..54cff417066ebfb51163b38a485f447d1e55ae64 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/message/ChannelNegotiateResponseMessage.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/ChannelNegotiateResponseMessage.java
@@ -16,6 +16,7 @@ public class ChannelNegotiateResponseMessage extends ContourNextLinkBinaryRespon
     private static final String TAG = ChannelNegotiateResponseMessage.class.getSimpleName();
 
     private byte radioChannel = 0;
+    private byte radioRSSI = 0;
 
     protected ChannelNegotiateResponseMessage(MedtronicCnlSession pumpSession, byte[] payload) throws EncryptionException, ChecksumException, IOException {
         super(payload);
@@ -25,15 +26,21 @@ public class ChannelNegotiateResponseMessage extends ContourNextLinkBinaryRespon
         Log.d(TAG, "negotiateChannel: Check response length");
         if (responseBytes.length > 46) {
             radioChannel = responseBytes[76];
+            radioRSSI = responseBytes[59];
             if (responseBytes[76] != pumpSession.getRadioChannel()) {
                 throw new IOException(String.format(Locale.getDefault(), "Expected to get a message for channel %d. Got %d", pumpSession.getRadioChannel(), responseBytes[76]));
             }
         } else {
             radioChannel = ((byte) 0);
+            radioRSSI = ((byte) 0);
         }
     }
 
     public byte getRadioChannel() {
         return radioChannel;
     }
+
+    public byte getRadioRSSI() {
+        return radioRSSI;
+    }
 }
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkMessage.java
index 0d358090e414caec209005169b6d089cd38f7cf8..8c340cb9ef425cdd34e8bf322e2eef4aaa791926 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkMessage.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkMessage.java
@@ -8,9 +8,7 @@ import java.nio.ByteBuffer;
 import java.util.concurrent.TimeoutException;
 
 import info.nightscout.android.USB.UsbHidDriver;
-import info.nightscout.android.medtronic.exception.ChecksumException;
-import info.nightscout.android.medtronic.exception.EncryptionException;
-import info.nightscout.android.medtronic.exception.UnexpectedMessageException;
+import info.nightscout.android.medtronic.MainActivity;
 import info.nightscout.android.utils.HexDump;
 
 /**
@@ -20,7 +18,7 @@ public abstract class ContourNextLinkMessage {
     private static final String TAG = ContourNextLinkMessage.class.getSimpleName();
 
     private static final int USB_BLOCKSIZE = 64;
-    private static final int READ_TIMEOUT_MS = 10000;
+    private static final int READ_TIMEOUT_MS = 15000; //ASTM standard is 15 seconds (note was previously set at 10 seconds)
     private static final String BAYER_USB_HEADER = "ABC";
 
     protected ByteBuffer mPayload;
@@ -142,6 +140,56 @@ public abstract class ContourNextLinkMessage {
         return responseMessage.toByteArray();
     }
 
+    // safety check to make sure a expected 0x81 response is received before next expected 0x80 response
+    // very infrequent as clearMessage catches most issues but very important to save a CNL error situation
+
+    protected int readMessage_0x81(UsbHidDriver mDevice) throws IOException, TimeoutException {
+
+        int responseSize = 0;
+        boolean doRetry;
+        do {
+            byte[] responseBytes = readMessage(mDevice);
+            if (responseBytes[18] != (byte) 0x81) {
+                doRetry = true;
+                Log.d(TAG, "readMessage0x81: did not get 0x81 response, got " + responseBytes[18]);
+            } else {
+                doRetry = false;
+                responseSize = responseBytes.length;
+            }
+
+        } while (doRetry);
+
+        return responseSize;
+    }
+
+    // intercept unexpected messages from the CNL
+    // these usually come from pump requests as it can occasionally resend message responses several times (possibly due to a missed CNL ACK during CNL-PUMP comms?)
+    // mostly noted on the higher radio channels, channel 26 shows this the most
+    // if these messages are not cleared the CNL will likely error needing to be unplugged to reset as it expects them to be read before any further commands are sent
+
+    protected int clearMessage(UsbHidDriver mDevice) throws IOException {
+
+        byte[] responseBuffer = new byte[USB_BLOCKSIZE];
+        int bytesRead;
+        int bytesClear = 0;
+
+        do {
+            bytesRead = mDevice.read(responseBuffer, 2000);
+            if (bytesRead > 0) {
+                bytesClear += bytesRead;
+                String responseString = HexDump.dumpHexString(responseBuffer);
+                Log.d(TAG, "READ: " + responseString);
+            }
+        } while (bytesRead > 0);
+
+        if (bytesClear > 0) {
+            Log.d(TAG, "clearMessage: message stream cleared bytes: " + bytesClear);
+        }
+
+        return bytesClear;
+    }
+
+
     public enum ASCII {
         STX(0x02),
         EOT(0x04),
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/EHSMMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/EHSMMessage.java
index d930a59e3ae785b1bfec5255b3f914c1ffb2422f..0e064536b650efd76e2ee8dad5867a787671339f 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/message/EHSMMessage.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/EHSMMessage.java
@@ -20,6 +20,10 @@ public class EHSMMessage extends  MedtronicSendMessageRequestMessage<ContourNext
 
     @Override
     public ContourNextLinkResponseMessage send(UsbHidDriver mDevice, int millis) throws IOException, TimeoutException, UnexpectedMessageException {
+
+        // clear unexpected incoming messages
+        clearMessage(mDevice);
+
         sendMessage(mDevice);
         if (millis > 0) {
             try {
@@ -27,11 +31,17 @@ public class EHSMMessage extends  MedtronicSendMessageRequestMessage<ContourNext
             } catch (InterruptedException e) {
             }
         }
+
         // The End EHSM Session only has an 0x81 response
+        if (readMessage_0x81(mDevice) != 48) {
+            throw new UnexpectedMessageException("length of EHSMMessage response does not match");
+        }
+/*
         readMessage(mDevice);
         if (this.encode().length != 54) {
             throw new UnexpectedMessageException("length of EHSMMessage response does not match");
         }
+*/
         return null;
     }
 }
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 982bdba7bb025a7dff5d690d190a2926f66da227..39403a8f995610813fc4dcb1c7b22b4a69f28d5d 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
@@ -22,6 +22,7 @@ public class PumpStatusRequestMessage extends MedtronicSendMessageRequestMessage
     }
 
     public PumpStatusResponseMessage send(UsbHidDriver mDevice, int millis) throws IOException, TimeoutException, ChecksumException, EncryptionException, UnexpectedMessageException {
+
         sendMessage(mDevice);
         if (millis > 0) {
             try {
@@ -31,7 +32,7 @@ public class PumpStatusRequestMessage extends MedtronicSendMessageRequestMessage
             }
         }
         // Read the 0x81
-        readMessage(mDevice);
+        readMessage_0x81(mDevice);
         if (millis > 0) {
             try {
                 Log.d(TAG, "waiting " + millis +" ms");
@@ -41,6 +42,9 @@ public class PumpStatusRequestMessage extends MedtronicSendMessageRequestMessage
         }
         PumpStatusResponseMessage response = this.getResponse(readMessage(mDevice));
 
+        // clear unexpected incoming messages
+        clearMessage(mDevice);
+
         return response;
     }
 
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 24cbb144d87a530c034e5666127346298e3fcf70..592800406888cb5c6ce3860642c785b274ce79a2 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
@@ -19,6 +19,7 @@ public class PumpTimeRequestMessage extends MedtronicSendMessageRequestMessage<P
 
     @Override
     public PumpTimeResponseMessage send(UsbHidDriver mDevice, int millis) throws IOException, TimeoutException, ChecksumException, EncryptionException, UnexpectedMessageException {
+
         sendMessage(mDevice);
         if (millis > 0) {
             try {
@@ -27,7 +28,7 @@ public class PumpTimeRequestMessage extends MedtronicSendMessageRequestMessage<P
             }
         }
         // Read the 0x81
-        readMessage(mDevice);
+        readMessage_0x81(mDevice);
         if (millis > 0) {
             try {
                 Thread.sleep(millis);
@@ -37,6 +38,9 @@ public class PumpTimeRequestMessage extends MedtronicSendMessageRequestMessage<P
         // Read the 0x80
         PumpTimeResponseMessage response = this.getResponse(readMessage(mDevice));
 
+        // Pump sends additional 0x80 message when not using EHSM, lets clear this and any unexpected incoming messages
+        clearMessage(mDevice);
+
         return response;
     }
 
@@ -44,4 +48,4 @@ public class PumpTimeRequestMessage extends MedtronicSendMessageRequestMessage<P
     protected PumpTimeResponseMessage getResponse(byte[] payload) throws ChecksumException, EncryptionException, IOException, UnexpectedMessageException {
         return new PumpTimeResponseMessage(mPumpSession, payload);
     }
-}
+}
\ No newline at end of file
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 06d88ce206d0d88fa28fbda2bfb313c0d61131d6..2005880b7929d3dbd808d1f7be6e6592f07b1948 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
@@ -10,6 +10,7 @@ import info.nightscout.android.BuildConfig;
 import info.nightscout.android.medtronic.MedtronicCnlSession;
 import info.nightscout.android.medtronic.exception.ChecksumException;
 import info.nightscout.android.medtronic.exception.EncryptionException;
+import info.nightscout.android.medtronic.exception.UnexpectedMessageException;
 import info.nightscout.android.utils.HexDump;
 
 /**
@@ -20,14 +21,14 @@ public class PumpTimeResponseMessage extends MedtronicSendMessageResponseMessage
 
     private Date pumpTime;
 
-    protected PumpTimeResponseMessage(MedtronicCnlSession pumpSession, byte[] payload) throws EncryptionException, ChecksumException {
+    protected PumpTimeResponseMessage(MedtronicCnlSession pumpSession, byte[] payload) throws EncryptionException, ChecksumException, UnexpectedMessageException {
         super(pumpSession, payload);
 
         if (this.encode().length < (61 + 8)) {
             // Invalid message. Return an invalid date.
             // TODO - deal with this more elegantly
             Log.e(TAG, "Invalid message received for getPumpTime");
-            pumpTime = new Date();
+            throw new UnexpectedMessageException("Invalid message received for getPumpTime");
         } else {
             ByteBuffer dateBuffer = ByteBuffer.allocate(8);
             dateBuffer.order(ByteOrder.BIG_ENDIAN);
diff --git a/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlAlarmManager.java b/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlAlarmManager.java
index 240a2bfe44d853781c7d44f79dbae445d04555df..08737107d34864e8164ba6e04f25f4b327ed4c5a 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlAlarmManager.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlAlarmManager.java
@@ -80,7 +80,8 @@ public class MedtronicCnlAlarmManager {
 
     // restarting the alarm after MedtronicCnlIntentService.POLL_PERIOD_MS from now
     public static void restartAlarm() {
-        setAlarmAfterMillis(MainActivity.pollInterval + MedtronicCnlIntentService.POLL_GRACE_PERIOD_MS);
+        //setAlarmAfterMillis(MainActivity.pollInterval + MedtronicCnlIntentService.POLL_GRACE_PERIOD_MS);
+        setAlarmAfterMillis(MainActivity.pollInterval); // grace already accounted for when using current intent time to set default restart
     }
 
     // Cancel the alarm.
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 23fdd5dcf4a4fba01066e5e9b1ac38c6792e48e1..f76773d627f11b38b4ebb8ff136dde7850abb112 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
@@ -20,6 +20,8 @@ import java.security.NoSuchAlgorithmException;
 import java.util.Date;
 import java.util.Locale;
 import java.util.concurrent.TimeoutException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
 
 import info.nightscout.android.R;
 import info.nightscout.android.USB.UsbHidDriver;
@@ -98,6 +100,25 @@ public class MedtronicCnlIntentService extends IntentService {
     protected void onHandleIntent(Intent intent) {
         Log.d(TAG, "onHandleIntent called");
 
+        long timePollStarted = System.currentTimeMillis();
+        long timePollExpected = timePollStarted;
+        if (MainActivity.timeLastGoodSGV != 0) {
+            timePollExpected = MainActivity.timeLastGoodSGV + POLL_PERIOD_MS + POLL_GRACE_PERIOD_MS + (POLL_PERIOD_MS * ((timePollStarted - 1000L - (MainActivity.timeLastGoodSGV + POLL_GRACE_PERIOD_MS)) / POLL_PERIOD_MS));
+        }
+
+        // avoid polling when too close to sensor-pump comms
+        if (((timePollExpected - timePollStarted) > 5000L) && ((timePollExpected - timePollStarted) < (POLL_GRACE_PERIOD_MS + 45000L))) {
+            sendStatus("Please wait: Poll due in " + ((timePollExpected - timePollStarted) / 1000L) + " seconds");
+            MedtronicCnlAlarmManager.setAlarm(timePollExpected);
+            MedtronicCnlAlarmReceiver.completeWakefulIntent(intent);
+            return;
+        }
+
+        long pollInterval = MainActivity.pollInterval;
+        if ((MainActivity.pumpBattery > 0) && (MainActivity.pumpBattery <= 25)) {
+            pollInterval = MainActivity.lowBatteryPollInterval;
+        }
+
         if (!hasUsbHostFeature()) {
             sendStatus("It appears that this device doesn't support USB OTG.");
             Log.e(TAG, "Device does not support USB OTG");
@@ -135,14 +156,16 @@ public class MedtronicCnlIntentService extends IntentService {
             return;
         }
 
+        DateFormat df = new SimpleDateFormat("HH:mm:ss");
+
         MedtronicCnlReader cnlReader = new MedtronicCnlReader(mHidDevice);
 
         Realm realm = Realm.getDefaultInstance();
         realm.beginTransaction();
 
         try {
-            sendStatus("Connecting to the Contour Next Link...");
-            Log.d(TAG, "Connecting to the Contour Next Link.");
+            sendStatus("Connecting to Contour Next Link");
+            Log.d(TAG, "Connecting to Contour Next Link");
             cnlReader.requestDeviceInfo();
 
             // Is the device already configured?
@@ -162,6 +185,7 @@ public class MedtronicCnlIntentService extends IntentService {
             try {
                 cnlReader.enterPassthroughMode();
                 cnlReader.openConnection();
+
                 cnlReader.requestReadInfo();
 
                 String key = info.getKey();
@@ -193,17 +217,12 @@ public class MedtronicCnlIntentService extends IntentService {
                 if (radioChannel == 0) {
                     sendStatus("Could not communicate with the 640g. Are you near the pump?");
                     Log.i(TAG, "Could not communicate with the 640g. Are you near the pump?");
-
-                    // reduce polling interval to half until pump is available
-                    MedtronicCnlAlarmManager.setAlarm(activePump.getLastQueryTS() +
-                            (MainActivity.pollInterval / (MainActivity.reducePollOnPumpAway?2L:1L))
-                    );
+                    pollInterval = MainActivity.pollInterval / (MainActivity.reducePollOnPumpAway?2L:1L); // reduce polling interval to half until pump is available
                 } else {
                     setActivePumpMac(pumpMAC);
                     activePump.setLastRadioChannel(radioChannel);
-                    sendStatus(String.format(Locale.getDefault(), "Connected to Contour Next Link on channel %d.", (int) radioChannel));
+                    sendStatus(String.format(Locale.getDefault(), "Connected on channel %d  RSSI: %d%%", (int) radioChannel, cnlReader.getPumpSession().getRadioRSSIpercentage()));
                     Log.d(TAG, String.format("Connected to Contour Next Link on channel %d.", (int) radioChannel));
-                    cnlReader.beginEHSMSession();
 
                     // read pump status
                     PumpStatusEvent pumpRecord = realm.createObject(PumpStatusEvent.class);
@@ -223,13 +242,28 @@ public class MedtronicCnlIntentService extends IntentService {
                     pumpRecord.setPumpDate(new Date(pumpTime - pumpOffset));
                     cnlReader.updatePumpStatus(pumpRecord);
 
-                    cnlReader.endEHSMSession();
-
                     if (pumpRecord.getSgv() != 0) {
+
+                        String offsetSign = "";
+                        if (pumpOffset > 0) {
+                            offsetSign = "+";
+                        }
+                        sendStatus("SGV: " + MainActivity.strFormatSGV(pumpRecord.getSgv()) + "  At: " + df.format(pumpRecord.getEventDate().getTime()) + "  Pump: " + offsetSign + (pumpOffset / 1000L) + "sec");  //note: event time is currently stored with offset
+
+                        // Check if pump sent old event when new expected and schedule a re-poll
+                        if (((pumpRecord.getEventDate().getTime() - MainActivity.timeLastGoodSGV) < 5000L) && ((timePollExpected - timePollStarted) < 5000L)) {
+                            pollInterval = 90000L; // polling interval set to 90 seconds
+                            sendStatus("Pump sent old SGV event, re-polling...");
+                        }
+
+                        MainActivity.timeLastGoodSGV =  pumpRecord.getEventDate().getTime(); // track last good sgv event time
+                        MainActivity.pumpBattery =  pumpRecord.getBatteryPercentage(); // track pump battery
+                        MainActivity.countUnavailableSGV = 0; // reset unavailable sgv count
+
                         // Check that the record doesn't already exist before committing
                         RealmResults<PumpStatusEvent> checkExistingRecords = activePump.getPumpHistory()
                                 .where()
-                                .equalTo("eventDate", pumpRecord.getEventDate())
+                                .equalTo("eventDate", pumpRecord.getEventDate())    // >>>>>>> check as event date may not = exact pump event date due to it being stored with offset added this could lead to dup events due to slight variability in time offset
                                 .equalTo("sgv", pumpRecord.getSgv())
                                 .findAll();
 
@@ -240,15 +274,24 @@ public class MedtronicCnlIntentService extends IntentService {
 
                         Log.d(TAG, "history reading size: " + activePump.getPumpHistory().size());
                         Log.d(TAG, "history reading date: " + activePump.getPumpHistory().last().getEventDate());
+                    } else {
+                        sendStatus("SGV: unavailable from pump");
+                        MainActivity.countUnavailableSGV ++; // poll clash detection
                     }
 
                     realm.commitTransaction();
                     // Tell the Main Activity we have new data
                     sendMessage(Constants.ACTION_UPDATE_PUMP);
                 }
+
             } catch (UnexpectedMessageException e) {
                 Log.e(TAG, "Unexpected Message", e);
                 sendStatus("Communication Error: " + e.getMessage());
+                pollInterval = MainActivity.pollInterval / (MainActivity.reducePollOnPumpAway?2L:1L);
+            } catch (TimeoutException e) {
+                Log.e(TAG, "Timeout communicating with the Contour Next Link.", e);
+                sendStatus("Timeout communicating with the Contour Next Link.");
+                pollInterval = MainActivity.pollInterval / (MainActivity.reducePollOnPumpAway?2L:1L);
             } catch (NoSuchAlgorithmException e) {
                 Log.e(TAG, "Could not determine CNL HMAC", e);
                 sendStatus("Error connecting to Contour Next Link: Hashing error.");
@@ -283,10 +326,34 @@ public class MedtronicCnlIntentService extends IntentService {
                 }
                 realm.close();
             }
-
             // TODO - set status if offline or Nightscout not reachable
             sendToXDrip();
             uploadToNightscout();
+
+            // smart polling and pump-sensor poll clash detection
+            long lastActualPollTime = timePollStarted;
+            if (MainActivity.timeLastGoodSGV > 0) {
+                lastActualPollTime = MainActivity.timeLastGoodSGV + POLL_GRACE_PERIOD_MS + (POLL_PERIOD_MS * ((System.currentTimeMillis() - (MainActivity.timeLastGoodSGV + POLL_GRACE_PERIOD_MS)) / POLL_PERIOD_MS));
+            }
+            long nextActualPollTime = lastActualPollTime + POLL_PERIOD_MS;
+            long nextRequestedPollTime = lastActualPollTime + pollInterval;
+            if ((nextRequestedPollTime - System.currentTimeMillis()) < 10000L) {
+                nextRequestedPollTime = nextActualPollTime;
+            }
+            // extended unavailable SGV may be due to clash with the current polling time
+            // while we wait for a good SGV event, polling is auto adjusted by offsetting the next poll based on miss count
+            if (MainActivity.countUnavailableSGV > 0) {
+                if (MainActivity.timeLastGoodSGV == 0) {
+                    nextRequestedPollTime += POLL_PERIOD_MS / 5L; // if there is a uploader/sensor poll clash on startup then this will push the next attempt out by 60 seconds
+                }
+                else if (MainActivity.countUnavailableSGV > 2) {
+                    sendStatus("Warning: No SGV available from pump for " + MainActivity.countUnavailableSGV + " attempts");
+                    nextRequestedPollTime += ((long) ((MainActivity.countUnavailableSGV - 2) % 5)) * (POLL_PERIOD_MS / 10L); // adjust poll time in 1/10 steps to avoid potential poll clash (max adjustment at 5/10)
+                }
+            }
+            MedtronicCnlAlarmManager.setAlarm(nextRequestedPollTime);
+            sendStatus("Next poll due at: " + df.format(nextRequestedPollTime));
+
             MedtronicCnlAlarmReceiver.completeWakefulIntent(intent);
         }
     }
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
index 23335545a77d68efc80fd96e5a562e16e293ff51..eef010f25bcd95a441250f3090c01fd3d367e4e3 100644
--- a/app/src/main/java/info/nightscout/android/xdrip_plus/XDripPlusUploadIntentService.java
+++ b/app/src/main/java/info/nightscout/android/xdrip_plus/XDripPlusUploadIntentService.java
@@ -70,6 +70,7 @@ public class XDripPlusUploadIntentService extends IntentService {
             List<PumpStatusEvent> records = all_records.subList(0, 1);
             doXDripUpload(records);
         }
+        mRealm.close();
         XDripPlusUploadReceiver.completeWakefulIntent(intent);
     }
 
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 95148622918e6cc996d1ce7e5c3075d7ff3e399a..3dfa26586c1b258eca12ab5d0ba8e3f142d02d82 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -128,18 +128,21 @@
         android:id="@+id/scrollView"
         android:layout_width="match_parent"
         android:layout_height="fill_parent">
+        android:gravity="bottom"
 
         <LinearLayout
             android:orientation="vertical"
             android:layout_width="match_parent"
             android:layout_height="wrap_content">
+            android:gravity="bottom"
 
             <TextView
                 android:id="@+id/textview_log"
                 android:layout_width="fill_parent"
                 android:layout_height="wrap_content"
                 android:layout_margin="10sp"
-                android:maxLines="20"
+                android:maxLines="800"
+                android:gravity="bottom"
                 android:text="" />
         </LinearLayout>
     </ScrollView>