- merges of bug fixes from RileyLinkAAPS
This commit is contained in:
parent
c9d35696cf
commit
6a73937b2a
27 changed files with 1124 additions and 189 deletions
|
@ -31,7 +31,7 @@ import info.nightscout.utils.SP;
|
||||||
public abstract class RileyLinkCommunicationManager {
|
public abstract class RileyLinkCommunicationManager {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(RileyLinkCommunicationManager.class);
|
private static final Logger LOG = LoggerFactory.getLogger(RileyLinkCommunicationManager.class);
|
||||||
|
private static final int SCAN_TIMEOUT = 1500;
|
||||||
protected final RFSpy rfspy;
|
protected final RFSpy rfspy;
|
||||||
protected final Context context;
|
protected final Context context;
|
||||||
protected int receiverDeviceAwakeForMinutes = 1; // override this in constructor of specific implementation
|
protected int receiverDeviceAwakeForMinutes = 1; // override this in constructor of specific implementation
|
||||||
|
@ -41,16 +41,13 @@ public abstract class RileyLinkCommunicationManager {
|
||||||
protected RileyLinkServiceData rileyLinkServiceData;
|
protected RileyLinkServiceData rileyLinkServiceData;
|
||||||
protected RileyLinkTargetFrequency targetFrequency;
|
protected RileyLinkTargetFrequency targetFrequency;
|
||||||
private double[] scanFrequencies;
|
private double[] scanFrequencies;
|
||||||
|
|
||||||
// internal flag
|
// internal flag
|
||||||
private boolean showPumpMessages = true;
|
private boolean showPumpMessages = true;
|
||||||
private int timeoutCount = 0;
|
private int timeoutCount = 0;
|
||||||
private long nextWakeUpRequired = 0L;
|
private long nextWakeUpRequired = 0L;
|
||||||
|
|
||||||
|
|
||||||
// protected PumpMessage sendAndListen(RLMessage msg) {
|
|
||||||
// return sendAndListen(msg, 4000); // 2000
|
|
||||||
// }
|
|
||||||
|
|
||||||
public RileyLinkCommunicationManager(Context context, RFSpy rfspy, RileyLinkTargetFrequency targetFrequency) {
|
public RileyLinkCommunicationManager(Context context, RFSpy rfspy, RileyLinkTargetFrequency targetFrequency) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.rfspy = rfspy;
|
this.rfspy = rfspy;
|
||||||
|
@ -95,7 +92,6 @@ public abstract class RileyLinkCommunicationManager {
|
||||||
// RileyLinkUtil.sendBroadcastMessage(RileyLinkConst.IPC.MSG_PUMP_quickTune);
|
// RileyLinkUtil.sendBroadcastMessage(RileyLinkConst.IPC.MSG_PUMP_quickTune);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showPumpMessages) {
|
if (showPumpMessages) {
|
||||||
|
@ -212,7 +208,7 @@ public abstract class RileyLinkCommunicationManager {
|
||||||
|
|
||||||
byte[] pumpMsgContent = createPumpMessageContent(RLMessageType.ReadSimpleData);
|
byte[] pumpMsgContent = createPumpMessageContent(RLMessageType.ReadSimpleData);
|
||||||
RFSpyResponse resp = rfspy.transmitThenReceive(new RadioPacket(pumpMsgContent), (byte)0, (byte)0,
|
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()) {
|
if (resp.wasTimeout()) {
|
||||||
LOG.error("scanForPump: Failed to find pump at frequency {}", frequencies[i]);
|
LOG.error("scanForPump: Failed to find pump at frequency {}", frequencies[i]);
|
||||||
} else if (resp.looksLikeRadioPacket()) {
|
} else if (resp.looksLikeRadioPacket()) {
|
||||||
|
@ -266,7 +262,7 @@ public abstract class RileyLinkCommunicationManager {
|
||||||
// RLMessage msg = makeRLMessage(RLMessageType.ReadSimpleData);
|
// RLMessage msg = makeRLMessage(RLMessageType.ReadSimpleData);
|
||||||
byte[] pumpMsgContent = createPumpMessageContent(RLMessageType.ReadSimpleData);
|
byte[] pumpMsgContent = createPumpMessageContent(RLMessageType.ReadSimpleData);
|
||||||
RadioPacket pkt = new RadioPacket(pumpMsgContent);
|
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()) {
|
if (resp.wasTimeout()) {
|
||||||
LOG.warn("tune_tryFrequency: no pump response at frequency {}", freqMHz);
|
LOG.warn("tune_tryFrequency: no pump response at frequency {}", freqMHz);
|
||||||
} else if (resp.looksLikeRadioPacket()) {
|
} else if (resp.looksLikeRadioPacket()) {
|
||||||
|
|
|
@ -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.defs.RileyLinkTargetFrequency;
|
||||||
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.operations.BLECommOperationResult;
|
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.ByteUtil;
|
||||||
|
import info.nightscout.androidaps.plugins.PumpCommon.utils.HexDump;
|
||||||
import info.nightscout.androidaps.plugins.PumpCommon.utils.StringUtil;
|
import info.nightscout.androidaps.plugins.PumpCommon.utils.StringUtil;
|
||||||
import info.nightscout.androidaps.plugins.PumpCommon.utils.ThreadUtil;
|
import info.nightscout.androidaps.plugins.PumpCommon.utils.ThreadUtil;
|
||||||
|
|
||||||
|
@ -107,6 +108,9 @@ public class RFSpy {
|
||||||
|
|
||||||
// prepend length, and send it.
|
// prepend length, and send it.
|
||||||
byte[] prepended = ByteUtil.concat(new byte[] { (byte)(bytes.length) }, bytes);
|
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,
|
BLECommOperationResult writeCheck = rileyLinkBle.writeCharacteristic_blocking(radioServiceUUID, radioDataUUID,
|
||||||
prepended);
|
prepended);
|
||||||
if (writeCheck.resultCode != BLECommOperationResult.RESULT_SUCCESS) {
|
if (writeCheck.resultCode != BLECommOperationResult.RESULT_SUCCESS) {
|
||||||
|
|
|
@ -17,7 +17,6 @@ public enum RileyLinkTargetDevice {
|
||||||
|
|
||||||
RileyLinkTargetDevice(int resourceId, boolean tuneUpEnabled) {
|
RileyLinkTargetDevice(int resourceId, boolean tuneUpEnabled) {
|
||||||
this.resourceId = resourceId;
|
this.resourceId = resourceId;
|
||||||
|
|
||||||
this.tuneUpEnabled = tuneUpEnabled;
|
this.tuneUpEnabled = tuneUpEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.ServiceTaskExecutor;
|
||||||
import info.nightscout.utils.SP;
|
import info.nightscout.utils.SP;
|
||||||
|
|
||||||
//import static info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by andy on 5/6/18.
|
* Created by andy on 5/6/18.
|
||||||
* Split from original file and renamed.
|
* Split from original file and renamed.
|
||||||
|
@ -61,6 +59,7 @@ public abstract class RileyLinkService extends Service {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
RileyLinkUtil.setContext(this.context);
|
RileyLinkUtil.setContext(this.context);
|
||||||
determineRileyLinkTargetFrequency();
|
determineRileyLinkTargetFrequency();
|
||||||
|
RileyLinkUtil.setRileyLinkService(this);
|
||||||
RileyLinkUtil.setRileyLinkTargetFrequency(rileyLinkTargetFrequency);
|
RileyLinkUtil.setRileyLinkTargetFrequency(rileyLinkTargetFrequency);
|
||||||
initRileyLinkServiceData();
|
initRileyLinkServiceData();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
public static String shortHexString(byte[] ra) {
|
||||||
String rval = "";
|
String rval = "";
|
||||||
if (ra == null) {
|
if (ra == null) {
|
||||||
|
@ -236,6 +244,102 @@ public class ByteUtil {
|
||||||
return k;
|
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<Byte> 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 {
|
public enum BitConversion {
|
||||||
LITTLE_ENDIAN, // 20 0 0 0 = reverse
|
LITTLE_ENDIAN, // 20 0 0 0 = reverse
|
||||||
BIG_ENDIAN // 0 0 0 20 = normal - java
|
BIG_ENDIAN // 0 0 0 20 = normal - java
|
||||||
|
|
|
@ -80,4 +80,19 @@ public class StringUtil {
|
||||||
public static String toDateTimeString(LocalDateTime localDateTime) {
|
public static String toDateTimeString(LocalDateTime localDateTime) {
|
||||||
return localDateTime.toString("dd.MM.yyyy HH:mm:ss");
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.ByteUtil;
|
||||||
import info.nightscout.androidaps.plugins.PumpCommon.utils.HexDump;
|
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.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.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.ButtonPressCarelinkMessageBody;
|
||||||
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.message.CarelinkLongMessageBody;
|
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.CarelinkShortMessageBody;
|
||||||
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.message.GetHistoryPageCarelinkMessageBody;
|
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.MessageBody;
|
||||||
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.message.PacketType;
|
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.message.PacketType;
|
||||||
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.message.PumpAckMessageBody;
|
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;
|
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() {
|
public LocalDateTime getPumpTime() {
|
||||||
|
|
||||||
Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.RealTimeClock);
|
Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.RealTimeClock);
|
||||||
|
@ -638,7 +734,7 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
|
||||||
LOG.debug("Set Bolus: Body - {}", HexDump.toHexStringDisplayable(body));
|
LOG.debug("Set Bolus: Body - {}", HexDump.toHexStringDisplayable(body));
|
||||||
|
|
||||||
PumpMessage msg = makePumpMessage(MedtronicCommandType.SetBolus, //
|
PumpMessage msg = makePumpMessage(MedtronicCommandType.SetBolus, //
|
||||||
new CarelinkLongMessageBody(ByteUtil.concat((byte)body.length, body)));
|
new CarelinkLongMessageBody(body));
|
||||||
|
|
||||||
PumpMessage pumpMessage = runCommandWithArgs(msg);
|
PumpMessage pumpMessage = runCommandWithArgs(msg);
|
||||||
|
|
||||||
|
@ -676,7 +772,6 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// FIXME:
|
|
||||||
public BatteryStatusDTO getRemainingBattery() {
|
public BatteryStatusDTO getRemainingBattery() {
|
||||||
|
|
||||||
Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetBatteryStatus);
|
Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetBatteryStatus);
|
||||||
|
|
|
@ -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.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -56,7 +56,9 @@ public class MedtronicConverter {
|
||||||
return decodeBatteryStatus(rawContent);
|
return decodeBatteryStatus(rawContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
case GetBasalProfileSTD: {
|
case GetBasalProfileSTD:
|
||||||
|
case GetBasalProfileA:
|
||||||
|
case GetBasalProfileB: {
|
||||||
return new BasalProfile(rawContent);
|
return new BasalProfile(rawContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,12 +116,6 @@ public class MedtronicConverter {
|
||||||
if ((i != 0) && (time_x == 0)) {
|
if ((i != 0) && (time_x == 0)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// String value = i18nControl.getMessage("CFG_BASE_FROM") + "=" + atd.getTimeString() + ", "
|
|
||||||
// + i18nControl.getMessage("CFG_BASE_AMOUNT") + "=" + vald;
|
|
||||||
|
|
||||||
// writeSetting(key, value, value, PumpConfigurationGroup.Basal);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return basalProfile;
|
return basalProfile;
|
||||||
|
@ -234,6 +230,7 @@ public class MedtronicConverter {
|
||||||
addSettingToMap("CFG_BASE_CLOCK_MODE", rd[getSettingIndexTimeDisplayFormat()] == 0 ? "12h" : "24h",
|
addSettingToMap("CFG_BASE_CLOCK_MODE", rd[getSettingIndexTimeDisplayFormat()] == 0 ? "12h" : "24h",
|
||||||
PumpConfigurationGroup.General, map);
|
PumpConfigurationGroup.General, map);
|
||||||
addSettingToMap("PCFG_INSULIN_CONCENTRATION", "" + (rd[9] != 0 ? 50 : 100), PumpConfigurationGroup.Insulin, 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);
|
addSettingToMap("PCFG_BASAL_PROFILES_ENABLED", parseResultEnable(rd[10]), PumpConfigurationGroup.Basal, map);
|
||||||
|
|
||||||
if (rd[10] == 1) {
|
if (rd[10] == 1) {
|
||||||
|
@ -319,7 +316,7 @@ public class MedtronicConverter {
|
||||||
|
|
||||||
|
|
||||||
public float getStrokesPerUnit(boolean isBasal) {
|
public float getStrokesPerUnit(boolean isBasal) {
|
||||||
return isBasal ? 40.0f : 10.0f;
|
return isBasal ? 40.0f : pumpModel.getBolusStrokes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.ArrayList;
|
||||||
import java.util.HashMap;
|
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.ByteUtil;
|
||||||
import info.nightscout.androidaps.plugins.PumpCommon.utils.StringUtil;
|
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;
|
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)
|
if (!statisticsEnabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -129,8 +129,8 @@ public abstract class MedtronicHistoryDecoder {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mapStatistics.get(status).containsKey(pumpHistoryEntry.getEntryType().name())) {
|
if (!mapStatistics.get(status).containsKey(pumpHistoryEntry.getEntryTypeName())) {
|
||||||
mapStatistics.get(status).put(pumpHistoryEntry.getEntryType().name(), "");
|
mapStatistics.get(status).put(pumpHistoryEntry.getEntryTypeName(), "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.joda.time.LocalDateTime;
|
import org.joda.time.LocalDateTime;
|
||||||
|
|
||||||
import info.nightscout.androidaps.plugins.PumpCommon.utils.HexDump;
|
import info.nightscout.androidaps.plugins.PumpCommon.utils.HexDump;
|
||||||
import info.nightscout.androidaps.plugins.PumpCommon.utils.StringUtil;
|
import info.nightscout.androidaps.plugins.PumpCommon.utils.StringUtil;
|
||||||
import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.PumpTimeStampedRecord;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application: GGC - GNU Gluco Control
|
* Application: GGC - GNU Gluco Control
|
||||||
|
@ -29,7 +30,7 @@ import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.PumpTimeStamped
|
||||||
* Author: Andy {andy@atech-software.com}
|
* Author: Andy {andy@atech-software.com}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public abstract class MedtronicHistoryEntry {
|
public abstract class MedtronicHistoryEntry implements MedtronicHistoryEntryInterface {
|
||||||
|
|
||||||
protected List<Byte> rawData;
|
protected List<Byte> rawData;
|
||||||
|
|
||||||
|
@ -40,7 +41,9 @@ public abstract class MedtronicHistoryEntry {
|
||||||
protected byte[] body;
|
protected byte[] body;
|
||||||
|
|
||||||
protected LocalDateTime dateTime;
|
protected LocalDateTime dateTime;
|
||||||
protected PumpTimeStampedRecord historyEntryDetails;
|
// protected PumpTimeStampedRecord historyEntryDetails;
|
||||||
|
|
||||||
|
private Map<String, Object> decodedData;
|
||||||
|
|
||||||
|
|
||||||
public void setData(List<Byte> listRawData, boolean doNotProcess) {
|
public void setData(List<Byte> 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() {
|
public int getHeadLength() {
|
||||||
return sizes[0];
|
return sizes[0];
|
||||||
}
|
}
|
||||||
|
@ -97,7 +126,9 @@ public abstract class MedtronicHistoryEntry {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
sb.append(getToStringStart());
|
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(", length=");
|
||||||
sb.append(getHeadLength());
|
sb.append(getHeadLength());
|
||||||
sb.append(",");
|
sb.append(",");
|
||||||
|
@ -108,6 +139,17 @@ public abstract class MedtronicHistoryEntry {
|
||||||
sb.append((getHeadLength() + getDateTimeLength() + getBodyLength()));
|
sb.append((getHeadLength() + getDateTimeLength() + getBodyLength()));
|
||||||
sb.append(")");
|
sb.append(")");
|
||||||
|
|
||||||
|
boolean hasData = hasData();
|
||||||
|
|
||||||
|
if (hasData) {
|
||||||
|
sb.append(", data=" + getDecodedData());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasData && !showRaw()) {
|
||||||
|
sb.append("]");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
if (head != null) {
|
if (head != null) {
|
||||||
sb.append(", head=");
|
sb.append(", head=");
|
||||||
sb.append(HexDump.toHexStringDisplayable(this.head));
|
sb.append(HexDump.toHexStringDisplayable(this.head));
|
||||||
|
@ -127,10 +169,10 @@ public abstract class MedtronicHistoryEntry {
|
||||||
sb.append(HexDump.toHexStringDisplayable(this.rawData));
|
sb.append(HexDump.toHexStringDisplayable(this.rawData));
|
||||||
sb.append("]");
|
sb.append("]");
|
||||||
|
|
||||||
sb.append(" DT: ");
|
// sb.append(" DT: ");
|
||||||
sb.append(this.dateTime == null ? " - " : this.dateTime.toString("dd.MM.yyyy HH:mm:ss"));
|
// sb.append(this.dateTime == null ? " - " : this.dateTime.toString("dd.MM.yyyy HH:mm:ss"));
|
||||||
|
|
||||||
sb.append(" Ext: ");
|
// sb.append(" Ext: ");
|
||||||
|
|
||||||
return sb.toString();
|
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() {
|
public String toShortString() {
|
||||||
if (head == null) {
|
if (head == null) {
|
||||||
return "Unidentified record. ";
|
return "Unidentified record. ";
|
||||||
|
@ -200,8 +250,7 @@ public abstract class MedtronicHistoryEntry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// if we extend to CGMS this need to be changed back
|
// if we extend to CGMS this need to be changed back
|
||||||
public abstract PumpHistoryEntryType getEntryType();
|
// public abstract PumpHistoryEntryType getEntryType();
|
||||||
|
|
||||||
}
|
}
|
|
@ -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<Byte> listRawData, boolean doNotProcess);
|
||||||
|
|
||||||
|
|
||||||
|
int getDateLength();
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package info.nightscout.androidaps.plugins.PumpMedtronic.comm.data;
|
package info.nightscout.androidaps.plugins.PumpMedtronic.comm.history;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
|
@ -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
|
* Application: GGC - GNU Gluco Control
|
|
@ -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<Byte> 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()) + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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)
|
||||||
|
* <p>
|
||||||
|
* See AUTHORS for copyright information.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* Filename: PumpHistoryEntryType Description: Pump History Entry Type.
|
||||||
|
* <p>
|
||||||
|
* Data is from several sources, so in comments there are "versions". Version: v1 - default doc fromc decoding-carelink
|
||||||
|
* v2 - Andy testing (?)
|
||||||
|
* <p>
|
||||||
|
* 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<Integer, CGMSHistoryEntryType> opCodeMap = new HashMap<Integer, CGMSHistoryEntryType>();
|
||||||
|
|
||||||
|
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 //
|
||||||
|
;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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)
|
||||||
|
* <p>
|
||||||
|
* See AUTHORS for copyright information.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* Filename: MinimedCGMSHistoryDecoder Description: Decoder for CGMS history data. For now we support just data from
|
||||||
|
* GlucoseHistory command. ISIGHistory and VCntrHistory are IGNORED for now.
|
||||||
|
* <p>
|
||||||
|
* 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<? extends MedtronicHistoryEntry> processPageAndCreateRecords(RawHistoryPage page) throws Exception {
|
||||||
|
List<Byte> dataClear = checkPage(page);
|
||||||
|
return createRecords(dataClear);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private List<? extends MedtronicHistoryEntry> createRecords(List<Byte> dataClearInput) {
|
||||||
|
// List<MinimedHistoryEntry> listRecords = new
|
||||||
|
// ArrayList<MinimedHistoryEntry>();
|
||||||
|
|
||||||
|
LOG.debug("createRecords not implemented... WIP");
|
||||||
|
// return listRecords;
|
||||||
|
|
||||||
|
List<Byte> dataClear = reverseList(dataClearInput);
|
||||||
|
|
||||||
|
System.out.println("Reversed:" + ByteUtil.getHex(ByteUtil.getByteArrayFromList(dataClear)));
|
||||||
|
|
||||||
|
prepareStatistics();
|
||||||
|
|
||||||
|
int counter = 0;
|
||||||
|
int record = 0;
|
||||||
|
|
||||||
|
List<MedtronicHistoryEntry> outList = new ArrayList<MedtronicHistoryEntry>();
|
||||||
|
|
||||||
|
// 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<Byte> listRawData = new ArrayList<Byte>();
|
||||||
|
// listRawData.add((byte) opCode);
|
||||||
|
|
||||||
|
// pe.setOpCode(opCode);
|
||||||
|
pe.setData(Arrays.asList((byte)opCode), false);
|
||||||
|
|
||||||
|
// System.out.println("Record: " + pe);
|
||||||
|
|
||||||
|
outList.add(pe);
|
||||||
|
} else {
|
||||||
|
List<Byte> listRawData = new ArrayList<Byte>();
|
||||||
|
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<Byte> listRawData = new ArrayList<Byte>();
|
||||||
|
// 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<Byte> reverseList(List<Byte> dataClearInput) {
|
||||||
|
|
||||||
|
List<Byte> outList = new ArrayList<Byte>();
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.joda.time.LocalDateTime;
|
import org.joda.time.LocalDateTime;
|
||||||
import org.slf4j.Logger;
|
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.ByteUtil;
|
||||||
import info.nightscout.androidaps.plugins.PumpCommon.utils.HexDump;
|
import info.nightscout.androidaps.plugins.PumpCommon.utils.HexDump;
|
||||||
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.data.RawHistoryPage;
|
import info.nightscout.androidaps.plugins.PumpCommon.utils.StringUtil;
|
||||||
import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.BasalProfileEntry;
|
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.BolusDTO;
|
||||||
import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.BolusWizardDTO;
|
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.MedtronicDeviceType;
|
||||||
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.PumpBolusType;
|
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.PumpBolusType;
|
||||||
import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicUtil;
|
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 {
|
public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(MedtronicPumpHistoryDecoder.class);
|
private static final Logger LOG = LoggerFactory.getLogger(MedtronicPumpHistoryDecoder.class);
|
||||||
private static final String TAG = "MdtPumpHistoryDecoder";
|
private static final String TAG = "MdtPump";
|
||||||
|
|
||||||
// PumpValuesWriter pumpValuesWriter = null;
|
// PumpValuesWriter pumpValuesWriter = null;
|
||||||
|
|
||||||
// DataAccessPlugInBase dataAccess = DataAccessPump.getInstance();
|
// DataAccessPlugInBase dataAccess = DataAccessPump.getInstance();
|
||||||
BolusDTO bolusEntry;
|
Map<String, BolusDTO> bolusHistory = new HashMap<>();
|
||||||
PumpHistoryEntry pumpHistoryEntry4BolusEntry;
|
|
||||||
// Temporary records for processing
|
// Temporary records for processing
|
||||||
private PumpHistoryEntry tbrPreviousRecord;
|
private PumpHistoryEntry tbrPreviousRecord;
|
||||||
private PumpHistoryEntry changeTimeRecord;
|
private PumpHistoryEntry changeTimeRecord;
|
||||||
|
private MedtronicDeviceType deviceType;
|
||||||
|
|
||||||
|
|
||||||
public MedtronicPumpHistoryDecoder() {
|
public MedtronicPumpHistoryDecoder() {
|
||||||
|
@ -72,11 +78,17 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
int record = 0;
|
int record = 0;
|
||||||
boolean incompletePacket = false;
|
boolean incompletePacket = false;
|
||||||
|
deviceType = MedtronicUtil.getMedtronicPumpModel();
|
||||||
|
|
||||||
List<MedtronicHistoryEntry> outList = new ArrayList<MedtronicHistoryEntry>();
|
List<MedtronicHistoryEntry> outList = new ArrayList<MedtronicHistoryEntry>();
|
||||||
String skipped = null;
|
String skipped = null;
|
||||||
int elementStart = 0;
|
int elementStart = 0;
|
||||||
|
|
||||||
|
if (dataClear.size() == 0) {
|
||||||
|
Log.e(TAG, "Empty page.");
|
||||||
|
// return;
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
int opCode = dataClear.get(counter);
|
int opCode = dataClear.get(counter);
|
||||||
boolean special = false;
|
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) {
|
public RecordDecodeStatus decodeRecord(MedtronicHistoryEntry entryIn, boolean x) {
|
||||||
// FIXME
|
// FIXME
|
||||||
// TODO
|
// 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
|
// FIXME
|
||||||
private void decodeChangeTime(PumpHistoryEntry entry) {
|
private void decodeChangeTime(PumpHistoryEntry entry) {
|
||||||
if (changeTimeRecord == null)
|
if (changeTimeRecord == null)
|
||||||
|
@ -475,9 +487,12 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// FIXME
|
// FIXME 554 ?
|
||||||
private void decodeEndResultTotals(PumpHistoryEntry entry) {
|
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),
|
// this.writeData(PumpBaseType.Report, PumpReport.InsulinTotalDay, getFormattedFloat(totals, 2),
|
||||||
// entry.getATechDate());
|
// entry.getATechDate());
|
||||||
|
@ -504,6 +519,7 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
|
||||||
} else {
|
} else {
|
||||||
// writeData(PumpBaseType.Basal, PumpBasalType.ValueChange, getFormattedFloat(rate, 3),
|
// writeData(PumpBaseType.Basal, PumpBasalType.ValueChange, getFormattedFloat(rate, 3),
|
||||||
// entry.getATechDate());
|
// entry.getATechDate());
|
||||||
|
entry.addDecodedData("Value", getFormattedFloat(rate, 3));
|
||||||
return RecordDecodeStatus.OK;
|
return RecordDecodeStatus.OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -549,7 +565,9 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
|
||||||
dto.correctionEstimate = (body[7] + (body[5] & 0x0F)) / 10.0f;
|
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());
|
// 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 amount = bitUtils.toInt(entry.getHead()[2], entry.getHead()[3]) / 10.0f;
|
||||||
float fixed = bitUtils.toInt(entry.getHead()[0], entry.getHead()[1]) / 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) :
|
// this.writeData(PumpBaseType.Event, PumpEventType.PrimeInfusionSet, fixed > 0 ? getFormattedFloat(fixed, 1) :
|
||||||
// getFormattedFloat(amount, 1), entry.getATechDate());
|
// getFormattedFloat(amount, 1), entry.getATechDate());
|
||||||
}
|
}
|
||||||
|
@ -576,9 +602,9 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void postProcess() {
|
public void postProcess() {
|
||||||
if (bolusEntry != null) {
|
// if (bolusEntry != null) {
|
||||||
writeBolus(pumpHistoryEntry4BolusEntry, bolusEntry);
|
// writeBolus(pumpHistoryEntry4BolusEntry, bolusEntry);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -609,42 +635,30 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
|
||||||
: PumpBolusType.Normal);
|
: PumpBolusType.Normal);
|
||||||
bolus.setLocalDateTime(entry.getLocalDateTime());
|
bolus.setLocalDateTime(entry.getLocalDateTime());
|
||||||
|
|
||||||
if (bolusEntry != null) {
|
String dateTime = StringUtil.toDateTimeString(entry.getLocalDateTime());
|
||||||
if (bolus.getBolusType() == PumpBolusType.Extended) {
|
|
||||||
if (bolusEntry.getLocalDateTime().equals(bolus.getLocalDateTime())) {
|
|
||||||
bolus.setImmediateAmount(bolusEntry.getDeliveredAmount());
|
|
||||||
bolus.setBolusType(PumpBolusType.Multiwave);
|
|
||||||
|
|
||||||
writeBolus(entry, bolus);
|
if (bolus.getBolusType() == PumpBolusType.Extended) {
|
||||||
} else {
|
// we check if we have coresponding normal entry
|
||||||
// FIXME ths might not be correct
|
if (bolusHistory.containsKey(dateTime)) {
|
||||||
writeBolus(entry, bolusEntry);
|
BolusDTO bolusDTO = bolusHistory.get(dateTime);
|
||||||
}
|
|
||||||
} else {
|
bolusDTO.setImmediateAmount(bolus.getDeliveredAmount());
|
||||||
writeBolus(entry, bolusEntry);
|
bolusDTO.setBolusType(PumpBolusType.Multiwave);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bolusEntry = bolus;
|
entry.addDecodedData("Object", bolus);
|
||||||
pumpHistoryEntry4BolusEntry = entry;
|
|
||||||
|
bolusHistory.put(dateTime, bolus);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void resetBolusEntry() {
|
// FIXME new pumps have single record (I think)
|
||||||
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
|
|
||||||
private void decodeTempBasal(PumpHistoryEntry entry) {
|
private void decodeTempBasal(PumpHistoryEntry entry) {
|
||||||
|
|
||||||
if (this.tbrPreviousRecord == null) {
|
if (this.tbrPreviousRecord == null) {
|
||||||
// LOG.debug(this.tbrPreviousRecord.toString());
|
// LOG.debug(this.tbrPreviousRecord.toString());
|
||||||
this.tbrPreviousRecord = entry;
|
this.tbrPreviousRecord = entry;
|
||||||
|
@ -668,21 +682,24 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
|
||||||
// LOG.debug("Rate: " + tbrRate.toString());
|
// LOG.debug("Rate: " + tbrRate.toString());
|
||||||
// LOG.debug("Durration: " + tbrDuration.toString());
|
// LOG.debug("Durration: " + tbrDuration.toString());
|
||||||
|
|
||||||
BasalProfileEntry basalProfileEntry = new BasalProfileEntry(tbrRate.getHead()[0], tbrDuration.getHead()[0]);
|
// if ((asUINT8(data[7]) >> 3) == 0) {
|
||||||
|
// mIsPercent = false;
|
||||||
// System.out.println(
|
// tbrRate = (double) (asUINT8(tbrRate.getRawData().get(1)) / 40.0;
|
||||||
// "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());
|
|
||||||
// } else {
|
// } 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;
|
tbrPreviousRecord = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.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
|
* Application: GGC - GNU Gluco Control
|
||||||
|
@ -62,20 +63,20 @@ public class PumpHistoryEntry extends MedtronicHistoryEntry {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getToStringStart() {
|
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()) + "]";
|
+ HexDump.getCorrectHexValue((byte)getOpCode()) + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public PumpTimeStampedRecord getHistoryEntryDetails() {
|
// public PumpTimeStampedRecord getHistoryEntryDetails() {
|
||||||
return historyEntryDetails;
|
// return historyEntryDetails;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
public void setHistoryEntryDetails(PumpTimeStampedRecord historyEntryDetails) {
|
// public void setHistoryEntryDetails(PumpTimeStampedRecord historyEntryDetails) {
|
||||||
this.historyEntryDetails = historyEntryDetails;
|
// this.historyEntryDetails = historyEntryDetails;
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
public int getOffset() {
|
public int getOffset() {
|
||||||
return offset;
|
return offset;
|
||||||
|
@ -85,4 +86,16 @@ public class PumpHistoryEntry extends MedtronicHistoryEntry {
|
||||||
public void setOffset(int offset) {
|
public void setOffset(int offset) {
|
||||||
this.offset = offset;
|
this.offset = offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getEntryTypeName() {
|
||||||
|
return this.entryType.name();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDateLength() {
|
||||||
|
return this.entryType.getDateLength();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -71,7 +71,7 @@ public enum PumpHistoryEntryType // implements CodeEnum
|
||||||
ChangeChildBlockEnable(0x23, "ChangeChildBlockEnable"), // 8?
|
ChangeChildBlockEnable(0x23, "ChangeChildBlockEnable"), // 8?
|
||||||
ChangeMaxBolus(0x24), // 8?
|
ChangeMaxBolus(0x24), // 8?
|
||||||
EventUnknown_MM522_0x25(0x25), // 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"), // ??
|
ChangeRemoteId(0x27, "ChangeRemoteID"), // ??
|
||||||
|
|
||||||
ChangeMaxBasal(0x2c), //
|
ChangeMaxBasal(0x2c), //
|
||||||
|
@ -88,7 +88,7 @@ public enum PumpHistoryEntryType // implements CodeEnum
|
||||||
EventUnknown_MM512_0x38(0x38), //
|
EventUnknown_MM512_0x38(0x38), //
|
||||||
EventUnknown_MM512_0x39(0x39), //
|
EventUnknown_MM512_0x39(0x39), //
|
||||||
EventUnknown_MM512_0x3b(0x3b), //
|
EventUnknown_MM512_0x3b(0x3b), //
|
||||||
ChangeParadigmLinkID(0x3c), // V3 ?
|
ChangeParadigmLinkID(0x3c, 2, 5, 14), // V3 ? V6: 2,5,14
|
||||||
|
|
||||||
BGReceived(0x3f, "BGReceived", 2, 5, 3), // Ian3F
|
BGReceived(0x3f, "BGReceived", 2, 5, 3), // Ian3F
|
||||||
JournalEntryMealMarker(0x40, 2, 5, 2), //
|
JournalEntryMealMarker(0x40, 2, 5, 2), //
|
||||||
|
@ -232,7 +232,12 @@ public enum PumpHistoryEntryType // implements CodeEnum
|
||||||
static void setSpecialRulesForEntryTypes() {
|
static void setSpecialRulesForEntryTypes() {
|
||||||
EndResultTotals.addSpecialRuleBody(new SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 3));
|
EndResultTotals.addSpecialRuleBody(new SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 3));
|
||||||
Bolus.addSpecialRuleHead(new SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 8));
|
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));
|
BolusWizardBolusEstimate.addSpecialRuleBody(new SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 15));
|
||||||
BolusReminder.addSpecialRuleBody(new SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 2));
|
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() {
|
public int getCode() {
|
||||||
return this.opCode;
|
return this.opCode;
|
||||||
}
|
}
|
||||||
|
@ -340,6 +350,8 @@ public enum PumpHistoryEntryType // implements CodeEnum
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// byte[] dh = { 2, 3 };
|
||||||
|
|
||||||
private int determineSizeByRule(int defaultValue, List<SpecialRule> rules) {
|
private int determineSizeByRule(int defaultValue, List<SpecialRule> rules) {
|
||||||
int size = defaultValue;
|
int size = defaultValue;
|
||||||
|
|
||||||
|
@ -353,8 +365,6 @@ public enum PumpHistoryEntryType // implements CodeEnum
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// byte[] dh = { 2, 3 };
|
|
||||||
|
|
||||||
enum DateFormat {
|
enum DateFormat {
|
||||||
None(0), //
|
None(0), //
|
||||||
LongDate(5), //
|
LongDate(5), //
|
|
@ -26,7 +26,7 @@ import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicUtil;
|
||||||
*/
|
*/
|
||||||
public class BasalProfile {
|
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 String TAG = "BasalProfile";
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(BasalProfile.class);
|
private static final Logger LOG = LoggerFactory.getLogger(BasalProfile.class);
|
||||||
private static final boolean DEBUG_BASALPROFILE = false;
|
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<BasalProfileEntry> 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() {
|
public void init() {
|
||||||
mRawData = new byte[MAX_RAW_DATA_SIZE];
|
mRawData = new byte[MAX_RAW_DATA_SIZE];
|
||||||
mRawData[0] = 0;
|
mRawData[0] = 0;
|
||||||
|
@ -108,6 +79,7 @@ public class BasalProfile {
|
||||||
for (int i = 0; i < entries.size(); i++) {
|
for (int i = 0; i < entries.size(); i++) {
|
||||||
BasalProfileEntry entry = entries.get(i);
|
BasalProfileEntry entry = entries.get(i);
|
||||||
String startString = entry.startTime.toString("HH:mm");
|
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,
|
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));
|
entry.rate_raw, startString, entry.startTime_raw));
|
||||||
|
|
||||||
|
@ -122,8 +94,7 @@ public class BasalProfile {
|
||||||
BasalProfileEntry entry = entries.get(i);
|
BasalProfileEntry entry = entries.get(i);
|
||||||
String startString = entry.startTime.toString("HH:mm");
|
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,
|
sb.append(String.format("Entry %d, rate=%.3f, start=%s\n", i + 1, entry.rate, startString));
|
||||||
entry.rate_raw, startString, entry.startTime_raw));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
|
@ -187,22 +158,19 @@ public class BasalProfile {
|
||||||
LOG.warn("Raw Data is empty.");
|
LOG.warn("Raw Data is empty.");
|
||||||
return entries; // an empty list
|
return entries; // an empty list
|
||||||
}
|
}
|
||||||
int i = 0;
|
|
||||||
boolean done = false;
|
boolean done = false;
|
||||||
int r, st;
|
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]);
|
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]);
|
st = readUnsignedByte(mRawData[i + 2]);
|
||||||
entries.add(new BasalProfileEntry(r, st));
|
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;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,16 +196,8 @@ public class BasalProfile {
|
||||||
|
|
||||||
byte[] strokes = MedtronicUtil.getBasalStrokes(profileEntry.rate, true);
|
byte[] strokes = MedtronicUtil.getBasalStrokes(profileEntry.rate, true);
|
||||||
|
|
||||||
// TODO check if this is correct
|
|
||||||
outData.add(profileEntry.rate_raw[0]);
|
outData.add(profileEntry.rate_raw[0]);
|
||||||
outData.add(profileEntry.rate_raw[1]);
|
outData.add(profileEntry.rate_raw[1]);
|
||||||
|
|
||||||
// int time = profileEntry.startTime.getHourOfDay();
|
|
||||||
|
|
||||||
// if (profileEntry.startTime.getMinuteOfHour() == 30) {
|
|
||||||
// time++;
|
|
||||||
// }
|
|
||||||
|
|
||||||
outData.add(profileEntry.startTime_raw);
|
outData.add(profileEntry.startTime_raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -133,4 +133,10 @@ public class BolusDTO extends PumpTimeStampedRecord {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "BolusDTO [type=" + bolusType.name() + ", " + getValue() + "]";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,4 +20,10 @@ public class PumpSettingDTO {
|
||||||
this.configurationGroup = configurationGroup;
|
this.configurationGroup = configurationGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "PumpSettingDTO [key=" + key + ",value=" + value + ",group=" + configurationGroup.name() + "]";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
public TempBasalPair(double insulinRate, boolean isPercent, int durationMinutes) {
|
||||||
this.insulinRate = insulinRate;
|
this.insulinRate = insulinRate;
|
||||||
this.isPercent = isPercent;
|
this.isPercent = isPercent;
|
||||||
|
@ -90,8 +107,7 @@ public class TempBasalPair {
|
||||||
list.add((byte)5);
|
list.add((byte)5);
|
||||||
|
|
||||||
byte[] insulinRate = MedtronicUtil.getBasalStrokes(this.insulinRate, true);
|
byte[] insulinRate = MedtronicUtil.getBasalStrokes(this.insulinRate, true);
|
||||||
byte[] timeMin = MedtronicUtil.getByteArrayFromUnsignedShort(
|
byte timeMin = (byte)MedtronicUtil.getIntervalFromMinutes(durationMinutes);
|
||||||
MedtronicUtil.getIntervalFromMinutes(durationMinutes), true);
|
|
||||||
|
|
||||||
// list.add((byte) 0); // ?
|
// list.add((byte) 0); // ?
|
||||||
|
|
||||||
|
@ -100,19 +116,19 @@ public class TempBasalPair {
|
||||||
if (insulinRate.length == 1)
|
if (insulinRate.length == 1)
|
||||||
list.add((byte)0x00);
|
list.add((byte)0x00);
|
||||||
else
|
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((byte) 0); // percent amount
|
||||||
|
|
||||||
list.add(timeMin[0]); // 3 (time) - OK
|
list.add(timeMin); // 3 (time) - OK
|
||||||
|
|
||||||
if (insulinRate.length == 1)
|
if (insulinRate.length == 1)
|
||||||
list.add((byte)0x00);
|
list.add((byte)0x00);
|
||||||
else
|
else
|
||||||
list.add(insulinRate[1]);
|
list.add(insulinRate[0]);
|
||||||
|
|
||||||
list.add(insulinRate[0]);
|
list.add(insulinRate[1]);
|
||||||
|
|
||||||
return MedtronicUtil.createByteArray(list);
|
return MedtronicUtil.createByteArray(list);
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ public enum MedtronicDeviceType {
|
||||||
|
|
||||||
MedtronicConverterType pumpConverter;
|
MedtronicConverterType pumpConverter;
|
||||||
MedtronicConverterType cgmsConverter;
|
MedtronicConverterType cgmsConverter;
|
||||||
private String pumpModel = "";
|
private String pumpModel;
|
||||||
|
|
||||||
// String smallReservoirPump;
|
// String smallReservoirPump;
|
||||||
// String bigReservoirPump;
|
// String bigReservoirPump;
|
||||||
|
@ -144,6 +144,11 @@ public enum MedtronicDeviceType {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean isLargerFormat() {
|
||||||
|
return isSameDevice(this, Medtronic_523andHigher);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public int getBolusStrokes() {
|
public int getBolusStrokes() {
|
||||||
return (isLargerFormat(this)) ? 40 : 10;
|
return (isLargerFormat(this)) ? 40 : 10;
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,8 +62,6 @@ public class MedtronicPumpStatus extends PumpStatus {
|
||||||
boolean rileyLinkAddressChanged = false;
|
boolean rileyLinkAddressChanged = false;
|
||||||
private String[] frequencies;
|
private String[] frequencies;
|
||||||
private boolean isFrequencyUS = false;
|
private boolean isFrequencyUS = false;
|
||||||
|
|
||||||
// fixme
|
|
||||||
private Map<String, PumpType> medtronicPumpMap = null;
|
private Map<String, PumpType> medtronicPumpMap = null;
|
||||||
private Map<String, MedtronicDeviceType> medtronicDeviceTypeMap = null;
|
private Map<String, MedtronicDeviceType> medtronicDeviceTypeMap = null;
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,10 @@ public class MedtronicConst {
|
||||||
|
|
||||||
public class Statistics {
|
public class Statistics {
|
||||||
|
|
||||||
|
public static final String StatsPrefix = "medtronic_";
|
||||||
public static final String FirstPumpStart = Prefix + "first_pump_use";
|
public static final String FirstPumpStart = Prefix + "first_pump_use";
|
||||||
public static final String LastGoodPumpCommunicationTime = Prefix + "lastGoodPumpCommunicationTime";
|
public static final String LastGoodPumpCommunicationTime = Prefix + "lastGoodPumpCommunicationTime";
|
||||||
public static final String LastGoodPumpFrequency = Prefix + "LastGoodPumpFrequency";
|
public static final String LastGoodPumpFrequency = Prefix + "LastGoodPumpFrequency";
|
||||||
static final String StatsPrefix = "medtronic_";
|
|
||||||
public static final String TBRsSet = StatsPrefix + "tbrs_set";
|
public static final String TBRsSet = StatsPrefix + "tbrs_set";
|
||||||
public static final String StandardBoluses = StatsPrefix + "std_boluses_delivered";
|
public static final String StandardBoluses = StatsPrefix + "std_boluses_delivered";
|
||||||
public static final String SMBBoluses = StatsPrefix + "smb_boluses_delivered";
|
public static final String SMBBoluses = StatsPrefix + "smb_boluses_delivered";
|
||||||
|
|
|
@ -68,9 +68,9 @@ public class MedtronicUtil extends RileyLinkUtil {
|
||||||
byte lowByte = (byte)(shortValue & 0xFF);
|
byte lowByte = (byte)(shortValue & 0xFF);
|
||||||
|
|
||||||
if (highByte > 0) {
|
if (highByte > 0) {
|
||||||
return createByteArray(lowByte, highByte);
|
return createByteArray(highByte, lowByte);
|
||||||
} else {
|
} 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) {
|
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<String, PumpSettingDTO> settings) {
|
public static void setSettings(Map<String, PumpSettingDTO> settings) {
|
||||||
MedtronicUtil.settings = settings;
|
MedtronicUtil.settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue