Refactoring

This commit is contained in:
Bart Sopers 2021-02-14 18:39:18 +01:00
parent d1bf9cefad
commit 34553bbcf6
20 changed files with 336 additions and 256 deletions

View file

@ -1,117 +0,0 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.CrcUtil;
abstract class CommandBase implements Command {
static final short HEADER_LENGTH = 6;
final CommandType commandType;
final int address;
final short sequenceNumber;
final boolean multiCommandFlag;
CommandBase(CommandType commandType, int address, short sequenceNumber, boolean multiCommandFlag) {
this.commandType = commandType;
this.address = address;
this.sequenceNumber = sequenceNumber;
this.multiCommandFlag = multiCommandFlag;
}
@Override public CommandType getCommandType() {
return commandType;
}
public int getAddress() {
return address;
}
public short getSequenceNumber() {
return sequenceNumber;
}
public boolean isMultiCommandFlag() {
return multiCommandFlag;
}
static byte[] formatCommand(byte[] command) {
List<Byte> temp = new ArrayList<>();
byte[] prefix = "S0.0=".getBytes(StandardCharsets.UTF_8);
for (byte b : prefix) {
temp.add(b);
}
byte[] length = ByteBuffer.allocate(2).putShort((short) command.length).array();
for (int i = 0; i < 2; i++) {
temp.add(length[i]);
}
// Append command
for (byte b : command) {
temp.add(b);
}
byte[] suffix = ",G0.0".getBytes(StandardCharsets.UTF_8);
for (byte b : suffix) {
temp.add(b);
}
byte[] out = new byte[((short) temp.size())];
for (int i2 = 0; i2 < temp.size(); i2++) {
out[i2] = temp.get(i2);
}
return out;
}
static byte[] appendCrc(byte[] command) {
return ByteBuffer.allocate(command.length + 2) //
.put(command) //
.putShort(CrcUtil.createCrc(command)) //
.array();
}
static byte[] encodeHeader(int address, short sequenceNumber, short length, boolean multiCommandFlag) {
return ByteBuffer.allocate(6) //
.putInt(address) //
.putShort((short) (((sequenceNumber & 0x0f) << 10) | length | ((multiCommandFlag ? 1 : 0) << 15))) //
.array();
}
static abstract class Builder<T extends Builder<T, R>, R extends Command> {
Integer address;
Short sequenceNumber;
boolean multiCommandFlag = false;
public final R build() {
if (address == null) {
throw new IllegalArgumentException("address can not be null");
}
if (sequenceNumber == null) {
throw new IllegalArgumentException("sequenceNumber can not be null");
}
return buildCommand();
}
public final T setAddress(int address) {
this.address = address;
return (T) this;
}
public final T setSequenceNumber(short sequenceNumber) {
this.sequenceNumber = sequenceNumber;
return (T) this;
}
public final T setMultiCommandFlag(boolean multiCommandFlag) {
this.multiCommandFlag = multiCommandFlag;
return (T) this;
}
abstract R buildCommand();
}
}

View file

