From 88516e2bb67fa7888f03a5489d0b8a92de6ddc82 Mon Sep 17 00:00:00 2001
From: Pogman <subaziro@gmail.com>
Date: Sat, 18 Feb 2017 16:08:31 +0000
Subject: [PATCH] Fixes to stop the CNL from going into an error state:

 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
---
 .../message/ContourNextLinkMessage.java       | 52 ++++++++++++++++++-
 .../medtronic/message/EHSMMessage.java        | 10 ++++
 .../message/PumpStatusRequestMessage.java     |  6 ++-
 .../message/PumpTimeRequestMessage.java       |  8 ++-
 .../message/PumpTimeResponseMessage.java      |  6 ++-
 5 files changed, 76 insertions(+), 6 deletions(-)

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 0d35809..86305a3 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
@@ -20,7 +20,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 +142,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 d930a59..0e06453 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 982bdba..32e1479 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,10 @@ public class PumpStatusRequestMessage extends MedtronicSendMessageRequestMessage
     }
 
     public PumpStatusResponseMessage send(UsbHidDriver mDevice, int millis) throws IOException, TimeoutException, ChecksumException, EncryptionException, UnexpectedMessageException {
+
+        // clear unexpected incoming messages
+        clearMessage(mDevice);
+
         sendMessage(mDevice);
         if (millis > 0) {
             try {
@@ -31,7 +35,7 @@ public class PumpStatusRequestMessage extends MedtronicSendMessageRequestMessage
             }
         }
         // Read the 0x81
-        readMessage(mDevice);
+        readMessage_0x81(mDevice);
         if (millis > 0) {
             try {
                 Log.d(TAG, "waiting " + millis +" ms");
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 24cbb14..6aa7772 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,10 @@ public class PumpTimeRequestMessage extends MedtronicSendMessageRequestMessage<P
 
     @Override
     public PumpTimeResponseMessage send(UsbHidDriver mDevice, int millis) throws IOException, TimeoutException, ChecksumException, EncryptionException, UnexpectedMessageException {
+
+        // clear unexpected incoming messages
+        clearMessage(mDevice);
+
         sendMessage(mDevice);
         if (millis > 0) {
             try {
@@ -27,7 +31,7 @@ public class PumpTimeRequestMessage extends MedtronicSendMessageRequestMessage<P
             }
         }
         // Read the 0x81
-        readMessage(mDevice);
+        readMessage_0x81(mDevice);
         if (millis > 0) {
             try {
                 Thread.sleep(millis);
@@ -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 06d88ce..2a816cc 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,15 @@ 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");
+//            pumpTime = new Date();
         } else {
             ByteBuffer dateBuffer = ByteBuffer.allocate(8);
             dateBuffer.order(ByteOrder.BIG_ENDIAN);
-- 
GitLab