Finished Omnipod Dash program basal command

This commit is contained in:
Bart Sopers 2021-02-17 16:10:18 +01:00
parent 8d554fa35b
commit a3b0044874
8 changed files with 66 additions and 33 deletions

View file

@ -36,12 +36,12 @@ public final class ProgramBasalCommand extends HeaderEnabledCommand {
this.delayUntilNextTenthPulseInUsec = delayUntilNextTenthPulseInUsec;
}
public short getLength() {
return (short) (insulinProgramElements.size() * 2 + 14);
short getLength() {
return (short) (insulinProgramElements.size() * 6 + 10);
}
public byte getBodyLength() {
return (byte) (insulinProgramElements.size() * 2 + 12);
byte getBodyLength() {
return (byte) (insulinProgramElements.size() * 6 + 8);
}
@Override public byte[] getEncoded() {
@ -60,11 +60,11 @@ public final class ProgramBasalCommand extends HeaderEnabledCommand {
byte[] interlockCommand = this.interlockCommand.getEncoded();
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(interlockCommand) //
.put(bolusCommand) //
.array();
.array());
}
@Override public String toString() {
@ -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(pulsesPerSlot);
List<LongInsulinProgramElement> 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, (short) (currentSlot.getEighthSecondsRemaining() * 8),
shortInsulinProgramElements, currentSlot.getIndex(), checksum, currentSlot.getEighthSecondsRemaining(),
currentSlot.getPulsesRemaining(), ProgramInsulinCommand.DeliveryType.BASAL);
return new ProgramBasalCommand(interlockCommand, uniqueId, sequenceNumber, multiCommandFlag,

View file

@ -27,12 +27,12 @@ final class ProgramInsulinCommand extends NonceEnabledCommand {
this.deliveryType = deliveryType;
}
short getLength() {
return (short) (insulinProgramElements.size() * 6 + 10);
public short getLength() {
return (short) (insulinProgramElements.size() * 2 + 14);
}
byte getBodyLength() {
return (byte) (insulinProgramElements.size() * 6 + 8);
public byte getBodyLength() {
return (byte) (insulinProgramElements.size() * 2 + 12);
}
@Override public byte[] getEncoded() {

View file

@ -5,10 +5,10 @@ public enum CommandType {
GET_VERSION((byte) 0x07),
GET_STATUS((byte) 0x0e),
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_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
DEACTIVATE((byte) 0x1c),
PROGRAM_BEEPS((byte) 0x1e),

View file

@ -1,8 +1,6 @@
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 implements Encodable {
public class CurrentLongInsulinProgramElement {
private final byte index;
private final int delayUntilNextTenthPulseInUsec;
private final short remainingTenthPulses;
@ -32,8 +30,4 @@ public class CurrentLongInsulinProgramElement implements Encodable {
", remainingTenthPulses=" + remainingTenthPulses +
'}';
}
@Override public byte[] getEncoded() {
return new byte[0];
}
}

View file

@ -30,8 +30,8 @@ public final class ProgramBasalUtil {
if (i == 0) {
previousTenthPulsesPerSlot = tenthPulsesPerSlot[i];
numberOfSlotsInCurrentElement = 1;
} else if (previousTenthPulsesPerSlot != tenthPulsesPerSlot[i] || numberOfSlotsInCurrentElement >= MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT) {
elements.add(new LongInsulinProgramElement(startSlotIndex, numberOfSlotsInCurrentElement, (short) (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement), (int) ((NUMBER_OF_USEC_IN_SLOT * numberOfSlotsInCurrentElement) / (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement))));
} 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))));
previousTenthPulsesPerSlot = tenthPulsesPerSlot[i];
numberOfSlotsInCurrentElement = 1;
@ -40,7 +40,7 @@ public final class ProgramBasalUtil {
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;
}
@ -205,7 +205,7 @@ public final class ProgramBasalUtil {
int durationInSeconds = endTimeInSeconds - 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 secondsRemaining = secondsPassedInCurrentSlot % 1_800;
int delayUntilNextTenthPulseInUsec = delayBetweenTenthPulsesInUsec;
@ -215,7 +215,7 @@ public final class ProgramBasalUtil {
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);
}

View file

@ -5,18 +5,18 @@ import java.nio.ByteBuffer;
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.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 boolean extraAlternatePulse;
public ShortInsulinProgramElement(byte numberOfSlotsMinusOne, short pulsesPerSlot, boolean extraAlternatePulse) {
this.numberOfSlotsMinusOne = numberOfSlotsMinusOne;
public ShortInsulinProgramElement(byte numberOfSlots, short pulsesPerSlot, boolean extraAlternatePulse) {
this.numberOfSlots = numberOfSlots;
this.pulsesPerSlot = pulsesPerSlot;
this.extraAlternatePulse = extraAlternatePulse;
}
@Override public byte[] getEncoded() {
byte firstByte = (byte) ((((numberOfSlotsMinusOne - 1) & 0x0f) << 4) //
byte firstByte = (byte) ((((numberOfSlots - 1) & 0x0f) << 4) //
| ((extraAlternatePulse ? 1 : 0) << 3) //
| ((pulsesPerSlot >>> 8) & 0x03));
@ -28,7 +28,7 @@ public class ShortInsulinProgramElement implements Encodable {
@Override public String toString() {
return "ShortInsulinProgramElement{" +
"numberOfSlotsMinusOne=" + numberOfSlotsMinusOne +
"numberOfSlotsMinusOne=" + numberOfSlots +
", pulsesPerSlot=" + pulsesPerSlot +
", extraAlternatePulse=" + extraAlternatePulse +
'}';

View file

@ -12,8 +12,8 @@ public class ProgramReminder implements Encodable {
}
@Override public byte[] getEncoded() {
return new byte[]{(byte) (((this.atStart ? 0 : 1) << 7)
| ((this.atEnd ? 0 : 1) << 6)
return new byte[]{(byte) (((this.atStart ? 1 : 0) << 7)
| ((this.atEnd ? 1 : 0) << 6)
| (this.atInterval & 0x3f))};
}
}

View file

@ -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);
}
}