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 b66a3c12f160c93cfd63f194a529e175366abddb..7e1e44b3f82e3c189ae5cf8cd1c71f6716419cc0 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 4a3f94bd07cacac066df13a416f51f06b4e6e3d3..c93aa7fb6d2f02c96c8e504dec348f449a6920f4 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 ad114c682a2eeac28d4e1e19a0f42a1131a72c26..c7dc1ab6535d3390577c91c8ee60744cc2348c80 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 0000000000000000000000000000000000000000..f5bde36799dda28dfcc2ffbd84d9324e168d806a --- /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 2639e76c56591663bd69c1745892e11de2603ec9..159ac178835177155bf6f69bbeb475130b75bcbd 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 0000000000000000000000000000000000000000..0aab014e551a3b773d51797caf315f2de68a884e --- /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 0000000000000000000000000000000000000000..fec7c00038cfa9368ee6340ecff94ce5e5bf7311 --- /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 87eaf9f20fd82c03383a8f7408a03fa794d7bfb2..10f4d26e0af48ee6035450bd17cd0e1bf8c1fce1 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 8bb77ad63f543c992a1afbee43760462ad23cdec..8481a169404e89a2edb3025c516ef3f38d426e3b 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 814f29de870282cf6b54da5c6619dbbadc4f6864..1e6dad6b23df39893aba22f2424990c833106cf5 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;