Finished Omnipod Dash program basal command
This commit is contained in:
parent
8d554fa35b
commit
a3b0044874
|
@ -36,12 +36,12 @@ public final class ProgramBasalCommand extends HeaderEnabledCommand {
|
||||||
this.delayUntilNextTenthPulseInUsec = delayUntilNextTenthPulseInUsec;
|
this.delayUntilNextTenthPulseInUsec = delayUntilNextTenthPulseInUsec;
|
||||||
}
|
}
|
||||||
|
|
||||||
public short getLength() {
|
short getLength() {
|
||||||
return (short) (insulinProgramElements.size() * 2 + 14);
|
return (short) (insulinProgramElements.size() * 6 + 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte getBodyLength() {
|
byte getBodyLength() {
|
||||||
return (byte) (insulinProgramElements.size() * 2 + 12);
|
return (byte) (insulinProgramElements.size() * 6 + 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public byte[] getEncoded() {
|
@Override public byte[] getEncoded() {
|
||||||
|
@ -60,11 +60,11 @@ public final class ProgramBasalCommand extends HeaderEnabledCommand {
|
||||||
byte[] interlockCommand = this.interlockCommand.getEncoded();
|
byte[] interlockCommand = this.interlockCommand.getEncoded();
|
||||||
byte[] header = encodeHeader(uniqueId, sequenceNumber, (short) (bolusCommand.length + interlockCommand.length), multiCommandFlag);
|
byte[] header = encodeHeader(uniqueId, sequenceNumber, (short) (bolusCommand.length + interlockCommand.length), multiCommandFlag);
|
||||||
|
|
||||||
return ByteBuffer.allocate(bolusCommand.length + interlockCommand.length + header.length) //
|
return appendCrc(ByteBuffer.allocate(bolusCommand.length + interlockCommand.length + header.length) //
|
||||||
.put(header) //
|
.put(header) //
|
||||||
.put(interlockCommand) //
|
.put(interlockCommand) //
|
||||||
.put(bolusCommand) //
|
.put(bolusCommand) //
|
||||||
.array();
|
.array());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public String toString() {
|
@Override public String toString() {
|
||||||
|
@ -116,12 +116,12 @@ public final class ProgramBasalCommand extends HeaderEnabledCommand {
|
||||||
short[] pulsesPerSlot = ProgramBasalUtil.mapBasalProgramToPulsesPerSlot(basalProgram);
|
short[] pulsesPerSlot = ProgramBasalUtil.mapBasalProgramToPulsesPerSlot(basalProgram);
|
||||||
CurrentSlot currentSlot = ProgramBasalUtil.calculateCurrentSlot(pulsesPerSlot, currentTime);
|
CurrentSlot currentSlot = ProgramBasalUtil.calculateCurrentSlot(pulsesPerSlot, currentTime);
|
||||||
short checksum = ProgramBasalUtil.createChecksum(pulsesPerSlot, currentSlot);
|
short checksum = ProgramBasalUtil.createChecksum(pulsesPerSlot, currentSlot);
|
||||||
List<LongInsulinProgramElement> longInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToLongInsulinProgramElements(pulsesPerSlot);
|
List<LongInsulinProgramElement> longInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToLongInsulinProgramElements(ProgramBasalUtil.mapBasalProgramToTenthPulsesPerSlot(basalProgram));
|
||||||
List<ShortInsulinProgramElement> shortInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot);
|
List<ShortInsulinProgramElement> shortInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot);
|
||||||
CurrentLongInsulinProgramElement currentLongInsulinProgramElement = ProgramBasalUtil.calculateCurrentLongInsulinProgramElement(longInsulinProgramElements, currentTime);
|
CurrentLongInsulinProgramElement currentLongInsulinProgramElement = ProgramBasalUtil.calculateCurrentLongInsulinProgramElement(longInsulinProgramElements, currentTime);
|
||||||
|
|
||||||
ProgramInsulinCommand interlockCommand = new ProgramInsulinCommand(uniqueId, sequenceNumber, multiCommandFlag, nonce,
|
ProgramInsulinCommand interlockCommand = new ProgramInsulinCommand(uniqueId, sequenceNumber, multiCommandFlag, nonce,
|
||||||
shortInsulinProgramElements, currentSlot.getIndex(), checksum, (short) (currentSlot.getEighthSecondsRemaining() * 8),
|
shortInsulinProgramElements, currentSlot.getIndex(), checksum, currentSlot.getEighthSecondsRemaining(),
|
||||||
currentSlot.getPulsesRemaining(), ProgramInsulinCommand.DeliveryType.BASAL);
|
currentSlot.getPulsesRemaining(), ProgramInsulinCommand.DeliveryType.BASAL);
|
||||||
|
|
||||||
return new ProgramBasalCommand(interlockCommand, uniqueId, sequenceNumber, multiCommandFlag,
|
return new ProgramBasalCommand(interlockCommand, uniqueId, sequenceNumber, multiCommandFlag,
|
||||||
|
|
|
@ -27,12 +27,12 @@ final class ProgramInsulinCommand extends NonceEnabledCommand {
|
||||||
this.deliveryType = deliveryType;
|
this.deliveryType = deliveryType;
|
||||||
}
|
}
|
||||||
|
|
||||||
short getLength() {
|
public short getLength() {
|
||||||
return (short) (insulinProgramElements.size() * 6 + 10);
|
return (short) (insulinProgramElements.size() * 2 + 14);
|
||||||
}
|
}
|
||||||
|
|
||||||
byte getBodyLength() {
|
public byte getBodyLength() {
|
||||||
return (byte) (insulinProgramElements.size() * 6 + 8);
|
return (byte) (insulinProgramElements.size() * 2 + 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public byte[] getEncoded() {
|
@Override public byte[] getEncoded() {
|
||||||
|
|
|
@ -5,10 +5,10 @@ public enum CommandType {
|
||||||
GET_VERSION((byte) 0x07),
|
GET_VERSION((byte) 0x07),
|
||||||
GET_STATUS((byte) 0x0e),
|
GET_STATUS((byte) 0x0e),
|
||||||
SILENCE_ALERTS((byte) 0x11),
|
SILENCE_ALERTS((byte) 0x11),
|
||||||
PROGRAM_BASAL((byte) 0x13),
|
PROGRAM_BASAL((byte) 0x13), // Always preceded by 0x1a
|
||||||
PROGRAM_TEMP_BASAL((byte) 0x16), // Always preceded by 0x1a
|
PROGRAM_TEMP_BASAL((byte) 0x16), // Always preceded by 0x1a
|
||||||
PROGRAM_BOLUS((byte) 0x17), // Always preceded by 0x1a
|
PROGRAM_BOLUS((byte) 0x17), // Always preceded by 0x1a
|
||||||
PROGRAM_ALERTS((byte) 0x19), // Always preceded by 0x1a
|
PROGRAM_ALERTS((byte) 0x19),
|
||||||
PROGRAM_INSULIN((byte) 0x1a), // Always followed by one of: 0x13, 0x16, 0x17
|
PROGRAM_INSULIN((byte) 0x1a), // Always followed by one of: 0x13, 0x16, 0x17
|
||||||
DEACTIVATE((byte) 0x1c),
|
DEACTIVATE((byte) 0x1c),
|
||||||
PROGRAM_BEEPS((byte) 0x1e),
|
PROGRAM_BEEPS((byte) 0x1e),
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program;
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program;
|
||||||
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable;
|
public class CurrentLongInsulinProgramElement {
|
||||||
|
|
||||||
public class CurrentLongInsulinProgramElement implements Encodable {
|
|
||||||
private final byte index;
|
private final byte index;
|
||||||
private final int delayUntilNextTenthPulseInUsec;
|
private final int delayUntilNextTenthPulseInUsec;
|
||||||
private final short remainingTenthPulses;
|
private final short remainingTenthPulses;
|
||||||
|
@ -32,8 +30,4 @@ public class CurrentLongInsulinProgramElement implements Encodable {
|
||||||
", remainingTenthPulses=" + remainingTenthPulses +
|
", remainingTenthPulses=" + remainingTenthPulses +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public byte[] getEncoded() {
|
|
||||||
return new byte[0];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,8 @@ public final class ProgramBasalUtil {
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
previousTenthPulsesPerSlot = tenthPulsesPerSlot[i];
|
previousTenthPulsesPerSlot = tenthPulsesPerSlot[i];
|
||||||
numberOfSlotsInCurrentElement = 1;
|
numberOfSlotsInCurrentElement = 1;
|
||||||
} else if (previousTenthPulsesPerSlot != tenthPulsesPerSlot[i] || numberOfSlotsInCurrentElement >= MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT) {
|
} else if (previousTenthPulsesPerSlot != tenthPulsesPerSlot[i] || (numberOfSlotsInCurrentElement + 1) * previousTenthPulsesPerSlot > 65_534) {
|
||||||
elements.add(new LongInsulinProgramElement(startSlotIndex, numberOfSlotsInCurrentElement, (short) (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement), (int) ((NUMBER_OF_USEC_IN_SLOT * numberOfSlotsInCurrentElement) / (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement))));
|
elements.add(new LongInsulinProgramElement(startSlotIndex, numberOfSlotsInCurrentElement, (short) (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement), (int) (((long) NUMBER_OF_USEC_IN_SLOT * numberOfSlotsInCurrentElement) / (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement))));
|
||||||
|
|
||||||
previousTenthPulsesPerSlot = tenthPulsesPerSlot[i];
|
previousTenthPulsesPerSlot = tenthPulsesPerSlot[i];
|
||||||
numberOfSlotsInCurrentElement = 1;
|
numberOfSlotsInCurrentElement = 1;
|
||||||
|
@ -40,7 +40,7 @@ public final class ProgramBasalUtil {
|
||||||
numberOfSlotsInCurrentElement++;
|
numberOfSlotsInCurrentElement++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elements.add(new LongInsulinProgramElement(startSlotIndex, numberOfSlotsInCurrentElement, (short) (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement), (int) ((NUMBER_OF_USEC_IN_SLOT * numberOfSlotsInCurrentElement) / (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement))));
|
elements.add(new LongInsulinProgramElement(startSlotIndex, numberOfSlotsInCurrentElement, (short) (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement), (int) (((long) NUMBER_OF_USEC_IN_SLOT * numberOfSlotsInCurrentElement) / (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement))));
|
||||||
|
|
||||||
return elements;
|
return elements;
|
||||||
}
|
}
|
||||||
|
@ -205,7 +205,7 @@ public final class ProgramBasalUtil {
|
||||||
|
|
||||||
int durationInSeconds = endTimeInSeconds - startTimeInSeconds;
|
int durationInSeconds = endTimeInSeconds - startTimeInSeconds;
|
||||||
int secondsPassedInCurrentSlot = secondOfDay - startTimeInSeconds;
|
int secondsPassedInCurrentSlot = secondOfDay - startTimeInSeconds;
|
||||||
long remainingTenThousandthPulses = (durationInSeconds - secondsPassedInCurrentSlot) * (long) totalNumberOfTenThousandthPulsesInSlot;
|
long remainingTenThousandthPulses = (long) ((durationInSeconds - secondsPassedInCurrentSlot) / (double) durationInSeconds * totalNumberOfTenThousandthPulsesInSlot);
|
||||||
int delayBetweenTenthPulsesInUsec = (int) (durationInSeconds * 1_000_000L * 1_000 / totalNumberOfTenThousandthPulsesInSlot);
|
int delayBetweenTenthPulsesInUsec = (int) (durationInSeconds * 1_000_000L * 1_000 / totalNumberOfTenThousandthPulsesInSlot);
|
||||||
int secondsRemaining = secondsPassedInCurrentSlot % 1_800;
|
int secondsRemaining = secondsPassedInCurrentSlot % 1_800;
|
||||||
int delayUntilNextTenthPulseInUsec = delayBetweenTenthPulsesInUsec;
|
int delayUntilNextTenthPulseInUsec = delayBetweenTenthPulsesInUsec;
|
||||||
|
@ -215,7 +215,7 @@ public final class ProgramBasalUtil {
|
||||||
delayUntilNextTenthPulseInUsec += delayBetweenTenthPulsesInUsec;
|
delayUntilNextTenthPulseInUsec += delayBetweenTenthPulsesInUsec;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
short remainingTenthPulses = (short) ((0 != remainingTenThousandthPulses % 1_000 ? 1 : 0) + remainingTenThousandthPulses / 1_000);
|
short remainingTenthPulses = (short) ((remainingTenThousandthPulses % 1_000 != 0 ? 1 : 0) + remainingTenThousandthPulses / 1_000);
|
||||||
|
|
||||||
return new CurrentLongInsulinProgramElement(index, delayUntilNextTenthPulseInUsec, remainingTenthPulses);
|
return new CurrentLongInsulinProgramElement(index, delayUntilNextTenthPulseInUsec, remainingTenthPulses);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,18 +5,18 @@ import java.nio.ByteBuffer;
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable;
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable;
|
||||||
|
|
||||||
public class ShortInsulinProgramElement implements Encodable {
|
public class ShortInsulinProgramElement implements Encodable {
|
||||||
private final byte numberOfSlotsMinusOne; // 4 bits
|
private final byte numberOfSlots; // 4 bits
|
||||||
private final short pulsesPerSlot; // 10 bits
|
private final short pulsesPerSlot; // 10 bits
|
||||||
private final boolean extraAlternatePulse;
|
private final boolean extraAlternatePulse;
|
||||||
|
|
||||||
public ShortInsulinProgramElement(byte numberOfSlotsMinusOne, short pulsesPerSlot, boolean extraAlternatePulse) {
|
public ShortInsulinProgramElement(byte numberOfSlots, short pulsesPerSlot, boolean extraAlternatePulse) {
|
||||||
this.numberOfSlotsMinusOne = numberOfSlotsMinusOne;
|
this.numberOfSlots = numberOfSlots;
|
||||||
this.pulsesPerSlot = pulsesPerSlot;
|
this.pulsesPerSlot = pulsesPerSlot;
|
||||||
this.extraAlternatePulse = extraAlternatePulse;
|
this.extraAlternatePulse = extraAlternatePulse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public byte[] getEncoded() {
|
@Override public byte[] getEncoded() {
|
||||||
byte firstByte = (byte) ((((numberOfSlotsMinusOne - 1) & 0x0f) << 4) //
|
byte firstByte = (byte) ((((numberOfSlots - 1) & 0x0f) << 4) //
|
||||||
| ((extraAlternatePulse ? 1 : 0) << 3) //
|
| ((extraAlternatePulse ? 1 : 0) << 3) //
|
||||||
| ((pulsesPerSlot >>> 8) & 0x03));
|
| ((pulsesPerSlot >>> 8) & 0x03));
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ public class ShortInsulinProgramElement implements Encodable {
|
||||||
|
|
||||||
@Override public String toString() {
|
@Override public String toString() {
|
||||||
return "ShortInsulinProgramElement{" +
|
return "ShortInsulinProgramElement{" +
|
||||||
"numberOfSlotsMinusOne=" + numberOfSlotsMinusOne +
|
"numberOfSlotsMinusOne=" + numberOfSlots +
|
||||||
", pulsesPerSlot=" + pulsesPerSlot +
|
", pulsesPerSlot=" + pulsesPerSlot +
|
||||||
", extraAlternatePulse=" + extraAlternatePulse +
|
", extraAlternatePulse=" + extraAlternatePulse +
|
||||||
'}';
|
'}';
|
||||||
|
|
|
@ -12,8 +12,8 @@ public class ProgramReminder implements Encodable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public byte[] getEncoded() {
|
@Override public byte[] getEncoded() {
|
||||||
return new byte[]{(byte) (((this.atStart ? 0 : 1) << 7)
|
return new byte[]{(byte) (((this.atStart ? 1 : 0) << 7)
|
||||||
| ((this.atEnd ? 0 : 1) << 6)
|
| ((this.atEnd ? 1 : 0) << 6)
|
||||||
| (this.atInterval & 0x3f))};
|
| (this.atInterval & 0x3f))};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
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 java.util.Arrays;
|
||||||
|
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.definition.ProgramReminder;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
|
||||||
|
public class ProgramBasalCommandTest {
|
||||||
|
@Test
|
||||||
|
public void testProgramBasalCommand() throws DecoderException {
|
||||||
|
List<BasalProgram.Segment> segments = Arrays.asList(
|
||||||
|
new BasalProgram.Segment((short) 0, (short) 48, 300)
|
||||||
|
);
|
||||||
|
BasalProgram basalProgram = new BasalProgram(segments);
|
||||||
|
Date date = new Date(2021, 1, 17, 14, 47, 43);
|
||||||
|
|
||||||
|
byte[] encoded = new ProgramBasalCommand.Builder() //
|
||||||
|
.setUniqueId(37879809) //
|
||||||
|
.setNonce(1229869870) //
|
||||||
|
.setSequenceNumber((short) 10) //
|
||||||
|
.setBasalProgram(basalProgram) //
|
||||||
|
.setCurrentTime(date) //
|
||||||
|
.setProgramReminder(new ProgramReminder(false, true, (byte) 0)) //
|
||||||
|
.build() //
|
||||||
|
.getEncoded();
|
||||||
|
|
||||||
|
System.out.println(Hex.encodeHexString(encoded));
|
||||||
|
assertArrayEquals(Hex.decodeHex("0242000128241A12494E532E0005E81D1708000CF01EF01EF01E130E40001593004C4B403840005B8D80827C"), encoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue