From 6a73937b2ae0971aaa3b933ded3ad062e00c897d Mon Sep 17 00:00:00 2001 From: Andy Rozman Date: Sun, 12 Aug 2018 16:30:32 +0100 Subject: [PATCH] - merges of bug fixes from RileyLinkAAPS --- .../RileyLinkCommunicationManager.java | 12 +- .../PumpCommon/hw/rileylink/ble/RFSpy.java | 4 + .../rileylink/defs/RileyLinkTargetDevice.java | 1 - .../rileylink/service/RileyLinkService.java | 3 +- .../plugins/PumpCommon/utils/ByteUtil.java | 104 +++++ .../plugins/PumpCommon/utils/StringUtil.java | 15 + .../comm/MedtronicCommunicationManager.java | 107 +++++- .../{message => }/MedtronicConverter.java | 15 +- .../MedtronicHistoryDecoder.java | 10 +- .../MedtronicHistoryEntry.java | 69 +++- .../MedtronicHistoryEntryInterface.java | 18 + .../{data => history}/RawHistoryPage.java | 2 +- .../RecordDecodeStatus.java | 2 +- .../comm/history/cgms/CGMSHistoryEntry.java | 72 ++++ .../history/cgms/CGMSHistoryEntryType.java | 167 ++++++++ .../cgms/MedtronicCGMSHistoryDecoder.java | 361 ++++++++++++++++++ .../pump}/MedtronicPumpHistoryDecoder.java | 147 +++---- .../pump}/PumpHistoryEntry.java | 37 +- .../pump}/PumpHistoryEntryType.java | 22 +- .../PumpMedtronic/data/dto/BasalProfile.java | 58 +-- .../PumpMedtronic/data/dto/BolusDTO.java | 6 + .../data/dto/PumpSettingDTO.java | 6 + .../PumpMedtronic/data/dto/TempBasalPair.java | 30 +- .../defs/MedtronicDeviceType.java | 7 +- .../driver/MedtronicPumpStatus.java | 2 - .../PumpMedtronic/util/MedtronicConst.java | 2 +- .../PumpMedtronic/util/MedtronicUtil.java | 34 +- 27 files changed, 1124 insertions(+), 189 deletions(-) rename app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/{message => }/MedtronicConverter.java (96%) rename app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/{data/history2 => history}/MedtronicHistoryDecoder.java (94%) rename app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/{data/history2 => history}/MedtronicHistoryEntry.java (73%) create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/MedtronicHistoryEntryInterface.java rename app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/{data => history}/RawHistoryPage.java (96%) rename app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/{data/history2 => history}/RecordDecodeStatus.java (94%) create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/cgms/CGMSHistoryEntry.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/cgms/CGMSHistoryEntryType.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.java rename app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/{data/history2 => history/pump}/MedtronicPumpHistoryDecoder.java (88%) rename app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/{data/history2 => history/pump}/PumpHistoryEntry.java (71%) rename app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/{data/history2 => history/pump}/PumpHistoryEntryType.java (92%) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/hw/rileylink/RileyLinkCommunicationManager.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/hw/rileylink/RileyLinkCommunicationManager.java index 101bdee066..11f6a85595 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/hw/rileylink/RileyLinkCommunicationManager.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/hw/rileylink/RileyLinkCommunicationManager.java @@ -31,7 +31,7 @@ import info.nightscout.utils.SP; public abstract class RileyLinkCommunicationManager { private static final Logger LOG = LoggerFactory.getLogger(RileyLinkCommunicationManager.class); - + private static final int SCAN_TIMEOUT = 1500; protected final RFSpy rfspy; protected final Context context; protected int receiverDeviceAwakeForMinutes = 1; // override this in constructor of specific implementation @@ -41,16 +41,13 @@ public abstract class RileyLinkCommunicationManager { protected RileyLinkServiceData rileyLinkServiceData; protected RileyLinkTargetFrequency targetFrequency; private double[] scanFrequencies; + // internal flag private boolean showPumpMessages = true; private int timeoutCount = 0; private long nextWakeUpRequired = 0L; - // protected PumpMessage sendAndListen(RLMessage msg) { - // return sendAndListen(msg, 4000); // 2000 - // } - public RileyLinkCommunicationManager(Context context, RFSpy rfspy, RileyLinkTargetFrequency targetFrequency) { this.context = context; this.rfspy = rfspy; @@ -95,7 +92,6 @@ public abstract class RileyLinkCommunicationManager { // RileyLinkUtil.sendBroadcastMessage(RileyLinkConst.IPC.MSG_PUMP_quickTune); } } - } if (showPumpMessages) { @@ -212,7 +208,7 @@ public abstract class RileyLinkCommunicationManager { byte[] pumpMsgContent = createPumpMessageContent(RLMessageType.ReadSimpleData); RFSpyResponse resp = rfspy.transmitThenReceive(new RadioPacket(pumpMsgContent), (byte)0, (byte)0, - (byte)0, (byte)0, 1500, (byte)0); + (byte)0, (byte)0, SCAN_TIMEOUT, (byte)0); if (resp.wasTimeout()) { LOG.error("scanForPump: Failed to find pump at frequency {}", frequencies[i]); } else if (resp.looksLikeRadioPacket()) { @@ -266,7 +262,7 @@ public abstract class RileyLinkCommunicationManager { // RLMessage msg = makeRLMessage(RLMessageType.ReadSimpleData); byte[] pumpMsgContent = createPumpMessageContent(RLMessageType.ReadSimpleData); RadioPacket pkt = new RadioPacket(pumpMsgContent); - RFSpyResponse resp = rfspy.transmitThenReceive(pkt, (byte)0, (byte)0, (byte)0, (byte)0, 1500, (byte)0); + RFSpyResponse resp = rfspy.transmitThenReceive(pkt, (byte)0, (byte)0, (byte)0, (byte)0, SCAN_TIMEOUT, (byte)0); if (resp.wasTimeout()) { LOG.warn("tune_tryFrequency: no pump response at frequency {}", freqMHz); } else if (resp.looksLikeRadioPacket()) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/hw/rileylink/ble/RFSpy.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/hw/rileylink/ble/RFSpy.java index 88d82f83b1..5d913e70b4 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/hw/rileylink/ble/RFSpy.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/hw/rileylink/ble/RFSpy.java @@ -18,6 +18,7 @@ import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RXFil import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkTargetFrequency; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.operations.BLECommOperationResult; import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil; +import info.nightscout.androidaps.plugins.PumpCommon.utils.HexDump; import info.nightscout.androidaps.plugins.PumpCommon.utils.StringUtil; import info.nightscout.androidaps.plugins.PumpCommon.utils.ThreadUtil; @@ -107,6 +108,9 @@ public class RFSpy { // prepend length, and send it. byte[] prepended = ByteUtil.concat(new byte[] { (byte)(bytes.length) }, bytes); + + //LOG.debug("writeToData (command={},raw={})", command.name(), HexDump.toHexStringDisplayable(prepended)); + BLECommOperationResult writeCheck = rileyLinkBle.writeCharacteristic_blocking(radioServiceUUID, radioDataUUID, prepended); if (writeCheck.resultCode != BLECommOperationResult.RESULT_SUCCESS) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/hw/rileylink/defs/RileyLinkTargetDevice.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/hw/rileylink/defs/RileyLinkTargetDevice.java index 9dffd2d2c1..5b149370fb 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/hw/rileylink/defs/RileyLinkTargetDevice.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/hw/rileylink/defs/RileyLinkTargetDevice.java @@ -17,7 +17,6 @@ public enum RileyLinkTargetDevice { RileyLinkTargetDevice(int resourceId, boolean tuneUpEnabled) { this.resourceId = resourceId; - this.tuneUpEnabled = tuneUpEnabled; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/hw/rileylink/service/RileyLinkService.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/hw/rileylink/service/RileyLinkService.java index dd4ed5b228..05cbee89ee 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/hw/rileylink/service/RileyLinkService.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/hw/rileylink/service/RileyLinkService.java @@ -32,8 +32,6 @@ import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks. import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.ServiceTaskExecutor; import info.nightscout.utils.SP; -//import static info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.; - /** * Created by andy on 5/6/18. * Split from original file and renamed. @@ -61,6 +59,7 @@ public abstract class RileyLinkService extends Service { this.context = context; RileyLinkUtil.setContext(this.context); determineRileyLinkTargetFrequency(); + RileyLinkUtil.setRileyLinkService(this); RileyLinkUtil.setRileyLinkTargetFrequency(rileyLinkTargetFrequency); initRileyLinkServiceData(); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/utils/ByteUtil.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/utils/ByteUtil.java index 8dbf7c3e79..d3cdc9a46f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/utils/ByteUtil.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/utils/ByteUtil.java @@ -72,6 +72,14 @@ public class ByteUtil { } + public static byte[] substring(byte[] a, int start) { + int len = a.length - start; + byte[] rval = new byte[len]; + System.arraycopy(a, start, rval, 0, len); + return rval; + } + + public static String shortHexString(byte[] ra) { String rval = ""; if (ra == null) { @@ -236,6 +244,102 @@ public class ByteUtil { return k; } + + /** + * Gets the correct hex value. + * + * @param inp the inp + * @return the correct hex value + */ + public static String getCorrectHexValue(int inp) { + String hx = Integer.toHexString((char)inp); + + if (hx.length() == 0) + return "00"; + else if (hx.length() == 1) + return "0" + hx; + else if (hx.length() == 2) + return hx; + else if (hx.length() == 4) + return hx.substring(2); + else { + System.out.println("Hex Error: " + inp); + } + + return null; + } + + + public static byte[] getByteArrayFromList(List list) { + byte[] out = new byte[list.size()]; + + for (int i = 0; i < list.size(); i++) { + out[i] = list.get(i); + } + + return out; + } + + + public static String getHex(byte abyte0[]) { + return abyte0 != null ? getHex(abyte0, abyte0.length) : null; + } + + + public static String getHex(byte abyte0[], int i) { + StringBuffer stringbuffer = new StringBuffer(); + if (abyte0 != null) { + i = Math.min(i, abyte0.length); + for (int j = 0; j < i; j++) { + stringbuffer.append(getHex(abyte0[j])); + if (j < i - 1) { + stringbuffer.append(" "); + } + } + + } + return new String(stringbuffer); + } + + + public static String getHex(byte byte0) { + String s = byte0 != -1 ? "0x" : ""; + return s + getHexCompact(byte0); + } + + + public static String getHexCompact(byte byte0) { + int i = byte0 != -1 ? convertUnsignedByteToInt(byte0) : (int)byte0; + return getHexCompact(i); + } + + + public static int convertUnsignedByteToInt(byte data) { + return data & 0xff; + } + + + // public String getHexCompact(int i) { + // long l = i != -1 ? convertUnsignedIntToLong(i) : i; + // return getHexCompact(l); + // } + + public static String getHexCompact(int l) { + String s = Long.toHexString(l).toUpperCase(); + String s1 = isOdd(s.length()) ? "0" : ""; + return l != -1L ? s1 + s : "-1"; + } + + + public static boolean isEven(int i) { + return i % 2 == 0; + } + + + public static boolean isOdd(int i) { + return !isEven(i); + } + public enum BitConversion { LITTLE_ENDIAN, // 20 0 0 0 = reverse BIG_ENDIAN // 0 0 0 20 = normal - java diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/utils/StringUtil.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/utils/StringUtil.java index 28a4b8b32b..c1a5e376d1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/utils/StringUtil.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCommon/utils/StringUtil.java @@ -80,4 +80,19 @@ public class StringUtil { public static String toDateTimeString(LocalDateTime localDateTime) { return localDateTime.toString("dd.MM.yyyy HH:mm:ss"); } + + + public static String getStringInLength(String value, int length) { + StringBuilder val = new StringBuilder(value); + + if (val.length() > length) { + return val.substring(0, length); + } + + for (int i = val.length(); i < length; i++) { + val.append(" "); + } + + return val.toString(); + } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/MedtronicCommunicationManager.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/MedtronicCommunicationManager.java index 9fc2474802..4477647cc1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/MedtronicCommunicationManager.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/MedtronicCommunicationManager.java @@ -19,13 +19,12 @@ import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.Riley import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil; import info.nightscout.androidaps.plugins.PumpCommon.utils.HexDump; import info.nightscout.androidaps.plugins.PumpMedtronic.comm.data.Page; -import info.nightscout.androidaps.plugins.PumpMedtronic.comm.data.RawHistoryPage; import info.nightscout.androidaps.plugins.PumpMedtronic.comm.data.history.Record; +import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.RawHistoryPage; import info.nightscout.androidaps.plugins.PumpMedtronic.comm.message.ButtonPressCarelinkMessageBody; import info.nightscout.androidaps.plugins.PumpMedtronic.comm.message.CarelinkLongMessageBody; import info.nightscout.androidaps.plugins.PumpMedtronic.comm.message.CarelinkShortMessageBody; import info.nightscout.androidaps.plugins.PumpMedtronic.comm.message.GetHistoryPageCarelinkMessageBody; -import info.nightscout.androidaps.plugins.PumpMedtronic.comm.message.MedtronicConverter; import info.nightscout.androidaps.plugins.PumpMedtronic.comm.message.MessageBody; import info.nightscout.androidaps.plugins.PumpMedtronic.comm.message.PacketType; import info.nightscout.androidaps.plugins.PumpMedtronic.comm.message.PumpAckMessageBody; @@ -592,14 +591,111 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager } - public BasalProfile getBasalProfile() { + public BasalProfile getBasalProfile_Old() { - Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetBasalProfileSTD); + Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetBasalProfileA); return responseObject == null ? null : (BasalProfile)responseObject; } + public BasalProfile getBasalProfile() { + + // wakeUp + wakeUp(receiverDeviceAwakeForMinutes, false); + + MedtronicUtil.setPumpDeviceState(PumpDeviceState.Active); + + MedtronicCommandType commandType = MedtronicCommandType.GetBasalProfileSTD; + + for (int retries = 0; retries <= MAX_COMMAND_RETRIES; retries++) { + + // create message + PumpMessage msg; + + // if (bodyData == null) + msg = makePumpMessage(commandType); + + // send and wait for response + PumpMessage response = sendAndListen(msg, DEFAULT_TIMEOUT + (DEFAULT_TIMEOUT * retries)); + + // LOG.debug("1st Response: " + HexDump.toHexStringDisplayable(response.getRawContent())); + // LOG.debug("1st Response: " + HexDump.toHexStringDisplayable(response.getMessageBody().getTxData())); + + String check = checkResponseContent(response, commandType.commandDescription, commandType.expectedLength); + + byte[] data = null; + + int runs = 1; + + if (check == null) { + + data = response.getRawContent(); + + PumpMessage ackMsg = makePumpMessage(MedtronicCommandType.CommandACK, new PumpAckMessageBody()); + + while (checkIfWeHaveMoreData(commandType, response, data)) { + + runs++; + + PumpMessage response2 = sendAndListen(ackMsg, DEFAULT_TIMEOUT + (DEFAULT_TIMEOUT * retries)); + + // LOG.debug("{} Response: {}", runs, HexDump.toHexStringDisplayable(response2.getRawContent())); + // LOG.debug("{} Response: {}", runs, + // HexDump.toHexStringDisplayable(response2.getMessageBody().getTxData())); + + String check2 = checkResponseContent(response2, commandType.commandDescription, + commandType.expectedLength); + + if (check2 == null) { + + data = ByteUtil.concat(data, ByteUtil.substring(response2.getMessageBody().getTxData(), 1)); + + } else { + this.errorMessage = check; + } + } + + } else { + errorMessage = check; + } + + Object dataResponse = medtronicConverter.convertResponse(commandType, data); + + LOG.debug("Converted response for {} is {}.", commandType.name(), dataResponse); + + MedtronicUtil.setPumpDeviceState(PumpDeviceState.Sleeping); + + return (BasalProfile)dataResponse; + } + + return null; + + } + + + private boolean checkIfWeHaveMoreData(MedtronicCommandType commandType, PumpMessage response, byte[] data) { + + if (commandType == MedtronicCommandType.GetBasalProfileSTD || // + commandType == MedtronicCommandType.GetBasalProfileA || // + commandType == MedtronicCommandType.GetBasalProfileB) { + byte[] responseRaw = response.getRawContent(); + + int last = responseRaw.length - 1; + + LOG.debug("Length: " + data.length); + + if (data.length >= BasalProfile.MAX_RAW_DATA_SIZE) { + return false; + } + + return !(responseRaw[last] == 0x00 && responseRaw[last - 1] == 0x00 && responseRaw[last - 2] == 0x00); + } + + return false; + } + + public LocalDateTime getPumpTime() { Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.RealTimeClock); @@ -638,7 +734,7 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager LOG.debug("Set Bolus: Body - {}", HexDump.toHexStringDisplayable(body)); PumpMessage msg = makePumpMessage(MedtronicCommandType.SetBolus, // - new CarelinkLongMessageBody(ByteUtil.concat((byte)body.length, body))); + new CarelinkLongMessageBody(body)); PumpMessage pumpMessage = runCommandWithArgs(msg); @@ -676,7 +772,6 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager } - // FIXME: public BatteryStatusDTO getRemainingBattery() { Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetBatteryStatus); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/message/MedtronicConverter.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/MedtronicConverter.java similarity index 96% rename from app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/message/MedtronicConverter.java rename to app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/MedtronicConverter.java index d297e93619..b777e4e3a5 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/message/MedtronicConverter.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/MedtronicConverter.java @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.PumpMedtronic.comm.message; +package info.nightscout.androidaps.plugins.PumpMedtronic.comm; import java.util.HashMap; import java.util.Map; @@ -56,7 +56,9 @@ public class MedtronicConverter { return decodeBatteryStatus(rawContent); } - case GetBasalProfileSTD: { + case GetBasalProfileSTD: + case GetBasalProfileA: + case GetBasalProfileB: { return new BasalProfile(rawContent); } @@ -114,12 +116,6 @@ public class MedtronicConverter { if ((i != 0) && (time_x == 0)) { break; } - - // String value = i18nControl.getMessage("CFG_BASE_FROM") + "=" + atd.getTimeString() + ", " - // + i18nControl.getMessage("CFG_BASE_AMOUNT") + "=" + vald; - - // writeSetting(key, value, value, PumpConfigurationGroup.Basal); - } return basalProfile; @@ -234,6 +230,7 @@ public class MedtronicConverter { addSettingToMap("CFG_BASE_CLOCK_MODE", rd[getSettingIndexTimeDisplayFormat()] == 0 ? "12h" : "24h", PumpConfigurationGroup.General, map); addSettingToMap("PCFG_INSULIN_CONCENTRATION", "" + (rd[9] != 0 ? 50 : 100), PumpConfigurationGroup.Insulin, map); + LOG.debug("Insulin concentration: " + rd[9]); addSettingToMap("PCFG_BASAL_PROFILES_ENABLED", parseResultEnable(rd[10]), PumpConfigurationGroup.Basal, map); if (rd[10] == 1) { @@ -319,7 +316,7 @@ public class MedtronicConverter { public float getStrokesPerUnit(boolean isBasal) { - return isBasal ? 40.0f : 10.0f; + return isBasal ? 40.0f : pumpModel.getBolusStrokes(); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/data/history2/MedtronicHistoryDecoder.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/MedtronicHistoryDecoder.java similarity index 94% rename from app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/data/history2/MedtronicHistoryDecoder.java rename to app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/MedtronicHistoryDecoder.java index 7c16ca14af..e85ecde1eb 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/data/history2/MedtronicHistoryDecoder.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/MedtronicHistoryDecoder.java @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.PumpMedtronic.comm.data.history2; +package info.nightscout.androidaps.plugins.PumpMedtronic.comm.history; import java.util.ArrayList; import java.util.HashMap; @@ -11,7 +11,6 @@ import org.slf4j.LoggerFactory; import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil; import info.nightscout.androidaps.plugins.PumpCommon.utils.StringUtil; -import info.nightscout.androidaps.plugins.PumpMedtronic.comm.data.RawHistoryPage; import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicUtil; /** @@ -118,7 +117,8 @@ public abstract class MedtronicHistoryDecoder { } - protected void addToStatistics(MedtronicHistoryEntry pumpHistoryEntry, RecordDecodeStatus status, Integer opCode) { + protected void addToStatistics(MedtronicHistoryEntryInterface pumpHistoryEntry, RecordDecodeStatus status, + Integer opCode) { if (!statisticsEnabled) return; @@ -129,8 +129,8 @@ public abstract class MedtronicHistoryDecoder { return; } - if (!mapStatistics.get(status).containsKey(pumpHistoryEntry.getEntryType().name())) { - mapStatistics.get(status).put(pumpHistoryEntry.getEntryType().name(), ""); + if (!mapStatistics.get(status).containsKey(pumpHistoryEntry.getEntryTypeName())) { + mapStatistics.get(status).put(pumpHistoryEntry.getEntryTypeName(), ""); } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/data/history2/MedtronicHistoryEntry.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/MedtronicHistoryEntry.java similarity index 73% rename from app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/data/history2/MedtronicHistoryEntry.java rename to app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/MedtronicHistoryEntry.java index a472daf842..8aec6f638a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/data/history2/MedtronicHistoryEntry.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/MedtronicHistoryEntry.java @@ -1,12 +1,13 @@ -package info.nightscout.androidaps.plugins.PumpMedtronic.comm.data.history2; +package info.nightscout.androidaps.plugins.PumpMedtronic.comm.history; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.joda.time.LocalDateTime; import info.nightscout.androidaps.plugins.PumpCommon.utils.HexDump; import info.nightscout.androidaps.plugins.PumpCommon.utils.StringUtil; -import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.PumpTimeStampedRecord; /** * Application: GGC - GNU Gluco Control @@ -29,7 +30,7 @@ import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.PumpTimeStamped * Author: Andy {andy@atech-software.com} */ -public abstract class MedtronicHistoryEntry { +public abstract class MedtronicHistoryEntry implements MedtronicHistoryEntryInterface { protected List rawData; @@ -40,7 +41,9 @@ public abstract class MedtronicHistoryEntry { protected byte[] body; protected LocalDateTime dateTime; - protected PumpTimeStampedRecord historyEntryDetails; + // protected PumpTimeStampedRecord historyEntryDetails; + + private Map decodedData; public void setData(List listRawData, boolean doNotProcess) { @@ -77,6 +80,32 @@ public abstract class MedtronicHistoryEntry { } + public String getDecodedData() { + if (decodedData == null) + if (isNoDataEntry()) + return "No data"; + else + return ""; + else + return decodedData.toString(); + } + + + public boolean hasData() { + return (decodedData != null) || (isNoDataEntry()) || getEntryTypeName().equals("UnabsorbedInsulin"); + } + + + public boolean isNoDataEntry() { + return (sizes[0] == 2 && sizes[1] == 5 && sizes[2] == 0); + } + + + public boolean showRaw() { + return getEntryTypeName().equals("EndResultTotals"); + } + + public int getHeadLength() { return sizes[0]; } @@ -97,7 +126,9 @@ public abstract class MedtronicHistoryEntry { StringBuilder sb = new StringBuilder(); sb.append(getToStringStart()); - sb.append(", DT: " + ((this.dateTime == null) ? "x" : StringUtil.toDateTimeString(this.dateTime))); + sb.append(", DT: " + + StringUtil.getStringInLength((this.dateTime == null) ? "x" : StringUtil.toDateTimeString(this.dateTime), + 19)); sb.append(", length="); sb.append(getHeadLength()); sb.append(","); @@ -108,6 +139,17 @@ public abstract class MedtronicHistoryEntry { sb.append((getHeadLength() + getDateTimeLength() + getBodyLength())); sb.append(")"); + boolean hasData = hasData(); + + if (hasData) { + sb.append(", data=" + getDecodedData()); + } + + if (hasData && !showRaw()) { + sb.append("]"); + return sb.toString(); + } + if (head != null) { sb.append(", head="); sb.append(HexDump.toHexStringDisplayable(this.head)); @@ -127,10 +169,10 @@ public abstract class MedtronicHistoryEntry { sb.append(HexDump.toHexStringDisplayable(this.rawData)); sb.append("]"); - sb.append(" DT: "); - sb.append(this.dateTime == null ? " - " : this.dateTime.toString("dd.MM.yyyy HH:mm:ss")); + // sb.append(" DT: "); + // sb.append(this.dateTime == null ? " - " : this.dateTime.toString("dd.MM.yyyy HH:mm:ss")); - sb.append(" Ext: "); + // sb.append(" Ext: "); return sb.toString(); } @@ -192,6 +234,14 @@ public abstract class MedtronicHistoryEntry { } + public void addDecodedData(String key, Object value) { + if (decodedData == null) + decodedData = new HashMap<>(); + + decodedData.put(key, value); + } + + public String toShortString() { if (head == null) { return "Unidentified record. "; @@ -200,8 +250,7 @@ public abstract class MedtronicHistoryEntry { } } - // if we extend to CGMS this need to be changed back - public abstract PumpHistoryEntryType getEntryType(); + // public abstract PumpHistoryEntryType getEntryType(); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/MedtronicHistoryEntryInterface.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/MedtronicHistoryEntryInterface.java new file mode 100644 index 0000000000..411808f7d7 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/MedtronicHistoryEntryInterface.java @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.plugins.PumpMedtronic.comm.history; + +import java.util.List; + +/** + * Created by andy on 7/24/18. + */ +public interface MedtronicHistoryEntryInterface { + + String getEntryTypeName(); + + + void setData(List listRawData, boolean doNotProcess); + + + int getDateLength(); + +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/data/RawHistoryPage.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/RawHistoryPage.java similarity index 96% rename from app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/data/RawHistoryPage.java rename to app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/RawHistoryPage.java index e1055c8302..e3cd50f6da 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/data/RawHistoryPage.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/RawHistoryPage.java @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.PumpMedtronic.comm.data; +package info.nightscout.androidaps.plugins.PumpMedtronic.comm.history; import java.util.Arrays; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/data/history2/RecordDecodeStatus.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/RecordDecodeStatus.java similarity index 94% rename from app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/data/history2/RecordDecodeStatus.java rename to app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/RecordDecodeStatus.java index ce67b06e57..9c16c848c9 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/data/history2/RecordDecodeStatus.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/RecordDecodeStatus.java @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.PumpMedtronic.comm.data.history2; +package info.nightscout.androidaps.plugins.PumpMedtronic.comm.history; /** * Application: GGC - GNU Gluco Control diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/cgms/CGMSHistoryEntry.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/cgms/CGMSHistoryEntry.java new file mode 100644 index 0000000000..52847d84b6 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/cgms/CGMSHistoryEntry.java @@ -0,0 +1,72 @@ +package info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.cgms; + +import java.util.List; + +import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil; +import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.MedtronicHistoryEntry; + +/** + * Created by andy on 27.03.15. + */ +public class CGMSHistoryEntry extends MedtronicHistoryEntry { + + private CGMSHistoryEntryType entryType; + private Integer opCode; // this is set only when we have unknown entry... + + + public CGMSHistoryEntryType getEntryType() { + return entryType; + } + + + public void setEntryType(CGMSHistoryEntryType entryType) { + this.entryType = entryType; + + this.sizes[0] = entryType.getHeadLength(); + this.sizes[1] = entryType.getDateLength(); + this.sizes[2] = entryType.getBodyLength(); + } + + + @Override + public String getEntryTypeName() { + return this.entryType.name(); + } + + + public void setData(List listRawData, boolean doNotProcess) { + if (this.entryType.schemaSet) { + super.setData(listRawData, doNotProcess); + } else { + this.rawData = listRawData; + } + } + + + @Override + public int getDateLength() { + return this.entryType.getDateLength(); + } + + + @Override + public int getOpCode() { + if (opCode == null) + return entryType.getOpCode(); + else + return opCode; + } + + + public void setOpCode(Integer opCode) { + this.opCode = opCode; + } + + + @Override + public String getToStringStart() { + return "CGMSHistoryEntry [type=" + entryType.name() + " [" + getOpCode() + ", 0x" + + ByteUtil.getCorrectHexValue(getOpCode()) + "]"; + } + +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/cgms/CGMSHistoryEntryType.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/cgms/CGMSHistoryEntryType.java new file mode 100644 index 0000000000..3c58ff663e --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/cgms/CGMSHistoryEntryType.java @@ -0,0 +1,167 @@ +package info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.cgms; + +import java.util.HashMap; +import java.util.Map; + +/** + * Application: GGC - GNU Gluco Control + * Plug-in: GGC PlugIn Base (base class for all plugins) + *

+ * See AUTHORS for copyright information. + *

+ * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later + * version. + *

+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + *

+ * Filename: PumpHistoryEntryType Description: Pump History Entry Type. + *

+ * Data is from several sources, so in comments there are "versions". Version: v1 - default doc fromc decoding-carelink + * v2 - Andy testing (?) + *

+ * Author: Andy {andy@atech-software.com} + */ + +public enum CGMSHistoryEntryType { + + None(0, "None", 1, 0, 0, DateType.None), // + + DataEnd(0x01, "DataEnd", 1, 0, 0, DateType.None), // + + SensorWeakSignal(0x02, "SensorWeakSignal", 1, 0, 0, DateType.PreviousTimeStamp), // + + SensorCal(0x03, "SensorCal", 1, 0, 1, DateType.PreviousTimeStamp), // + + SensorTimestamp(0x08, "SensorTimestamp", 1, 4, 0, DateType.MinuteSpecific), // + + BatteryChange(0x0a, "BatteryChange',packet_size=4", 1, 4, 0, DateType.MinuteSpecific), // + + SensorStatus(0x0b, "SensorStatus", 1, 4, 0, DateType.MinuteSpecific), // + + DateTimeChange(0x0c, "DateTimeChange", 1, 4, 0, DateType.SecondSpecific), // + + SensorSync(0x0d, "SensorSync',packet_size=4", 1, 4, 0, DateType.MinuteSpecific), // + + CalBGForGH(0x0e, "CalBGForGH',packet_size=5", 1, 4, 1, DateType.MinuteSpecific), // + + SensorCalFactor(0x0f, "SensorCalFactor", 1, 4, 2, DateType.MinuteSpecific), // + + // # 0x10: '10-Something',packet_size=7,date_type='minSpecific',op='0x10'), + + Something10(0x10, "10-Something", 1, 4, 0, DateType.MinuteSpecific), // + + Something19(0x13, "19-Something", 1, 0, 0, DateType.PreviousTimeStamp), + + // V2 + Something05(0x05, "05-Something", 1, 0, 0, DateType.PreviousTimeStamp), + + GlucoseSensorData(0xFF, "GlucoseSensorData", 1, 0, 0, DateType.PreviousTimeStamp); + ; + + private static Map opCodeMap = new HashMap(); + + static { + for (CGMSHistoryEntryType type : values()) { + opCodeMap.put(type.opCode, type); + } + } + + public boolean schemaSet = false; + private int opCode; + private String description; + private int headLength; + private int dateLength; + private int bodyLength; + private int totalLength; + private DateType dateType; + + + CGMSHistoryEntryType(int opCode, String name, int head, int date, int body, DateType dateType) { + this.opCode = opCode; + this.description = name; + this.headLength = head; + this.dateLength = date; + this.bodyLength = body; + this.totalLength = (head + date + body); + this.schemaSet = true; + this.dateType = dateType; + } + + + // private CGMSHistoryEntryType(int opCode, String name, int length) + // { + // this.opCode = opCode; + // this.description = name; + // this.headLength = 0; + // this.dateLength = 0; + // this.bodyLength = 0; + // this.totalLength = length + 1; // opCode + // } + + public static CGMSHistoryEntryType getByCode(int opCode) { + if (opCodeMap.containsKey(opCode)) { + return opCodeMap.get(opCode); + } else + return CGMSHistoryEntryType.None; + } + + + public int getCode() { + return this.opCode; + } + + + public int getTotalLength() { + return totalLength; + } + + + public int getOpCode() { + return opCode; + } + + + public String getDescription() { + return description; + } + + + public int getHeadLength() { + return headLength; + } + + + public int getDateLength() { + return dateLength; + } + + + public int getBodyLength() { + return bodyLength; + } + + + public DateType getDateType() { + return dateType; + } + + + public boolean hasDate() { + return (this.dateType == DateType.MinuteSpecific) || (this.dateType == DateType.SecondSpecific); + } + + public enum DateType { + None, // + MinuteSpecific, // + SecondSpecific, // + PreviousTimeStamp // + ; + + } + +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.java new file mode 100644 index 0000000000..6b33888918 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.java @@ -0,0 +1,361 @@ +package info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.cgms; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.joda.time.LocalDateTime; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil; +import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.MedtronicHistoryDecoder; +import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.MedtronicHistoryEntry; +import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.RawHistoryPage; +import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.RecordDecodeStatus; + +/** + * Application: GGC - GNU Gluco Control + * Plug-in: GGC PlugIn Base (base class for all plugins) + *

+ * See AUTHORS for copyright information. + *

+ * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later + * version. + *

+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + *

+ * Filename: MinimedCGMSHistoryDecoder Description: Decoder for CGMS history data. For now we support just data from + * GlucoseHistory command. ISIGHistory and VCntrHistory are IGNORED for now. + *

+ * Author: Andy {andy@atech-software.com} + */ + +public class MedtronicCGMSHistoryDecoder extends MedtronicHistoryDecoder { + + private static final Logger LOG = LoggerFactory.getLogger(MedtronicCGMSHistoryDecoder.class); + + + // CGMSValuesWriter cgmsValuesWriter = null; + + public MedtronicCGMSHistoryDecoder() { + } + + + public RecordDecodeStatus decodeRecord(MedtronicHistoryEntry entryIn) { + CGMSHistoryEntry precord = (CGMSHistoryEntry)entryIn; + try { + return decodeRecord(precord, false); + } catch (Exception ex) { + LOG.error(" Error decoding: type={}, ex={}", precord.getEntryType().name(), ex.getMessage(), ex); + return RecordDecodeStatus.Error; + } + } + + + public RecordDecodeStatus decodeRecord(CGMSHistoryEntry entry, boolean x) { + // FIXME + // TODO + // CGMSHistoryEntry entry = (CGMSHistoryEntry) entryIn; + + if (entry.getDateTimeLength() > 0) { + LocalDateTime dt = parseDate(entry); + System.out.println("DT: " + dt); + } + + // LOG.debug("decodeRecord: type={}", entry.getEntryType()); + + switch ((CGMSHistoryEntryType)entry.getEntryType()) { + + case SensorWeakSignal: + break; + case SensorCal: + break; + case SensorTimestamp: + break; + case BatteryChange: + break; + case SensorStatus: + break; + case DateTimeChange: + break; + case SensorSync: + break; + case CalBGForGH: + break; + case SensorCalFactor: + LOG.debug("{}", entry.toString()); + break; + case Something10: + break; + case Something19: + break; + + case None: + case DataEnd: + break; + } + + return RecordDecodeStatus.NotSupported; + } + + + @Override + public void postProcess() { + + } + + + @Override + public List processPageAndCreateRecords(RawHistoryPage page) throws Exception { + List dataClear = checkPage(page); + return createRecords(dataClear); + } + + + private List createRecords(List dataClearInput) { + // List listRecords = new + // ArrayList(); + + LOG.debug("createRecords not implemented... WIP"); + // return listRecords; + + List dataClear = reverseList(dataClearInput); + + System.out.println("Reversed:" + ByteUtil.getHex(ByteUtil.getByteArrayFromList(dataClear))); + + prepareStatistics(); + + int counter = 0; + int record = 0; + + List outList = new ArrayList(); + + // create CGMS entries (without dates) + do { + int opCode = getUnsignedInt(dataClear.get(counter)); + counter++; + + CGMSHistoryEntryType entryType; + + if (opCode == 0) { + // continue; + } else if ((opCode > 0) && (opCode < 20)) { + entryType = CGMSHistoryEntryType.getByCode(opCode); + + if (entryType == CGMSHistoryEntryType.None) { + this.unknownOpCodes.put(opCode, opCode); + // System.out.println("Unknown code: " + opCode); + + CGMSHistoryEntry pe = new CGMSHistoryEntry(); + pe.setEntryType(CGMSHistoryEntryType.None); + pe.setOpCode(opCode); + + // List listRawData = new ArrayList(); + // listRawData.add((byte) opCode); + + // pe.setOpCode(opCode); + pe.setData(Arrays.asList((byte)opCode), false); + + // System.out.println("Record: " + pe); + + outList.add(pe); + } else { + List listRawData = new ArrayList(); + listRawData.add((byte)opCode); + + for (int j = 0; j < (entryType.getTotalLength() - 1); j++) { + listRawData.add(dataClear.get(counter)); + counter++; + } + + CGMSHistoryEntry pe = new CGMSHistoryEntry(); + pe.setEntryType(entryType); + + pe.setOpCode(opCode); + pe.setData(listRawData, false); + + // System.out.println("Record: " + pe); + + outList.add(pe); + } + } else { + CGMSHistoryEntry pe = new CGMSHistoryEntry(); + pe.setEntryType(CGMSHistoryEntryType.GlucoseSensorData); + + // List listRawData = new ArrayList(); + // listRawData.add((byte) opCode); + + // pe.setOpCode(opCode); + pe.setData(Arrays.asList((byte)opCode), false); + + // System.out.println("Record: " + pe); + + outList.add(pe); + } + + } while (counter < dataClear.size()); + + int i = outList.size() - 1; + + for (; i >= 0; i--) { + // CGMSHistoryEntryType type = (CGMSHistoryEntryType) outList.get(i).getDateLength(); + + if (outList.get(i).getDateLength() > 0) { + System.out.println("Recordccc2: " + outList.get(i)); + + decodeRecord(outList.get(i)); + // 2015-04-11T14:02:00 + + break; + } + + // System.out.println("Record2: " + outList.get(i)); + + } + + // System.exit(1); + + // FIXME + for (; i >= 0; i--) { + // System.out.println("Record2: " + outList.get(i)); + + CGMSHistoryEntry che = (CGMSHistoryEntry)outList.get(i); + + parseDate(che); + + System.out.println("Record2: " + outList.get(i)); + + } + + return outList; + + } + + + private List reverseList(List dataClearInput) { + + List outList = new ArrayList(); + + for (int i = dataClearInput.size() - 1; i > 0; i--) { + outList.add(dataClearInput.get(i)); + } + + return outList; + } + + + private int parseMinutes(int one) { + // minute = (one & 0b111111 ) + // return minute + + // int yourInteger = Integer.parseInt("100100101", 2); + + return (one & Integer.parseInt("0111111", 2)); + } + + + private int parseHours(int one) { + // def parse_hours (one): + // return (one & 0x1F ) + + return (one & 0x1F); + } + + + private int parseDay(int one) { + // def parse_day (one): + // return one & 0x1F + return one & 0x1F; + } + + + private int parseMonths(int first_byte, int second_byte) { + // def parse_months (first_byte, second_byte): + // first_two_bits = first_byte >> 6 + // second_two_bits = second_byte >> 6 + // return (first_two_bits << 2) + second_two_bits + + int first_two_bits = first_byte >> 6; + int second_two_bits = second_byte >> 6; + + return (first_two_bits << 2) + second_two_bits; + } + + + private int parseYear(int year) { + // def parse_years_lax(year): + // """ + // simple mask plus correction + // """ + // y = (year & Mask.year) + 2000 + // return y + return (year & 0x0F) + 2000; + + } + + + private LocalDateTime parseDate(CGMSHistoryEntry entry) { + if (entry.getEntryType().hasDate()) + return null; + + byte data[] = entry.getDatetime(); + + // def parse_date (data, unmask=False, strict=False, + // minute_specific=False): + // """ + // Some dates are formatted/stored down to the second (Sensor + // CalBGForPH) while + // others are stored down to the minute (CGM SensorTimestamp dates). + // """ + // data = data[:] + // seconds = 0 + // minutes = 0 + // hours = 0 + // + // year = times.parse_years(data[0]) + // day = parse_day(data[1]) + // minutes = parse_minutes(data[2]) + // + // hours = parse_hours(data[3])2015parse + // + // month = parse_months(data[3], data[2]) + + // 2015-04-11T14:02:00 + + // date is reversed + + if (entry.getEntryType().getDateType() == CGMSHistoryEntryType.DateType.MinuteSpecific) { + LocalDateTime date = new LocalDateTime(parseDay(data[2]), parseMonths(data[0], data[1]), + parseYear(data[3]), parseHours(data[0]), parseMinutes(data[1]), 0); + + // ATechDate date = new ATechDate(parseDay(data[0]), + // parseMonths(data[2], data[1]), parseYear(data[2]), + // parseHours(data[2]), parseMinutes(data[1]), 0, + // ATechDateType.DateAndTimeSec); + + entry.setLocalDateTime(date); + + return date; + + } else if (entry.getEntryType().getDateType() == CGMSHistoryEntryType.DateType.SecondSpecific) { + LOG.warn("parseDate for SecondSpecific type is not implemented."); + throw new RuntimeException(); + // return null; + } else + return null; + + } + + + @Override + protected void runPostDecodeTasks() { + this.showStatistics(); + } + +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/data/history2/MedtronicPumpHistoryDecoder.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/pump/MedtronicPumpHistoryDecoder.java similarity index 88% rename from app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/data/history2/MedtronicPumpHistoryDecoder.java rename to app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/pump/MedtronicPumpHistoryDecoder.java index 1d55b7a71d..07b7d25d5b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/data/history2/MedtronicPumpHistoryDecoder.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/pump/MedtronicPumpHistoryDecoder.java @@ -1,7 +1,9 @@ -package info.nightscout.androidaps.plugins.PumpMedtronic.comm.data.history2; +package info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.joda.time.LocalDateTime; import org.slf4j.Logger; @@ -11,10 +13,14 @@ import android.util.Log; import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil; import info.nightscout.androidaps.plugins.PumpCommon.utils.HexDump; -import info.nightscout.androidaps.plugins.PumpMedtronic.comm.data.RawHistoryPage; -import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.BasalProfileEntry; +import info.nightscout.androidaps.plugins.PumpCommon.utils.StringUtil; +import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.MedtronicHistoryDecoder; +import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.MedtronicHistoryEntry; +import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.RawHistoryPage; +import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.RecordDecodeStatus; import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.BolusDTO; import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.BolusWizardDTO; +import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.TempBasalPair; import info.nightscout.androidaps.plugins.PumpMedtronic.defs.MedtronicDeviceType; import info.nightscout.androidaps.plugins.PumpMedtronic.defs.PumpBolusType; import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicUtil; @@ -43,16 +49,16 @@ import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicUtil; public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder { private static final Logger LOG = LoggerFactory.getLogger(MedtronicPumpHistoryDecoder.class); - private static final String TAG = "MdtPumpHistoryDecoder"; + private static final String TAG = "MdtPump"; // PumpValuesWriter pumpValuesWriter = null; // DataAccessPlugInBase dataAccess = DataAccessPump.getInstance(); - BolusDTO bolusEntry; - PumpHistoryEntry pumpHistoryEntry4BolusEntry; + Map bolusHistory = new HashMap<>(); // Temporary records for processing private PumpHistoryEntry tbrPreviousRecord; private PumpHistoryEntry changeTimeRecord; + private MedtronicDeviceType deviceType; public MedtronicPumpHistoryDecoder() { @@ -72,11 +78,17 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder { int counter = 0; int record = 0; boolean incompletePacket = false; + deviceType = MedtronicUtil.getMedtronicPumpModel(); List outList = new ArrayList(); String skipped = null; int elementStart = 0; + if (dataClear.size() == 0) { + Log.e(TAG, "Empty page."); + // return; + } + do { int opCode = dataClear.get(counter); boolean special = false; @@ -237,19 +249,6 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder { } - // private void decodeCalBGForPH(PumpHistoryEntry entry) { - // int high = (entry.getDatetime()[4] & 0x80) >> 7; - // int bg = bitUtils.toInt(high, getUnsignedInt(entry.getHead()[0])); - // - // writeData(PumpBaseType.AdditionalData, PumpAdditionalDataType.BloodGlucose, "" + bg, entry.getATechDate()); - // } - - // masks = [ ( 0x80, 7), (0x40, 6), (0x20, 5), (0x10, 4) ] - // nibbles = [ ] - // for mask, shift in masks: - // nibbles.append( ( (year & mask) >> shift ) ) - // return nibbles - public RecordDecodeStatus decodeRecord(MedtronicHistoryEntry entryIn, boolean x) { // FIXME // TODO @@ -454,6 +453,19 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder { } + // private void decodeCalBGForPH(PumpHistoryEntry entry) { + // int high = (entry.getDatetime()[4] & 0x80) >> 7; + // int bg = bitUtils.toInt(high, getUnsignedInt(entry.getHead()[0])); + // + // writeData(PumpBaseType.AdditionalData, PumpAdditionalDataType.BloodGlucose, "" + bg, entry.getATechDate()); + // } + + // masks = [ ( 0x80, 7), (0x40, 6), (0x20, 5), (0x10, 4) ] + // nibbles = [ ] + // for mask, shift in masks: + // nibbles.append( ( (year & mask) >> shift ) ) + // return nibbles + // FIXME private void decodeChangeTime(PumpHistoryEntry entry) { if (changeTimeRecord == null) @@ -475,9 +487,12 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder { } - // FIXME + // FIXME 554 ? private void decodeEndResultTotals(PumpHistoryEntry entry) { - float totals = bitUtils.toInt(entry.getHead()[2], entry.getHead()[3]) * 0.025f; + float totals = bitUtils.toInt((int)entry.getHead()[0], (int)entry.getHead()[1], (int)entry.getHead()[2], + (int)entry.getHead()[3], ByteUtil.BitConversion.BIG_ENDIAN) * 0.025f; + + entry.addDecodedData("Totals", totals); // this.writeData(PumpBaseType.Report, PumpReport.InsulinTotalDay, getFormattedFloat(totals, 2), // entry.getATechDate()); @@ -504,6 +519,7 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder { } else { // writeData(PumpBaseType.Basal, PumpBasalType.ValueChange, getFormattedFloat(rate, 3), // entry.getATechDate()); + entry.addDecodedData("Value", getFormattedFloat(rate, 3)); return RecordDecodeStatus.OK; } @@ -549,7 +565,9 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder { dto.correctionEstimate = (body[7] + (body[5] & 0x0F)) / 10.0f; } - entry.setHistoryEntryDetails(dto); + dto.localDateTime = entry.getLocalDateTime(); + entry.addDecodedData("Object", dto); + // entry.setHistoryEntryDetails(dto); // this.writeData(PumpBaseType.Event, PumpEventType.BolusWizard, dto.getValue(), entry.getATechDate()); @@ -569,6 +587,14 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder { float amount = bitUtils.toInt(entry.getHead()[2], entry.getHead()[3]) / 10.0f; float fixed = bitUtils.toInt(entry.getHead()[0], entry.getHead()[1]) / 10.0f; + entry.addDecodedData("Amount", amount); + entry.addDecodedData("FixedAmount", fixed); + + // amount = (double) (asUINT8(data[4]) << 2) / 40.0; + // programmedAmount = (double) (asUINT8(data[2]) << 2) / 40.0; + // primeType = programmedAmount == 0 ? "manual" : "fixed"; + // return true; + // this.writeData(PumpBaseType.Event, PumpEventType.PrimeInfusionSet, fixed > 0 ? getFormattedFloat(fixed, 1) : // getFormattedFloat(amount, 1), entry.getATechDate()); } @@ -576,9 +602,9 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder { @Override public void postProcess() { - if (bolusEntry != null) { - writeBolus(pumpHistoryEntry4BolusEntry, bolusEntry); - } + // if (bolusEntry != null) { + // writeBolus(pumpHistoryEntry4BolusEntry, bolusEntry); + // } } @@ -609,42 +635,30 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder { : PumpBolusType.Normal); bolus.setLocalDateTime(entry.getLocalDateTime()); - if (bolusEntry != null) { - if (bolus.getBolusType() == PumpBolusType.Extended) { - if (bolusEntry.getLocalDateTime().equals(bolus.getLocalDateTime())) { - bolus.setImmediateAmount(bolusEntry.getDeliveredAmount()); - bolus.setBolusType(PumpBolusType.Multiwave); + String dateTime = StringUtil.toDateTimeString(entry.getLocalDateTime()); - writeBolus(entry, bolus); - } else { - // FIXME ths might not be correct - writeBolus(entry, bolusEntry); - } - } else { - writeBolus(entry, bolusEntry); + if (bolus.getBolusType() == PumpBolusType.Extended) { + // we check if we have coresponding normal entry + if (bolusHistory.containsKey(dateTime)) { + BolusDTO bolusDTO = bolusHistory.get(dateTime); + + bolusDTO.setImmediateAmount(bolus.getDeliveredAmount()); + bolusDTO.setBolusType(PumpBolusType.Multiwave); + + return; } } - bolusEntry = bolus; - pumpHistoryEntry4BolusEntry = entry; + entry.addDecodedData("Object", bolus); + + bolusHistory.put(dateTime, bolus); + } - private void resetBolusEntry() { - bolusEntry = null; - pumpHistoryEntry4BolusEntry = null; - } - - - private void writeBolus(PumpHistoryEntry pumpHistoryEntry, BolusDTO bolus) { - // writeData(PumpBaseType.Bolus, bolus.getBolusType(), bolus.getValue(), bolus.getATechDate()); - pumpHistoryEntry.setHistoryEntryDetails(bolus); - resetBolusEntry(); - } - - - // FIXME + // FIXME new pumps have single record (I think) private void decodeTempBasal(PumpHistoryEntry entry) { + if (this.tbrPreviousRecord == null) { // LOG.debug(this.tbrPreviousRecord.toString()); this.tbrPreviousRecord = entry; @@ -668,21 +682,24 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder { // LOG.debug("Rate: " + tbrRate.toString()); // LOG.debug("Durration: " + tbrDuration.toString()); - BasalProfileEntry basalProfileEntry = new BasalProfileEntry(tbrRate.getHead()[0], tbrDuration.getHead()[0]); - - // System.out.println( - // "TBR: amount=" + tbr.getAmount() + ", duration=" + tbr.getDuration() - // + " min. Packed: " + tbr.getValue()); - - // FIXME set Unit - - // FIXME AAPS - // if (tbr.getDuration() > 0) { - // writeData(PumpBaseType.Basal, PumpBasalType.TemporaryBasalRate, tbr.getValue(), entry.getATechDate()); + // if ((asUINT8(data[7]) >> 3) == 0) { + // mIsPercent = false; + // tbrRate = (double) (asUINT8(tbrRate.getRawData().get(1)) / 40.0; // } else { - // writeData(PumpBaseType.Basal, PumpBasalType.TemporaryBasalRateCanceled, "", entry.getATechDate()); + // mIsPercent = true; + // basalRate = asUINT8(data[1]); // } + // FIXME + TempBasalPair tbr = new TempBasalPair(tbrRate.getHead()[0], tbrDuration.getHead()[0], (ByteUtil.asUINT8(tbrRate + .getDatetime()[4]) >> 3) == 0); + + // System.out.println("TBR: amount=" + tbr.getInsulinRate() + ", duration=" + tbr.getDurationMinutes() + // // + " min. Packed: " + tbr.getValue() + // ); + + entry.addDecodedData("Object", tbr); + tbrPreviousRecord = null; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/data/history2/PumpHistoryEntry.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/pump/PumpHistoryEntry.java similarity index 71% rename from app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/data/history2/PumpHistoryEntry.java rename to app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/pump/PumpHistoryEntry.java index d88cf32f1c..cf878ff424 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/data/history2/PumpHistoryEntry.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/pump/PumpHistoryEntry.java @@ -1,7 +1,8 @@ -package info.nightscout.androidaps.plugins.PumpMedtronic.comm.data.history2; +package info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump; import info.nightscout.androidaps.plugins.PumpCommon.utils.HexDump; -import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.PumpTimeStampedRecord; +import info.nightscout.androidaps.plugins.PumpCommon.utils.StringUtil; +import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.MedtronicHistoryEntry; /** * Application: GGC - GNU Gluco Control @@ -62,20 +63,20 @@ public class PumpHistoryEntry extends MedtronicHistoryEntry { @Override public String getToStringStart() { - return "PumpHistoryRecord [type=" + entryType.name() + " [" + getOpCode() + ", 0x" + return "PumpHistoryRecord [type=" + StringUtil.getStringInLength(entryType.name(), 20) + " [" + + StringUtil.getStringInLength("" + getOpCode(), 3) + ", 0x" + HexDump.getCorrectHexValue((byte)getOpCode()) + "]"; } - public PumpTimeStampedRecord getHistoryEntryDetails() { - return historyEntryDetails; - } - - - public void setHistoryEntryDetails(PumpTimeStampedRecord historyEntryDetails) { - this.historyEntryDetails = historyEntryDetails; - } - + // public PumpTimeStampedRecord getHistoryEntryDetails() { + // return historyEntryDetails; + // } + // + // + // public void setHistoryEntryDetails(PumpTimeStampedRecord historyEntryDetails) { + // this.historyEntryDetails = historyEntryDetails; + // } public int getOffset() { return offset; @@ -85,4 +86,16 @@ public class PumpHistoryEntry extends MedtronicHistoryEntry { public void setOffset(int offset) { this.offset = offset; } + + + @Override + public String getEntryTypeName() { + return this.entryType.name(); + } + + + @Override + public int getDateLength() { + return this.entryType.getDateLength(); + } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/data/history2/PumpHistoryEntryType.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/pump/PumpHistoryEntryType.java similarity index 92% rename from app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/data/history2/PumpHistoryEntryType.java rename to app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/pump/PumpHistoryEntryType.java index 769b957031..6f189fdad4 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/data/history2/PumpHistoryEntryType.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/comm/history/pump/PumpHistoryEntryType.java @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.PumpMedtronic.comm.data.history2; +package info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump; import java.util.ArrayList; import java.util.HashMap; @@ -71,7 +71,7 @@ public enum PumpHistoryEntryType // implements CodeEnum ChangeChildBlockEnable(0x23, "ChangeChildBlockEnable"), // 8? ChangeMaxBolus(0x24), // 8? EventUnknown_MM522_0x25(0x25), // 8? - ToggleRemote(0x26, "EnableDisableRemote", 2, 5, 0), // 2, 5, 14 + ToggleRemote(0x26, "EnableDisableRemote", 2, 5, 14), // 2, 5, 14 V6:2,5,14 ChangeRemoteId(0x27, "ChangeRemoteID"), // ?? ChangeMaxBasal(0x2c), // @@ -88,7 +88,7 @@ public enum PumpHistoryEntryType // implements CodeEnum EventUnknown_MM512_0x38(0x38), // EventUnknown_MM512_0x39(0x39), // EventUnknown_MM512_0x3b(0x3b), // - ChangeParadigmLinkID(0x3c), // V3 ? + ChangeParadigmLinkID(0x3c, 2, 5, 14), // V3 ? V6: 2,5,14 BGReceived(0x3f, "BGReceived", 2, 5, 3), // Ian3F JournalEntryMealMarker(0x40, 2, 5, 2), // @@ -232,7 +232,12 @@ public enum PumpHistoryEntryType // implements CodeEnum static void setSpecialRulesForEntryTypes() { EndResultTotals.addSpecialRuleBody(new SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 3)); Bolus.addSpecialRuleHead(new SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 8)); - BolusWizardChange.addSpecialRuleBody(new SpecialRule(MedtronicDeviceType.Medtronic_522andHigher, 143)); + // BolusWizardChange.addSpecialRuleBody(new SpecialRule(MedtronicDeviceType.Medtronic_522andHigher, 143)); + BolusWizardChange.addSpecialRuleBody(new SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 143)); // V5: + // 522 + // has + // old + // form BolusWizardBolusEstimate.addSpecialRuleBody(new SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 15)); BolusReminder.addSpecialRuleBody(new SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 2)); } @@ -260,6 +265,11 @@ public enum PumpHistoryEntryType // implements CodeEnum // } // + public static boolean isRelevantEntry() { + return true; + } + + public int getCode() { return this.opCode; } @@ -340,6 +350,8 @@ public enum PumpHistoryEntryType // implements CodeEnum } + // byte[] dh = { 2, 3 }; + private int determineSizeByRule(int defaultValue, List rules) { int size = defaultValue; @@ -353,8 +365,6 @@ public enum PumpHistoryEntryType // implements CodeEnum return size; } - // byte[] dh = { 2, 3 }; - enum DateFormat { None(0), // LongDate(5), // diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/data/dto/BasalProfile.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/data/dto/BasalProfile.java index 540e3618a2..7a5670ea14 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/data/dto/BasalProfile.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/data/dto/BasalProfile.java @@ -26,7 +26,7 @@ import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicUtil; */ public class BasalProfile { - protected static final int MAX_RAW_DATA_SIZE = (48 * 3) + 1; + public static final int MAX_RAW_DATA_SIZE = (48 * 3) + 1; // private static final String TAG = "BasalProfile"; private static final Logger LOG = LoggerFactory.getLogger(BasalProfile.class); private static final boolean DEBUG_BASALPROFILE = false; @@ -50,35 +50,6 @@ public class BasalProfile { } - public static void testParser() { - byte[] testData = new byte[] { - 32, 0, 0, 38, 0, 13, 44, 0, 19, 38, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - /* - * from decocare: - * _test_schedule = {'total': 22.50, 'schedule': [ - * { 'start': '12:00A', 'rate': 0.80 }, - * { 'start': '6:30A', 'rate': 0.95 }, - * { 'start': '9:30A', 'rate': 1.10 }, - * { 'start': '2:00P', 'rate': 0.95 }, - * ]} - */ - BasalProfile profile = new BasalProfile(); - profile.setRawData(testData); - List entries = profile.getEntries(); - if (entries.isEmpty()) { - LOG.error("testParser: failed"); - } else { - for (int i = 0; i < entries.size(); i++) { - BasalProfileEntry e = entries.get(i); - LOG.debug(String.format("testParser entry #%d: rate: %.2f, start %d:%d", i, e.rate, - e.startTime.getHourOfDay(), e.startTime.getMinuteOfHour())); - } - } - - } - - public void init() { mRawData = new byte[MAX_RAW_DATA_SIZE]; mRawData[0] = 0; @@ -108,6 +79,7 @@ public class BasalProfile { for (int i = 0; i < entries.size(); i++) { BasalProfileEntry entry = entries.get(i); String startString = entry.startTime.toString("HH:mm"); + // this doesn't work LOG.debug(String.format("Entry %d, rate=%.3f (0x%02X), start=%s (0x%02X)", i + 1, entry.rate, entry.rate_raw, startString, entry.startTime_raw)); @@ -122,8 +94,7 @@ public class BasalProfile { BasalProfileEntry entry = entries.get(i); String startString = entry.startTime.toString("HH:mm"); - sb.append(String.format("Entry %d, rate=%.3f (0x%02X), start=%s (0x%02X)\n", i + 1, entry.rate, - entry.rate_raw, startString, entry.startTime_raw)); + sb.append(String.format("Entry %d, rate=%.3f, start=%s\n", i + 1, entry.rate, startString)); } return sb.toString(); @@ -187,22 +158,19 @@ public class BasalProfile { LOG.warn("Raw Data is empty."); return entries; // an empty list } - int i = 0; boolean done = false; int r, st; - while (!done) { + + for (int i = 0; i < mRawData.length - 2; i += 3) { + + if ((mRawData[i] == 0) && (mRawData[i + 1] == 0) && (mRawData[i + 2] == 0)) + break; r = MedtronicUtil.makeUnsignedShort(mRawData[i + 1], mRawData[i]); // readUnsignedByte(mRawData[i]); - // What is mRawData[i+1]? Not used in decocare. st = readUnsignedByte(mRawData[i + 2]); entries.add(new BasalProfileEntry(r, st)); - i = i + 3; - if (i >= MAX_RAW_DATA_SIZE) { - done = true; - } else if ((mRawData[i] == 0) && (mRawData[i + 1] == 0) && (mRawData[i + 2] == 0)) { - done = true; - } } + return entries; } @@ -228,16 +196,8 @@ public class BasalProfile { byte[] strokes = MedtronicUtil.getBasalStrokes(profileEntry.rate, true); - // TODO check if this is correct outData.add(profileEntry.rate_raw[0]); outData.add(profileEntry.rate_raw[1]); - - // int time = profileEntry.startTime.getHourOfDay(); - - // if (profileEntry.startTime.getMinuteOfHour() == 30) { - // time++; - // } - outData.add(profileEntry.startTime_raw); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/data/dto/BolusDTO.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/data/dto/BolusDTO.java index 3add8d5c74..e08a880fee 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/data/dto/BolusDTO.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/data/dto/BolusDTO.java @@ -133,4 +133,10 @@ public class BolusDTO extends PumpTimeStampedRecord { } + + @Override + public String toString() { + return "BolusDTO [type=" + bolusType.name() + ", " + getValue() + "]"; + } + } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/data/dto/PumpSettingDTO.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/data/dto/PumpSettingDTO.java index a52abb2aaa..4eb249d4b5 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/data/dto/PumpSettingDTO.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/data/dto/PumpSettingDTO.java @@ -20,4 +20,10 @@ public class PumpSettingDTO { this.configurationGroup = configurationGroup; } + + @Override + public String toString() { + return "PumpSettingDTO [key=" + key + ",value=" + value + ",group=" + configurationGroup.name() + "]"; + } + } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/data/dto/TempBasalPair.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/data/dto/TempBasalPair.java index 8d0cd51667..4f77e2c1cf 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/data/dto/TempBasalPair.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/data/dto/TempBasalPair.java @@ -26,6 +26,23 @@ public class TempBasalPair { } + /** + * This constructor is for use with PumpHistoryDecoder + * + * @param rateByte + * @param startTimeByte + * @param isPercent + */ + public TempBasalPair(byte rateByte, int startTimeByte, boolean isPercent) { + if (isPercent) + this.insulinRate = rateByte; + else + this.insulinRate = rateByte * 0.025; + this.durationMinutes = startTimeByte * 30; + this.isPercent = isPercent; + } + + public TempBasalPair(double insulinRate, boolean isPercent, int durationMinutes) { this.insulinRate = insulinRate; this.isPercent = isPercent; @@ -90,8 +107,7 @@ public class TempBasalPair { list.add((byte)5); byte[] insulinRate = MedtronicUtil.getBasalStrokes(this.insulinRate, true); - byte[] timeMin = MedtronicUtil.getByteArrayFromUnsignedShort( - MedtronicUtil.getIntervalFromMinutes(durationMinutes), true); + byte timeMin = (byte)MedtronicUtil.getIntervalFromMinutes(durationMinutes); // list.add((byte) 0); // ? @@ -100,19 +116,19 @@ public class TempBasalPair { if (insulinRate.length == 1) list.add((byte)0x00); else - list.add(insulinRate[1]); + list.add(insulinRate[0]); - list.add(insulinRate[0]); + list.add(insulinRate[1]); // list.add((byte) 0); // percent amount - list.add(timeMin[0]); // 3 (time) - OK + list.add(timeMin); // 3 (time) - OK if (insulinRate.length == 1) list.add((byte)0x00); else - list.add(insulinRate[1]); + list.add(insulinRate[0]); - list.add(insulinRate[0]); + list.add(insulinRate[1]); return MedtronicUtil.createByteArray(list); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/defs/MedtronicDeviceType.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/defs/MedtronicDeviceType.java index c0f318be9d..68409fb63c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/defs/MedtronicDeviceType.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/defs/MedtronicDeviceType.java @@ -73,7 +73,7 @@ public enum MedtronicDeviceType { MedtronicConverterType pumpConverter; MedtronicConverterType cgmsConverter; - private String pumpModel = ""; + private String pumpModel; // String smallReservoirPump; // String bigReservoirPump; @@ -144,6 +144,11 @@ public enum MedtronicDeviceType { } + public boolean isLargerFormat() { + return isSameDevice(this, Medtronic_523andHigher); + } + + public int getBolusStrokes() { return (isLargerFormat(this)) ? 40 : 10; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/driver/MedtronicPumpStatus.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/driver/MedtronicPumpStatus.java index b281458c32..f152eadf9c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/driver/MedtronicPumpStatus.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/driver/MedtronicPumpStatus.java @@ -62,8 +62,6 @@ public class MedtronicPumpStatus extends PumpStatus { boolean rileyLinkAddressChanged = false; private String[] frequencies; private boolean isFrequencyUS = false; - - // fixme private Map medtronicPumpMap = null; private Map medtronicDeviceTypeMap = null; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/util/MedtronicConst.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/util/MedtronicConst.java index 666e0668ba..3f7085a0d2 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/util/MedtronicConst.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/util/MedtronicConst.java @@ -20,10 +20,10 @@ public class MedtronicConst { public class Statistics { + public static final String StatsPrefix = "medtronic_"; public static final String FirstPumpStart = Prefix + "first_pump_use"; public static final String LastGoodPumpCommunicationTime = Prefix + "lastGoodPumpCommunicationTime"; public static final String LastGoodPumpFrequency = Prefix + "LastGoodPumpFrequency"; - static final String StatsPrefix = "medtronic_"; public static final String TBRsSet = StatsPrefix + "tbrs_set"; public static final String StandardBoluses = StatsPrefix + "std_boluses_delivered"; public static final String SMBBoluses = StatsPrefix + "smb_boluses_delivered"; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/util/MedtronicUtil.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/util/MedtronicUtil.java index a09924146a..2fc520e36b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/util/MedtronicUtil.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMedtronic/util/MedtronicUtil.java @@ -68,9 +68,9 @@ public class MedtronicUtil extends RileyLinkUtil { byte lowByte = (byte)(shortValue & 0xFF); if (highByte > 0) { - return createByteArray(lowByte, highByte); + return createByteArray(highByte, lowByte); } else { - return returnFixedSize ? createByteArray(lowByte, highByte) : createByteArray(lowByte); + return returnFixedSize ? createByteArray(highByte, lowByte) : createByteArray(lowByte); } } @@ -119,7 +119,34 @@ public class MedtronicUtil extends RileyLinkUtil { public static byte[] getBolusStrokes(double amount) { - return getStrokes(amount, medtronicPumpModel.getBolusStrokes(), false); + + int strokesPerUnit = medtronicPumpModel.getBolusStrokes(); + + int length; + int scrollRate; + + if (strokesPerUnit >= 40) { + length = 2; + + // 40-stroke pumps scroll faster for higher unit values + + if (amount > 10) + scrollRate = 4; + else if (amount > 1) + scrollRate = 2; + else + scrollRate = 1; + + } else { + length = 1; + scrollRate = 1; + } + + int strokes = (int)(amount * ((strokesPerUnit * 1.0d) / (scrollRate * 1.0d))) * scrollRate; + + byte[] body = ByteUtil.fromHexString(String.format("%02x%0" + (2 * length) + "x", length, strokes)); + + return body; } @@ -307,4 +334,5 @@ public class MedtronicUtil extends RileyLinkUtil { public static void setSettings(Map settings) { MedtronicUtil.settings = settings; } + }