From 2982b957b62fb39c7ed5d2ca2792fa92fb4d0c6e Mon Sep 17 00:00:00 2001 From: Lennart Goedhart <lennart@omnibase.com.au> Date: Mon, 27 Mar 2017 19:21:11 +1100 Subject: [PATCH] Clean up and bug fixes from PR104 and PR105. Add support for getting pump basal rates. --- .../medtronic/MedtronicCnlSession.java | 9 --- .../ContourNextLinkBinaryRequestMessage.java | 4 +- .../ContourNextLinkResponseMessage.java | 4 +- .../message/MedtronicRequestMessage.java | 44 ------------- .../MedtronicSendMessageRequestMessage.java | 5 +- .../PumpBasalPatternResponseMessage.java | 17 +++-- .../message/PumpStatusRequestMessage.java | 2 +- .../message/PumpStatusResponseMessage.java | 6 +- .../service/MedtronicCnlIntentService.java | 1 - .../android/model/medtronicNg/PumpInfo.java | 31 ++++++++- .../upload/nightscout/NightScoutUpload.java | 66 ++++++++++--------- .../info/nightscout/api/BolusEndpoints.java | 14 ++-- .../info/nightscout/api/GlucoseEndpoints.java | 18 ++--- 13 files changed, 101 insertions(+), 120 deletions(-) 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 9c7952f..a86820f 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlSession.java +++ b/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlSession.java @@ -11,7 +11,6 @@ import java.security.NoSuchAlgorithmException; public class MedtronicCnlSession { private static final String HMAC_PADDING = "A4BD6CED9A42602564F413123"; - private byte[] HMAC; private byte[] key; private String stickSerial; @@ -25,10 +24,6 @@ public class MedtronicCnlSession { private int bayerSequenceNumber = 1; private int medtronicSequenceNumber = 1; - /*public byte[] getHMAC() { - return HMAC; - }*/ - public byte[] getHMAC() throws NoSuchAlgorithmException { String shortSerial = this.stickSerial.replaceAll("\\d+-", ""); byte[] message = (shortSerial + HMAC_PADDING).getBytes(); @@ -106,10 +101,6 @@ public class MedtronicCnlSession { this.radioRSSI = radioRSSI; } - public void setHMAC(byte[] hmac) { - this.HMAC = hmac; - } - public void setKey(byte[] key) { this.key = key; } diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkBinaryRequestMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkBinaryRequestMessage.java index c56ef02..96e72ed 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkBinaryRequestMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkBinaryRequestMessage.java @@ -15,8 +15,6 @@ import info.nightscout.android.medtronic.exception.ChecksumException; public abstract class ContourNextLinkBinaryRequestMessage<T> extends ContourNextLinkRequestMessage<T> { private final static int ENVELOPE_SIZE = 33; - //protected ByteBuffer mBayerEnvelope; - //protected ByteBuffer mBayerPayload; protected CommandType mCommandType = CommandType.NO_TYPE; protected MedtronicCnlSession mPumpSession; @@ -27,6 +25,8 @@ public abstract class ContourNextLinkBinaryRequestMessage<T> extends ContourNext this.mCommandType = commandType; // Validate checksum + // FIXME - this is not needed. Because we're setting the checksum in buildPayload, we know it's + // going to be okay. However, this check does need to be done when reading a message. byte messageChecksum = this.mPayload.get(32); byte calculatedChecksum = (byte) (MessageUtils.oneByteSum(this.mPayload.array()) - messageChecksum); diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkResponseMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkResponseMessage.java index dda70d1..d20a561 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkResponseMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkResponseMessage.java @@ -17,11 +17,11 @@ public abstract class ContourNextLinkResponseMessage extends ContourNextLinkMess } - public void checkControlMessage(ASCII controlCharacter) throws IOException, TimeoutException, UnexpectedMessageException { + public void checkControlMessage(ASCII controlCharacter) throws UnexpectedMessageException { checkControlMessage(mPayload.array(), controlCharacter); } - public void checkControlMessage(byte[] msg, ASCII controlCharacter) throws IOException, TimeoutException, UnexpectedMessageException { + public void checkControlMessage(byte[] msg, ASCII controlCharacter) throws UnexpectedMessageException { if (msg.length != 1 || !controlCharacter.equals(msg[0])) { throw new UnexpectedMessageException(String.format(Locale.getDefault(), "Expected to get control character '%d' Got '%d'.", (int) controlCharacter.getValue(), (int) msg[0])); diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicRequestMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicRequestMessage.java index de69316..9963dd3 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicRequestMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicRequestMessage.java @@ -24,36 +24,6 @@ public abstract class MedtronicRequestMessage<T> extends ContourNextLinkBinaryRe super(commandType, pumpSession, buildPayload(commandAction, payload)); } - public enum SendMessageType { - BEGIN_EHSM_SESSION(0x412), - TIME_REQUEST(0x0403), - READ_PUMP_STATUS_REQUEST(0x0112), - READ_BASAL_PATTERN_REQUEST(0x0112), - END_EHSM_SESSION(0x412), - - READ_HISTORY_INFO_MESSAGE(0x030C), - READ_HISTORY_MESSAGE(0x0304), - READ_TRACE_HISTORY_MESSAGE(0x0302), - - INITIATE_MULTIPACKET_TRANSFER_COMMAND(0xFF00), - - NO_TYPE(0x0); - - private short value; - - SendMessageType(int messageType) { - value = (short) messageType; - } - - public short getValue() { - return value; - } - - public boolean equals(short value) { - return this.value == value; - } - } - /** * MedtronicMessage: * +---------------+-------------------+----------------------+--------------------+ @@ -98,18 +68,4 @@ public abstract class MedtronicRequestMessage<T> extends ContourNextLinkBinaryRe super.sendMessage(mDevice); mPumpSession.incrMedtronicSequenceNumber(); } - - protected static byte sendSequenceNumber(SendMessageType sendMessageType) { - switch (sendMessageType) { - case BEGIN_EHSM_SESSION: - return (byte) 0x80; - case TIME_REQUEST: - return (byte) 0x02; - case READ_PUMP_STATUS_REQUEST: - return (byte) 0x03; - default: - return 0x00; - } - } - } diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicSendMessageRequestMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicSendMessageRequestMessage.java index 7905382..50aee6a 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicSendMessageRequestMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicSendMessageRequestMessage.java @@ -48,9 +48,9 @@ public abstract class MedtronicSendMessageRequestMessage<T> extends MedtronicRe * +-----------------+------------------------------+--------------+-------------------+--------------------------------+ * <p/> * MedtronicSendMessage (decrypted payload): - * +-------------------------+----------------------+----------------------+--------------------+ + * +-------------------------+--------------------------+----------------------+--------------------+ * | byte sendSequenceNumber | BE short sendMessageType | byte[] Payload bytes | BE short CCITT CRC | - * +-------------------------+----------------------+----------------------+--------------------+ + * +-------------------------+--------------------------+----------------------+--------------------+ */ protected static byte[] buildPayload(SendMessageType sendMessageType, MedtronicCnlSession pumpSession, byte[] payload) throws EncryptionException { byte payloadLength = (byte) (payload == null ? 0 : payload.length); @@ -78,6 +78,7 @@ public abstract class MedtronicSendMessageRequestMessage<T> extends MedtronicRe return payloadBuffer.array(); } + // TODO - This should be dynamically incremented in the Session object protected static byte sendSequenceNumber(SendMessageType sendMessageType) { switch (sendMessageType) { case BEGIN_EHSM_SESSION: diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/PumpBasalPatternResponseMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/PumpBasalPatternResponseMessage.java index e3f96eb..7bc6cf9 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/PumpBasalPatternResponseMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/PumpBasalPatternResponseMessage.java @@ -5,9 +5,11 @@ import android.util.Log; import java.nio.ByteBuffer; import java.nio.ByteOrder; +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.model.medtronicNg.PumpInfo; import info.nightscout.android.utils.HexDump; /** @@ -29,13 +31,18 @@ public class PumpBasalPatternResponseMessage extends MedtronicSendMessageRespons } */ - ByteBuffer basalRatesBuffer = ByteBuffer.allocate(payload.length); - basalRatesBuffer.order(ByteOrder.BIG_ENDIAN); - basalRatesBuffer.put(this.encode()); - String responseString = HexDump.dumpHexString(basalRatesBuffer.array()); - Log.d(TAG, "PumpStatus: " + responseString); + byte bufferSize = (byte) (this.encode()[0x38] - 2); // TODO - getting the size should be part of the superclass. + ByteBuffer basalBuffer = ByteBuffer.allocate(bufferSize); + basalBuffer.order(ByteOrder.BIG_ENDIAN); + basalBuffer.put(this.encode(), 0x39, bufferSize); + if (BuildConfig.DEBUG) { + String outputString = HexDump.dumpHexString(basalBuffer.array()); + Log.d(TAG, "BASAL PAYLOAD: " + outputString); + } } + public void updateBasalPatterns(PumpInfo pumpInfo) { + } } 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 39403a8..163f427 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 @@ -21,8 +21,8 @@ public class PumpStatusRequestMessage extends MedtronicSendMessageRequestMessage super(SendMessageType.READ_PUMP_STATUS_REQUEST, pumpSession, null); } + // TODO - this needs refactoring public PumpStatusResponseMessage send(UsbHidDriver mDevice, int millis) throws IOException, TimeoutException, ChecksumException, EncryptionException, UnexpectedMessageException { - sendMessage(mDevice); if (millis > 0) { try { diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusResponseMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusResponseMessage.java index 68c60b7..f97a739 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusResponseMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusResponseMessage.java @@ -59,9 +59,10 @@ public class PumpStatusResponseMessage extends MedtronicSendMessageResponseMessa throw new UnexpectedMessageException("Invalid message received for updatePumpStatus"); } - ByteBuffer statusBuffer = ByteBuffer.allocate(96); + byte bufferSize = (byte) (this.encode()[0x38] - 2); // TODO - getting the size should be part of the superclass. + ByteBuffer statusBuffer = ByteBuffer.allocate(bufferSize); statusBuffer.order(ByteOrder.BIG_ENDIAN); - statusBuffer.put(this.encode(), 0x39, 96); + statusBuffer.put(this.encode(), 0x39, bufferSize); if (BuildConfig.DEBUG) { String outputString = HexDump.dumpHexString(statusBuffer.array()); @@ -184,6 +185,7 @@ public class PumpStatusResponseMessage extends MedtronicSendMessageResponseMessa // CGM SGV pumpRecord.setSgv(sgv); + pumpRecord.setSgvDate(new Date(sgvDate.getTime() - pumpRecord.getPumpTimeOffset())); // SGV Date pumpRecord.setCgmTrend(cgmTrend); 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 f76773d..3d9e0eb 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 @@ -208,7 +208,6 @@ public class MedtronicCnlIntentService extends IntentService { if (activePump == null) { activePump = realm.createObject(PumpInfo.class, pumpMAC); - //activePump.setPumpMac(pumpMAC); } activePump.updateLastQueryTS(); diff --git a/app/src/main/java/info/nightscout/android/model/medtronicNg/PumpInfo.java b/app/src/main/java/info/nightscout/android/model/medtronicNg/PumpInfo.java index f7d864d..456c6f1 100644 --- a/app/src/main/java/info/nightscout/android/model/medtronicNg/PumpInfo.java +++ b/app/src/main/java/info/nightscout/android/model/medtronicNg/PumpInfo.java @@ -1,9 +1,9 @@ package info.nightscout.android.model.medtronicNg; +import android.util.Log; + import io.realm.RealmList; import io.realm.RealmObject; -import io.realm.Sort; -import io.realm.annotations.Ignore; import io.realm.annotations.PrimaryKey; /** @@ -17,6 +17,7 @@ public class PumpInfo extends RealmObject { private long lastQueryTS = 0; private RealmList<ContourNextLinkInfo> associatedCnls; private RealmList<PumpStatusEvent> pumpHistory = new RealmList<>(); + private RealmList<BasalSchedule> basalSchedules; public long getPumpMac() { return pumpMac; @@ -69,4 +70,30 @@ public class PumpInfo extends RealmObject { public void updateLastQueryTS() { lastQueryTS = System.currentTimeMillis(); } + + public RealmList<BasalSchedule> getBasalSchedules() { + return basalSchedules; + } + + public void setBasalSchedules(RealmList<BasalSchedule> basalSchedules) { + this.basalSchedules = basalSchedules; + } + + public boolean checkBasalRatesMatch(PumpStatusEvent pumpRecord) { + byte activeBasal = pumpRecord.getActiveBasalPattern(); + + BasalSchedule schedule = basalSchedules + .where() + .equalTo("scheduleNumber", activeBasal) + .findFirst(); + + if(schedule == null) { + Log.d("Schedule Check", "Didn't find a matching schedule for " + activeBasal); + return false; + } else { + Log.d("Schedule Check", "Found a schedule for " + activeBasal + " with name " + schedule.getName()); + return true; + } + } + } diff --git a/app/src/main/java/info/nightscout/android/upload/nightscout/NightScoutUpload.java b/app/src/main/java/info/nightscout/android/upload/nightscout/NightScoutUpload.java index 55a2120..790bf02 100644 --- a/app/src/main/java/info/nightscout/android/upload/nightscout/NightScoutUpload.java +++ b/app/src/main/java/info/nightscout/android/upload/nightscout/NightScoutUpload.java @@ -15,6 +15,7 @@ import info.nightscout.android.model.medtronicNg.PumpStatusEvent; import info.nightscout.android.upload.nightscout.serializer.EntriesSerializer; import android.support.annotation.NonNull; + import info.nightscout.api.UploadApi; import info.nightscout.api.GlucoseEndpoints; import info.nightscout.api.BolusEndpoints.BolusEntry; @@ -27,19 +28,19 @@ import info.nightscout.api.DeviceEndpoints.PumpStatus; import info.nightscout.api.DeviceEndpoints.PumpInfo; import info.nightscout.api.DeviceEndpoints.DeviceStatus; -public class NightScoutUpload { +class NightScoutUpload { private static final String TAG = NightscoutUploadIntentService.class.getSimpleName(); private static final SimpleDateFormat ISO8601_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault()); - public NightScoutUpload () { + NightScoutUpload() { } - public Boolean doRESTUpload(String url, - String secret, - int uploaderBatteryLevel, - List<PumpStatusEvent> records) { + Boolean doRESTUpload(String url, + String secret, + int uploaderBatteryLevel, + List<PumpStatusEvent> records) { Boolean success = false; try { success = isUploaded(records, url, secret, uploaderBatteryLevel); @@ -51,15 +52,15 @@ public class NightScoutUpload { private boolean isUploaded(List<PumpStatusEvent> records, - String baseURL, - String secret, - int uploaderBatteryLevel) throws Exception { + String baseURL, + String secret, + int uploaderBatteryLevel) throws Exception { UploadApi uploadApi = new UploadApi(baseURL, formToken(secret)); boolean eventsUploaded = uploadEvents(uploadApi.getGlucoseEndpoints(), - uploadApi.getBolusApi(), - records ); + uploadApi.getBolusApi(), + records); boolean deviceStatusUploaded = uploadDeviceStatus(uploadApi.getDeviceEndpoints(), uploaderBatteryLevel, records); @@ -69,7 +70,7 @@ public class NightScoutUpload { private boolean uploadEvents(GlucoseEndpoints glucoseEndpoints, BolusEndpoints bolusEndpoints, - List<PumpStatusEvent> records ) throws Exception { + List<PumpStatusEvent> records) throws Exception { List<GlucoseEntry> glucoseEntries = new ArrayList<>(); @@ -77,35 +78,40 @@ public class NightScoutUpload { for (PumpStatusEvent record : records) { - GlucoseEntry glucoseEntry = new GlucoseEntry(); + GlucoseEntry glucoseEntry = new GlucoseEntry(); glucoseEntry.setType("sgv"); glucoseEntry.setDirection(EntriesSerializer.getDirectionStringStatus(record.getCgmTrend())); glucoseEntry.setDevice(record.getDeviceName()); glucoseEntry.setSgv(record.getSgv()); - glucoseEntry.setDate(record.getEventDate().getTime()); - glucoseEntry.setDateString(record.getEventDate().toString()); + glucoseEntry.setDate(record.getSgvDate().getTime()); + glucoseEntry.setDateString(record.getSgvDate().toString()); glucoseEntries.add(glucoseEntry); - BolusEntry bolusEntry = new BolusEntry(); + if (record.getBolusWizardBGL() != 0) { + BolusEntry bolusEntry = new BolusEntry(); - bolusEntry.setType("mbg"); - bolusEntry.setDate(record.getEventDate().getTime()); - bolusEntry.setDateString(record.getEventDate().toString()); - bolusEntry.setDevice(record.getDeviceName()); - bolusEntry.setMbg(record.getBolusWizardBGL()); + bolusEntry.setType("mbg"); + bolusEntry.setDate(record.getEventDate().getTime()); + bolusEntry.setDateString(record.getEventDate().toString()); + bolusEntry.setDevice(record.getDeviceName()); + bolusEntry.setMbg(record.getBolusWizardBGL()); - bolusEntries.add(bolusEntry); + bolusEntries.add(bolusEntry); + } } - glucoseEndpoints.sendEntries(glucoseEntries).execute(); - bolusEndpoints.sendEntries(bolusEntries).execute(); - + if (glucoseEntries.size() > 0) { + glucoseEndpoints.sendEntries(glucoseEntries).execute(); + } + if (bolusEntries.size() > 0) { + bolusEndpoints.sendEntries(bolusEntries).execute(); + } - return true; + return true; } private boolean uploadDeviceStatus(DeviceEndpoints deviceEndpoints, @@ -134,7 +140,7 @@ public class NightScoutUpload { iob, battery, pumpstatus - ); + ); DeviceStatus deviceStatus = new DeviceStatus( uploaderBatteryLevel, @@ -146,14 +152,14 @@ public class NightScoutUpload { deviceEntries.add(deviceStatus); } - for (DeviceStatus status: deviceEntries) { + for (DeviceStatus status : deviceEntries) { deviceEndpoints.sendDeviceStatus(status).execute(); } - return true ; + return true; } - @NonNull + @NonNull private String formToken(String secret) throws NoSuchAlgorithmException, UnsupportedEncodingException { MessageDigest digest = MessageDigest.getInstance("SHA-1"); byte[] bytes = secret.getBytes("UTF-8"); diff --git a/app/src/main/java/info/nightscout/api/BolusEndpoints.java b/app/src/main/java/info/nightscout/api/BolusEndpoints.java index 67d2291..a1c2a56 100644 --- a/app/src/main/java/info/nightscout/api/BolusEndpoints.java +++ b/app/src/main/java/info/nightscout/api/BolusEndpoints.java @@ -1,7 +1,5 @@ package info.nightscout.api; -import java.math.BigDecimal; -import java.util.Date; import java.util.List; import okhttp3.ResponseBody; @@ -15,8 +13,8 @@ public interface BolusEndpoints { class BolusEntry { String type; String dateString; - float date; - float mbg; + long date; + int mbg; String device; public BolusEntry() { } @@ -37,19 +35,19 @@ public interface BolusEndpoints { this.dateString = dateString; } - public float getDate() { + public long getDate() { return date; } - public void setDate(float date) { + public void setDate(long date) { this.date = date; } - public float getMbg() { + public int getMbg() { return mbg; } - public void setMbg(float mbg) { + public void setMbg(int mbg) { this.mbg = mbg; } diff --git a/app/src/main/java/info/nightscout/api/GlucoseEndpoints.java b/app/src/main/java/info/nightscout/api/GlucoseEndpoints.java index 07c1c10..d34c5e7 100644 --- a/app/src/main/java/info/nightscout/api/GlucoseEndpoints.java +++ b/app/src/main/java/info/nightscout/api/GlucoseEndpoints.java @@ -1,16 +1,10 @@ package info.nightscout.api; - - -import java.lang.reflect.Array; -import java.math.BigDecimal; -import java.util.Date; import java.util.List; import okhttp3.ResponseBody; import retrofit2.Call; import retrofit2.http.Body; -import retrofit2.http.GET; import retrofit2.http.Headers; import retrofit2.http.POST; @@ -20,8 +14,8 @@ public interface GlucoseEndpoints { String type; String dateString; - float date; - float sgv; + long date; + int sgv; String direction; String device; @@ -41,19 +35,19 @@ public interface GlucoseEndpoints { this.dateString = dateString; } - public float getDate() { + public long getDate() { return date; } - public void setDate(float date) { + public void setDate(long date) { this.date = date; } - public float getSgv() { + public int getSgv() { return sgv; } - public void setSgv(float sgv) { + public void setSgv(int sgv) { this.sgv = sgv; } -- GitLab