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 9c7952f3803a8a17437d51345a26be47dec1d092..a86820f7b72797aa1a2f7c1c19dc5fb6034db430 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 c56ef020740bc1ee0f9ea71e77e9807814e08cb0..96e72ed8559b0dfbb6d472cc490b7db683dd7a06 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 dda70d1050ae9462942d13098a248a7552a3354b..d20a5613e3345ccdc13a7499852074372490b249 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 de69316e245171b9b0f3047c4c82a0b5326444b6..9963dd32e133b884e589777d9d2705813df11c5f 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 79053820b388eaea7223d30c7d6e3e94f2959305..50aee6a666fbba3edb5733bf3e629b17bce98cfe 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 e3f96eb6984e98e341f8cbab06f4d8d196d90ffc..7bc6cf93671f90167dc59210188bc8c96613d621 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 39403a8f995610813fc4dcb1c7b22b4a69f28d5d..163f42775f2161bcf92ae7e743c2a0435ba99165 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 68c60b7707bc3147d341a7b7e4849477f681e031..f97a73934acf42bcb5ffffb6f778a440af158563 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 f76773d627f11b38b4ebb8ff136dde7850abb112..3d9e0eb7cea5e6e3fbdf9b866e6a1ad59b32ad8e 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 f7d864da473096c2cabf1f20e4b81930efbb0593..456c6f139830618d580de258f78ac517d3b9258e 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 55a2120df7189c2faa87076382db1906fdd93f91..790bf02e01b765e925623dceee1bef26d5c3e5c5 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 67d2291198532976c64d25eae16718087cb28f43..a1c2a56e35eacaa534b5e5ede7de4fca577672c8 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 07c1c10a8c2e60705ba348d7c9a0758216f74b1a..d34c5e7abdae5efadc346bc560eb54aee252dacb 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; }