From 880fe8873759ae94177d2ccf524c9b4dfe0107c1 Mon Sep 17 00:00:00 2001
From: Volker Richert <v.richert@addmore.de>
Date: Sat, 10 Dec 2016 18:08:25 +0100
Subject: [PATCH] refactoring

---
 .../android/medtronic/MedtronicCnlReader.java | 93 +++++++------------
 .../message/ContourNextLinkBinaryMessage.java | 30 ++++--
 .../ContourNextLinkCommandMessage.java        | 13 +++
 ...ContourNextLinkCommandResponseMessage.java | 13 +++
 .../message/ContourNextLinkMessage.java       | 17 ++++
 .../DeviceInfoRequestCommandMessage.java      | 44 +++++++++
 .../DeviceInfoResponseCommandMessage.java     | 35 +++++++
 .../message/ReadInfoResponseMessage.java      |  4 -
 .../RequestLinkKeyResponseMessage.java        |  9 --
 .../service/MedtronicCnlIntentService.java    |  6 +-
 10 files changed, 178 insertions(+), 86 deletions(-)
 create mode 100644 app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkCommandResponseMessage.java
 create mode 100644 app/src/main/java/info/nightscout/android/medtronic/message/DeviceInfoRequestCommandMessage.java
 create mode 100644 app/src/main/java/info/nightscout/android/medtronic/message/DeviceInfoResponseCommandMessage.java

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 b66a3c1..7e1e44b 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlReader.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlReader.java
@@ -15,8 +15,6 @@ import java.util.Arrays;
 import java.util.Date;
 import java.util.Locale;
 import java.util.concurrent.TimeoutException;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 import info.nightscout.android.USB.UsbHidDriver;
 import info.nightscout.android.medtronic.message.BeginEHSMMessage;
@@ -26,6 +24,7 @@ import info.nightscout.android.medtronic.message.ContourNextLinkBinaryMessage;
 import info.nightscout.android.medtronic.message.ContourNextLinkCommandMessage;
 import info.nightscout.android.medtronic.message.ContourNextLinkMessage;
 import info.nightscout.android.medtronic.message.ContourNextLinkMessageHandler;
+import info.nightscout.android.medtronic.message.DeviceInfoResponseCommandMessage;
 import info.nightscout.android.medtronic.message.EncryptionException;
 import info.nightscout.android.medtronic.message.EndEHSMMessage;
 import info.nightscout.android.medtronic.message.MedtronicMessage;
@@ -40,6 +39,7 @@ import info.nightscout.android.medtronic.message.PumpTimeResponseMessage;
 import info.nightscout.android.medtronic.message.ReadInfoResponseMessage;
 import info.nightscout.android.medtronic.message.RequestLinkKeyRequestMessage;
 import info.nightscout.android.medtronic.message.RequestLinkKeyResponseMessage;
+import info.nightscout.android.medtronic.message.DeviceInfoRequestCommandMessage;
 import info.nightscout.android.medtronic.message.UnexpectedMessageException;
 import info.nightscout.android.model.medtronicNg.PumpStatusEvent;
 import info.nightscout.android.utils.HexDump;
@@ -172,73 +172,44 @@ public class MedtronicCnlReader implements ContourNextLinkMessageHandler {
         }
     }
 
