diff --git a/app/build.gradle b/app/build.gradle index b48e315c651f14dea31f0c579dac6a2ec348761c..6087f89f0703604736d3fdec83f036ad0c5d6d7b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -161,4 +161,7 @@ dependencies { compile 'com.squareup.retrofit2:retrofit:2.1.0' compile 'com.squareup.retrofit2:converter-gson:2.1.0' compile 'com.google.android.gms:play-services-appindexing:8.4.0' + + // https://mvnrepository.com/artifact/org.anarres.lzo/lzo-core + compile group: 'org.anarres.lzo', name: 'lzo-core', version: '1.0.5' } \ No newline at end of file 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 6a493ac5550eed62fcc97909a2c124a9228643d5..a4bc1796fb01ef6c6f22425b658eddfa3b7707d6 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/MainActivity.java +++ b/app/src/main/java/info/nightscout/android/medtronic/MainActivity.java @@ -59,6 +59,8 @@ import java.text.DateFormat; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.Date; +import java.util.Iterator; +import java.util.List; import java.util.Locale; import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/pump/PumpTimeResponseMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/pump/PumpTimeResponseMessage.java index 914e539ca2108f5c2576c22d1b6ff7c8020787ce..3a45dfd8d6ba615eee10f55bcc007843ce2f53e5 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/pump/PumpTimeResponseMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/pump/PumpTimeResponseMessage.java @@ -24,6 +24,60 @@ public class PumpTimeResponseMessage extends MedtronicSendMessageResponseMessage protected PumpTimeResponseMessage(MedtronicCnlSession pumpSession, byte[] payload) throws EncryptionException, ChecksumException { super(pumpSession, payload); + /** + 2017-03-11 11:50:29 +0000 UTC I ContourNextLinkMessage :0 READ: + 2017-03-11 11:50:29 +0000 UTC I ContourNextLinkMessage :0 ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9 ?A ?B ?C ?D ?E ?F + 2017-03-11 11:50:29 +0000 UTC I ContourNextLinkMessage :0 0x00000000 51 03 30 30 30 30 30 30 00 00 00 00 00 00 00 00 Q.000000........ + 2017-03-11 11:50:29 +0000 UTC I ContourNextLinkMessage :0 0x00000010 00 00 81 05 00 00 00 00 00 00 00 00 0F 00 00 00 ................ + 2017-03-11 11:50:29 +0000 UTC I ContourNextLinkMessage :0 0x00000020 D2 55 0D 00 04 00 00 00 00 03 00 01 02 02 58 03 .U............X. + + 2017-03-11 11:50:31 +0000 UTC I ContourNextLinkMessage :0 READ: + 2017-03-11 11:50:31 +0000 UTC I ContourNextLinkMessage :0 ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9 ?A ?B ?C ?D ?E ?F + 2017-03-11 11:50:31 +0000 UTC I ContourNextLinkMessage :0 0x00000000 51 03 30 30 30 30 30 30 00 00 00 00 00 00 00 00 Q.000000........ + 2017-03-11 11:50:31 +0000 UTC I ContourNextLinkMessage :0 0x00000010 00 00 80 D0 8E 00 80 00 00 00 00 00 28 00 00 00 ............(... + 2017-03-11 11:50:31 +0000 UTC I ContourNextLinkMessage :0 0x00000020 D8 55 26 00 06 EB 2F 11 EE 45 F7 23 00 01 0B 10 .U&.../..E.#.... + 2017-03-11 11:50:31 +0000 UTC I ContourNextLinkMessage :0 0x00000030 82 06 F7 23 00 02 0C 04 0E A9 BF 51 60 15 80 A7 ...#.......Q`... + 2017-03-11 11:50:31 +0000 UTC I ContourNextLinkMessage :0 0x00000040 20 65 39 1A EC 5A 4E 1D 29 .e9..ZN.) + + 2017-03-11 11:50:31 +0000 UTC I MedtronicResponseMessage :0 DECRYPTED: + 2017-03-11 11:50:31 +0000 UTC I MedtronicResponseMessage :0 ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9 ?A ?B ?C ?D ?E ?F + 2017-03-11 11:50:31 +0000 UTC I MedtronicResponseMessage :0 0x00000000 51 03 30 30 30 30 30 30 00 00 00 00 00 00 00 00 Q.000000........ + 2017-03-11 11:50:31 +0000 UTC I MedtronicResponseMessage :0 0x00000010 00 00 80 D0 8E 00 80 00 00 00 00 00 28 00 00 00 ............(... + 2017-03-11 11:50:31 +0000 UTC I MedtronicResponseMessage :0 0x00000020 D8 55 26 00 06 EB 2F 11 EE 45 F7 23 00 01 0B 10 .U&.../..E.#.... + 2017-03-11 11:50:31 +0000 UTC I MedtronicResponseMessage :0 0x00000030 82 06 F7 23 00 02 0C 04 0E 01 04 07 01 80 8D DF ...#............ + 2017-03-11 11:50:31 +0000 UTC I MedtronicResponseMessage :0 0x00000040 24 9F C8 D0 7F 7A 1D 1D 29 $....z..) + 2017-03-11 11:50:31 +0000 UTC I PumpTimeResponseMessage :0 PAYLOAD: + 2017-03-11 11:50:31 +0000 UTC I PumpTimeResponseMessage :0 ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 + 2017-03-11 11:50:31 +0000 UTC I PumpTimeResponseMessage :0 0x00000000 80 8D DF 24 9F C8 D0 7F ...$.... + + Steam with wrong (old) key + 2017-03-11 11:48:04 +0000 UTC I ContourNextLinkMessage :0 READ: + 2017-03-11 11:48:04 +0000 UTC I ContourNextLinkMessage :0 ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9 ?A ?B ?C ?D ?E ?F + 2017-03-11 11:48:04 +0000 UTC I ContourNextLinkMessage :0 0x00000000 51 03 30 30 30 30 30 30 00 00 00 00 00 00 00 00 Q.000000........ + 2017-03-11 11:48:04 +0000 UTC I ContourNextLinkMessage :0 0x00000010 00 00 81 04 00 00 00 00 00 00 00 00 0F 00 00 00 ................ + 2017-03-11 11:48:04 +0000 UTC I ContourNextLinkMessage :0 0x00000020 D1 55 0D 00 04 00 00 00 00 03 00 01 02 02 58 03 .U............X. + 2017-03-11 11:48:07 +0000 UTC I ContourNextLinkMessage :0 READ: + 2017-03-11 11:48:07 +0000 UTC I ContourNextLinkMessage :0 ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9 ?A ?B ?C ?D ?E ?F + 2017-03-11 11:48:07 +0000 UTC I ContourNextLinkMessage :0 0x00000000 51 03 30 30 30 30 30 30 00 00 00 00 00 00 00 00 Q.000000........ + 2017-03-11 11:48:07 +0000 UTC I ContourNextLinkMessage :0 0x00000010 00 00 80 CE 8E 00 80 00 00 00 00 00 0D 00 00 00 ................ + 2017-03-11 11:48:07 +0000 UTC I ContourNextLinkMessage :0 0x00000020 24 55 0B 00 00 00 02 00 00 03 00 00 7D 65 $U..........}e + 2017-03-11 11:48:07 +0000 UTC W PumpTimeResponseMessage :0 Invalid message received for getPumpTime + 2017-03-11 11:48:07 +0000 UTC W MedtronicCnlReader :0 Unexpected Message + 2017-03-11 11:48:07 +0000 UTC W MedtronicCnlReader :0 info.nightscout.android.medtronic.exception.UnexpectedMessageException: Invalid message received for getPumpTime + 2017-03-11 11:48:07 +0000 UTC W MedtronicCnlReader :0 at info.nightscout.android.medtronic.message.PumpTimeResponseMessage.<init>(PumpTimeResponseMessage.java:31) + 2017-03-11 11:48:07 +0000 UTC W MedtronicCnlReader :0 at info.nightscout.android.medtronic.message.PumpTimeRequestMessage.getResponse(PumpTimeRequestMessage.java:49) + 2017-03-11 11:48:07 +0000 UTC W MedtronicCnlReader :0 at info.nightscout.android.medtronic.message.PumpTimeRequestMessage.send(PumpTimeRequestMessage.java:39) + 2017-03-11 11:48:07 +0000 UTC W MedtronicCnlReader :0 at info.nightscout.android.medtronic.message.PumpTimeRequestMessage.send(PumpTimeRequestMessage.java:15) + 2017-03-11 11:48:07 +0000 UTC W MedtronicCnlReader :0 at info.nightscout.android.medtronic.message.ContourNextLinkRequestMessage.send(ContourNextLinkRequestMessage.java:26) + 2017-03-11 11:48:07 +0000 UTC W MedtronicCnlReader :0 at info.nightscout.android.medtronic.MedtronicCnlReader.getPumpTime(MedtronicCnlReader.java:177) + 2017-03-11 11:48:07 +0000 UTC W MedtronicCnlReader :0 at info.nightscout.android.medtronic.service.MedtronicCnlIntentService.onHandleIntent(MedtronicCnlIntentService.java:236) + 2017-03-11 11:48:07 +0000 UTC W MedtronicCnlReader :0 at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:66) + 2017-03-11 11:48:07 +0000 UTC W MedtronicCnlReader :0 at android.os.Handler.dispatchMessage(Handler.java:102) + 2017-03-11 11:48:07 +0000 UTC W MedtronicCnlReader :0 at android.os.Looper.loop(Looper.java:148) + 2017-03-11 11:48:07 +0000 UTC W MedtronicCnlReader :0 at android.os.HandlerThread.run(HandlerThread.java:61) + 2017-03-11 11:48:07 +0000 UTC I UsbHidDriver :0 Wrote amt=64 attempted=64 + + */ if (this.encode().length < (61 + 8)) { // Invalid message. Return an invalid date. // TODO - deal with this more elegantly diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/pump/ReadHistoryBaseRequestMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/pump/ReadHistoryBaseRequestMessage.java index 39e3168116d00493128dc5d6be681199ab39071b..70a3150b142e7c640c260318d92e28ecf0a4037a 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/pump/ReadHistoryBaseRequestMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/pump/ReadHistoryBaseRequestMessage.java @@ -2,6 +2,12 @@ package info.nightscout.android.medtronic.message.pump; import android.util.Log; +import org.anarres.lzo.LzoAlgorithm; +import org.anarres.lzo.LzoDecompressor; +import org.anarres.lzo.LzoInputStream; +import org.anarres.lzo.LzoLibrary; + +import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -23,18 +29,21 @@ import info.nightscout.android.medtronic.message.pump.command.multipacket.Repeat import info.nightscout.android.utils.HexDump; import static android.R.attr.value; +import static android.R.id.message; /** * Created by lgoedhart on 26/03/2016. */ public abstract class ReadHistoryBaseRequestMessage<T extends AbstractResponseMessage> extends MedtronicSendMessageRequestMessage<T> { private static final String TAG = ReadHistoryBaseRequestMessage.class.getSimpleName(); + private final LzoDecompressor lzoODecompressor; private long segmentSize; private short packetSize; private short lastPacketSize; private short packetsToFetch; private byte[][] segments; + private byte historyDataType; protected enum HistoryDataType { PUMP_DATA(0x2), @@ -58,6 +67,8 @@ public abstract class ReadHistoryBaseRequestMessage<T extends AbstractResponseMe this.expectedSize = expectedSize; this.bytesFetched = 0; this.receviedEndHistoryCommand = false; + + lzoODecompressor = LzoLibrary.getInstance().newDecompressor(LzoAlgorithm.LZO1X, null); } @Override @@ -128,15 +139,18 @@ public abstract class ReadHistoryBaseRequestMessage<T extends AbstractResponseMe } protected int[] missingSegmentKeys() { - ArrayList<Integer> keys = new ArrayList<>(this.segments.length); + int[] keys = new int[this.segments.length]; int count = 0; - for ( byte[] segment: this.segments){ + for ( int i = 0; i < this.segments.length; i++) { + byte[] segment = this.segments[i]; if (segment==null) { - keys.add(count); + keys[count++] = i; }; - count ++; } - return keys.toArray(); + + int[] result = new int[count]; + System.arraycopy(keys, 0, result, 0, count); + return result; } /* get missingSegmentKeys() { @@ -190,28 +204,36 @@ public abstract class ReadHistoryBaseRequestMessage<T extends AbstractResponseMe // TODO - all of this should go into different classes... // Decompress the message if ((buffer.getInt(0x00) & 0xffffffffl) == 0x030E) { - const HEADER_SIZE = 12; // TODO should be a static get. + final byte HEADER_SIZE = 12; // TODO should be a static get. // It's an UnmergedHistoryUpdateCompressed response. We need to decompress it - const dataType = segmentPayload[0x02]; // Returns a HISTORY_DATA_TYPE - const historySizeCompressed = segmentPayload.readUInt32BE(0x03); - const historySizeUncompressed = segmentPayload.readUInt32BE(0x07); - const historyCompressed = segmentPayload[0x0B]; + final byte dataType = buffer.get(0x02); // Returns a HISTORY_DATA_TYPE + final long historySizeCompressed = (buffer.getInt(0x03) & 0xffffffffl); //segmentPayload.readUInt32BE(0x03); + final long historySizeUncompressed = (buffer.getInt(0x03) & 0xffffffffl); //segmentPayload.readUInt32BE(0x07); + final boolean historyCompressed = (buffer.get(0x0B) != 0); - if (dataType !== this.historyDataType) { - reject(new InvalidMessageError('Unexpected history type in response')); + if (dataType != this.historyDataType) { + throw new InvalidMessageException("Unexpected history type in response"); } // Check that we have the correct number of bytes in this message - if (segmentPayload.length - HEADER_SIZE !== historySizeCompressed) { - reject(new InvalidMessageError('Unexpected message size')); + if (segmentPayload.length - HEADER_SIZE != historySizeCompressed) { + throw new InvalidMessageException("Unexpected message size"); } - let blockPayload = null; + byte[] blockPayload; if (historyCompressed) { - blockPayload = lzo.decompress(segmentPayload.slice(HEADER_SIZE)); - if (blockPayload.length !== historySizeUncompressed) { - debug(`Unexpected uncompressed message size. Expected ${historySizeUncompressed}, got ${blockPayload.length}. Original size ${historySizeCompressed}, compressed: ${historyCompressed}.`); - reject(new InvalidMessageError('Unexpected uncompressed message size.')); + byte[] lzoSegemnt; + System.arraycopy(segmentPayload, HEADER_SIZE, lzoSegemnt, 0, segmentPayload.length -HEADER_SIZE); + LzoInputStream stream = new LzoInputStream( + new ByteArrayInputStream(lzoSegemnt), lzoODecompressor); + + blockPayload = new byte[stream.available()]; + + int size = stream.read(blockPayload); + + if (size != historySizeUncompressed) { + Log.d(TAG, "Unexpected uncompressed message size. Expected ${historySizeUncompressed}, got ${blockPayload.length}. Original size ${historySizeCompressed}, compressed: ${historyCompressed}."); + throw (new InvalidMessageException("Unexpected uncompressed message size.")); } } else { blockPayload = segmentPayload.slice(HEADER_SIZE);