@ -2,12 +2,15 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
import java.nio.ByteBuffer;
public final class DeactivateCommand extends CommandBase {
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.NonceEnabledCommand;
public final class DeactivateCommand extends NonceEnabledCommand {
private static final short LENGTH = 6;
private static final byte BODY_LENGTH = 4;
private DeactivateCommand(int address, short sequenceNumber, boolean multiCommandFlag) {
super(CommandType.DEACTIVATE, address, sequenceNumber, multiCommandFlag);
private DeactivateCommand(int address, short sequenceNumber, boolean multiCommandFlag, int nonce) {
super(CommandType.DEACTIVATE, address, sequenceNumber, multiCommandFlag, nonce);
}
@Override public byte[] getEncoded() {
@ -15,7 +18,7 @@ public final class DeactivateCommand extends CommandBase {
.put(encodeHeader(address, sequenceNumber, LENGTH, multiCommandFlag)) //
.put(commandType.getValue()) //
.put(BODY_LENGTH) //
.putInt(1229869870) // FIXME ?? was: byte array of int 777211465 converted to little endian
.putInt(nonce) //
.array());
}
@ -28,9 +31,9 @@ public final class DeactivateCommand extends CommandBase {
'}';
}
public static final class Builder extends CommandBase.Builder<Builder, DeactivateCommand> {
@Override final DeactivateCommand buildCommand() {
return new DeactivateCommand(address, sequenceNumber, multiCommandFlag);
public static final class Builder extends NonceEnabledBuilder<Builder, DeactivateCommand> {
@Override protected final DeactivateCommand buildCommand() {
return new DeactivateCommand(Builder.this.address, sequenceNumber, multiCommandFlag, nonce);
}
}
}

View file

@ -2,7 +2,10 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
import java.nio.ByteBuffer;
public final class GetVersionCommand extends CommandBase {
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;
public final class GetVersionCommand extends HeaderEnabledCommand {
public static final int DEFAULT_ADDRESS = -1; // FIXME move
private static final short LENGTH = 6;
@ -30,8 +33,8 @@ public final class GetVersionCommand extends CommandBase {
'}';
}
public static final class Builder extends CommandBase.Builder<Builder, GetVersionCommand> {
@Override final GetVersionCommand buildCommand() {
public static final class Builder extends HeaderEnabledBuilder<Builder, GetVersionCommand> {
@Override protected final GetVersionCommand buildCommand() {
return new GetVersionCommand(address, sequenceNumber, multiCommandFlag);
}
}

View file

@ -4,13 +4,15 @@ import java.nio.ByteBuffer;
import java.util.ArrayList;
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.NonceEnabledCommand;
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertConfiguration;
public final class ProgramAlertsCommand extends CommandBase {
public final class ProgramAlertsCommand extends NonceEnabledCommand {
private final List<AlertConfiguration> alertConfigurations;
private ProgramAlertsCommand(int address, short sequenceNumber, boolean multiCommandFlag, List<AlertConfiguration> alertConfigurations) {
super(CommandType.PROGRAM_ALERTS, address, sequenceNumber, multiCommandFlag);
private ProgramAlertsCommand(int address, short sequenceNumber, boolean multiCommandFlag, List<AlertConfiguration> alertConfigurations, int nonce) {
super(CommandType.PROGRAM_ALERTS, address, sequenceNumber, multiCommandFlag, nonce);
this.alertConfigurations = new ArrayList<>(alertConfigurations);
}
@ -19,7 +21,7 @@ public final class ProgramAlertsCommand extends CommandBase {
.put(encodeHeader(address, sequenceNumber, getLength(), multiCommandFlag)) //
.put(commandType.getValue()) //
.put(getBodyLength()) //
.putInt(1229869870); // FIXME ?? was: byte array of int 777211465 converted to little endian
.putInt(nonce);
for (AlertConfiguration configuration : alertConfigurations) {
byteBuffer.put(configuration.getEncoded());
}
@ -44,7 +46,7 @@ public final class ProgramAlertsCommand extends CommandBase {
'}';
}
public static final class Builder extends CommandBase.Builder<Builder, ProgramAlertsCommand> {
public static final class Builder extends NonceEnabledBuilder<Builder, ProgramAlertsCommand> {
private List<AlertConfiguration> alertConfigurations;
public Builder setAlertConfigurations(List<AlertConfiguration> alertConfigurations) {
@ -52,11 +54,11 @@ public final class ProgramAlertsCommand extends CommandBase {
return this;
}
@Override final ProgramAlertsCommand buildCommand() {
@Override protected final ProgramAlertsCommand buildCommand() {
if (this.alertConfigurations == null) {
throw new IllegalArgumentException("alertConfigurations can not be null");
}
return new ProgramAlertsCommand(address, sequenceNumber, multiCommandFlag, alertConfigurations);
return new ProgramAlertsCommand(address, sequenceNumber, multiCommandFlag, alertConfigurations, nonce);
}
}
}

View file

@ -4,102 +4,35 @@ import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ProgramReminder;
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command;
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType;
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.program.InsulinProgramElement;
public final class ProgramBasalCommand extends CommandBase {
private final List<InsulinProgramElement> insulinProgramElements;
private final ProgramReminder programReminder;
private final byte currentHalfOurEntryIndex;
private final short remainingPulsesInCurrentHalfHourEntry;
private final int delayUntilNextTenthPulseInUsec;
// Always preceded by 0x1a ProgramInsulinCommand
public final class ProgramBasalCommand implements Command {
private final List<InsulinProgramElement> uniqueInsulinProgramElements;
private ProgramBasalCommand(int address, short sequenceNumber, boolean multiCommandFlag, ProgramReminder programReminder, List<InsulinProgramElement> insulinProgramElements, byte currentHalfOurEntryIndex, short remainingPulsesInCurrentHalfHourEntry, int delayUntilNextTenthPulseInUsec) {
super(CommandType.PROGRAM_BASAL, address, sequenceNumber, multiCommandFlag);
this.insulinProgramElements = new ArrayList<>(insulinProgramElements);
this.programReminder = programReminder;
this.currentHalfOurEntryIndex = currentHalfOurEntryIndex;
this.remainingPulsesInCurrentHalfHourEntry = remainingPulsesInCurrentHalfHourEntry;
this.delayUntilNextTenthPulseInUsec = delayUntilNextTenthPulseInUsec;
private ProgramBasalCommand(List<InsulinProgramElement> uniqueInsulinProgramElements) {
this.uniqueInsulinProgramElements = new ArrayList<>(uniqueInsulinProgramElements);
}
public short getLength() {
return (short) (uniqueInsulinProgramElements.size() * 2 + 14);
}
public byte getBodyLength() {
return (byte) (insulinProgramElements.size() * 6 + 8);
return (byte) (uniqueInsulinProgramElements.size() * 2 + 12);
}
@Override public byte[] getEncoded() {
ByteBuffer basalCommandBuffer = ByteBuffer.allocate(this.getBodyLength()) //
.put(commandType.getValue()) //
.put(getBodyLength()) //
.put(programReminder.getEncoded()) //
.put(currentHalfOurEntryIndex) //
.putShort(remainingPulsesInCurrentHalfHourEntry) //
.putInt(delayUntilNextTenthPulseInUsec);
for (InsulinProgramElement element : insulinProgramElements) {
basalCommandBuffer.put(element.getEncoded());
}
byte[] basalCommand = basalCommandBuffer.array();
// TODO basal interlock and header
return basalCommand;
return ByteBuffer.allocate(getLength()) //
// TODO
.array();
}
public static final class Builder extends CommandBase.Builder<Builder, ProgramBasalCommand> {
private List<InsulinProgramElement> insulinProgramElements;
private ProgramReminder programReminder;
private Byte currentHalfOurEntryIndex;
private Short remainingPulsesInCurrentHalfHourEntry;
private Integer delayUntilNextTenthPulseInUsec;
public Builder setInsulinProgramElements(List<InsulinProgramElement> insulinProgramElements) {
if (insulinProgramElements == null) {
throw new IllegalArgumentException("insulinProgramElements can not be null");
}
this.insulinProgramElements = new ArrayList<>(insulinProgramElements);
return this;
}
public Builder setProgramReminder(ProgramReminder programReminder) {
this.programReminder = programReminder;
return this;
}
public Builder setCurrentHalfOurEntryIndex(byte currentHalfOurEntryIndex) {
this.currentHalfOurEntryIndex = currentHalfOurEntryIndex;
return this;
}
public Builder setRemainingPulsesInCurrentHalfHourEntry(short remainingPulsesInCurrentHalfHourEntry) {
this.remainingPulsesInCurrentHalfHourEntry = remainingPulsesInCurrentHalfHourEntry;
return this;
}
public Builder setDelayUntilNextTenthPulseInUsec(Integer delayUntilNextTenthPulseInUsec) {
this.delayUntilNextTenthPulseInUsec = delayUntilNextTenthPulseInUsec;
return this;
}
@Override final ProgramBasalCommand buildCommand() {
if (insulinProgramElements == null) {
throw new IllegalArgumentException("insulinProgramElements can not be null");
}
if (programReminder == null) {
throw new IllegalArgumentException("programReminder can not be null");
}
if (currentHalfOurEntryIndex == null) {
throw new IllegalArgumentException("currentHalfOurEntryIndex can not be null");
}
if (remainingPulsesInCurrentHalfHourEntry == null) {
throw new IllegalArgumentException("remainingPulsesInCurrentHalfHourEntry can not be null");
}
if (delayUntilNextTenthPulseInUsec == null) {
throw new IllegalArgumentException("durationUntilNextTenthPulseInUsec can not be null");
}
return new ProgramBasalCommand(address, sequenceNumber, multiCommandFlag, programReminder, insulinProgramElements, currentHalfOurEntryIndex, remainingPulsesInCurrentHalfHourEntry, delayUntilNextTenthPulseInUsec);
}
@Override public CommandType getCommandType() {
return CommandType.PROGRAM_BASAL;
}
// TODO builder
}

View file

@ -0,0 +1,147 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command;
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.definition.ProgramReminder;
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.program.InsulinProgramElement;
// Always followed by one of: 0x13, 0x16, 0x17
public final class ProgramInsulinCommand extends HeaderEnabledCommand {
private final List<InsulinProgramElement> insulinProgramElements;
private final ProgramReminder programReminder;
private final byte currentHalfOurEntryIndex;
private final short remainingPulsesInCurrentHalfHourEntry;
private final int delayUntilNextTenthPulseInUsec;
private final Command interlockCommand;
private static final List<CommandType> ALLOWED_INTERLOCK_COMMANDS = Arrays.asList(
CommandType.PROGRAM_BASAL,
CommandType.PROGRAM_TEMP_BASAL,
CommandType.PROGRAM_BOLUS
);
private ProgramInsulinCommand(int address, short sequenceNumber, boolean multiCommandFlag, ProgramReminder programReminder, List<InsulinProgramElement> insulinProgramElements, byte currentHalfOurEntryIndex, short remainingPulsesInCurrentHalfHourEntry, int delayUntilNextTenthPulseInUsec, Command interlockCommand) {
super(CommandType.PROGRAM_INSULIN, address, sequenceNumber, multiCommandFlag);
this.insulinProgramElements = new ArrayList<>(insulinProgramElements);
this.programReminder = programReminder;
this.currentHalfOurEntryIndex = currentHalfOurEntryIndex;
this.remainingPulsesInCurrentHalfHourEntry = remainingPulsesInCurrentHalfHourEntry;
this.delayUntilNextTenthPulseInUsec = delayUntilNextTenthPulseInUsec;
this.interlockCommand = interlockCommand;
}
public short getLength() {
return (short) (insulinProgramElements.size() * 6 + 10);
}
public byte getBodyLength() {
return (byte) (insulinProgramElements.size() * 6 + 8);
}
@Override public byte[] getEncoded() {
ByteBuffer commandBuffer = ByteBuffer.allocate(this.getLength()) //
.put(commandType.getValue()) //
.put(getBodyLength()) //
.put(programReminder.getEncoded()) //
.put(currentHalfOurEntryIndex) //
.putShort(remainingPulsesInCurrentHalfHourEntry) //
.putInt(delayUntilNextTenthPulseInUsec);
for (InsulinProgramElement element : insulinProgramElements) {
commandBuffer.put(element.getEncoded());
}
byte[] command = commandBuffer.array();
// TODO interlock and header
return command;
}
public static final class ProgramBasalBuilder extends HeaderEnabledBuilder<ProgramBasalBuilder, ProgramInsulinCommand> {
private List<InsulinProgramElement> insulinProgramElements;
private ProgramReminder programReminder;
private Byte currentHalfOurEntryIndex;
private Short remainingPulsesInCurrentHalfHourEntry;
private Integer delayUntilNextTenthPulseInUsec;
private Command interlockCommand;
public ProgramBasalBuilder setInsulinProgramElements(List<InsulinProgramElement> insulinProgramElements) {
if (insulinProgramElements == null) {
throw new IllegalArgumentException("insulinProgramElements can not be null");
}
this.insulinProgramElements = new ArrayList<>(insulinProgramElements);
return this;
}
public ProgramBasalBuilder setProgramReminder(ProgramReminder programReminder) {
this.programReminder = programReminder;
return this;
}
public ProgramBasalBuilder setCurrentHalfOurEntryIndex(byte currentHalfOurEntryIndex) {
this.currentHalfOurEntryIndex = currentHalfOurEntryIndex;
return this;
}
public ProgramBasalBuilder setRemainingPulsesInCurrentHalfHourEntry(short remainingPulsesInCurrentHalfHourEntry) {
this.remainingPulsesInCurrentHalfHourEntry = remainingPulsesInCurrentHalfHourEntry;
return this;
}
public ProgramBasalBuilder setDelayUntilNextTenthPulseInUsec(Integer delayUntilNextTenthPulseInUsec) {
this.delayUntilNextTenthPulseInUsec = delayUntilNextTenthPulseInUsec;
return this;
}
public ProgramBasalBuilder setInterlockCommand(Command interlockCommand) {
if (!ALLOWED_INTERLOCK_COMMANDS.contains(interlockCommand.getCommandType())) {
throw new IllegalArgumentException("Illegal interlock command type");
}
this.interlockCommand = interlockCommand;
return this;
}
@Override protected final ProgramInsulinCommand buildCommand() {
if (insulinProgramElements == null) {
throw new IllegalArgumentException("insulinProgramElements can not be null");
}
if (programReminder == null) {
throw new IllegalArgumentException("programReminder can not be null");
}
if (currentHalfOurEntryIndex == null) {
throw new IllegalArgumentException("currentHalfOurEntryIndex can not be null");
}
if (remainingPulsesInCurrentHalfHourEntry == null) {
throw new IllegalArgumentException("remainingPulsesInCurrentHalfHourEntry can not be null");
}
if (delayUntilNextTenthPulseInUsec == null) {
throw new IllegalArgumentException("durationUntilNextTenthPulseInUsec can not be null");
}
if (interlockCommand == null) {
throw new IllegalArgumentException("interlockCommand can not be null");
}
return new ProgramInsulinCommand(address, sequenceNumber, multiCommandFlag, programReminder, insulinProgramElements, currentHalfOurEntryIndex, remainingPulsesInCurrentHalfHourEntry, delayUntilNextTenthPulseInUsec, interlockCommand);
}
}
@Override public String toString() {
return "ProgramInsulinCommand{" +
"insulinProgramElements=" + insulinProgramElements +
", programReminder=" + programReminder +
", currentHalfOurEntryIndex=" + currentHalfOurEntryIndex +
", remainingPulsesInCurrentHalfHourEntry=" + remainingPulsesInCurrentHalfHourEntry +
", delayUntilNextTenthPulseInUsec=" + delayUntilNextTenthPulseInUsec +
", commandType=" + commandType +
", address=" + address +
", sequenceNumber=" + sequenceNumber +
", multiCommandFlag=" + multiCommandFlag +
'}';
}
}

View file

@ -4,7 +4,10 @@ import java.nio.ByteBuffer;
import java.util.Calendar;
import java.util.Date;
public final class SetUniqueIdCommand extends CommandBase {
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;
public final class SetUniqueIdCommand extends HeaderEnabledCommand {
private static final int DEFAULT_ADDRESS = -1;
private static final short LENGTH = 21;
private static final byte BODY_LENGTH = 19;
@ -59,7 +62,7 @@ public final class SetUniqueIdCommand extends CommandBase {
'}';
}
public static final class Builder extends CommandBase.Builder<Builder, SetUniqueIdCommand> {
public static final class Builder extends HeaderEnabledBuilder<Builder, SetUniqueIdCommand> {
private Integer lotNumber;
private Integer podSequenceNumber;
private Date initializationTime;
@ -79,7 +82,7 @@ public final class SetUniqueIdCommand extends CommandBase {
return this;
}
@Override final SetUniqueIdCommand buildCommand() {
@Override protected final SetUniqueIdCommand buildCommand() {
if (lotNumber == null) {
throw new IllegalArgumentException("lotNumber can not be null");
}

View file

@ -3,16 +3,18 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
import java.nio.ByteBuffer;
import java.util.BitSet;
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.NonceEnabledCommand;
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable;
public final class SilenceAlertsCommand extends CommandBase {
public final class SilenceAlertsCommand extends NonceEnabledCommand {
private static final short LENGTH = (short) 7;
private static final byte BODY_LENGTH = (byte) 5;
private final SilenceAlertCommandParameters parameters;
private SilenceAlertsCommand(int address, short sequenceNumber, boolean multiCommandFlag, SilenceAlertCommandParameters parameters) {
super(CommandType.SILENCE_ALERTS, address, sequenceNumber, multiCommandFlag);
private SilenceAlertsCommand(int address, short sequenceNumber, boolean multiCommandFlag, SilenceAlertCommandParameters parameters, int nonce) {
super(CommandType.SILENCE_ALERTS, address, sequenceNumber, multiCommandFlag, nonce);
this.parameters = parameters;
}
@ -21,7 +23,7 @@ public final class SilenceAlertsCommand extends CommandBase {
.put(encodeHeader(address, sequenceNumber, LENGTH, multiCommandFlag)) //
.put(commandType.getValue()) //
.put(BODY_LENGTH) //
.putInt(1229869870) // FIXME ?? was: byte array of int 777211465 converted to little endian
.putInt(nonce) //
.put(parameters.getEncoded()) //
.array());
}
@ -72,7 +74,7 @@ public final class SilenceAlertsCommand extends CommandBase {
}
}
public static class Builder extends CommandBase.Builder<Builder, SilenceAlertsCommand> {
public static class Builder extends NonceEnabledBuilder<Builder, SilenceAlertsCommand> {
private boolean silenceAutoOffAlert;
private boolean silenceMultiCommandAlert;
private boolean silenceExpirationImminentAlert;
@ -122,8 +124,8 @@ public final class SilenceAlertsCommand extends CommandBase {
return this;
}
@Override SilenceAlertsCommand buildCommand() {
return new SilenceAlertsCommand(address, sequenceNumber, multiCommandFlag, new SilenceAlertCommandParameters(silenceAutoOffAlert, silenceMultiCommandAlert, silenceExpirationImminentAlert, silenceUserSetExpirationAlert, silenceLowReservoirAlert, silenceSuspendInProgressAlert, silenceSuspendEndedAlert, silencePodExpirationAlert));
@Override protected final SilenceAlertsCommand buildCommand() {
return new SilenceAlertsCommand(address, sequenceNumber, multiCommandFlag, new SilenceAlertCommandParameters(silenceAutoOffAlert, silenceMultiCommandAlert, silenceExpirationImminentAlert, silenceUserSetExpirationAlert, silenceLowReservoirAlert, silenceSuspendInProgressAlert, silenceSuspendEndedAlert, silencePodExpirationAlert), nonce);
}
}
}

View file

@ -3,18 +3,21 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
import java.nio.ByteBuffer;
import java.util.BitSet;
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.NonceEnabledCommand;
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType;
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable;
public final class StopDeliveryCommand extends CommandBase {
public final class StopDeliveryCommand extends NonceEnabledCommand {
private static final short LENGTH = 7;
private static final byte BODY_LENGTH = 5;
private final DeliveryType deliveryType;
private final BeepType beepType;
private StopDeliveryCommand(int address, short sequenceNumber, boolean multiCommandFlag, DeliveryType deliveryType, BeepType beepType) {
super(CommandType.STOP_DELIVERY, address, sequenceNumber, multiCommandFlag);
private StopDeliveryCommand(int address, short sequenceNumber, boolean multiCommandFlag, DeliveryType deliveryType, BeepType beepType, int nonce) {
super(CommandType.STOP_DELIVERY, address, sequenceNumber, multiCommandFlag, nonce);
this.deliveryType = deliveryType;
this.beepType = beepType;
}
@ -24,7 +27,7 @@ public final class StopDeliveryCommand extends CommandBase {
.put(encodeHeader(address, sequenceNumber, LENGTH, multiCommandFlag)) //
.put(commandType.getValue()) //
.put(BODY_LENGTH) //
.putInt(1229869870) // FIXME ?? was: byte array of int 777211465 converted to little endian
.putInt(nonce) //
.put((byte) ((beepType.getValue() << 4) | deliveryType.getEncoded()[0])) //
.array());
}
@ -65,7 +68,7 @@ public final class StopDeliveryCommand extends CommandBase {
}
}
public static final class Builder extends CommandBase.Builder<Builder, StopDeliveryCommand> {
public static final class Builder extends NonceEnabledBuilder<Builder, StopDeliveryCommand> {
private DeliveryType deliveryType;
private BeepType beepType = BeepType.LONG_SINGLE_BEEP;
@ -79,14 +82,14 @@ public final class StopDeliveryCommand extends CommandBase {
return this;
}
@Override final StopDeliveryCommand buildCommand() {
@Override protected final StopDeliveryCommand buildCommand() {
if (deliveryType == null) {
throw new IllegalArgumentException("deliveryType can not be null");
}
if (beepType == null) {
throw new IllegalArgumentException("beepType can not be null");
}
return new StopDeliveryCommand(address, sequenceNumber, multiCommandFlag, deliveryType, beepType);
return new StopDeliveryCommand(address, sequenceNumber, multiCommandFlag, deliveryType, beepType, nonce);
}
}

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base;
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable;

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base;
public enum CommandType {
SET_UNIQUE_ID((byte) 0x03),
@ -6,10 +6,10 @@ public enum CommandType {
GET_STATUS((byte) 0x0e),
SILENCE_ALERTS((byte) 0x11),
PROGRAM_BASAL((byte) 0x13),
PROGRAM_TEMP_BASAL((byte) 0x16),
BOLUS((byte) 0x17),
PROGRAM_ALERTS((byte) 0x19),
DELIVERY_INTERLOCK((byte) 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_INSULIN((byte) 0x1a), // Always followed by one of: 0x13, 0x16, 0x17
DEACTIVATE((byte) 0x1c),
PROGRAM_BEEPS((byte) 0x1e),
STOP_DELIVERY((byte) 0x1f);

View file

@ -0,0 +1,76 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base;
import java.nio.ByteBuffer;
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.CrcUtil;
public abstract class HeaderEnabledCommand implements Command {
protected static final short HEADER_LENGTH = 6;
protected final CommandType commandType;
protected final int address;
protected final short sequenceNumber;
protected final boolean multiCommandFlag;
protected HeaderEnabledCommand(CommandType commandType, int address, short sequenceNumber, boolean multiCommandFlag) {
this.commandType = commandType;
this.address = address;
this.sequenceNumber = sequenceNumber;
this.multiCommandFlag = multiCommandFlag;
}
@Override public CommandType getCommandType() {
return commandType;
}
protected static byte[] appendCrc(byte[] command) {
return ByteBuffer.allocate(command.length + 2) //
.put(command) //
.putShort(CrcUtil.createCrc(command)) //
.array();
}
protected static byte[] encodeHeader(int address, short sequenceNumber, short length, boolean multiCommandFlag) {
return ByteBuffer.allocate(6) //
.putInt(address) //
.putShort((short) (((sequenceNumber & 0x0f) << 10) | length | ((multiCommandFlag ? 1 : 0) << 15))) //
.array();
}
protected static abstract class HeaderEnabledBuilder<T extends HeaderEnabledBuilder<T, R>, R extends Command> implements Builder<R> {
protected Integer address;
protected Short sequenceNumber;
protected boolean multiCommandFlag = false;
public R build() {
if (address == null) {
throw new IllegalArgumentException("address can not be null");
}
if (sequenceNumber == null) {
throw new IllegalArgumentException("sequenceNumber can not be null");
}
return buildCommand();
}
public final T setAddress(int address) {
this.address = address;
return (T) this;
}
public final T setSequenceNumber(short sequenceNumber) {
this.sequenceNumber = sequenceNumber;
return (T) this;
}
public final T setMultiCommandFlag(boolean multiCommandFlag) {
this.multiCommandFlag = multiCommandFlag;
return (T) this;
}
protected abstract R buildCommand();
}
protected interface Builder<R extends Command> {
R build();
}
}

View file

@ -0,0 +1,26 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base;
public abstract class NonceEnabledCommand extends HeaderEnabledCommand {
protected final int nonce;
protected NonceEnabledCommand(CommandType commandType, int address, short sequenceNumber, boolean multiCommandFlag, int nonce) {
super(commandType, address, sequenceNumber, multiCommandFlag);
this.nonce = nonce;
}
protected static abstract class NonceEnabledBuilder<T extends NonceEnabledBuilder<T, R>, R extends Command> extends HeaderEnabledBuilder<T, R> {
protected Integer nonce;
public final R build() {
if (nonce == null) {
throw new IllegalArgumentException("nonce can not be null");
}
return super.build();
}
public final T setNonce(int nonce) {
this.nonce = nonce;
return (T) this;
}
}
}

View file

@ -1,9 +0,0 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.interlock;
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable;
public class BasalInterlock implements Encodable {
@Override public byte[] getEncoded() {
return new byte[0];
}
}

View file

@ -16,12 +16,12 @@ public class InsulinProgramElement implements Encodable {
}
@Override public byte[] getEncoded() {
byte firstByte = (byte) ((((numberOfHalfOurEntries - 1) & 0x0f) << 4)
| ((extraAlternatePulse ? 1 : 0) << 3)
byte firstByte = (byte) ((((numberOfHalfOurEntries - 1) & 0x0f) << 4) //
| ((extraAlternatePulse ? 1 : 0) << 3) //
| ((numberOfPulsesPerHalfOurEntry >>> 8) & 0x03));
return ByteBuffer.allocate(2) //
.put(firstByte)
.put(firstByte) //
.put((byte) (numberOfPulsesPerHalfOurEntry & 0xff)) //
.array();
}

View file

@ -12,6 +12,7 @@ public class DeactivateCommandTest {
byte[] encoded = new DeactivateCommand.Builder() //
.setAddress(37879809) //
.setSequenceNumber((short) 5) //
.setNonce(1229869870) //
.build() //
.getEncoded();

View file

@ -26,6 +26,7 @@ public class ProgramAlertsCommandTest {
.setAddress(37879811) //
.setSequenceNumber((short) 3) //
.setMultiCommandFlag(true) //
.setNonce(1229869870) //
.setAlertConfigurations(configurations) //
.build() //
.getEncoded();
@ -41,6 +42,7 @@ public class ProgramAlertsCommandTest {
byte[] encoded = new ProgramAlertsCommand.Builder() //
.setAddress(37879811) //
.setSequenceNumber((short) 8) //
.setNonce(1229869870) //
.setAlertConfigurations(configurations) //
.build() //
.getEncoded();
@ -56,6 +58,7 @@ public class ProgramAlertsCommandTest {
byte[] encoded = new ProgramAlertsCommand.Builder() //
.setAddress(37879811) //
.setSequenceNumber((short) 15) //
.setNonce(1229869870) //
.setAlertConfigurations(configurations) //
.build() //
.getEncoded();
@ -73,6 +76,7 @@ public class ProgramAlertsCommandTest {
.setAddress(37879811) //
.setSequenceNumber((short) 10) //
.setMultiCommandFlag(false) //
.setNonce(1229869870) //
.setAlertConfigurations(configurations) //
.build() //
.getEncoded();

View file

@ -13,7 +13,7 @@ public class SetUniqueIdCommandTest {
public void testEncoding() throws DecoderException {
byte[] encoded = new SetUniqueIdCommand.Builder() //
.setAddress(37879811) //
.setSequenceNumber((short) 6)
.setSequenceNumber((short) 6) //
.setLotNumber(135556289) //
.setPodSequenceNumber(681767) //
.setInitializationTime(new Date(2021, 1, 10, 14, 41)) //

View file

@ -11,7 +11,8 @@ public class SilenceAlertsCommandTest {
public void testSilenceLowReservoirAlert() throws DecoderException {
byte[] encoded = new SilenceAlertsCommand.Builder() //
.setAddress(37879811) //
.setSequenceNumber((short) 1)
.setSequenceNumber((short) 1) //
.setNonce(1229869870) //
.setSilenceLowReservoirAlert(true) //
.build() //
.getEncoded();

View file

@ -14,6 +14,7 @@ public class StopDeliveryCommandTest {
byte[] encoded = new StopDeliveryCommand.Builder() //
.setAddress(37879811) //
.setSequenceNumber((short) 0) //
.setNonce(1229869870) //
.setDeliveryType(StopDeliveryCommand.DeliveryType.TEMP_BASAL) //
.setBeepType(BeepType.LONG_SINGLE_BEEP) //
.build() //
@ -27,6 +28,7 @@ public class StopDeliveryCommandTest {
byte[] encoded = new StopDeliveryCommand.Builder() //
.setAddress(37879811) //
.setSequenceNumber((short) 2) //
.setNonce(1229869870) //
.setDeliveryType(StopDeliveryCommand.DeliveryType.ALL) //
.setBeepType(BeepType.SILENT) //
.build() //