-    public void requestDeviceInfo() throws IOException, TimeoutException, UnexpectedMessageException {
-        new ContourNextLinkCommandMessage("X").send(this);
+    public void requestDeviceInfo()
+            throws IOException, TimeoutException, UnexpectedMessageException, ChecksumException, EncryptionException {
+        DeviceInfoResponseCommandMessage response = new DeviceInfoRequestCommandMessage().send(mDevice);
 
-        boolean doRetry = false;
-
-        // TODO - parse this into an ASTM record for the device info.
-        try {
-            // The stick will return either the ASTM message, or the ENQ first. The order can change,
-            // so we need to handle both cases
-            byte[] response1 = readMessage();
-            byte[] response2 = readMessage();
-
-            if (response1[0] == ASCII.EOT.value) {
-                // response 1 is the ASTM message
-                checkControlMessage(response2, ASCII.ENQ.value);
-                extractStickSerial(new String(response1));
-            } else {
-                // response 2 is the ASTM message
-                checkControlMessage(response1, ASCII.ENQ.value);
-                extractStickSerial(new String(response2));
-            }
-        } catch (TimeoutException e) {
-            // Terminate comms with the pump, then try again
-            new ContourNextLinkCommandMessage(ASCII.EOT.value).send(this);
-            doRetry = true;
-        } finally {
-            if (doRetry) {
-                requestDeviceInfo();
-            }
-        }
+        //TODO - extract more details form the device info.
+        mStickSerial = response.getSerial();
     }
 
-    private void extractStickSerial(String astmMessage) {
-        Pattern pattern = Pattern.compile(".*?\\^(\\d{4}-\\d{7})\\^.*");
-        Matcher matcher = pattern.matcher(astmMessage);
-        if (matcher.find()) {
-            mStickSerial = matcher.group(1);
-        }
-    }
 
-    public void enterControlMode() throws IOException, TimeoutException, UnexpectedMessageException {
-        boolean doRetry = false;
-
-        try {
-            new ContourNextLinkCommandMessage(ASCII.NAK.value).send(this);
-            checkControlMessage(readMessage(), ASCII.EOT.value);
-            new ContourNextLinkCommandMessage(ASCII.ENQ.value).send(this);
-            checkControlMessage(readMessage(), ASCII.ACK.value);
-        } catch (UnexpectedMessageException e2) {
-            // Terminate comms with the pump, then try again
-            new ContourNextLinkCommandMessage(ASCII.EOT.value).send(this);
-            doRetry = true;
-        } finally {
-            if (doRetry) {
-                enterControlMode();
+    public void enterControlMode() throws IOException, TimeoutException, UnexpectedMessageException, ChecksumException, EncryptionException {
+        boolean doRetry;
+
+        do {
+            doRetry = false;
+            try {
+                new ContourNextLinkCommandMessage(ASCII.NAK.value)
+                        .send(mDevice).checkControlMessage(ASCII.EOT.value);
+                new ContourNextLinkCommandMessage(ASCII.ENQ.value)
+                        .send(mDevice).checkControlMessage(ASCII.ACK.value);
+            } catch (UnexpectedMessageException e2) {
+                try {
+                    new ContourNextLinkCommandMessage(ASCII.EOT.value).send(this);
+                } catch (IOException e) {}
+                finally {
+                    doRetry = true;
+                }
             }
-        }
+        } while (doRetry);
     }
 
-    public void enterPassthroughMode() throws IOException, TimeoutException, UnexpectedMessageException {
+    public void enterPassthroughMode() throws IOException, TimeoutException, UnexpectedMessageException, ChecksumException, EncryptionException {
         Log.d(TAG, "Begin enterPasshtroughMode");
-        new ContourNextLinkCommandMessage("W|").send(this);
-        checkControlMessage(readMessage(), ASCII.ACK.value);
-        new ContourNextLinkCommandMessage("Q|").send(this);
-        checkControlMessage(readMessage(), ASCII.ACK.value);
-        new ContourNextLinkCommandMessage("1|").send(this);
-        checkControlMessage(readMessage(), ASCII.ACK.value);
+        new ContourNextLinkCommandMessage("W|")
+                .send(mDevice).checkControlMessage(ASCII.ACK.value);
+        new ContourNextLinkCommandMessage("Q|")
+                .send(mDevice).checkControlMessage(ASCII.ACK.value);
+        new ContourNextLinkCommandMessage("1|")
+                .send(mDevice).checkControlMessage(ASCII.ACK.value);
         Log.d(TAG, "Finished enterPasshtroughMode");
     }
 
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 4a3f94b..c93aa7f 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
@@ -7,6 +7,7 @@ import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.Locale;
+import java.util.concurrent.TimeoutException;
 
 /**
  * Created by lgoedhart on 26/03/2016.
@@ -14,7 +15,6 @@ import java.util.Locale;
 public class ContourNextLinkBinaryMessage extends ContourNextLinkMessage {
     //protected ByteBuffer mBayerEnvelope;
     //protected ByteBuffer mBayerPayload;
-    protected MedtronicCnlSession mPumpSession;
     protected CommandType mCommandType = CommandType.NO_TYPE;
 
     static int ENVELOPE_SIZE = 33;
@@ -56,6 +56,19 @@ public class ContourNextLinkBinaryMessage extends ContourNextLinkMessage {
         }
     }
 
+    public static ContourNextLinkMessage fromBytes(byte[] bytes) throws ChecksumException {
+        ContourNextLinkMessage message = new ContourNextLinkMessage(bytes);
+        message.validate();
+
+        return message;
+    }
+
+
+    public void checkControlMessage(byte controlCharacter) throws IOException, TimeoutException, UnexpectedMessageException {
+        checkControlMessage(mPayload.array(), controlCharacter);
+    }
+
+
     /**
      * Handle incrementing sequence number
      *
@@ -96,13 +109,6 @@ public class ContourNextLinkBinaryMessage extends ContourNextLinkMessage {
         return payloadBuffer.array();
     }
 
-    public static ContourNextLinkMessage fromBytes(byte[] bytes) throws ChecksumException {
-        ContourNextLinkMessage message = new ContourNextLinkMessage(bytes);
-        message.validate();
-
-        return message;
-    }
-
     protected void validate(ContourNextLinkMessage message)  throws ChecksumException {
         // Validate checksum
         byte messageChecksum = message.mPayload.get(32);
@@ -111,7 +117,13 @@ public class ContourNextLinkBinaryMessage extends ContourNextLinkMessage {
         if (messageChecksum != calculatedChecksum) {
             throw new ChecksumException(String.format(Locale.getDefault(), "Expected to get %d. Got %d", (int) calculatedChecksum, (int) messageChecksum));
         }
+    }
 
-
+    protected void checkControlMessage(byte[] msg, byte controlCharacter) throws IOException, TimeoutException, UnexpectedMessageException {
+        if (msg.length != 1 || msg[0] != controlCharacter) {
+            throw new UnexpectedMessageException(String.format(Locale.getDefault(), "Expected to get control character '%d' Got '%d'.",
+                    (int) controlCharacter, (int) msg[0]));
+        }
     }
+
 }
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkCommandMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkCommandMessage.java
index ad114c6..c7dc1ab 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkCommandMessage.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkCommandMessage.java
@@ -1,5 +1,10 @@
 package info.nightscout.android.medtronic.message;
 
+import java.io.IOException;
+import java.util.concurrent.TimeoutException;
+
+import info.nightscout.android.USB.UsbHidDriver;
+
 /**
  * Created by lgoedhart on 26/03/2016.
  */
@@ -11,4 +16,12 @@ public class ContourNextLinkCommandMessage extends ContourNextLinkMessage {
     public ContourNextLinkCommandMessage(String command) {
         super(command.getBytes());
     }
+
+    public ContourNextLinkCommandResponseMessage send(UsbHidDriver mDevice) throws IOException, TimeoutException, EncryptionException, ChecksumException, UnexpectedMessageException {
+        sendMessage(mDevice);
+
+        ContourNextLinkCommandResponseMessage response = new ContourNextLinkCommandResponseMessage(mPumpSession, readMessage(mDevice));;
+
+        return response;
+    }
 }
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkCommandResponseMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkCommandResponseMessage.java
new file mode 100644
index 0000000..f5bde36
--- /dev/null
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkCommandResponseMessage.java
@@ -0,0 +1,13 @@
+package info.nightscout.android.medtronic.message;
+
+import info.nightscout.android.medtronic.MedtronicCnlSession;
+
+/**
+ * Created by volker on 10.12.2016.
+ */
+public class ContourNextLinkCommandResponseMessage extends ContourNextLinkBinaryMessage {
+
+    public ContourNextLinkCommandResponseMessage(MedtronicCnlSession pumpSession, byte[] payload) throws ChecksumException {
+        super(CommandType.NO_TYPE, pumpSession, payload);
+    }
+}
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 2639e76..159ac17 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,6 +8,7 @@ import java.nio.ByteBuffer;
 import java.util.concurrent.TimeoutException;
 
 import info.nightscout.android.USB.UsbHidDriver;
+import info.nightscout.android.medtronic.MedtronicCnlSession;
 import info.nightscout.android.utils.HexDump;
 
 import static android.R.id.message;
@@ -23,6 +24,7 @@ public class ContourNextLinkMessage {
     private static final String BAYER_USB_HEADER = "ABC";
 
     protected ByteBuffer mPayload;
+    protected MedtronicCnlSession mPumpSession;
 
     protected ContourNextLinkMessage(byte[] bytes) {
         setPayload(bytes);
@@ -99,4 +101,19 @@ public class ContourNextLinkMessage {
     }
 
     protected void validate() {};
+
+
+    public enum ASCII {
+        STX(0x02),
+        EOT(0x04),
+        ENQ(0x05),
+        ACK(0x06),
+        NAK(0x15);
+
+        protected byte value;
+
+        ASCII(int code) {
+            this.value = (byte) code;
+        }
+    }
 }
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/DeviceInfoRequestCommandMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/DeviceInfoRequestCommandMessage.java
new file mode 100644
index 0000000..0aab014
--- /dev/null
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/DeviceInfoRequestCommandMessage.java
@@ -0,0 +1,44 @@
+package info.nightscout.android.medtronic.message;
+
+import java.io.IOException;
+import java.util.concurrent.TimeoutException;
+
+import info.nightscout.android.USB.UsbHidDriver;
+
+/**
+ * Created by volker on 10.12.2016.
+ */
+
+public class DeviceInfoRequestCommandMessage extends ContourNextLinkMessage {
+    public DeviceInfoRequestCommandMessage() {
+        super("X".getBytes());
+    }
+
+    public DeviceInfoResponseCommandMessage send(UsbHidDriver mDevice) throws IOException, TimeoutException, EncryptionException, ChecksumException, UnexpectedMessageException {
+        sendMessage(mDevice);
+
+        byte[] response1 = readMessage(mDevice);
+        byte[] response2 = readMessage(mDevice);
+
+        boolean doRetry = false;
+        DeviceInfoResponseCommandMessage response = null;
+
+        do {
+            try {
+                if (response1[0] == ASCII.EOT.value) {
+                    // response 1 is the ASTM message
+                    response = new DeviceInfoResponseCommandMessage(mPumpSession, response1);
+                    response.checkControlMessage(response2, ASCII.ENQ.value);
+                } else {
+                    // response 2 is the ASTM message
+                    response = new DeviceInfoResponseCommandMessage(mPumpSession, response1);
+                    response.checkControlMessage(response1, ASCII.ENQ.value);
+                }
+            } catch (TimeoutException e) {
+                doRetry = true;
+            }
+        } while (doRetry);
+
+        return response;
+    }
+}
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/DeviceInfoResponseCommandMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/DeviceInfoResponseCommandMessage.java
new file mode 100644
index 0000000..fec7c00
--- /dev/null
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/DeviceInfoResponseCommandMessage.java
@@ -0,0 +1,35 @@
+package info.nightscout.android.medtronic.message;
+
+import java.io.IOException;
+import java.util.concurrent.TimeoutException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import info.nightscout.android.medtronic.MedtronicCnlSession;
+
+/**
+ * Created by lgoedhart on 10/05/2016.
+ */
+public class DeviceInfoResponseCommandMessage extends MedtronicResponseMessage {
+    private String serial = "";
+    private final Pattern pattern = Pattern.compile(".*?\\^(\\d{4}-\\d{7})\\^.*");
+
+    protected DeviceInfoResponseCommandMessage(MedtronicCnlSession pumpSession, byte[] payload)
+            throws ChecksumException, EncryptionException, TimeoutException, UnexpectedMessageException, IOException {
+        super(pumpSession, payload);
+
+        extractStickSerial(new String(payload));
+    }
+
+    public String getSerial() {
+        return serial;
+    }
+
+    private void extractStickSerial(String astmMessage) {
+        Matcher matcher = pattern.matcher(astmMessage);
+        if (matcher.find()) {
+            serial = matcher.group(1);
+        }
+    }
+
+}
\ No newline at end of file
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 87eaf9f..10f4d26 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
@@ -22,10 +22,6 @@ public class ReadInfoResponseMessage extends MedtronicResponseMessage {
         pumpMAC = infoBuffer.getLong(8);
     }
 
-    public static ContourNextLinkMessage fromBytes(MedtronicCnlSession pumpSession, byte[] bytes) throws ChecksumException, EncryptionException {
-        return new ReadInfoResponseMessage(pumpSession, bytes);
-    }
-
     public long getLinkMAC() {
         return linkMAC;
     }
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
index 8bb77ad..8481a16 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/message/RequestLinkKeyResponseMessage.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/RequestLinkKeyResponseMessage.java
@@ -22,15 +22,6 @@ public class RequestLinkKeyResponseMessage extends MedtronicResponseMessage {
         setPackedLinkKey(infoBuffer.array());
     }
 
-    public static ContourNextLinkMessage fromBytes(MedtronicCnlSession pumpSession, byte[] bytes) throws ChecksumException, EncryptionException {
-        // TODO - turn this into a factory
-        ContourNextLinkMessage message = MedtronicResponseMessage.fromBytes(pumpSession, bytes);
-
-        // TODO - Validate the MessageType
-
-        return message;
-    }
-
     public byte[] getKey() {
         return key;
     }
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 814f29d..1e6dad6 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
@@ -25,10 +25,10 @@ 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.message.ChecksumException;
-import info.nightscout.android.medtronic.message.EncryptionException;
+import info.nightscout.android.medtronic.message.exception.ChecksumException;
+import info.nightscout.android.medtronic.message.exception.EncryptionException;
 import info.nightscout.android.medtronic.message.MessageUtils;
-import info.nightscout.android.medtronic.message.UnexpectedMessageException;
+import info.nightscout.android.medtronic.message.exception.UnexpectedMessageException;
 import info.nightscout.android.model.medtronicNg.ContourNextLinkInfo;
 import info.nightscout.android.model.medtronicNg.PumpInfo;
 import info.nightscout.android.model.medtronicNg.PumpStatusEvent;
-- 
GitLab