Add Omnipod Dash bolus command
This commit is contained in:
parent
cfbd8aeea4
commit
23450aee7e
11 changed files with 261 additions and 77 deletions
|
@ -8,9 +8,9 @@ import java.util.List;
|
|||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.HeaderEnabledCommand;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.NonceEnabledCommandBuilder;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.BasalInsulinProgramElement;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.CurrentLongInsulinProgramElement;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.CurrentSlot;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.LongInsulinProgramElement;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.ProgramBasalUtil;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.ShortInsulinProgramElement;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BasalProgram;
|
||||
|
@ -19,13 +19,13 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definitio
|
|||
// Always preceded by 0x1a ProgramInsulinCommand
|
||||
public final class ProgramBasalCommand extends HeaderEnabledCommand {
|
||||
private final ProgramInsulinCommand interlockCommand;
|
||||
private final List<LongInsulinProgramElement> insulinProgramElements;
|
||||
private final List<BasalInsulinProgramElement> insulinProgramElements;
|
||||
private final ProgramReminder programReminder;
|
||||
private final byte currentInsulinProgramElementIndex;
|
||||
private final short remainingTenthPulsesInCurrentInsulinProgramElement;
|
||||
private final int delayUntilNextTenthPulseInUsec;
|
||||
|
||||
ProgramBasalCommand(ProgramInsulinCommand interlockCommand, int uniqueId, short sequenceNumber, boolean multiCommandFlag, List<LongInsulinProgramElement> insulinProgramElements, ProgramReminder programReminder, byte currentInsulinProgramElementIndex, short remainingTenthPulsesInCurrentInsulinProgramElement, int delayUntilNextTenthPulseInUsec) {
|
||||
ProgramBasalCommand(ProgramInsulinCommand interlockCommand, int uniqueId, short sequenceNumber, boolean multiCommandFlag, List<BasalInsulinProgramElement> insulinProgramElements, ProgramReminder programReminder, byte currentInsulinProgramElementIndex, short remainingTenthPulsesInCurrentInsulinProgramElement, int delayUntilNextTenthPulseInUsec) {
|
||||
super(CommandType.PROGRAM_BASAL, uniqueId, sequenceNumber, multiCommandFlag);
|
||||
|
||||
this.interlockCommand = interlockCommand;
|
||||
|
@ -52,18 +52,18 @@ public final class ProgramBasalCommand extends HeaderEnabledCommand {
|
|||
.put(currentInsulinProgramElementIndex) //
|
||||
.putShort(remainingTenthPulsesInCurrentInsulinProgramElement) //
|
||||
.putInt(delayUntilNextTenthPulseInUsec);
|
||||
for (LongInsulinProgramElement insulinProgramElement : insulinProgramElements) {
|
||||
for (BasalInsulinProgramElement insulinProgramElement : insulinProgramElements) {
|
||||
buffer.put(insulinProgramElement.getEncoded());
|
||||
}
|
||||
|
||||
byte[] bolusCommand = buffer.array();
|
||||
byte[] basalCommand = buffer.array();
|
||||
byte[] interlockCommand = this.interlockCommand.getEncoded();
|
||||
byte[] header = encodeHeader(uniqueId, sequenceNumber, (short) (bolusCommand.length + interlockCommand.length), multiCommandFlag);
|
||||
byte[] header = encodeHeader(uniqueId, sequenceNumber, (short) (basalCommand.length + interlockCommand.length), multiCommandFlag);
|
||||
|
||||
return appendCrc(ByteBuffer.allocate(bolusCommand.length + interlockCommand.length + header.length) //
|
||||
return appendCrc(ByteBuffer.allocate(basalCommand.length + interlockCommand.length + header.length) //
|
||||
.put(header) //
|
||||
.put(interlockCommand) //
|
||||
.put(bolusCommand) //
|
||||
.put(basalCommand) //
|
||||
.array());
|
||||
}
|
||||
|
||||
|
@ -116,12 +116,12 @@ public final class ProgramBasalCommand extends HeaderEnabledCommand {
|
|||
short[] pulsesPerSlot = ProgramBasalUtil.mapBasalProgramToPulsesPerSlot(basalProgram);
|
||||
CurrentSlot currentSlot = ProgramBasalUtil.calculateCurrentSlot(pulsesPerSlot, currentTime);
|
||||
short checksum = ProgramBasalUtil.createChecksum(pulsesPerSlot, currentSlot);
|
||||
List<LongInsulinProgramElement> longInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToLongInsulinProgramElements(ProgramBasalUtil.mapBasalProgramToTenthPulsesPerSlot(basalProgram));
|
||||
List<BasalInsulinProgramElement> longInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToLongInsulinProgramElements(ProgramBasalUtil.mapBasalProgramToTenthPulsesPerSlot(basalProgram));
|
||||
List<ShortInsulinProgramElement> shortInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot);
|
||||
CurrentLongInsulinProgramElement currentLongInsulinProgramElement = ProgramBasalUtil.calculateCurrentLongInsulinProgramElement(longInsulinProgramElements, currentTime);
|
||||
|
||||
ProgramInsulinCommand interlockCommand = new ProgramInsulinCommand(uniqueId, sequenceNumber, multiCommandFlag, nonce,
|
||||
shortInsulinProgramElements, currentSlot.getIndex(), checksum, currentSlot.getEighthSecondsRemaining(),
|
||||
shortInsulinProgramElements, checksum, currentSlot.getIndex(), currentSlot.getEighthSecondsRemaining(),
|
||||
currentSlot.getPulsesRemaining(), ProgramInsulinCommand.DeliveryType.BASAL);
|
||||
|
||||
return new ProgramBasalCommand(interlockCommand, uniqueId, sequenceNumber, multiCommandFlag,
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collections;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.HeaderEnabledCommand;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.NonceEnabledCommandBuilder;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.BolusShortInsulinProgramElement;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ProgramReminder;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.MessageUtil;
|
||||
|
||||
// NOT SUPPORTED: extended bolus
|
||||
public final class ProgramBolusCommand extends HeaderEnabledCommand {
|
||||
private static final short LENGTH = 15;
|
||||
private static final byte BODY_LENGTH = 13;
|
||||
|
||||
private final ProgramInsulinCommand interlockCommand;
|
||||
private final ProgramReminder programReminder;
|
||||
private final short numberOfTenthPulses;
|
||||
private final int delayUntilFirstTenthPulseInUsec;
|
||||
|
||||
ProgramBolusCommand(ProgramInsulinCommand interlockCommand, int uniqueId, short sequenceNumber, boolean multiCommandFlag, ProgramReminder programReminder, short numberOfTenthPulses, int delayUntilFirstTenthPulseInUsec) {
|
||||
super(CommandType.PROGRAM_BOLUS, uniqueId, sequenceNumber, multiCommandFlag);
|
||||
this.interlockCommand = interlockCommand;
|
||||
this.programReminder = programReminder;
|
||||
this.numberOfTenthPulses = numberOfTenthPulses;
|
||||
this.delayUntilFirstTenthPulseInUsec = delayUntilFirstTenthPulseInUsec;
|
||||
}
|
||||
|
||||
@Override public byte[] getEncoded() {
|
||||
byte[] bolusCommand = ByteBuffer.allocate(LENGTH) //
|
||||
.put(commandType.getValue()) //
|
||||
.put(BODY_LENGTH) //
|
||||
.put(programReminder.getEncoded()) //
|
||||
.putShort(numberOfTenthPulses) //
|
||||
.putInt(delayUntilFirstTenthPulseInUsec) //
|
||||
.putShort((short) 0) // Extended bolus pulses
|
||||
.putInt(0) // Delay between tenth extended pulses in usec
|
||||
.array();
|
||||
|
||||
byte[] interlockCommand = this.interlockCommand.getEncoded();
|
||||
byte[] header = encodeHeader(uniqueId, sequenceNumber, (short) (bolusCommand.length + interlockCommand.length), multiCommandFlag);
|
||||
|
||||
return appendCrc(ByteBuffer.allocate(header.length + interlockCommand.length + bolusCommand.length) //
|
||||
.put(header) //
|
||||
.put(interlockCommand) //
|
||||
.put(bolusCommand) //
|
||||
.array());
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "ProgramBolusCommand{" +
|
||||
"interlockCommand=" + interlockCommand +
|
||||
", programReminder=" + programReminder +
|
||||
", numberOfTenthPulses=" + numberOfTenthPulses +
|
||||
", delayUntilFirstTenthPulseInUsec=" + delayUntilFirstTenthPulseInUsec +
|
||||
", commandType=" + commandType +
|
||||
", uniqueId=" + uniqueId +
|
||||
", sequenceNumber=" + sequenceNumber +
|
||||
", multiCommandFlag=" + multiCommandFlag +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static final class Builder extends NonceEnabledCommandBuilder<Builder, ProgramBolusCommand> {
|
||||
private Double numberOfUnits;
|
||||
private Byte delayBetweenPulsesInEighthSeconds;
|
||||
private ProgramReminder programReminder;
|
||||
|
||||
public Builder setNumberOfUnits(double numberOfUnits) {
|
||||
if (numberOfUnits <= 0.0D) {
|
||||
throw new IllegalArgumentException("Number of units should be greater than zero");
|
||||
}
|
||||
if ((int) (numberOfUnits * 1000) % 50 != 0) {
|
||||
throw new IllegalArgumentException("Number of units must be dividable by 0.05");
|
||||
}
|
||||
this.numberOfUnits = ((int) (numberOfUnits * 100)) / 100.0d;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setDelayBetweenPulsesInEighthSeconds(byte delayBetweenPulsesInEighthSeconds) {
|
||||
this.delayBetweenPulsesInEighthSeconds = delayBetweenPulsesInEighthSeconds;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setProgramReminder(ProgramReminder programReminder) {
|
||||
this.programReminder = programReminder;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override protected ProgramBolusCommand buildCommand() {
|
||||
if (numberOfUnits == null) {
|
||||
throw new IllegalArgumentException("numberOfUnits can not be null");
|
||||
}
|
||||
if (delayBetweenPulsesInEighthSeconds == null) {
|
||||
throw new IllegalArgumentException("delayBetweenPulsesInEighthSeconds can not be null");
|
||||
}
|
||||
if (programReminder == null) {
|
||||
throw new IllegalArgumentException("programReminder can not be null");
|
||||
}
|
||||
|
||||
short numberOfPulses = (short) Math.round(numberOfUnits * 20);
|
||||
short byte10And11 = (short) (numberOfPulses * delayBetweenPulsesInEighthSeconds);
|
||||
|
||||
ProgramInsulinCommand interlockCommand = new ProgramInsulinCommand(uniqueId, sequenceNumber, multiCommandFlag, nonce,
|
||||
Collections.singletonList(new BolusShortInsulinProgramElement(numberOfPulses)), createChecksum((byte) 0x01, byte10And11, numberOfPulses),
|
||||
(byte) 0x01, byte10And11, (short) numberOfPulses, ProgramInsulinCommand.DeliveryType.BOLUS);
|
||||
|
||||
int delayUntilFirstTenthPulseInUsec = delayBetweenPulsesInEighthSeconds / 8 * 100_000;
|
||||
|
||||
return new ProgramBolusCommand(interlockCommand, uniqueId, sequenceNumber, multiCommandFlag, programReminder, (short) (numberOfPulses * 10), delayUntilFirstTenthPulseInUsec);
|
||||
}
|
||||
}
|
||||
|
||||
private static short createChecksum(byte numberOfSlots, short byte10And11, short numberOfPulses) {
|
||||
return MessageUtil.createCheckSum(ByteBuffer.allocate(7) //
|
||||
.put(numberOfSlots) //
|
||||
.putShort(byte10And11) //
|
||||
.putShort(numberOfPulses) //
|
||||
.putShort(numberOfPulses) //
|
||||
.array());
|
||||
}
|
||||
}
|
|
@ -11,19 +11,19 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.i
|
|||
// Always followed by one of: 0x13, 0x16, 0x17
|
||||
final class ProgramInsulinCommand extends NonceEnabledCommand {
|
||||
private final List<ShortInsulinProgramElement> insulinProgramElements;
|
||||
private final byte currentSlot;
|
||||
private final short checksum;
|
||||
private final short remainingEighthSecondsInCurrentSlot;
|
||||
private final short remainingPulsesInCurrentSlot;
|
||||
private final byte byte9;
|
||||
private final short byte10And11;
|
||||
private final short byte12And13;
|
||||
private final DeliveryType deliveryType;
|
||||
|
||||
ProgramInsulinCommand(int uniqueId, short sequenceNumber, boolean multiCommandFlag, int nonce, List<ShortInsulinProgramElement> insulinProgramElements, byte currentSlot, short checksum, short remainingEighthSecondsInCurrentSlot, short remainingPulsesInCurrentSlot, DeliveryType deliveryType) {
|
||||
ProgramInsulinCommand(int uniqueId, short sequenceNumber, boolean multiCommandFlag, int nonce, List<ShortInsulinProgramElement> insulinProgramElements, short checksum, byte byte9, short byte10And11, short byte12And13, DeliveryType deliveryType) {
|
||||
super(CommandType.PROGRAM_INSULIN, uniqueId, sequenceNumber, multiCommandFlag, nonce);
|
||||
this.insulinProgramElements = new ArrayList<>(insulinProgramElements);
|
||||
this.currentSlot = currentSlot;
|
||||
this.checksum = checksum;
|
||||
this.remainingEighthSecondsInCurrentSlot = remainingEighthSecondsInCurrentSlot;
|
||||
this.remainingPulsesInCurrentSlot = remainingPulsesInCurrentSlot;
|
||||
this.byte9 = byte9;
|
||||
this.byte10And11 = byte10And11;
|
||||
this.byte12And13 = byte12And13;
|
||||
this.deliveryType = deliveryType;
|
||||
}
|
||||
|
||||
|
@ -42,9 +42,9 @@ final class ProgramInsulinCommand extends NonceEnabledCommand {
|
|||
.putInt(nonce) //
|
||||
.put(deliveryType.getValue()) //
|
||||
.putShort(checksum) //
|
||||
.put(currentSlot) //
|
||||
.putShort(remainingEighthSecondsInCurrentSlot) //
|
||||
.putShort(remainingPulsesInCurrentSlot);
|
||||
.put(byte9) // BASAL: currentSlot // BOLUS: number of ShortInsulinProgramElements
|
||||
.putShort(byte10And11) // BASAL: remainingEighthSecondsInCurrentSlot // BOLUS: immediate pulses multiplied by delay between pulses in eighth seconds
|
||||
.putShort(byte12And13); // BASAL: remainingPulsesInCurrentSlot // BOLUS: immediate pulses
|
||||
|
||||
for (ShortInsulinProgramElement element : insulinProgramElements) {
|
||||
buffer.put(element.getEncoded());
|
||||
|
@ -69,13 +69,21 @@ final class ProgramInsulinCommand extends NonceEnabledCommand {
|
|||
}
|
||||
}
|
||||
|
||||
public short createChecksum(byte[] bytes) {
|
||||
short sum = 0;
|
||||
for (byte b : bytes) {
|
||||
sum += (short) (b & 0xff);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "ProgramInsulinCommand{" +
|
||||
"insulinProgramElements=" + insulinProgramElements +
|
||||
", currentSlot=" + currentSlot +
|
||||
", checksum=" + checksum +
|
||||
", remainingEighthSecondsInCurrentSlot=" + remainingEighthSecondsInCurrentSlot +
|
||||
", remainingPulsesInCurrentSlot=" + remainingPulsesInCurrentSlot +
|
||||
", byte9=" + byte9 +
|
||||
", byte10And11=" + byte10And11 +
|
||||
", byte12And13=" + byte12And13 +
|
||||
", deliveryType=" + deliveryType +
|
||||
", nonce=" + nonce +
|
||||
", commandType=" + commandType +
|
||||
|
|
|
@ -2,7 +2,7 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.CrcUtil;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.MessageUtil;
|
||||
|
||||
public abstract class HeaderEnabledCommand implements Command {
|
||||
protected static final short HEADER_LENGTH = 6;
|
||||
|
@ -26,7 +26,7 @@ public abstract class HeaderEnabledCommand implements Command {
|
|||
protected static byte[] appendCrc(byte[] command) {
|
||||
return ByteBuffer.allocate(command.length + 2) //
|
||||
.put(command) //
|
||||
.putShort(CrcUtil.createCrc(command)) //
|
||||
.putShort(MessageUtil.createCrc(command)) //
|
||||
.array();
|
||||
}
|
||||
|
||||
|
|
|
@ -4,13 +4,13 @@ import java.nio.ByteBuffer;
|
|||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable;
|
||||
|
||||
public class LongInsulinProgramElement implements Encodable {
|
||||
public class BasalInsulinProgramElement implements Encodable {
|
||||
private final byte startSlotIndex;
|
||||
private final byte numberOfSlots;
|
||||
private final short totalTenthPulses;
|
||||
private final int delayBetweenTenthPulsesInUsec;
|
||||
|
||||
public LongInsulinProgramElement(byte startSlotIndex, byte numberOfSlots, short totalTenthPulses, int delayBetweenTenthPulsesInUsec) {
|
||||
public BasalInsulinProgramElement(byte startSlotIndex, byte numberOfSlots, short totalTenthPulses, int delayBetweenTenthPulsesInUsec) {
|
||||
this.startSlotIndex = startSlotIndex;
|
||||
this.numberOfSlots = numberOfSlots;
|
||||
this.totalTenthPulses = totalTenthPulses;
|
|
@ -0,0 +1,34 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class BasalShortInsulinProgramElement implements ShortInsulinProgramElement {
|
||||
private final byte numberOfSlots; // 4 bits
|
||||
private final short pulsesPerSlot; // 10 bits
|
||||
private final boolean extraAlternatePulse;
|
||||
|
||||
public BasalShortInsulinProgramElement(byte numberOfSlots, short pulsesPerSlot, boolean extraAlternatePulse) {
|
||||
this.numberOfSlots = numberOfSlots;
|
||||
this.pulsesPerSlot = pulsesPerSlot;
|
||||
this.extraAlternatePulse = extraAlternatePulse;
|
||||
}
|
||||
|
||||
@Override public byte[] getEncoded() {
|
||||
byte firstByte = (byte) ((((numberOfSlots - 1) & 0x0f) << 4) //
|
||||
| ((extraAlternatePulse ? 1 : 0) << 3) //
|
||||
| ((pulsesPerSlot >>> 8) & 0x03));
|
||||
|
||||
return ByteBuffer.allocate(2) //
|
||||
.put(firstByte) //
|
||||
.put((byte) (pulsesPerSlot & 0xff)) //
|
||||
.array();
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "ShortInsulinProgramElement{" +
|
||||
"numberOfSlotsMinusOne=" + numberOfSlots +
|
||||
", pulsesPerSlot=" + pulsesPerSlot +
|
||||
", extraAlternatePulse=" + extraAlternatePulse +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class BolusShortInsulinProgramElement implements ShortInsulinProgramElement {
|
||||
private short numberOfPulses;
|
||||
|
||||
public BolusShortInsulinProgramElement(short numberOfPulses) {
|
||||
this.numberOfPulses = numberOfPulses;
|
||||
}
|
||||
|
||||
public short getNumberOfPulses() {
|
||||
return numberOfPulses;
|
||||
}
|
||||
|
||||
@Override public byte[] getEncoded() {
|
||||
return ByteBuffer.allocate(2).putShort(numberOfPulses).array();
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ import java.util.Date;
|
|||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BasalProgram;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.MessageUtil;
|
||||
|
||||
public final class ProgramBasalUtil {
|
||||
private static final byte NUMBER_OF_BASAL_SLOTS = 48;
|
||||
|
@ -16,12 +17,12 @@ public final class ProgramBasalUtil {
|
|||
private ProgramBasalUtil() {
|
||||
}
|
||||
|
||||
public static List<LongInsulinProgramElement> mapPulsesPerSlotToLongInsulinProgramElements(short[] tenthPulsesPerSlot) {
|
||||
public static List<BasalInsulinProgramElement> mapPulsesPerSlotToLongInsulinProgramElements(short[] tenthPulsesPerSlot) {
|
||||
if (tenthPulsesPerSlot.length != NUMBER_OF_BASAL_SLOTS) {
|
||||
throw new IllegalArgumentException("Basal program must contain 48 slots");
|
||||
}
|
||||
|
||||
List<LongInsulinProgramElement> elements = new ArrayList<>();
|
||||
List<BasalInsulinProgramElement> elements = new ArrayList<>();
|
||||
long previousTenthPulsesPerSlot = 0;
|
||||
byte numberOfSlotsInCurrentElement = 0;
|
||||
byte startSlotIndex = 0;
|
||||
|
@ -31,7 +32,7 @@ public final class ProgramBasalUtil {
|
|||
previousTenthPulsesPerSlot = tenthPulsesPerSlot[i];
|
||||
numberOfSlotsInCurrentElement = 1;
|
||||
} else if (previousTenthPulsesPerSlot != tenthPulsesPerSlot[i] || (numberOfSlotsInCurrentElement + 1) * previousTenthPulsesPerSlot > 65_534) {
|
||||
elements.add(new LongInsulinProgramElement(startSlotIndex, numberOfSlotsInCurrentElement, (short) (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement), (int) (((long) NUMBER_OF_USEC_IN_SLOT * numberOfSlotsInCurrentElement) / (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement))));
|
||||
elements.add(new BasalInsulinProgramElement(startSlotIndex, numberOfSlotsInCurrentElement, (short) (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement), (int) (((long) NUMBER_OF_USEC_IN_SLOT * numberOfSlotsInCurrentElement) / (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement))));
|
||||
|
||||
previousTenthPulsesPerSlot = tenthPulsesPerSlot[i];
|
||||
numberOfSlotsInCurrentElement = 1;
|
||||
|
@ -40,7 +41,7 @@ public final class ProgramBasalUtil {
|
|||
numberOfSlotsInCurrentElement++;
|
||||
}
|
||||
}
|
||||
elements.add(new LongInsulinProgramElement(startSlotIndex, numberOfSlotsInCurrentElement, (short) (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement), (int) (((long) NUMBER_OF_USEC_IN_SLOT * numberOfSlotsInCurrentElement) / (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement))));
|
||||
elements.add(new BasalInsulinProgramElement(startSlotIndex, numberOfSlotsInCurrentElement, (short) (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement), (int) (((long) NUMBER_OF_USEC_IN_SLOT * numberOfSlotsInCurrentElement) / (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement))));
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
@ -69,7 +70,7 @@ public final class ProgramBasalUtil {
|
|||
if (numberOfSlotsInCurrentElement < MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT) {
|
||||
numberOfSlotsInCurrentElement++;
|
||||
} else {
|
||||
elements.add(new ShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, false));
|
||||
elements.add(new BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, false));
|
||||
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots];
|
||||
numberOfSlotsInCurrentElement = 1;
|
||||
extraAlternatePulse = false;
|
||||
|
@ -96,7 +97,7 @@ public final class ProgramBasalUtil {
|
|||
} else {
|
||||
// End of alternate pulse segment (no slots left in element)
|
||||
|
||||
elements.add(new ShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, true));
|
||||
elements.add(new BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, true));
|
||||
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots];
|
||||
numberOfSlotsInCurrentElement = 1;
|
||||
extraAlternatePulse = false;
|
||||
|
@ -105,7 +106,7 @@ public final class ProgramBasalUtil {
|
|||
} else {
|
||||
// End of alternate pulse segment (new number of pulses per slot)
|
||||
|
||||
elements.add(new ShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, true));
|
||||
elements.add(new BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, true));
|
||||
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots];
|
||||
numberOfSlotsInCurrentElement = 1;
|
||||
extraAlternatePulse = false;
|
||||
|
@ -115,7 +116,7 @@ public final class ProgramBasalUtil {
|
|||
}
|
||||
} else if (previousPulsesPerSlot != pulsesPerSlot[currentTotalNumberOfSlots]) {
|
||||
// End of segment (new number of pulses per slot)
|
||||
elements.add(new ShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, false));
|
||||
elements.add(new BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, false));
|
||||
|
||||
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots];
|
||||
currentTotalNumberOfSlots++;
|
||||
|
@ -126,7 +127,7 @@ public final class ProgramBasalUtil {
|
|||
}
|
||||
}
|
||||
|
||||
elements.add(new ShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse));
|
||||
elements.add(new BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse));
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
@ -181,7 +182,7 @@ public final class ProgramBasalUtil {
|
|||
return new CurrentSlot(index, (short) (secondsRemaining * 8), pulsesRemaining);
|
||||
}
|
||||
|
||||
public static CurrentLongInsulinProgramElement calculateCurrentLongInsulinProgramElement(List<LongInsulinProgramElement> elements, Date currentTime) {
|
||||
public static CurrentLongInsulinProgramElement calculateCurrentLongInsulinProgramElement(List<BasalInsulinProgramElement> elements, Date currentTime) {
|
||||
Calendar instance = Calendar.getInstance();
|
||||
instance.setTime(currentTime);
|
||||
|
||||
|
@ -193,7 +194,7 @@ public final class ProgramBasalUtil {
|
|||
int startSlotIndex = 0;
|
||||
|
||||
byte index = 0;
|
||||
for (LongInsulinProgramElement element : elements) {
|
||||
for (BasalInsulinProgramElement element : elements) {
|
||||
int startTimeInSeconds = startSlotIndex * 1_800;
|
||||
int endTimeInSeconds = startTimeInSeconds + element.getNumberOfSlots() * 1_800;
|
||||
|
||||
|
@ -236,12 +237,6 @@ public final class ProgramBasalUtil {
|
|||
buffer.putShort(pulses);
|
||||
}
|
||||
|
||||
byte[] bytes = buffer.array();
|
||||
|
||||
short sum = 0;
|
||||
for (byte b : bytes) {
|
||||
sum += (short) (b & 0xff);
|
||||
}
|
||||
return sum;
|
||||
return MessageUtil.createCheckSum(buffer.array());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,36 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable;
|
||||
|
||||
public class ShortInsulinProgramElement implements Encodable {
|
||||
private final byte numberOfSlots; // 4 bits
|
||||
private final short pulsesPerSlot; // 10 bits
|
||||
private final boolean extraAlternatePulse;
|
||||
|
||||
public ShortInsulinProgramElement(byte numberOfSlots, short pulsesPerSlot, boolean extraAlternatePulse) {
|
||||
this.numberOfSlots = numberOfSlots;
|
||||
this.pulsesPerSlot = pulsesPerSlot;
|
||||
this.extraAlternatePulse = extraAlternatePulse;
|
||||
}
|
||||
|
||||
@Override public byte[] getEncoded() {
|
||||
byte firstByte = (byte) ((((numberOfSlots - 1) & 0x0f) << 4) //
|
||||
| ((extraAlternatePulse ? 1 : 0) << 3) //
|
||||
| ((pulsesPerSlot >>> 8) & 0x03));
|
||||
|
||||
return ByteBuffer.allocate(2) //
|
||||
.put(firstByte) //
|
||||
.put((byte) (pulsesPerSlot & 0xff)) //
|
||||
.array();
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "ShortInsulinProgramElement{" +
|
||||
"numberOfSlotsMinusOne=" + numberOfSlots +
|
||||
", pulsesPerSlot=" + pulsesPerSlot +
|
||||
", extraAlternatePulse=" + extraAlternatePulse +
|
||||
'}';
|
||||
}
|
||||
public interface ShortInsulinProgramElement extends Encodable {
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util;
|
||||
|
||||
public class CrcUtil {
|
||||
public class MessageUtil {
|
||||
|
||||
private static final short[] crc16table = {0, -32763, -32753, 10, -32741, 30, 20, -32751, -32717, 54, 60, -32711, 40, -32723, -32729, 34, -32669, 102, 108, -32663, 120, -32643, -32649, 114, 80, -32683, -32673, 90, -32693, 78, 68, -32703, -32573, 198, 204, -32567, 216, -32547, -32553, 210, 240, -32523, -32513, 250, -32533, 238, 228, -32543, 160, -32603, -32593, 170, -32581, 190, 180, -32591, -32621, 150, 156, -32615, 136, -32627, -32633, 130, -32381, 390, 396, -32375, 408, -32355, -32361, 402, 432, -32331, -32321, 442, -32341, 430, 420, -32351, 480, -32283, -32273, 490, -32261, 510, 500, -32271, -32301, 470, 476, -32295, 456, -32307, -32313, 450, 320, -32443, -32433, 330, -32421, 350, 340, -32431, -32397, 374, 380, -32391, 360, -32403, -32409, 354, -32477, 294, 300, -32471, 312, -32451, -32457, 306, 272, -32491, -32481, 282, -32501, 270, 260, -32511, -31997, 774, 780, -31991, 792, -31971, -31977, 786, 816, -31947, -31937, 826, -31957, 814, 804, -31967, 864, -31899, -31889, 874, -31877, 894, 884, -31887, -31917, 854, 860, -31911, 840, -31923, -31929, 834, 960, -31803, -31793, 970, -31781, 990, 980, -31791, -31757, 1014, 1020, -31751, 1000, -31763, -31769, 994, -31837, 934, 940, -31831, 952, -31811, -31817, 946, 912, -31851, -31841, 922, -31861, 910, 900, -31871, 640, -32123, -32113, 650, -32101, 670, 660, -32111, -32077, 694, 700, -32071, 680, -32083, -32089, 674, -32029, 742, 748, -32023, 760, -32003, -32009, 754, 720, -32043, -32033, 730, -32053, 718, 708, -32063, -32189, 582, 588, -32183, 600, -32163, -32169, 594, 624, -32139, -32129, 634, -32149, 622, 612, -32159, 544, -32219, -32209, 554, -32197, 574, 564, -32207, -32237, 534, 540, -32231, 520, -32243, -32249, 514};
|
||||
|
||||
|
@ -29,4 +29,12 @@ public class CrcUtil {
|
|||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
public static short createCheckSum(byte[] bytes) {
|
||||
short sum = 0;
|
||||
for (byte b : bytes) {
|
||||
sum += (short) (b & 0xff);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
|
||||
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.junit.Test;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ProgramReminder;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
public class ProgramBolusCommandTest {
|
||||
@Test
|
||||
public void testProgramBolusCommand() throws DecoderException {
|
||||
byte[] encoded = new ProgramBolusCommand.Builder() //
|
||||
.setNumberOfUnits(5) //
|
||||
.setProgramReminder(new ProgramReminder(false, true, (byte) 0)) //
|
||||
.setDelayBetweenPulsesInEighthSeconds((byte) 16) //
|
||||
.setUniqueId(37879809) //
|
||||
.setSequenceNumber((short) 14) //
|
||||
.setNonce(1229869870) //
|
||||
.build() //
|
||||
.getEncoded();
|
||||
|
||||
assertArrayEquals(Hex.decodeHex("02420001381F1A0E494E532E02010F01064000640064170D4003E800030D4000000000000080F6"), encoded);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue