From 323f7ae30e0f05a770df3595100a104ffc88ac2f Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Fri, 12 Feb 2021 17:36:58 +0100 Subject: [PATCH 01/83] Introduce builder for Omnipod Dash commands --- .../dash/driver/pod/command/CommandBase.java | 47 +++++++++-- .../driver/pod/command/DeactivateCommand.java | 16 ++-- .../driver/pod/command/GetVersionCommand.java | 23 +++--- .../pod/command/ProgramAlertsCommand.java | 26 ++++-- .../pod/command/ProgramBasalCommand.java | 52 ++++++++++++ .../pod/command/SetUniqueIdCommand.java | 44 +++++++++-- .../pod/command/SilenceAlertsCommand.java | 79 +++++++++++++++++-- .../pod/command/StopDeliveryCommand.java | 45 ++++++++++- .../pod/command/interlock/BasalInterlock.java | 4 + .../pod/definition/ProgramReminder.java | 19 +++++ .../program/InsulinProgramElement.java | 26 ++++++ .../pod/command/DeactivateCommandTest.java | 5 +- .../pod/command/GetVersionCommandTest.java | 5 +- .../pod/command/ProgramAlertsCommandTest.java | 30 ++++++- .../pod/command/SetUniqueIdCommandTest.java | 8 +- .../pod/command/SilenceAlertsCommandTest.java | 6 +- .../pod/command/StopDeliveryCommandTest.java | 14 +++- 17 files changed, 396 insertions(+), 53 deletions(-) create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/interlock/BasalInterlock.java create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/ProgramReminder.java create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/program/InsulinProgramElement.java diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/CommandBase.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/CommandBase.java index e871c07827..637128ceec 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/CommandBase.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/CommandBase.java @@ -13,13 +13,13 @@ abstract class CommandBase implements Command { final CommandType commandType; final int address; final short sequenceNumber; - final boolean unknown; + final boolean multiCommandFlag; - CommandBase(CommandType commandType, int address, short sequenceNumber, boolean unknown) { + CommandBase(CommandType commandType, int address, short sequenceNumber, boolean multiCommandFlag) { this.commandType = commandType; this.address = address; this.sequenceNumber = sequenceNumber; - this.unknown = unknown; + this.multiCommandFlag = multiCommandFlag; } @Override public CommandType getCommandType() { @@ -34,8 +34,8 @@ abstract class CommandBase implements Command { return sequenceNumber; } - public boolean isUnknown() { - return unknown; + public boolean isMultiCommandFlag() { + return multiCommandFlag; } static byte[] formatCommand(byte[] command) { @@ -75,10 +75,43 @@ abstract class CommandBase implements Command { .array(); } - static byte[] encodeHeader(int address, short sequenceNumber, short length, boolean unknown) { + static byte[] encodeHeader(int address, short sequenceNumber, short length, boolean multiCommandFlag) { return ByteBuffer.allocate(6) // .putInt(address) // - .putShort((short) (((sequenceNumber & 0x0f) << 10) | length | ((unknown ? 1 : 0) << 15))) // + .putShort((short) (((sequenceNumber & 0x0f) << 10) | length | ((multiCommandFlag ? 1 : 0) << 15))) // .array(); } + + static abstract class Builder, 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(); + } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommand.java index 57f32dcdb1..813f64c22f 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommand.java @@ -2,17 +2,17 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command; import java.nio.ByteBuffer; -public class DeactivateCommand extends CommandBase { +public final class DeactivateCommand extends CommandBase { private static final short LENGTH = 6; private static final byte BODY_LENGTH = 4; - DeactivateCommand(int address, short sequenceNumber, boolean unknown) { - super(CommandType.DEACTIVATE, address, sequenceNumber, unknown); + private DeactivateCommand(int address, short sequenceNumber, boolean multiCommandFlag) { + super(CommandType.DEACTIVATE, address, sequenceNumber, multiCommandFlag); } @Override public byte[] getEncoded() { return appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) // - .put(encodeHeader(address, sequenceNumber, LENGTH, unknown)) // + .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 @@ -24,7 +24,13 @@ public class DeactivateCommand extends CommandBase { "commandType=" + commandType + ", address=" + address + ", sequenceNumber=" + sequenceNumber + - ", unknown=" + unknown + + ", multiCommandFlag=" + multiCommandFlag + '}'; } + + public static final class Builder extends CommandBase.Builder { + @Override final DeactivateCommand buildCommand() { + return new DeactivateCommand(address, sequenceNumber, multiCommandFlag); + } + } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommand.java index b1e2296f48..f6426a44a9 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommand.java @@ -2,22 +2,19 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command; import java.nio.ByteBuffer; -public class GetVersionCommand extends CommandBase { - private static final int DEFAULT_ADDRESS = -1; +public final class GetVersionCommand extends CommandBase { + public static final int DEFAULT_ADDRESS = -1; // FIXME move + private static final short LENGTH = 6; private static final byte BODY_LENGTH = 4; - public GetVersionCommand(short sequenceNumber, boolean unknown) { - this(DEFAULT_ADDRESS, sequenceNumber, unknown); - } - - public GetVersionCommand(int address, short sequenceNumber, boolean unknown) { - super(CommandType.GET_VERSION, address, sequenceNumber, unknown); + private GetVersionCommand(int address, short sequenceNumber, boolean multiCommandFlag) { + super(CommandType.GET_VERSION, address, sequenceNumber, multiCommandFlag); } @Override public byte[] getEncoded() { return appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) // - .put(encodeHeader(address, sequenceNumber, LENGTH, unknown)) // + .put(encodeHeader(address, sequenceNumber, LENGTH, multiCommandFlag)) // .put(commandType.getValue()) // .put(BODY_LENGTH) // .putInt(address) // @@ -29,7 +26,13 @@ public class GetVersionCommand extends CommandBase { "commandType=" + commandType + ", address=" + address + ", sequenceNumber=" + sequenceNumber + - ", unknown=" + unknown + + ", multiCommandFlag=" + multiCommandFlag + '}'; } + + public static final class Builder extends CommandBase.Builder { + @Override final GetVersionCommand buildCommand() { + return new GetVersionCommand(address, sequenceNumber, multiCommandFlag); + } + } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.java index 8950e8a7e1..ceed5c6a3b 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.java @@ -6,17 +6,17 @@ import java.util.List; import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertConfiguration; -public class ProgramAlertsCommand extends CommandBase { +public final class ProgramAlertsCommand extends CommandBase { private final List alertConfigurations; - ProgramAlertsCommand(int address, short sequenceNumber, boolean unknown, List alertConfigurations) { - super(CommandType.PROGRAM_ALERTS, address, sequenceNumber, unknown); + private ProgramAlertsCommand(int address, short sequenceNumber, boolean multiCommandFlag, List alertConfigurations) { + super(CommandType.PROGRAM_ALERTS, address, sequenceNumber, multiCommandFlag); this.alertConfigurations = new ArrayList<>(alertConfigurations); } @Override public byte[] getEncoded() { ByteBuffer byteBuffer = ByteBuffer.allocate(getLength() + HEADER_LENGTH) // - .put(encodeHeader(address, sequenceNumber, getLength(), unknown)) // + .put(encodeHeader(address, sequenceNumber, getLength(), multiCommandFlag)) // .put(commandType.getValue()) // .put(getBodyLength()) // .putInt(1229869870); // FIXME ?? was: byte array of int 777211465 converted to little endian @@ -40,7 +40,23 @@ public class ProgramAlertsCommand extends CommandBase { ", commandType=" + commandType + ", address=" + address + ", sequenceNumber=" + sequenceNumber + - ", unknown=" + unknown + + ", multiCommandFlag=" + multiCommandFlag + '}'; } + + public static final class Builder extends CommandBase.Builder { + private List alertConfigurations; + + public Builder setAlertConfigurations(List alertConfigurations) { + this.alertConfigurations = alertConfigurations; + return this; + } + + @Override final ProgramAlertsCommand buildCommand() { + if (this.alertConfigurations == null) { + throw new IllegalArgumentException("alertConfigurations can not be null"); + } + return new ProgramAlertsCommand(address, sequenceNumber, multiCommandFlag, alertConfigurations); + } + } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java new file mode 100644 index 0000000000..ea9863ae75 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java @@ -0,0 +1,52 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command; + +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.definition.program.InsulinProgramElement; + +public final class ProgramBasalCommand extends CommandBase { + private final List insulinProgramElements; + + private ProgramBasalCommand(int address, short sequenceNumber, boolean multiCommandFlag, ProgramReminder programReminder, List insulinProgramElements) { + super(CommandType.PROGRAM_BASAL, address, sequenceNumber, multiCommandFlag); + this.insulinProgramElements = new ArrayList<>(insulinProgramElements); + this.programReminder = programReminder; + } + + private final ProgramReminder programReminder; + + @Override public byte[] getEncoded() { + return new byte[0]; + } + + public static final class Builder extends CommandBase.Builder { + private List insulinProgramElements; + private ProgramReminder programReminder; + + public Builder setInsulinProgramElements(List 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; + } + + @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"); + } + return new ProgramBasalCommand(address, sequenceNumber, multiCommandFlag, programReminder, insulinProgramElements); + } + } + +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommand.java index c4849e1fd6..fae43f9119 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommand.java @@ -4,7 +4,7 @@ import java.nio.ByteBuffer; import java.util.Calendar; import java.util.Date; -public class SetUniqueIdCommand extends CommandBase { +public final class SetUniqueIdCommand extends CommandBase { private static final int DEFAULT_ADDRESS = -1; private static final short LENGTH = 21; private static final byte BODY_LENGTH = 19; @@ -13,8 +13,8 @@ public class SetUniqueIdCommand extends CommandBase { private final int podSequenceNumber; private final Date initializationTime; - SetUniqueIdCommand(int address, short sequenceNumber, int lotNumber, int podSequenceNumber, Date initializationTime, boolean unknown) { - super(CommandType.SET_UNIQUE_ID, address, sequenceNumber, unknown); + private SetUniqueIdCommand(int address, short sequenceNumber, boolean multiCommandFlag, int lotNumber, int podSequenceNumber, Date initializationTime) { + super(CommandType.SET_UNIQUE_ID, address, sequenceNumber, multiCommandFlag); this.lotNumber = lotNumber; this.podSequenceNumber = podSequenceNumber; this.initializationTime = initializationTime; @@ -22,7 +22,7 @@ public class SetUniqueIdCommand extends CommandBase { @Override public byte[] getEncoded() { return appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) // - .put(encodeHeader(DEFAULT_ADDRESS, sequenceNumber, LENGTH, unknown)) // + .put(encodeHeader(DEFAULT_ADDRESS, sequenceNumber, LENGTH, multiCommandFlag)) // .put(commandType.getValue()) // .put(BODY_LENGTH) // .putInt(address) // @@ -55,7 +55,41 @@ public class SetUniqueIdCommand extends CommandBase { ", commandType=" + commandType + ", address=" + address + ", sequenceNumber=" + sequenceNumber + - ", unknown=" + unknown + + ", multiCommandFlag=" + multiCommandFlag + '}'; } + + public static final class Builder extends CommandBase.Builder { + private Integer lotNumber; + private Integer podSequenceNumber; + private Date initializationTime; + + public Builder setLotNumber(int lotNumber) { + this.lotNumber = lotNumber; + return this; + } + + public Builder setPodSequenceNumber(int podSequenceNumber) { + this.podSequenceNumber = podSequenceNumber; + return this; + } + + public Builder setInitializationTime(Date initializationTime) { + this.initializationTime = initializationTime; + return this; + } + + @Override final SetUniqueIdCommand buildCommand() { + if (lotNumber == null) { + throw new IllegalArgumentException("lotNumber can not be null"); + } + if (podSequenceNumber == null) { + throw new IllegalArgumentException("podSequenceNumber can not be null"); + } + if (initializationTime == null) { + throw new IllegalArgumentException("initializationTime can not be null"); + } + return new SetUniqueIdCommand(address, sequenceNumber, multiCommandFlag, lotNumber, podSequenceNumber, initializationTime); + } + } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java index bb2609846f..dd8f03fc97 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java @@ -3,20 +3,20 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command; import java.nio.ByteBuffer; import java.util.BitSet; -public class SilenceAlertsCommand extends CommandBase { +public final class SilenceAlertsCommand extends CommandBase { private static final short LENGTH = (short) 7; private static final byte BODY_LENGTH = (byte) 5; private final SilenceAlertCommandParameters parameters; - public SilenceAlertsCommand(int address, short sequenceNumber, boolean unknown, SilenceAlertCommandParameters parameters) { - super(CommandType.SILENCE_ALERTS, address, sequenceNumber, unknown); + private SilenceAlertsCommand(int address, short sequenceNumber, boolean multiCommandFlag, SilenceAlertCommandParameters parameters) { + super(CommandType.SILENCE_ALERTS, address, sequenceNumber, multiCommandFlag); this.parameters = parameters; } @Override public byte[] getEncoded() { return appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) // - .put(encodeHeader(address, sequenceNumber, LENGTH, unknown)) // + .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 @@ -24,7 +24,17 @@ public class SilenceAlertsCommand extends CommandBase { .array()); } - public static final class SilenceAlertCommandParameters { + @Override public String toString() { + return "SilenceAlertsCommand{" + + "parameters=" + parameters + + ", commandType=" + commandType + + ", address=" + address + + ", sequenceNumber=" + sequenceNumber + + ", multiCommandFlag=" + multiCommandFlag + + '}'; + } + + private static final class SilenceAlertCommandParameters { private final boolean silenceAutoOffAlert; private final boolean silenceMultiCommandAlert; private final boolean silenceExpirationImminentAlert; @@ -34,7 +44,7 @@ public class SilenceAlertsCommand extends CommandBase { private final boolean silenceSuspendEndedAlert; private final boolean silencePodExpirationAlert; - public SilenceAlertCommandParameters(boolean silenceAutoOffAlert, boolean silenceMultiCommandAlert, boolean silenceExpirationImminentAlert, boolean silenceUserSetExpirationAlert, boolean silenceLowReservoirAlert, boolean silenceSuspendInProgressAlert, boolean silenceSuspendEndedAlert, boolean silencePodExpirationAlert) { + private SilenceAlertCommandParameters(boolean silenceAutoOffAlert, boolean silenceMultiCommandAlert, boolean silenceExpirationImminentAlert, boolean silenceUserSetExpirationAlert, boolean silenceLowReservoirAlert, boolean silenceSuspendInProgressAlert, boolean silenceSuspendEndedAlert, boolean silencePodExpirationAlert) { this.silenceAutoOffAlert = silenceAutoOffAlert; this.silenceMultiCommandAlert = silenceMultiCommandAlert; this.silenceExpirationImminentAlert = silenceExpirationImminentAlert; @@ -45,7 +55,7 @@ public class SilenceAlertsCommand extends CommandBase { this.silencePodExpirationAlert = silencePodExpirationAlert; } - public byte[] getEncoded() { + private byte[] getEncoded() { BitSet bitSet = new BitSet(8); bitSet.set(0, this.silenceAutoOffAlert); bitSet.set(1, this.silenceMultiCommandAlert); @@ -58,4 +68,59 @@ public class SilenceAlertsCommand extends CommandBase { return bitSet.toByteArray(); } } + + public static class Builder extends CommandBase.Builder { + private boolean silenceAutoOffAlert; + private boolean silenceMultiCommandAlert; + private boolean silenceExpirationImminentAlert; + private boolean silenceUserSetExpirationAlert; + private boolean silenceLowReservoirAlert; + private boolean silenceSuspendInProgressAlert; + private boolean silenceSuspendEndedAlert; + private boolean silencePodExpirationAlert; + + public Builder setSilenceAutoOffAlert(boolean silenceAutoOffAlert) { + this.silenceAutoOffAlert = silenceAutoOffAlert; + return this; + } + + public Builder setSilenceMultiCommandAlert(boolean silenceMultiCommandAlert) { + this.silenceMultiCommandAlert = silenceMultiCommandAlert; + return this; + } + + public Builder setSilenceExpirationImminentAlert(boolean silenceExpirationImminentAlert) { + this.silenceExpirationImminentAlert = silenceExpirationImminentAlert; + return this; + } + + public Builder setSilenceUserSetExpirationAlert(boolean silenceUserSetExpirationAlert) { + this.silenceUserSetExpirationAlert = silenceUserSetExpirationAlert; + return this; + } + + public Builder setSilenceLowReservoirAlert(boolean silenceLowReservoirAlert) { + this.silenceLowReservoirAlert = silenceLowReservoirAlert; + return this; + } + + public Builder setSilenceSuspendInProgressAlert(boolean silenceSuspendInProgressAlert) { + this.silenceSuspendInProgressAlert = silenceSuspendInProgressAlert; + return this; + } + + public Builder setSilenceSuspendEndedAlert(boolean silenceSuspendEndedAlert) { + this.silenceSuspendEndedAlert = silenceSuspendEndedAlert; + return this; + } + + public Builder setSilencePodExpirationAlert(boolean silencePodExpirationAlert) { + this.silencePodExpirationAlert = silencePodExpirationAlert; + return this; + } + + @Override SilenceAlertsCommand buildCommand() { + return new SilenceAlertsCommand(address, sequenceNumber, multiCommandFlag, new SilenceAlertCommandParameters(silenceAutoOffAlert, silenceMultiCommandAlert, silenceExpirationImminentAlert, silenceUserSetExpirationAlert, silenceLowReservoirAlert, silenceSuspendInProgressAlert, silenceSuspendEndedAlert, silencePodExpirationAlert)); + } + } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java index 99cc1da256..b6aa2b97b8 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java @@ -5,22 +5,22 @@ import java.util.BitSet; import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType; -public class StopDeliveryCommand extends CommandBase { +public final class StopDeliveryCommand extends CommandBase { private static final short LENGTH = 7; private static final byte BODY_LENGTH = 5; private final DeliveryType deliveryType; private final BeepType beepType; - public StopDeliveryCommand(int address, short sequenceNumber, boolean unknown, DeliveryType deliveryType, BeepType beepType) { - super(CommandType.STOP_DELIVERY, address, sequenceNumber, unknown); + private StopDeliveryCommand(int address, short sequenceNumber, boolean multiCommandFlag, DeliveryType deliveryType, BeepType beepType) { + super(CommandType.STOP_DELIVERY, address, sequenceNumber, multiCommandFlag); this.deliveryType = deliveryType; this.beepType = beepType; } @Override public byte[] getEncoded() { return appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) // - .put(encodeHeader(address, sequenceNumber, LENGTH, unknown)) // + .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 @@ -28,6 +28,17 @@ public class StopDeliveryCommand extends CommandBase { .array()); } + @Override public String toString() { + return "StopDeliveryCommand{" + + "deliveryType=" + deliveryType + + ", beepType=" + beepType + + ", commandType=" + commandType + + ", address=" + address + + ", sequenceNumber=" + sequenceNumber + + ", multiCommandFlag=" + multiCommandFlag + + '}'; + } + public enum DeliveryType { BASAL(true, false, false), TEMP_BASAL(false, true, false), @@ -52,4 +63,30 @@ public class StopDeliveryCommand extends CommandBase { return bitSet.toByteArray()[0]; } } + + public static final class Builder extends CommandBase.Builder { + private DeliveryType deliveryType; + private BeepType beepType = BeepType.LONG_SINGLE_BEEP; + + public Builder setDeliveryType(DeliveryType deliveryType) { + this.deliveryType = deliveryType; + return this; + } + + public Builder setBeepType(BeepType beepType) { + this.beepType = beepType; + return this; + } + + @Override final StopDeliveryCommand buildCommand() { + if (this.deliveryType == null) { + throw new IllegalArgumentException("deliveryType can not be null"); + } + if (this.deliveryType == null) { + throw new IllegalArgumentException("beepType can not be null"); + } + return new StopDeliveryCommand(address, sequenceNumber, multiCommandFlag, deliveryType, beepType); + } + } + } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/interlock/BasalInterlock.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/interlock/BasalInterlock.java new file mode 100644 index 0000000000..32c5c00fd6 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/interlock/BasalInterlock.java @@ -0,0 +1,4 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.interlock; + +public class BasalInterlock { +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/ProgramReminder.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/ProgramReminder.java new file mode 100644 index 0000000000..8daf6fa609 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/ProgramReminder.java @@ -0,0 +1,19 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition; + +public class ProgramReminder { + private final boolean atStart; + private final boolean atEnd; + private final byte atInterval; + + public ProgramReminder(boolean atStart, boolean atEnd, byte atIntervalInMinutes) { + this.atStart = atStart; + this.atEnd = atEnd; + this.atInterval = atIntervalInMinutes; + } + + public byte getEncoded() { + return (byte) (((this.atStart ? 0 : 1) << 7) + | ((this.atEnd ? 0 : 1) << 6) + | (this.atInterval & 0x3f)); + } +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/program/InsulinProgramElement.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/program/InsulinProgramElement.java new file mode 100644 index 0000000000..2ffea46ec1 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/program/InsulinProgramElement.java @@ -0,0 +1,26 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.program; + +import java.nio.ByteBuffer; + +public class InsulinProgramElement { + private final byte numberOfHalfOurEntries; // 4 bits + private final short numberOfPulsesPerHalfOurEntry; // 10 bits + private final boolean extraAlternatePulse; + + public InsulinProgramElement(byte numberOfHalfOurEntries, short numberOfPulsesPerHalfOurEntry, boolean extraAlternatePulse) { + this.numberOfHalfOurEntries = numberOfHalfOurEntries; + this.numberOfPulsesPerHalfOurEntry = numberOfPulsesPerHalfOurEntry; + this.extraAlternatePulse = extraAlternatePulse; + } + + public byte[] getEncoded() { + byte firstByte = (byte) ((((numberOfHalfOurEntries - 1) & 0x0f) << 4) + | ((extraAlternatePulse ? 1 : 0) << 3) + | ((numberOfPulsesPerHalfOurEntry >>> 8) & 0x03)); + + return ByteBuffer.allocate(2) // + .put(firstByte) + .put((byte) (numberOfPulsesPerHalfOurEntry & 0xff)) // + .array(); + } +} diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommandTest.java b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommandTest.java index b0b4b5380b..a84b03cf58 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommandTest.java +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommandTest.java @@ -9,7 +9,10 @@ import static org.junit.Assert.assertArrayEquals; public class DeactivateCommandTest { @Test public void testEncoding() throws DecoderException { - byte[] encoded = new DeactivateCommand(37879809, (short) 5, false) // + byte[] encoded = new DeactivateCommand.Builder() // + .setAddress(37879809) // + .setSequenceNumber((short) 5) // + .build() // .getEncoded(); assertArrayEquals(Hex.decodeHex("0242000114061C04494E532E001C"), encoded); diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommandTest.java b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommandTest.java index 5750932ffa..46a31bca97 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommandTest.java +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommandTest.java @@ -9,7 +9,10 @@ import static org.junit.Assert.assertArrayEquals; public class GetVersionCommandTest { @Test public void testEncoding() throws DecoderException { - byte[] encoded = new GetVersionCommand((short) 0, false) // + byte[] encoded = new GetVersionCommand.Builder() // + .setSequenceNumber((short) 0) // + .setAddress(GetVersionCommand.DEFAULT_ADDRESS) // + .build() // .getEncoded(); assertArrayEquals(Hex.decodeHex("FFFFFFFF00060704FFFFFFFF82B2"), encoded); diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommandTest.java b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommandTest.java index f054efc0eb..9b2ba193fe 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommandTest.java +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommandTest.java @@ -22,7 +22,13 @@ public class ProgramAlertsCommandTest { configurations.add(new AlertConfiguration(AlertSlot.EXPIRATION, true, (short) 420, false, AlertTriggerType.TIME_TRIGGER, (short) 4305, BeepType.FOUR_TIMES_BIP_BEEP, BeepRepetitionType.XXX3)); configurations.add(new AlertConfiguration(AlertSlot.EXPIRATION_IMMINENT, true, (short) 0, false, AlertTriggerType.TIME_TRIGGER, (short) 4725, BeepType.FOUR_TIMES_BIP_BEEP, BeepRepetitionType.XXX4)); - byte[] encoded = new ProgramAlertsCommand(37879811, (short) 3, true, configurations).getEncoded(); + byte[] encoded = new ProgramAlertsCommand.Builder() // + .setAddress(37879811) // + .setSequenceNumber((short) 3) // + .setMultiCommandFlag(true) // + .setAlertConfigurations(configurations) // + .build() // + .getEncoded(); assertArrayEquals(Hex.decodeHex("024200038C121910494E532E79A410D1050228001275060280F5"), encoded); } @@ -32,7 +38,12 @@ public class ProgramAlertsCommandTest { List configurations = new ArrayList<>(); configurations.add(new AlertConfiguration(AlertSlot.LOW_RESERVOIR, true, (short) 0, false, AlertTriggerType.RESERVOIR_VOLUME_TRIGGER, (short) 200, BeepType.FOUR_TIMES_BIP_BEEP, BeepRepetitionType.XXX)); - byte[] encoded = new ProgramAlertsCommand(37879811, (short) 8, false, configurations).getEncoded(); + byte[] encoded = new ProgramAlertsCommand.Builder() // + .setAddress(37879811) // + .setSequenceNumber((short) 8) // + .setAlertConfigurations(configurations) // + .build() // + .getEncoded(); assertArrayEquals(Hex.decodeHex("02420003200C190A494E532E4C0000C801020149"), encoded); } @@ -42,7 +53,12 @@ public class ProgramAlertsCommandTest { List configurations = new ArrayList<>(); configurations.add(new AlertConfiguration(AlertSlot.USER_SET_EXPIRATION, true, (short) 0, false, AlertTriggerType.TIME_TRIGGER, (short) 4079, BeepType.FOUR_TIMES_BIP_BEEP, BeepRepetitionType.XXX2)); - byte[] encoded = new ProgramAlertsCommand(37879811, (short) 15, false, configurations).getEncoded(); + byte[] encoded = new ProgramAlertsCommand.Builder() // + .setAddress(37879811) // + .setSequenceNumber((short) 15) // + .setAlertConfigurations(configurations) // + .build() // + .getEncoded(); assertArrayEquals(Hex.decodeHex("024200033C0C190A494E532E38000FEF030203E2"), encoded); } @@ -53,7 +69,13 @@ public class ProgramAlertsCommandTest { List configurations = new ArrayList<>(); configurations.add(new AlertConfiguration(AlertSlot.EXPIRATION, true, (short) 55, false, AlertTriggerType.TIME_TRIGGER, (short) 5, BeepType.FOUR_TIMES_BIP_BEEP, BeepRepetitionType.XXX5)); - byte[] encoded = new ProgramAlertsCommand(37879811, (short) 10, false, configurations).getEncoded(); + byte[] encoded = new ProgramAlertsCommand.Builder() // + .setAddress(37879811) // + .setSequenceNumber((short) 10) // + .setMultiCommandFlag(false) // + .setAlertConfigurations(configurations) // + .build() // + .getEncoded(); assertArrayEquals(Hex.decodeHex("02420003280C190A494E532E7837000508020356"), encoded); } diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommandTest.java b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommandTest.java index 055f215e5d..7c6c4c1895 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommandTest.java +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommandTest.java @@ -11,7 +11,13 @@ import static org.junit.Assert.assertArrayEquals; public class SetUniqueIdCommandTest { @Test public void testEncoding() throws DecoderException { - byte[] encoded = new SetUniqueIdCommand(37879811, (short) 6, 135556289, 681767, new Date(2021, 1, 10, 14, 41), false) // + byte[] encoded = new SetUniqueIdCommand.Builder() // + .setAddress(37879811) // + .setSequenceNumber((short) 6) + .setLotNumber(135556289) // + .setPodSequenceNumber(681767) // + .setInitializationTime(new Date(2021, 1, 10, 14, 41)) // + .build() // .getEncoded(); assertArrayEquals(Hex.decodeHex("FFFFFFFF18150313024200031404020A150E2908146CC1000A67278344"), encoded); diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommandTest.java b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommandTest.java index 57d9ad20fb..0be759b03a 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommandTest.java +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommandTest.java @@ -9,7 +9,11 @@ import static org.junit.Assert.assertArrayEquals; public class SilenceAlertsCommandTest { @Test public void testSilenceLowReservoirAlert() throws DecoderException { - byte[] encoded = new SilenceAlertsCommand(37879811, (short) 1, false, new SilenceAlertsCommand.SilenceAlertCommandParameters(false, false, false, false, true, false, false, false)) // + byte[] encoded = new SilenceAlertsCommand.Builder() // + .setAddress(37879811) // + .setSequenceNumber((short) 1) + .setSilenceLowReservoirAlert(true) // + .build() // .getEncoded(); assertArrayEquals(Hex.decodeHex("0242000304071105494E532E1081CE"), encoded); diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommandTest.java b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommandTest.java index 35fa7e63a3..4277ba3711 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommandTest.java +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommandTest.java @@ -11,7 +11,12 @@ import static org.junit.Assert.assertArrayEquals; public class StopDeliveryCommandTest { @Test public void testStopTempBasal() throws DecoderException { - byte[] encoded = new StopDeliveryCommand(37879811, (short) 0, false, StopDeliveryCommand.DeliveryType.TEMP_BASAL, BeepType.LONG_SINGLE_BEEP) // + byte[] encoded = new StopDeliveryCommand.Builder() // + .setAddress(37879811) // + .setSequenceNumber((short) 0) // + .setDeliveryType(StopDeliveryCommand.DeliveryType.TEMP_BASAL) // + .setBeepType(BeepType.LONG_SINGLE_BEEP) // + .build() // .getEncoded(); assertArrayEquals(Hex.decodeHex("0242000300071F05494E532E6201B1"), encoded); @@ -19,7 +24,12 @@ public class StopDeliveryCommandTest { @Test public void testSuspendDelivery() throws DecoderException { - byte[] encoded = new StopDeliveryCommand(37879811, (short) 2, false, StopDeliveryCommand.DeliveryType.ALL, BeepType.SILENT) // + byte[] encoded = new StopDeliveryCommand.Builder() // + .setAddress(37879811) // + .setSequenceNumber((short) 2) // + .setDeliveryType(StopDeliveryCommand.DeliveryType.ALL) // + .setBeepType(BeepType.SILENT) // + .build() // .getEncoded(); assertArrayEquals(Hex.decodeHex("0242000308071F05494E532E078287"), encoded); From e2e2c579d4137aeca45ffcd4fb2a7b757ab66442 Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Fri, 12 Feb 2021 20:17:12 +0100 Subject: [PATCH 02/83] Small fix --- .../omnipod/dash/driver/pod/command/StopDeliveryCommand.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java index b6aa2b97b8..698163a2cf 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java @@ -79,10 +79,10 @@ public final class StopDeliveryCommand extends CommandBase { } @Override final StopDeliveryCommand buildCommand() { - if (this.deliveryType == null) { + if (deliveryType == null) { throw new IllegalArgumentException("deliveryType can not be null"); } - if (this.deliveryType == null) { + if (beepType == null) { throw new IllegalArgumentException("beepType can not be null"); } return new StopDeliveryCommand(address, sequenceNumber, multiCommandFlag, deliveryType, beepType); From d944df725f15283e6f4d07e96e58e21b2732cd86 Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Fri, 12 Feb 2021 21:06:10 +0100 Subject: [PATCH 03/83] WIP on ProgramBasalCommand --- .../pod/command/ProgramBasalCommand.java | 61 +++++++++++++++++-- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java index ea9863ae75..492f1fca55 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java @@ -1,5 +1,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; @@ -8,22 +9,50 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definitio public final class ProgramBasalCommand extends CommandBase { private final List insulinProgramElements; + private final ProgramReminder programReminder; + private final byte currentHalfOurEntryIndex; + private final short remainingPulsesInCurrentHalfHourEntry; + private final int delayUntilNextTenthPulseInUsec; - private ProgramBasalCommand(int address, short sequenceNumber, boolean multiCommandFlag, ProgramReminder programReminder, List insulinProgramElements) { + private ProgramBasalCommand(int address, short sequenceNumber, boolean multiCommandFlag, ProgramReminder programReminder, List 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 final ProgramReminder programReminder; + public byte getBodyLength() { + return (byte) (insulinProgramElements.size() * 6 + 8); + } @Override public byte[] getEncoded() { - return new byte[0]; + 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; } public static final class Builder extends CommandBase.Builder { private List insulinProgramElements; private ProgramReminder programReminder; + private Byte currentHalfOurEntryIndex; + private Short remainingPulsesInCurrentHalfHourEntry; + private Integer delayUntilNextTenthPulseInUsec; public Builder setInsulinProgramElements(List insulinProgramElements) { if (insulinProgramElements == null) { @@ -38,6 +67,21 @@ public final class ProgramBasalCommand extends CommandBase { 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"); @@ -45,7 +89,16 @@ public final class ProgramBasalCommand extends CommandBase { if (programReminder == null) { throw new IllegalArgumentException("programReminder can not be null"); } - return new ProgramBasalCommand(address, sequenceNumber, multiCommandFlag, programReminder, insulinProgramElements); + 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); } } From d1bf9cefad6fbe168d8cde6c7f21cefa0dbd101b Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Fri, 12 Feb 2021 21:47:16 +0100 Subject: [PATCH 04/83] Add Encodable interface --- .../pump/omnipod/dash/driver/pod/command/Command.java | 6 +++--- .../dash/driver/pod/command/SilenceAlertsCommand.java | 7 +++++-- .../dash/driver/pod/command/StopDeliveryCommand.java | 9 +++++---- .../driver/pod/command/interlock/BasalInterlock.java | 7 ++++++- .../dash/driver/pod/definition/AlertConfiguration.java | 4 ++-- .../omnipod/dash/driver/pod/definition/Encodable.java | 5 +++++ .../dash/driver/pod/definition/ProgramReminder.java | 8 ++++---- .../pod/definition/program/InsulinProgramElement.java | 6 ++++-- 8 files changed, 34 insertions(+), 18 deletions(-) create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/Encodable.java diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/Command.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/Command.java index b05534135e..50f013c280 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/Command.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/Command.java @@ -1,7 +1,7 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command; -public interface Command { - CommandType getCommandType(); +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable; - byte[] getEncoded(); +public interface Command extends Encodable { + CommandType getCommandType(); } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java index dd8f03fc97..bbf9d16b4d 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java @@ -3,6 +3,8 @@ 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.definition.Encodable; + public final class SilenceAlertsCommand extends CommandBase { private static final short LENGTH = (short) 7; private static final byte BODY_LENGTH = (byte) 5; @@ -34,7 +36,7 @@ public final class SilenceAlertsCommand extends CommandBase { '}'; } - private static final class SilenceAlertCommandParameters { + private static final class SilenceAlertCommandParameters implements Encodable { private final boolean silenceAutoOffAlert; private final boolean silenceMultiCommandAlert; private final boolean silenceExpirationImminentAlert; @@ -55,7 +57,8 @@ public final class SilenceAlertsCommand extends CommandBase { this.silencePodExpirationAlert = silencePodExpirationAlert; } - private byte[] getEncoded() { + @Override + public byte[] getEncoded() { BitSet bitSet = new BitSet(8); bitSet.set(0, this.silenceAutoOffAlert); bitSet.set(1, this.silenceMultiCommandAlert); diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java index 698163a2cf..df8ba3e3db 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java @@ -4,6 +4,7 @@ import java.nio.ByteBuffer; import java.util.BitSet; 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 { private static final short LENGTH = 7; @@ -24,7 +25,7 @@ public final class StopDeliveryCommand extends CommandBase { .put(commandType.getValue()) // .put(BODY_LENGTH) // .putInt(1229869870) // FIXME ?? was: byte array of int 777211465 converted to little endian - .put((byte) ((beepType.getValue() << 4) | deliveryType.getEncoded())) // + .put((byte) ((beepType.getValue() << 4) | deliveryType.getEncoded()[0])) // .array()); } @@ -39,7 +40,7 @@ public final class StopDeliveryCommand extends CommandBase { '}'; } - public enum DeliveryType { + public enum DeliveryType implements Encodable { BASAL(true, false, false), TEMP_BASAL(false, true, false), BOLUS(false, false, true), @@ -55,12 +56,12 @@ public final class StopDeliveryCommand extends CommandBase { this.bolus = bolus; } - public byte getEncoded() { + @Override public byte[] getEncoded() { BitSet bitSet = new BitSet(8); bitSet.set(0, this.basal); bitSet.set(1, this.tempBasal); bitSet.set(2, this.bolus); - return bitSet.toByteArray()[0]; + return bitSet.toByteArray(); } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/interlock/BasalInterlock.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/interlock/BasalInterlock.java index 32c5c00fd6..1a76987ac8 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/interlock/BasalInterlock.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/interlock/BasalInterlock.java @@ -1,4 +1,9 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.interlock; -public class BasalInterlock { +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]; + } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/AlertConfiguration.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/AlertConfiguration.java index f620df086d..8a52836d58 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/AlertConfiguration.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/AlertConfiguration.java @@ -2,7 +2,7 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definiti import java.nio.ByteBuffer; -public class AlertConfiguration { +public class AlertConfiguration implements Encodable { private AlertSlot slot; private boolean enabled; private short durationInMinutes; @@ -23,7 +23,7 @@ public class AlertConfiguration { this.beepRepetition = beepRepetition; } - public byte[] getEncoded() { + @Override public byte[] getEncoded() { byte firstByte = (byte) (slot.getValue() << 4); if (enabled) { firstByte |= 1 << 3; diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/Encodable.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/Encodable.java new file mode 100644 index 0000000000..d17d42050f --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/Encodable.java @@ -0,0 +1,5 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition; + +public interface Encodable { + byte[] getEncoded(); +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/ProgramReminder.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/ProgramReminder.java index 8daf6fa609..22b0402e4d 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/ProgramReminder.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/ProgramReminder.java @@ -1,6 +1,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition; -public class ProgramReminder { +public class ProgramReminder implements Encodable { private final boolean atStart; private final boolean atEnd; private final byte atInterval; @@ -11,9 +11,9 @@ public class ProgramReminder { this.atInterval = atIntervalInMinutes; } - public byte getEncoded() { - return (byte) (((this.atStart ? 0 : 1) << 7) + @Override public byte[] getEncoded() { + return new byte[]{(byte) (((this.atStart ? 0 : 1) << 7) | ((this.atEnd ? 0 : 1) << 6) - | (this.atInterval & 0x3f)); + | (this.atInterval & 0x3f))}; } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/program/InsulinProgramElement.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/program/InsulinProgramElement.java index 2ffea46ec1..57f197c4d4 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/program/InsulinProgramElement.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/program/InsulinProgramElement.java @@ -2,7 +2,9 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definiti import java.nio.ByteBuffer; -public class InsulinProgramElement { +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable; + +public class InsulinProgramElement implements Encodable { private final byte numberOfHalfOurEntries; // 4 bits private final short numberOfPulsesPerHalfOurEntry; // 10 bits private final boolean extraAlternatePulse; @@ -13,7 +15,7 @@ public class InsulinProgramElement { this.extraAlternatePulse = extraAlternatePulse; } - public byte[] getEncoded() { + @Override public byte[] getEncoded() { byte firstByte = (byte) ((((numberOfHalfOurEntries - 1) & 0x0f) << 4) | ((extraAlternatePulse ? 1 : 0) << 3) | ((numberOfPulsesPerHalfOurEntry >>> 8) & 0x03)); From 217a17d6318434632b6621169cbe1576a1b4db10 Mon Sep 17 00:00:00 2001 From: Andy Rozman Date: Sat, 13 Feb 2021 17:43:55 +0000 Subject: [PATCH 05/83] - added irish language back into selection box (was removed some time ago) --- app/src/main/res/values/arrays.xml | 3 +++ app/src/main/res/values/strings.xml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 0b02d9a048..da390b8f5b 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -32,6 +32,7 @@ @string/nl_lang @string/es_lang @string/el_lang + @string/ga_lang @string/it_lang @string/ko_lang @string/lt_lang @@ -46,6 +47,7 @@ @string/tr_lang @string/zh_lang + default en @@ -57,6 +59,7 @@ nl es el + ga it ko lt diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2982994458..09bf4b7391 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -11,7 +11,7 @@ Greek Chinese - + Irish Italian Korean From 34553bbcf6dd04efa92cfe7c836ff5eee4565bbd Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Sun, 14 Feb 2021 18:39:18 +0100 Subject: [PATCH 06/83] Refactoring --- .../dash/driver/pod/command/CommandBase.java | 117 -------------- .../driver/pod/command/DeactivateCommand.java | 17 +- .../driver/pod/command/GetVersionCommand.java | 9 +- .../pod/command/ProgramAlertsCommand.java | 16 +- .../pod/command/ProgramBasalCommand.java | 103 +++--------- .../pod/command/ProgramInsulinCommand.java | 147 ++++++++++++++++++ .../pod/command/SetUniqueIdCommand.java | 9 +- .../pod/command/SilenceAlertsCommand.java | 16 +- .../pod/command/StopDeliveryCommand.java | 17 +- .../pod/command/{ => base}/Command.java | 2 +- .../pod/command/{ => base}/CommandType.java | 10 +- .../command/base/HeaderEnabledCommand.java | 76 +++++++++ .../pod/command/base/NonceEnabledCommand.java | 26 ++++ .../pod/command/interlock/BasalInterlock.java | 9 -- .../program/InsulinProgramElement.java | 6 +- .../pod/command/DeactivateCommandTest.java | 1 + .../pod/command/ProgramAlertsCommandTest.java | 4 + .../pod/command/SetUniqueIdCommandTest.java | 2 +- .../pod/command/SilenceAlertsCommandTest.java | 3 +- .../pod/command/StopDeliveryCommandTest.java | 2 + 20 files changed, 336 insertions(+), 256 deletions(-) delete mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/CommandBase.java create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java rename omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/{ => base}/Command.java (91%) rename omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/{ => base}/CommandType.java (62%) create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/HeaderEnabledCommand.java create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/NonceEnabledCommand.java delete mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/interlock/BasalInterlock.java diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/CommandBase.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/CommandBase.java deleted file mode 100644 index 637128ceec..0000000000 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/CommandBase.java +++ /dev/null @@ -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 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, 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(); - } -} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommand.java index 813f64c22f..ff7571bc6d 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommand.java @@ -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 { - @Override final DeactivateCommand buildCommand() { - return new DeactivateCommand(address, sequenceNumber, multiCommandFlag); + public static final class Builder extends NonceEnabledBuilder { + @Override protected final DeactivateCommand buildCommand() { + return new DeactivateCommand(Builder.this.address, sequenceNumber, multiCommandFlag, nonce); } } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommand.java index f6426a44a9..0850c51059 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommand.java @@ -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 { - @Override final GetVersionCommand buildCommand() { + public static final class Builder extends HeaderEnabledBuilder { + @Override protected final GetVersionCommand buildCommand() { return new GetVersionCommand(address, sequenceNumber, multiCommandFlag); } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.java index ceed5c6a3b..46d6695e92 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.java @@ -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 alertConfigurations; - private ProgramAlertsCommand(int address, short sequenceNumber, boolean multiCommandFlag, List alertConfigurations) { - super(CommandType.PROGRAM_ALERTS, address, sequenceNumber, multiCommandFlag); + private ProgramAlertsCommand(int address, short sequenceNumber, boolean multiCommandFlag, List 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 { + public static final class Builder extends NonceEnabledBuilder { private List alertConfigurations; public Builder setAlertConfigurations(List 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); } } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java index 492f1fca55..95601577c0 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java @@ -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 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 uniqueInsulinProgramElements; - private ProgramBasalCommand(int address, short sequenceNumber, boolean multiCommandFlag, ProgramReminder programReminder, List 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 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 { - private List insulinProgramElements; - private ProgramReminder programReminder; - private Byte currentHalfOurEntryIndex; - private Short remainingPulsesInCurrentHalfHourEntry; - private Integer delayUntilNextTenthPulseInUsec; - - public Builder setInsulinProgramElements(List 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 } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java new file mode 100644 index 0000000000..ce841d0476 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java @@ -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 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 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 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 { + private List insulinProgramElements; + private ProgramReminder programReminder; + private Byte currentHalfOurEntryIndex; + private Short remainingPulsesInCurrentHalfHourEntry; + private Integer delayUntilNextTenthPulseInUsec; + private Command interlockCommand; + + public ProgramBasalBuilder setInsulinProgramElements(List 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 + + '}'; + } +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommand.java index fae43f9119..0a8d6086f4 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommand.java @@ -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 { + public static final class Builder extends HeaderEnabledBuilder { 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"); } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java index bbf9d16b4d..83e6e1370f 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java @@ -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 { + public static class Builder extends NonceEnabledBuilder { 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); } } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java index df8ba3e3db..1f1ef1fdce 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java @@ -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 { + public static final class Builder extends NonceEnabledBuilder { 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); } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/Command.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/Command.java similarity index 91% rename from omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/Command.java rename to omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/Command.java index 50f013c280..27f311c394 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/Command.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/Command.java @@ -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; diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/CommandType.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/CommandType.java similarity index 62% rename from omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/CommandType.java rename to omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/CommandType.java index 3df9df23b0..7e520d73c5 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/CommandType.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/CommandType.java @@ -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); diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/HeaderEnabledCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/HeaderEnabledCommand.java new file mode 100644 index 0000000000..bad2de5be4 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/HeaderEnabledCommand.java @@ -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, R extends Command> implements Builder { + 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 build(); + } +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/NonceEnabledCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/NonceEnabledCommand.java new file mode 100644 index 0000000000..f485a495e1 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/NonceEnabledCommand.java @@ -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, R extends Command> extends HeaderEnabledBuilder { + 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; + } + } +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/interlock/BasalInterlock.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/interlock/BasalInterlock.java deleted file mode 100644 index 1a76987ac8..0000000000 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/interlock/BasalInterlock.java +++ /dev/null @@ -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]; - } -} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/program/InsulinProgramElement.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/program/InsulinProgramElement.java index 57f197c4d4..2707efdfcb 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/program/InsulinProgramElement.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/program/InsulinProgramElement.java @@ -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(); } diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommandTest.java b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommandTest.java index a84b03cf58..50f5bb87ed 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommandTest.java +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommandTest.java @@ -12,6 +12,7 @@ public class DeactivateCommandTest { byte[] encoded = new DeactivateCommand.Builder() // .setAddress(37879809) // .setSequenceNumber((short) 5) // + .setNonce(1229869870) // .build() // .getEncoded(); diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommandTest.java b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommandTest.java index 9b2ba193fe..f23b026b2d 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommandTest.java +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommandTest.java @@ -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(); diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommandTest.java b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommandTest.java index 7c6c4c1895..7ba02e1860 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommandTest.java +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommandTest.java @@ -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)) // diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommandTest.java b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommandTest.java index 0be759b03a..674d706560 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommandTest.java +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommandTest.java @@ -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(); diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommandTest.java b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommandTest.java index 4277ba3711..83f94a9e76 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommandTest.java +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommandTest.java @@ -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() // From 69724058097bf62fd55457cdd38587985ea15d69 Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Sun, 14 Feb 2021 19:45:43 +0100 Subject: [PATCH 07/83] WIP on Omnipod Dash set basal --- omnipod-dash/build.gradle | 1 + .../pod/command/ProgramInsulinCommand.java | 122 ++++++++++-------- 2 files changed, 66 insertions(+), 57 deletions(-) diff --git a/omnipod-dash/build.gradle b/omnipod-dash/build.gradle index 66ca373984..8b9f9e4992 100644 --- a/omnipod-dash/build.gradle +++ b/omnipod-dash/build.gradle @@ -44,6 +44,7 @@ dependencies { kapt "com.google.dagger:dagger-android-processor:$dagger_version" kapt "com.google.dagger:dagger-compiler:$dagger_version" + implementation "org.apache.commons:commons-lang3:$commonslang3_version" implementation "commons-codec:commons-codec:$commonscodec_version" implementation "androidx.appcompat:appcompat:$appcompat_version" implementation "com.google.android.material:material:$material_version" diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java index ce841d0476..7732611566 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java @@ -7,17 +7,16 @@ 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.command.base.NonceEnabledCommand; 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 insulinProgramElements; - private final ProgramReminder programReminder; - private final byte currentHalfOurEntryIndex; +public final class ProgramInsulinCommand extends NonceEnabledCommand { + private final List max8HourInsulinProgramElements; + private final byte currentHalfHourEntryIndex; + private final short remainingEighthSecondsInCurrentHalfHourEntry; private final short remainingPulsesInCurrentHalfHourEntry; - private final int delayUntilNextTenthPulseInUsec; + private final DeliveryType deliveryType; private final Command interlockCommand; private static final List ALLOWED_INTERLOCK_COMMANDS = Arrays.asList( @@ -26,34 +25,36 @@ public final class ProgramInsulinCommand extends HeaderEnabledCommand { CommandType.PROGRAM_BOLUS ); - private ProgramInsulinCommand(int address, short sequenceNumber, boolean multiCommandFlag, ProgramReminder programReminder, List 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; + private ProgramInsulinCommand(int address, short sequenceNumber, boolean multiCommandFlag, int nonce, List max8HourInsulinProgramElements, byte currentHalfHourEntryIndex, short remainingEighthSecondsInCurrentHalfHourEntry, short remainingPulsesInCurrentHalfHourEntry, DeliveryType deliveryType, Command interlockCommand) { + super(CommandType.PROGRAM_INSULIN, address, sequenceNumber, multiCommandFlag, nonce); + this.max8HourInsulinProgramElements = new ArrayList<>(max8HourInsulinProgramElements); + this.currentHalfHourEntryIndex = currentHalfHourEntryIndex; + this.remainingEighthSecondsInCurrentHalfHourEntry = remainingEighthSecondsInCurrentHalfHourEntry; this.remainingPulsesInCurrentHalfHourEntry = remainingPulsesInCurrentHalfHourEntry; - this.delayUntilNextTenthPulseInUsec = delayUntilNextTenthPulseInUsec; + this.deliveryType = deliveryType; this.interlockCommand = interlockCommand; } public short getLength() { - return (short) (insulinProgramElements.size() * 6 + 10); + return (short) (max8HourInsulinProgramElements.size() * 6 + 10); } public byte getBodyLength() { - return (byte) (insulinProgramElements.size() * 6 + 8); + return (byte) (max8HourInsulinProgramElements.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); + .putInt(nonce) // + .put(deliveryType.getValue()) // + .putShort(createChecksum()) // + .put(currentHalfHourEntryIndex) // + .putShort(remainingEighthSecondsInCurrentHalfHourEntry) // + .putShort(remainingPulsesInCurrentHalfHourEntry); - for (InsulinProgramElement element : insulinProgramElements) { + for (InsulinProgramElement element : max8HourInsulinProgramElements) { commandBuffer.put(element.getEncoded()); } @@ -64,43 +65,47 @@ public final class ProgramInsulinCommand extends HeaderEnabledCommand { return command; } - public static final class ProgramBasalBuilder extends HeaderEnabledBuilder { - private List insulinProgramElements; - private ProgramReminder programReminder; + private short createChecksum() { + return 0; // TODO + } + + public static final class Builder extends NonceEnabledBuilder { + private List max8HourInsulinProgramElements; private Byte currentHalfOurEntryIndex; + private Short remainingEighthSecondsInCurrentHalfHourEntry; private Short remainingPulsesInCurrentHalfHourEntry; - private Integer delayUntilNextTenthPulseInUsec; + private DeliveryType deliveryType; private Command interlockCommand; - public ProgramBasalBuilder setInsulinProgramElements(List insulinProgramElements) { - if (insulinProgramElements == null) { - throw new IllegalArgumentException("insulinProgramElements can not be null"); + public Builder setMax8HourInsulinProgramElements(List max8HourInsulinProgramElements) { + if (max8HourInsulinProgramElements == null) { + throw new IllegalArgumentException("max8HourInsulinProgramElements can not be null"); } - this.insulinProgramElements = new ArrayList<>(insulinProgramElements); + this.max8HourInsulinProgramElements = new ArrayList<>(max8HourInsulinProgramElements); return this; } - public ProgramBasalBuilder setProgramReminder(ProgramReminder programReminder) { - this.programReminder = programReminder; - return this; - } - - public ProgramBasalBuilder setCurrentHalfOurEntryIndex(byte currentHalfOurEntryIndex) { + public Builder setCurrentHalfOurEntryIndex(byte currentHalfOurEntryIndex) { this.currentHalfOurEntryIndex = currentHalfOurEntryIndex; return this; } - public ProgramBasalBuilder setRemainingPulsesInCurrentHalfHourEntry(short remainingPulsesInCurrentHalfHourEntry) { + public Builder setRemainingEighthSecondsInCurrentHalfHourEntryIndex(short remainingEighthSecondsInCurrentHalfHourEntry) { + this.remainingEighthSecondsInCurrentHalfHourEntry = remainingEighthSecondsInCurrentHalfHourEntry; + return this; + } + + public Builder setRemainingPulsesInCurrentHalfHourEntry(short remainingPulsesInCurrentHalfHourEntry) { this.remainingPulsesInCurrentHalfHourEntry = remainingPulsesInCurrentHalfHourEntry; return this; } - public ProgramBasalBuilder setDelayUntilNextTenthPulseInUsec(Integer delayUntilNextTenthPulseInUsec) { - this.delayUntilNextTenthPulseInUsec = delayUntilNextTenthPulseInUsec; + public Builder setDeliveryType(DeliveryType deliveryType) { + this.deliveryType = deliveryType; return this; } - public ProgramBasalBuilder setInterlockCommand(Command interlockCommand) { + public Builder setInterlockCommand(Command interlockCommand) { if (!ALLOWED_INTERLOCK_COMMANDS.contains(interlockCommand.getCommandType())) { throw new IllegalArgumentException("Illegal interlock command type"); } @@ -109,39 +114,42 @@ public final class ProgramInsulinCommand extends HeaderEnabledCommand { } @Override protected final ProgramInsulinCommand buildCommand() { - if (insulinProgramElements == null) { + if (max8HourInsulinProgramElements == 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 (remainingEighthSecondsInCurrentHalfHourEntry == null) { + throw new IllegalArgumentException("remainingEighthSecondsInCurrentHalfHourEntry 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 (deliveryType == null) { + throw new IllegalArgumentException("deliveryType 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); + return new ProgramInsulinCommand(address, sequenceNumber, multiCommandFlag, nonce, max8HourInsulinProgramElements, currentHalfOurEntryIndex, remainingEighthSecondsInCurrentHalfHourEntry, remainingPulsesInCurrentHalfHourEntry, deliveryType, 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 + - '}'; + public enum DeliveryType { + BASAL((byte) 0x00), + TEMP_BASAL((byte) 0x01), + BOLUS((byte) 0x02); + + private final byte value; + + DeliveryType(byte value) { + this.value = value; + } + + public byte getValue() { + return value; + } } + } From c183a687988d8a9f0751daccd29f821a3406e395 Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Sun, 14 Feb 2021 21:12:22 +0100 Subject: [PATCH 08/83] WIP on Omnipod Dash set basal and some refactoring --- .../driver/pod/command/DeactivateCommand.java | 3 +- .../driver/pod/command/GetVersionCommand.java | 3 +- .../pod/command/ProgramAlertsCommand.java | 3 +- .../pod/command/ProgramBasalCommand.java | 118 ++++++++++++++++-- .../pod/command/ProgramInsulinCommand.java | 97 ++++++++++---- .../pod/command/SetUniqueIdCommand.java | 3 +- .../pod/command/SilenceAlertsCommand.java | 3 +- .../pod/command/StopDeliveryCommand.java | 4 +- .../command/base/HeaderEnabledCommand.java | 36 ------ .../pod/command/base/NonceEnabledCommand.java | 15 --- .../command/base/builder/CommandBuilder.java | 7 ++ .../builder/HeaderEnabledCommandBuilder.java | 36 ++++++ .../builder/NonceEnabledCommandBuilder.java | 19 +++ .../program/InsulinProgramElement.java | 28 ----- 14 files changed, 256 insertions(+), 119 deletions(-) create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/builder/CommandBuilder.java create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/builder/HeaderEnabledCommandBuilder.java create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/builder/NonceEnabledCommandBuilder.java delete mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/program/InsulinProgramElement.java diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommand.java index ff7571bc6d..7f6fee2ce6 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommand.java @@ -4,6 +4,7 @@ import java.nio.ByteBuffer; 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.command.base.builder.NonceEnabledCommandBuilder; public final class DeactivateCommand extends NonceEnabledCommand { private static final short LENGTH = 6; @@ -31,7 +32,7 @@ public final class DeactivateCommand extends NonceEnabledCommand { '}'; } - public static final class Builder extends NonceEnabledBuilder { + public static final class Builder extends NonceEnabledCommandBuilder { @Override protected final DeactivateCommand buildCommand() { return new DeactivateCommand(Builder.this.address, sequenceNumber, multiCommandFlag, nonce); } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommand.java index 0850c51059..6dc9f65f1e 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommand.java @@ -4,6 +4,7 @@ import java.nio.ByteBuffer; 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.HeaderEnabledCommandBuilder; public final class GetVersionCommand extends HeaderEnabledCommand { public static final int DEFAULT_ADDRESS = -1; // FIXME move @@ -33,7 +34,7 @@ public final class GetVersionCommand extends HeaderEnabledCommand { '}'; } - public static final class Builder extends HeaderEnabledBuilder { + public static final class Builder extends HeaderEnabledCommandBuilder { @Override protected final GetVersionCommand buildCommand() { return new GetVersionCommand(address, sequenceNumber, multiCommandFlag); } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.java index 46d6695e92..ec46411954 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.java @@ -6,6 +6,7 @@ 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.command.base.builder.NonceEnabledCommandBuilder; import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertConfiguration; public final class ProgramAlertsCommand extends NonceEnabledCommand { @@ -46,7 +47,7 @@ public final class ProgramAlertsCommand extends NonceEnabledCommand { '}'; } - public static final class Builder extends NonceEnabledBuilder { + public static final class Builder extends NonceEnabledCommandBuilder { private List alertConfigurations; public Builder setAlertConfigurations(List alertConfigurations) { diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java index 95601577c0..5060ffb138 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java @@ -6,33 +6,131 @@ 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.definition.program.InsulinProgramElement; +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.CommandBuilder; +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable; +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ProgramReminder; // Always preceded by 0x1a ProgramInsulinCommand public final class ProgramBasalCommand implements Command { - private final List uniqueInsulinProgramElements; + private final List insulinProgramElements; + private final ProgramReminder programReminder; + private final byte currentInsulinProgramElementIndex; + private final short remainingTenthPulsesInCurrentInsulinProgramElement; + private final int delayUntilNextTenthPulseInUsec; - private ProgramBasalCommand(List uniqueInsulinProgramElements) { - this.uniqueInsulinProgramElements = new ArrayList<>(uniqueInsulinProgramElements); + private ProgramBasalCommand(List insulinProgramElements, ProgramReminder programReminder, byte currentInsulinProgramElementIndex, short remainingTenthPulsesInCurrentInsulinProgramElement, int delayUntilNextTenthPulseInUsec) { + this.insulinProgramElements = new ArrayList<>(insulinProgramElements); + this.programReminder = programReminder; + this.currentInsulinProgramElementIndex = currentInsulinProgramElementIndex; + this.remainingTenthPulsesInCurrentInsulinProgramElement = remainingTenthPulsesInCurrentInsulinProgramElement; + this.delayUntilNextTenthPulseInUsec = delayUntilNextTenthPulseInUsec; } public short getLength() { - return (short) (uniqueInsulinProgramElements.size() * 2 + 14); + return (short) (insulinProgramElements.size() * 2 + 14); } public byte getBodyLength() { - return (byte) (uniqueInsulinProgramElements.size() * 2 + 12); + return (byte) (insulinProgramElements.size() * 2 + 12); } @Override public byte[] getEncoded() { - return ByteBuffer.allocate(getLength()) // - // TODO - .array(); + ByteBuffer buffer = ByteBuffer.allocate(getLength()) // + .put(getCommandType().getValue()) // + .put(getBodyLength()) // + .put(programReminder.getEncoded()) // + .put(currentInsulinProgramElementIndex) // + .putShort(remainingTenthPulsesInCurrentInsulinProgramElement) // + .putInt(delayUntilNextTenthPulseInUsec); + for (InsulinProgramElement insulinProgramElement : insulinProgramElements) { + buffer.put(insulinProgramElement.getEncoded()); + } + return buffer.array(); } @Override public CommandType getCommandType() { return CommandType.PROGRAM_BASAL; } - // TODO builder + @Override public String toString() { + return "ProgramBasalCommand{" + + "uniqueInsulinProgramElements=" + insulinProgramElements + + ", programReminder=" + programReminder + + ", currentInsulinProgramElementIndex=" + currentInsulinProgramElementIndex + + ", remainingTenthPulsesInCurrentInsulinProgramElement=" + remainingTenthPulsesInCurrentInsulinProgramElement + + ", delayUntilNextTenthPulseInUsec=" + delayUntilNextTenthPulseInUsec + + '}'; + } + + public static class InsulinProgramElement implements Encodable { + private final short totalTenthPulses; + private final int delayBetweenTenthPulses; + + public InsulinProgramElement(byte totalTenthPulses, short delayBetweenTenthPulses) { + this.totalTenthPulses = totalTenthPulses; + this.delayBetweenTenthPulses = delayBetweenTenthPulses; + } + + @Override public byte[] getEncoded() { + return ByteBuffer.allocate(6) // + .putShort(totalTenthPulses) // + .putInt(delayBetweenTenthPulses) // + .array(); + } + } + + public static final class Builder implements CommandBuilder { + private List insulinProgramElements; + private ProgramReminder programReminder; + private Byte currentInsulinProgramElementIndex; + private Short remainingTenthPulsesInCurrentInsulinProgramElement; + private Integer delayUntilNextTenthPulseInUsec; + + public Builder setInsulinProgramElements(List 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 setCurrentInsulinProgramElementIndex(Byte currentInsulinProgramElementIndex) { + this.currentInsulinProgramElementIndex = currentInsulinProgramElementIndex; + return this; + } + + public Builder setRemainingTenthPulsesInCurrentInsulinProgramElement(Short remainingTenthPulsesInCurrentInsulinProgramElement) { + this.remainingTenthPulsesInCurrentInsulinProgramElement = remainingTenthPulsesInCurrentInsulinProgramElement; + return this; + } + + public Builder setDelayUntilNextTenthPulseInUsec(Integer delayUntilNextTenthPulseInUsec) { + this.delayUntilNextTenthPulseInUsec = delayUntilNextTenthPulseInUsec; + return this; + } + + @Override public ProgramBasalCommand build() { + if (insulinProgramElements == null) { + throw new IllegalArgumentException("insulinProgramElements can not be null"); + } + if (programReminder == null) { + throw new IllegalArgumentException("programReminder can not be null"); + } + if (currentInsulinProgramElementIndex == null) { + throw new IllegalArgumentException("currentInsulinProgramElementIndex can not be null"); + } + if (remainingTenthPulsesInCurrentInsulinProgramElement == null) { + throw new IllegalArgumentException("remainingTenthPulsesInCurrentInsulinProgramElement can not be null"); + } + if (delayUntilNextTenthPulseInUsec == null) { + throw new IllegalArgumentException("delayUntilNextTenthPulseInUsec can not be null"); + } + return new ProgramBasalCommand(insulinProgramElements, programReminder, currentInsulinProgramElementIndex, remainingTenthPulsesInCurrentInsulinProgramElement, delayUntilNextTenthPulseInUsec); + } + } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java index 7732611566..30e175d616 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java @@ -8,12 +8,14 @@ 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.NonceEnabledCommand; -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.program.InsulinProgramElement; +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.NonceEnabledCommandBuilder; +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable; // Always followed by one of: 0x13, 0x16, 0x17 public final class ProgramInsulinCommand extends NonceEnabledCommand { - private final List max8HourInsulinProgramElements; + private final List insulinProgramElements; private final byte currentHalfHourEntryIndex; + private final short checksum; private final short remainingEighthSecondsInCurrentHalfHourEntry; private final short remainingPulsesInCurrentHalfHourEntry; private final DeliveryType deliveryType; @@ -25,10 +27,11 @@ public final class ProgramInsulinCommand extends NonceEnabledCommand { CommandType.PROGRAM_BOLUS ); - private ProgramInsulinCommand(int address, short sequenceNumber, boolean multiCommandFlag, int nonce, List max8HourInsulinProgramElements, byte currentHalfHourEntryIndex, short remainingEighthSecondsInCurrentHalfHourEntry, short remainingPulsesInCurrentHalfHourEntry, DeliveryType deliveryType, Command interlockCommand) { + private ProgramInsulinCommand(int address, short sequenceNumber, boolean multiCommandFlag, int nonce, List insulinProgramElements, byte currentHalfHourEntryIndex, short checksum, short remainingEighthSecondsInCurrentHalfHourEntry, short remainingPulsesInCurrentHalfHourEntry, DeliveryType deliveryType, Command interlockCommand) { super(CommandType.PROGRAM_INSULIN, address, sequenceNumber, multiCommandFlag, nonce); - this.max8HourInsulinProgramElements = new ArrayList<>(max8HourInsulinProgramElements); + this.insulinProgramElements = new ArrayList<>(insulinProgramElements); this.currentHalfHourEntryIndex = currentHalfHourEntryIndex; + this.checksum = checksum; this.remainingEighthSecondsInCurrentHalfHourEntry = remainingEighthSecondsInCurrentHalfHourEntry; this.remainingPulsesInCurrentHalfHourEntry = remainingPulsesInCurrentHalfHourEntry; this.deliveryType = deliveryType; @@ -36,11 +39,11 @@ public final class ProgramInsulinCommand extends NonceEnabledCommand { } public short getLength() { - return (short) (max8HourInsulinProgramElements.size() * 6 + 10); + return (short) (insulinProgramElements.size() * 6 + 10); } public byte getBodyLength() { - return (byte) (max8HourInsulinProgramElements.size() * 6 + 8); + return (byte) (insulinProgramElements.size() * 6 + 8); } @Override public byte[] getEncoded() { @@ -49,39 +52,40 @@ public final class ProgramInsulinCommand extends NonceEnabledCommand { .put(getBodyLength()) // .putInt(nonce) // .put(deliveryType.getValue()) // - .putShort(createChecksum()) // + .putShort(checksum) // .put(currentHalfHourEntryIndex) // .putShort(remainingEighthSecondsInCurrentHalfHourEntry) // .putShort(remainingPulsesInCurrentHalfHourEntry); - for (InsulinProgramElement element : max8HourInsulinProgramElements) { + for (InsulinProgramElement element : insulinProgramElements) { commandBuffer.put(element.getEncoded()); } byte[] command = commandBuffer.array(); + byte[] interlock = interlockCommand.getEncoded(); + short totalLength = (short) (command.length + interlock.length + HEADER_LENGTH); - // TODO interlock and header - - return command; + return ByteBuffer.allocate(totalLength) // + .put(encodeHeader(address, sequenceNumber, totalLength, multiCommandFlag)) // + .put(command) // + .put(interlock) // + .array(); } - private short createChecksum() { - return 0; // TODO - } - - public static final class Builder extends NonceEnabledBuilder { - private List max8HourInsulinProgramElements; + public static final class Builder extends NonceEnabledCommandBuilder { + private List insulinProgramElements; private Byte currentHalfOurEntryIndex; + private Short checksum; private Short remainingEighthSecondsInCurrentHalfHourEntry; private Short remainingPulsesInCurrentHalfHourEntry; private DeliveryType deliveryType; private Command interlockCommand; - public Builder setMax8HourInsulinProgramElements(List max8HourInsulinProgramElements) { - if (max8HourInsulinProgramElements == null) { - throw new IllegalArgumentException("max8HourInsulinProgramElements can not be null"); + public Builder setInsulinProgramElements(List insulinProgramElements) { + if (insulinProgramElements == null) { + throw new IllegalArgumentException("insulinProgramElements can not be null"); } - this.max8HourInsulinProgramElements = new ArrayList<>(max8HourInsulinProgramElements); + this.insulinProgramElements = new ArrayList<>(insulinProgramElements); return this; } @@ -90,6 +94,11 @@ public final class ProgramInsulinCommand extends NonceEnabledCommand { return this; } + public Builder setChecksum(short checksum) { + this.checksum = checksum; + return this; + } + public Builder setRemainingEighthSecondsInCurrentHalfHourEntryIndex(short remainingEighthSecondsInCurrentHalfHourEntry) { this.remainingEighthSecondsInCurrentHalfHourEntry = remainingEighthSecondsInCurrentHalfHourEntry; return this; @@ -114,12 +123,15 @@ public final class ProgramInsulinCommand extends NonceEnabledCommand { } @Override protected final ProgramInsulinCommand buildCommand() { - if (max8HourInsulinProgramElements == null) { + if (insulinProgramElements == null) { throw new IllegalArgumentException("insulinProgramElements can not be null"); } if (currentHalfOurEntryIndex == null) { throw new IllegalArgumentException("currentHalfOurEntryIndex can not be null"); } + if (checksum == null) { + throw new IllegalArgumentException("checksum can not be null"); + } if (remainingEighthSecondsInCurrentHalfHourEntry == null) { throw new IllegalArgumentException("remainingEighthSecondsInCurrentHalfHourEntry can not be null"); } @@ -132,7 +144,7 @@ public final class ProgramInsulinCommand extends NonceEnabledCommand { if (interlockCommand == null) { throw new IllegalArgumentException("interlockCommand can not be null"); } - return new ProgramInsulinCommand(address, sequenceNumber, multiCommandFlag, nonce, max8HourInsulinProgramElements, currentHalfOurEntryIndex, remainingEighthSecondsInCurrentHalfHourEntry, remainingPulsesInCurrentHalfHourEntry, deliveryType, interlockCommand); + return new ProgramInsulinCommand(address, sequenceNumber, multiCommandFlag, nonce, insulinProgramElements, currentHalfOurEntryIndex, checksum, remainingEighthSecondsInCurrentHalfHourEntry, remainingPulsesInCurrentHalfHourEntry, deliveryType, interlockCommand); } } @@ -152,4 +164,43 @@ public final class ProgramInsulinCommand extends NonceEnabledCommand { } } + @Override public String toString() { + return "ProgramInsulinCommand{" + + "insulinProgramElements=" + insulinProgramElements + + ", currentHalfHourEntryIndex=" + currentHalfHourEntryIndex + + ", checksum=" + checksum + + ", remainingEighthSecondsInCurrentHalfHourEntry=" + remainingEighthSecondsInCurrentHalfHourEntry + + ", remainingPulsesInCurrentHalfHourEntry=" + remainingPulsesInCurrentHalfHourEntry + + ", deliveryType=" + deliveryType + + ", interlockCommand=" + interlockCommand + + ", nonce=" + nonce + + ", commandType=" + commandType + + ", address=" + address + + ", sequenceNumber=" + sequenceNumber + + ", multiCommandFlag=" + multiCommandFlag + + '}'; + } + + public static class InsulinProgramElement implements Encodable { + private final byte numberOfHalfOurEntries; // 4 bits + private final short numberOfPulsesPerHalfOurEntry; // 10 bits + private final boolean extraAlternatePulse; + + public InsulinProgramElement(byte numberOfHalfOurEntries, short numberOfPulsesPerHalfOurEntry, boolean extraAlternatePulse) { + this.numberOfHalfOurEntries = numberOfHalfOurEntries; + this.numberOfPulsesPerHalfOurEntry = numberOfPulsesPerHalfOurEntry; + this.extraAlternatePulse = extraAlternatePulse; + } + + @Override public byte[] getEncoded() { + byte firstByte = (byte) ((((numberOfHalfOurEntries - 1) & 0x0f) << 4) // + | ((extraAlternatePulse ? 1 : 0) << 3) // + | ((numberOfPulsesPerHalfOurEntry >>> 8) & 0x03)); + + return ByteBuffer.allocate(2) // + .put(firstByte) // + .put((byte) (numberOfPulsesPerHalfOurEntry & 0xff)) // + .array(); + } + } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommand.java index 0a8d6086f4..7b36a22cd3 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommand.java @@ -6,6 +6,7 @@ import java.util.Date; 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.HeaderEnabledCommandBuilder; public final class SetUniqueIdCommand extends HeaderEnabledCommand { private static final int DEFAULT_ADDRESS = -1; @@ -62,7 +63,7 @@ public final class SetUniqueIdCommand extends HeaderEnabledCommand { '}'; } - public static final class Builder extends HeaderEnabledBuilder { + public static final class Builder extends HeaderEnabledCommandBuilder { private Integer lotNumber; private Integer podSequenceNumber; private Date initializationTime; diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java index 83e6e1370f..b818ff34ad 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java @@ -5,6 +5,7 @@ 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.command.base.builder.NonceEnabledCommandBuilder; import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable; public final class SilenceAlertsCommand extends NonceEnabledCommand { @@ -74,7 +75,7 @@ public final class SilenceAlertsCommand extends NonceEnabledCommand { } } - public static class Builder extends NonceEnabledBuilder { + public static class Builder extends NonceEnabledCommandBuilder { private boolean silenceAutoOffAlert; private boolean silenceMultiCommandAlert; private boolean silenceExpirationImminentAlert; diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java index 1f1ef1fdce..e4ea66a55f 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java @@ -4,8 +4,8 @@ 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.command.base.builder.NonceEnabledCommandBuilder; import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType; import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable; @@ -68,7 +68,7 @@ public final class StopDeliveryCommand extends NonceEnabledCommand { } } - public static final class Builder extends NonceEnabledBuilder { + public static final class Builder extends NonceEnabledCommandBuilder { private DeliveryType deliveryType; private BeepType beepType = BeepType.LONG_SINGLE_BEEP; diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/HeaderEnabledCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/HeaderEnabledCommand.java index bad2de5be4..219dc48724 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/HeaderEnabledCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/HeaderEnabledCommand.java @@ -37,40 +37,4 @@ public abstract class HeaderEnabledCommand implements Command { .array(); } - protected static abstract class HeaderEnabledBuilder, R extends Command> implements Builder { - 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 build(); - } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/NonceEnabledCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/NonceEnabledCommand.java index f485a495e1..16a136601b 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/NonceEnabledCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/NonceEnabledCommand.java @@ -8,19 +8,4 @@ public abstract class NonceEnabledCommand extends HeaderEnabledCommand { this.nonce = nonce; } - protected static abstract class NonceEnabledBuilder, R extends Command> extends HeaderEnabledBuilder { - 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; - } - } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/builder/CommandBuilder.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/builder/CommandBuilder.java new file mode 100644 index 0000000000..3b4ca66ca0 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/builder/CommandBuilder.java @@ -0,0 +1,7 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder; + +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command; + +public interface CommandBuilder { + R build(); +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/builder/HeaderEnabledCommandBuilder.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/builder/HeaderEnabledCommandBuilder.java new file mode 100644 index 0000000000..92d1f50c92 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/builder/HeaderEnabledCommandBuilder.java @@ -0,0 +1,36 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder; + +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command; + +public abstract class HeaderEnabledCommandBuilder, R extends Command> implements CommandBuilder { + 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(); +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/builder/NonceEnabledCommandBuilder.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/builder/NonceEnabledCommandBuilder.java new file mode 100644 index 0000000000..806eda8965 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/builder/NonceEnabledCommandBuilder.java @@ -0,0 +1,19 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder; + +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command; + +public abstract class NonceEnabledCommandBuilder, R extends Command> extends HeaderEnabledCommandBuilder { + 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; + } +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/program/InsulinProgramElement.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/program/InsulinProgramElement.java deleted file mode 100644 index 2707efdfcb..0000000000 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/program/InsulinProgramElement.java +++ /dev/null @@ -1,28 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.program; - -import java.nio.ByteBuffer; - -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable; - -public class InsulinProgramElement implements Encodable { - private final byte numberOfHalfOurEntries; // 4 bits - private final short numberOfPulsesPerHalfOurEntry; // 10 bits - private final boolean extraAlternatePulse; - - public InsulinProgramElement(byte numberOfHalfOurEntries, short numberOfPulsesPerHalfOurEntry, boolean extraAlternatePulse) { - this.numberOfHalfOurEntries = numberOfHalfOurEntries; - this.numberOfPulsesPerHalfOurEntry = numberOfPulsesPerHalfOurEntry; - this.extraAlternatePulse = extraAlternatePulse; - } - - @Override public byte[] getEncoded() { - byte firstByte = (byte) ((((numberOfHalfOurEntries - 1) & 0x0f) << 4) // - | ((extraAlternatePulse ? 1 : 0) << 3) // - | ((numberOfPulsesPerHalfOurEntry >>> 8) & 0x03)); - - return ByteBuffer.allocate(2) // - .put(firstByte) // - .put((byte) (numberOfPulsesPerHalfOurEntry & 0xff)) // - .array(); - } -} From a2b0ae47f92aba6b9d4b61c45942ffe6de3ec298 Mon Sep 17 00:00:00 2001 From: osodebailar Date: Mon, 15 Feb 2021 19:36:29 +0100 Subject: [PATCH 09/83] remove preference warning --- app/src/main/res/xml/pref_absorption_aaps.xml | 1 + .../main/res/xml/pref_absorption_oref1.xml | 1 + app/src/main/res/xml/pref_alerts.xml | 1 + app/src/main/res/xml/pref_automation.xml | 1 + app/src/main/res/xml/pref_bgsource.xml | 1 + app/src/main/res/xml/pref_bgsourcedexcom.xml | 1 + app/src/main/res/xml/pref_datachoices.xml | 1 + app/src/main/res/xml/pref_general.xml | 5 ++-- .../main/res/xml/pref_insight_local_full.xml | 1 + .../xml/pref_insight_local_pumpcontrol.xml | 1 + .../main/res/xml/pref_insulinoreffreepeak.xml | 1 + app/src/main/res/xml/pref_loop.xml | 1 + app/src/main/res/xml/pref_maintenance.xml | 2 +- .../main/res/xml/pref_nsclientinternal.xml | 1 + app/src/main/res/xml/pref_openapsama.xml | 1 + app/src/main/res/xml/pref_openapssmb.xml | 1 + app/src/main/res/xml/pref_openhumans.xml | 10 ++++--- app/src/main/res/xml/pref_overview.xml | 1 + app/src/main/res/xml/pref_pump.xml | 1 + app/src/main/res/xml/pref_safety.xml | 1 + app/src/main/res/xml/pref_smscommunicator.xml | 1 + app/src/main/res/xml/pref_tidepool.xml | 1 + app/src/main/res/xml/pref_virtualpump.xml | 1 + app/src/main/res/xml/pref_wear.xml | 1 + app/src/main/res/xml/pref_xdripstatus.xml | 1 + core/src/main/res/values/strings.xml | 27 +++++++++++++++++++ danar/src/main/res/xml/pref_danar.xml | 1 + danar/src/main/res/xml/pref_danarkorean.xml | 1 + danar/src/main/res/xml/pref_danarv2.xml | 1 + danars/src/main/res/xml/pref_danars.xml | 1 + medtronic/src/main/res/xml/pref_medtronic.xml | 1 + .../src/main/res/xml/pref_omnipod.xml | 4 ++- 32 files changed, 68 insertions(+), 7 deletions(-) diff --git a/app/src/main/res/xml/pref_absorption_aaps.xml b/app/src/main/res/xml/pref_absorption_aaps.xml index 7cc14ebb21..9a1be55a9e 100644 --- a/app/src/main/res/xml/pref_absorption_aaps.xml +++ b/app/src/main/res/xml/pref_absorption_aaps.xml @@ -5,6 +5,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/xml/pref_absorption_oref1.xml b/app/src/main/res/xml/pref_absorption_oref1.xml index b1c3a42160..389e43a838 100644 --- a/app/src/main/res/xml/pref_absorption_oref1.xml +++ b/app/src/main/res/xml/pref_absorption_oref1.xml @@ -5,6 +5,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/xml/pref_alerts.xml b/app/src/main/res/xml/pref_alerts.xml index ab5111d624..43ceb0cd2d 100644 --- a/app/src/main/res/xml/pref_alerts.xml +++ b/app/src/main/res/xml/pref_alerts.xml @@ -4,6 +4,7 @@ xmlns:validate="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/xml/pref_automation.xml b/app/src/main/res/xml/pref_automation.xml index e1c43f32b4..b408dcbeb3 100644 --- a/app/src/main/res/xml/pref_automation.xml +++ b/app/src/main/res/xml/pref_automation.xml @@ -3,6 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/xml/pref_bgsource.xml b/app/src/main/res/xml/pref_bgsource.xml index 098d57bc4f..9b9b2515d6 100644 --- a/app/src/main/res/xml/pref_bgsource.xml +++ b/app/src/main/res/xml/pref_bgsource.xml @@ -3,6 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/xml/pref_bgsourcedexcom.xml b/app/src/main/res/xml/pref_bgsourcedexcom.xml index 1ca8fa1140..495851995c 100644 --- a/app/src/main/res/xml/pref_bgsourcedexcom.xml +++ b/app/src/main/res/xml/pref_bgsourcedexcom.xml @@ -3,6 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/xml/pref_datachoices.xml b/app/src/main/res/xml/pref_datachoices.xml index e60840d09d..d8ac37ceae 100644 --- a/app/src/main/res/xml/pref_datachoices.xml +++ b/app/src/main/res/xml/pref_datachoices.xml @@ -3,6 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/xml/pref_general.xml b/app/src/main/res/xml/pref_general.xml index 8dd2f98b76..7c6a8058b8 100644 --- a/app/src/main/res/xml/pref_general.xml +++ b/app/src/main/res/xml/pref_general.xml @@ -3,8 +3,9 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> + android:key="@string/key_configbuilder_general" + android:title="@string/configbuilder_general" + app:initialExpandedChildrenCount="0"> diff --git a/app/src/main/res/xml/pref_insight_local_pumpcontrol.xml b/app/src/main/res/xml/pref_insight_local_pumpcontrol.xml index a863e56757..b9067e3a55 100644 --- a/app/src/main/res/xml/pref_insight_local_pumpcontrol.xml +++ b/app/src/main/res/xml/pref_insight_local_pumpcontrol.xml @@ -3,6 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/xml/pref_insulinoreffreepeak.xml b/app/src/main/res/xml/pref_insulinoreffreepeak.xml index 5b7b290ae0..7aa6b767c6 100644 --- a/app/src/main/res/xml/pref_insulinoreffreepeak.xml +++ b/app/src/main/res/xml/pref_insulinoreffreepeak.xml @@ -4,6 +4,7 @@ xmlns:validate="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/xml/pref_loop.xml b/app/src/main/res/xml/pref_loop.xml index 0d92a6bc5f..f94fd564e2 100644 --- a/app/src/main/res/xml/pref_loop.xml +++ b/app/src/main/res/xml/pref_loop.xml @@ -4,6 +4,7 @@ xmlns:validate="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/xml/pref_maintenance.xml b/app/src/main/res/xml/pref_maintenance.xml index cb7d3108cc..633411ed72 100644 --- a/app/src/main/res/xml/pref_maintenance.xml +++ b/app/src/main/res/xml/pref_maintenance.xml @@ -4,7 +4,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/xml/pref_nsclientinternal.xml b/app/src/main/res/xml/pref_nsclientinternal.xml index 8c64284d52..ada082b21b 100644 --- a/app/src/main/res/xml/pref_nsclientinternal.xml +++ b/app/src/main/res/xml/pref_nsclientinternal.xml @@ -4,6 +4,7 @@ xmlns:validate="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/xml/pref_openapsama.xml b/app/src/main/res/xml/pref_openapsama.xml index 3e285d7477..cf5913f060 100644 --- a/app/src/main/res/xml/pref_openapsama.xml +++ b/app/src/main/res/xml/pref_openapsama.xml @@ -4,6 +4,7 @@ xmlns:validate="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/xml/pref_openapssmb.xml b/app/src/main/res/xml/pref_openapssmb.xml index 1f1be8cb42..3e602b93c1 100644 --- a/app/src/main/res/xml/pref_openapssmb.xml +++ b/app/src/main/res/xml/pref_openapssmb.xml @@ -4,6 +4,7 @@ xmlns:validate="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/xml/pref_openhumans.xml b/app/src/main/res/xml/pref_openhumans.xml index b9ccc3e867..4e67c45f46 100644 --- a/app/src/main/res/xml/pref_openhumans.xml +++ b/app/src/main/res/xml/pref_openhumans.xml @@ -1,7 +1,11 @@ - + - + - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/xml/pref_overview.xml b/app/src/main/res/xml/pref_overview.xml index a98fc25905..a8192da144 100644 --- a/app/src/main/res/xml/pref_overview.xml +++ b/app/src/main/res/xml/pref_overview.xml @@ -4,6 +4,7 @@ xmlns:validate="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/xml/pref_pump.xml b/app/src/main/res/xml/pref_pump.xml index 161692a698..aff98727d5 100644 --- a/app/src/main/res/xml/pref_pump.xml +++ b/app/src/main/res/xml/pref_pump.xml @@ -3,6 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/xml/pref_safety.xml b/app/src/main/res/xml/pref_safety.xml index e3f5f2e23d..cfef4b6ba7 100644 --- a/app/src/main/res/xml/pref_safety.xml +++ b/app/src/main/res/xml/pref_safety.xml @@ -4,6 +4,7 @@ xmlns:validate="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/xml/pref_smscommunicator.xml b/app/src/main/res/xml/pref_smscommunicator.xml index dc61d1c1a2..dcf9064f48 100644 --- a/app/src/main/res/xml/pref_smscommunicator.xml +++ b/app/src/main/res/xml/pref_smscommunicator.xml @@ -4,6 +4,7 @@ xmlns:validate="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/xml/pref_tidepool.xml b/app/src/main/res/xml/pref_tidepool.xml index 96e3c8f218..d5eb3870fb 100644 --- a/app/src/main/res/xml/pref_tidepool.xml +++ b/app/src/main/res/xml/pref_tidepool.xml @@ -4,6 +4,7 @@ xmlns:validate="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/xml/pref_virtualpump.xml b/app/src/main/res/xml/pref_virtualpump.xml index 5e60fe4cb8..ad1e0344fa 100644 --- a/app/src/main/res/xml/pref_virtualpump.xml +++ b/app/src/main/res/xml/pref_virtualpump.xml @@ -3,6 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/xml/pref_wear.xml b/app/src/main/res/xml/pref_wear.xml index 4b4a1d15b5..d46a317400 100644 --- a/app/src/main/res/xml/pref_wear.xml +++ b/app/src/main/res/xml/pref_wear.xml @@ -3,6 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/xml/pref_xdripstatus.xml b/app/src/main/res/xml/pref_xdripstatus.xml index 00aa8262ef..15309d4f05 100644 --- a/app/src/main/res/xml/pref_xdripstatus.xml +++ b/app/src/main/res/xml/pref_xdripstatus.xml @@ -3,6 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 7d22c30592..82d31a9020 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -30,6 +30,33 @@ virtualpump_type QuickWizard wearcontrol + bgsource_upload + omnipod_preference_category_rileylink + localalertsettings + wear_settings + absorptionsettings + configbuilder_general + maintenance_settings + smscommunicator + openapssmb + tidepool + treatmentssafety + insight_local + insulin_oref_peak + loop_settings + virtualpump_settings + pump_settings + tidepool_settings + absorption_settings + overview_settings + openapsma_settings + medtronic_settings + danars_settings + xdripstatus_settings + nsclientinternal_settings + insight_local_settings + data_choices_settings + dexcom_settings Refresh diff --git a/danar/src/main/res/xml/pref_danar.xml b/danar/src/main/res/xml/pref_danar.xml index 27efaac878..282ee599ec 100644 --- a/danar/src/main/res/xml/pref_danar.xml +++ b/danar/src/main/res/xml/pref_danar.xml @@ -4,6 +4,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> diff --git a/danar/src/main/res/xml/pref_danarkorean.xml b/danar/src/main/res/xml/pref_danarkorean.xml index 5e46cdae54..0e685fe655 100644 --- a/danar/src/main/res/xml/pref_danarkorean.xml +++ b/danar/src/main/res/xml/pref_danarkorean.xml @@ -4,6 +4,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> diff --git a/danar/src/main/res/xml/pref_danarv2.xml b/danar/src/main/res/xml/pref_danarv2.xml index d0d36999a5..9b82d2189b 100644 --- a/danar/src/main/res/xml/pref_danarv2.xml +++ b/danar/src/main/res/xml/pref_danarv2.xml @@ -4,6 +4,7 @@ xmlns:validate="http://schemas.android.com/apk/res-auto"> diff --git a/danars/src/main/res/xml/pref_danars.xml b/danars/src/main/res/xml/pref_danars.xml index 8fc3d691b4..7c927aa2ae 100644 --- a/danars/src/main/res/xml/pref_danars.xml +++ b/danars/src/main/res/xml/pref_danars.xml @@ -4,6 +4,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> diff --git a/medtronic/src/main/res/xml/pref_medtronic.xml b/medtronic/src/main/res/xml/pref_medtronic.xml index 5006bf32b9..ad2c0f4d84 100644 --- a/medtronic/src/main/res/xml/pref_medtronic.xml +++ b/medtronic/src/main/res/xml/pref_medtronic.xml @@ -4,6 +4,7 @@ xmlns:validate="http://schemas.android.com/apk/res-auto"> diff --git a/omnipod-eros/src/main/res/xml/pref_omnipod.xml b/omnipod-eros/src/main/res/xml/pref_omnipod.xml index a56ea0ce0b..02f919fe95 100644 --- a/omnipod-eros/src/main/res/xml/pref_omnipod.xml +++ b/omnipod-eros/src/main/res/xml/pref_omnipod.xml @@ -2,7 +2,9 @@ - + Date: Wed, 17 Feb 2021 12:38:16 +0100 Subject: [PATCH 10/83] WIP on Omnipod Dash program basal command --- .../driver/pod/command/DeactivateCommand.java | 2 +- .../driver/pod/command/GetVersionCommand.java | 2 +- .../pod/command/ProgramAlertsCommand.java | 2 +- .../pod/command/ProgramBasalCommand.java | 122 +++++++------ .../pod/command/ProgramInsulinCommand.java | 164 +++--------------- .../pod/command/SetUniqueIdCommand.java | 2 +- .../pod/command/SilenceAlertsCommand.java | 2 +- .../pod/command/StopDeliveryCommand.java | 2 +- .../command/insulin/program/CurrentSlot.java | 33 ++++ .../program/LongInsulinProgramElement.java | 29 ++++ .../insulin/program/ProgramBasalUtil.java | 150 ++++++++++++++++ .../program/ShortInsulinProgramElement.java | 36 ++++ .../driver/pod/definition/BasalProgram.java | 92 ++++++++++ .../driver/pod/response/NakResponseTest.java | 2 +- 14 files changed, 430 insertions(+), 210 deletions(-) create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/CurrentSlot.java create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/LongInsulinProgramElement.java create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ProgramBasalUtil.java create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ShortInsulinProgramElement.java create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/BasalProgram.java diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommand.java index 7f6fee2ce6..784e95b40b 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommand.java @@ -10,7 +10,7 @@ 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, int nonce) { + DeactivateCommand(int address, short sequenceNumber, boolean multiCommandFlag, int nonce) { super(CommandType.DEACTIVATE, address, sequenceNumber, multiCommandFlag, nonce); } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommand.java index 6dc9f65f1e..e8cc704efa 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommand.java @@ -12,7 +12,7 @@ public final class GetVersionCommand extends HeaderEnabledCommand { private static final short LENGTH = 6; private static final byte BODY_LENGTH = 4; - private GetVersionCommand(int address, short sequenceNumber, boolean multiCommandFlag) { + GetVersionCommand(int address, short sequenceNumber, boolean multiCommandFlag) { super(CommandType.GET_VERSION, address, sequenceNumber, multiCommandFlag); } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.java index ec46411954..30150a086e 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.java @@ -12,7 +12,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definitio public final class ProgramAlertsCommand extends NonceEnabledCommand { private final List alertConfigurations; - private ProgramAlertsCommand(int address, short sequenceNumber, boolean multiCommandFlag, List alertConfigurations, int nonce) { + ProgramAlertsCommand(int address, short sequenceNumber, boolean multiCommandFlag, List alertConfigurations, int nonce) { super(CommandType.PROGRAM_ALERTS, address, sequenceNumber, multiCommandFlag, nonce); this.alertConfigurations = new ArrayList<>(alertConfigurations); } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java index 5060ffb138..f679adde88 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java @@ -2,23 +2,32 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Date; 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.builder.CommandBuilder; -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable; +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.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; import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ProgramReminder; // Always preceded by 0x1a ProgramInsulinCommand -public final class ProgramBasalCommand implements Command { - private final List insulinProgramElements; +public final class ProgramBasalCommand extends HeaderEnabledCommand { + private final ProgramInsulinCommand interlockCommand; + private final List insulinProgramElements; private final ProgramReminder programReminder; private final byte currentInsulinProgramElementIndex; private final short remainingTenthPulsesInCurrentInsulinProgramElement; private final int delayUntilNextTenthPulseInUsec; - private ProgramBasalCommand(List insulinProgramElements, ProgramReminder programReminder, byte currentInsulinProgramElementIndex, short remainingTenthPulsesInCurrentInsulinProgramElement, int delayUntilNextTenthPulseInUsec) { + ProgramBasalCommand(ProgramInsulinCommand interlockCommand, int address, short sequenceNumber, boolean multiCommandFlag, List insulinProgramElements, ProgramReminder programReminder, byte currentInsulinProgramElementIndex, short remainingTenthPulsesInCurrentInsulinProgramElement, int delayUntilNextTenthPulseInUsec) { + super(CommandType.PROGRAM_BASAL, address, sequenceNumber, multiCommandFlag); + + this.interlockCommand = interlockCommand; this.insulinProgramElements = new ArrayList<>(insulinProgramElements); this.programReminder = programReminder; this.currentInsulinProgramElementIndex = currentInsulinProgramElementIndex; @@ -42,55 +51,46 @@ public final class ProgramBasalCommand implements Command { .put(currentInsulinProgramElementIndex) // .putShort(remainingTenthPulsesInCurrentInsulinProgramElement) // .putInt(delayUntilNextTenthPulseInUsec); - for (InsulinProgramElement insulinProgramElement : insulinProgramElements) { + for (LongInsulinProgramElement insulinProgramElement : insulinProgramElements) { buffer.put(insulinProgramElement.getEncoded()); } - return buffer.array(); - } - @Override public CommandType getCommandType() { - return CommandType.PROGRAM_BASAL; + byte[] bolusCommand = buffer.array(); + byte[] interlockCommand = this.interlockCommand.getEncoded(); + byte[] header = encodeHeader(address, sequenceNumber, (short) (bolusCommand.length + interlockCommand.length), multiCommandFlag); + + return ByteBuffer.allocate(bolusCommand.length + interlockCommand.length + header.length) // + .put(header) // + .put(interlockCommand) // + .put(bolusCommand) // + .array(); } @Override public String toString() { return "ProgramBasalCommand{" + - "uniqueInsulinProgramElements=" + insulinProgramElements + + "interlockCommand=" + interlockCommand + + ", insulinProgramElements=" + insulinProgramElements + ", programReminder=" + programReminder + ", currentInsulinProgramElementIndex=" + currentInsulinProgramElementIndex + ", remainingTenthPulsesInCurrentInsulinProgramElement=" + remainingTenthPulsesInCurrentInsulinProgramElement + ", delayUntilNextTenthPulseInUsec=" + delayUntilNextTenthPulseInUsec + + ", commandType=" + commandType + + ", address=" + address + + ", sequenceNumber=" + sequenceNumber + + ", multiCommandFlag=" + multiCommandFlag + '}'; } - public static class InsulinProgramElement implements Encodable { - private final short totalTenthPulses; - private final int delayBetweenTenthPulses; - - public InsulinProgramElement(byte totalTenthPulses, short delayBetweenTenthPulses) { - this.totalTenthPulses = totalTenthPulses; - this.delayBetweenTenthPulses = delayBetweenTenthPulses; - } - - @Override public byte[] getEncoded() { - return ByteBuffer.allocate(6) // - .putShort(totalTenthPulses) // - .putInt(delayBetweenTenthPulses) // - .array(); - } - } - - public static final class Builder implements CommandBuilder { - private List insulinProgramElements; + public static final class Builder extends NonceEnabledCommandBuilder { + private BasalProgram basalProgram; private ProgramReminder programReminder; - private Byte currentInsulinProgramElementIndex; - private Short remainingTenthPulsesInCurrentInsulinProgramElement; - private Integer delayUntilNextTenthPulseInUsec; + private Date currentTime; - public Builder setInsulinProgramElements(List insulinProgramElements) { - if (insulinProgramElements == null) { - throw new IllegalArgumentException("insulinProgramElements can not be null"); + public Builder setBasalProgram(BasalProgram basalProgram) { + if (basalProgram == null) { + throw new IllegalArgumentException("basalProgram can not be null"); } - this.insulinProgramElements = new ArrayList<>(insulinProgramElements); + this.basalProgram = basalProgram; return this; } @@ -99,38 +99,36 @@ public final class ProgramBasalCommand implements Command { return this; } - public Builder setCurrentInsulinProgramElementIndex(Byte currentInsulinProgramElementIndex) { - this.currentInsulinProgramElementIndex = currentInsulinProgramElementIndex; + public Builder setCurrentTime(Date currentTime) { + this.currentTime = currentTime; return this; } - public Builder setRemainingTenthPulsesInCurrentInsulinProgramElement(Short remainingTenthPulsesInCurrentInsulinProgramElement) { - this.remainingTenthPulsesInCurrentInsulinProgramElement = remainingTenthPulsesInCurrentInsulinProgramElement; - return this; - } - - public Builder setDelayUntilNextTenthPulseInUsec(Integer delayUntilNextTenthPulseInUsec) { - this.delayUntilNextTenthPulseInUsec = delayUntilNextTenthPulseInUsec; - return this; - } - - @Override public ProgramBasalCommand build() { - if (insulinProgramElements == null) { - throw new IllegalArgumentException("insulinProgramElements can not be null"); + @Override protected ProgramBasalCommand buildCommand() { + if (basalProgram == null) { + throw new IllegalArgumentException("basalProgram can not be null"); } if (programReminder == null) { throw new IllegalArgumentException("programReminder can not be null"); } - if (currentInsulinProgramElementIndex == null) { - throw new IllegalArgumentException("currentInsulinProgramElementIndex can not be null"); + if (currentTime == null) { + throw new IllegalArgumentException("currentTime can not be null"); } - if (remainingTenthPulsesInCurrentInsulinProgramElement == null) { - throw new IllegalArgumentException("remainingTenthPulsesInCurrentInsulinProgramElement can not be null"); - } - if (delayUntilNextTenthPulseInUsec == null) { - throw new IllegalArgumentException("delayUntilNextTenthPulseInUsec can not be null"); - } - return new ProgramBasalCommand(insulinProgramElements, programReminder, currentInsulinProgramElementIndex, remainingTenthPulsesInCurrentInsulinProgramElement, delayUntilNextTenthPulseInUsec); + + short[] pulsesPerSlot = ProgramBasalUtil.mapBasalProgramToPulsesPerSlot(basalProgram); + CurrentSlot currentSlot = ProgramBasalUtil.calculateCurrentSlot(pulsesPerSlot, currentTime); + List longInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToLongInsulinProgramElements(pulsesPerSlot); + List shortInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot); + short checksum = ProgramBasalUtil.createChecksum(); + byte currentInsulinProgramElementIndex = 0; // TODO + short remainingTenthPulsesInCurrentInsulinProgramElement = 0; // TODO + int delayUntilNextPulseInUsec = 0; // TODO + + ProgramInsulinCommand interlockCommand = new ProgramInsulinCommand(address, sequenceNumber, multiCommandFlag, nonce, + shortInsulinProgramElements, currentSlot.getIndex(), checksum, (short) (currentSlot.getSecondsRemaining() * 8), + currentSlot.getPulsesRemaining(), ProgramInsulinCommand.DeliveryType.BASAL); + + return new ProgramBasalCommand(interlockCommand, address, sequenceNumber, multiCommandFlag, longInsulinProgramElements, programReminder, currentInsulinProgramElementIndex, remainingTenthPulsesInCurrentInsulinProgramElement, delayUntilNextPulseInUsec); } } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java index 30e175d616..6046e17a57 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java @@ -2,153 +2,58 @@ 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.NonceEnabledCommand; -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.NonceEnabledCommandBuilder; -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable; +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.ShortInsulinProgramElement; // Always followed by one of: 0x13, 0x16, 0x17 -public final class ProgramInsulinCommand extends NonceEnabledCommand { - private final List insulinProgramElements; - private final byte currentHalfHourEntryIndex; +final class ProgramInsulinCommand extends NonceEnabledCommand { + private final List insulinProgramElements; + private final byte currentSlot; private final short checksum; - private final short remainingEighthSecondsInCurrentHalfHourEntry; - private final short remainingPulsesInCurrentHalfHourEntry; + private final short remainingEighthSecondsInCurrentSlot; + private final short remainingPulsesInCurrentSlot; private final DeliveryType deliveryType; - private final Command interlockCommand; - private static final List ALLOWED_INTERLOCK_COMMANDS = Arrays.asList( - CommandType.PROGRAM_BASAL, - CommandType.PROGRAM_TEMP_BASAL, - CommandType.PROGRAM_BOLUS - ); - - private ProgramInsulinCommand(int address, short sequenceNumber, boolean multiCommandFlag, int nonce, List insulinProgramElements, byte currentHalfHourEntryIndex, short checksum, short remainingEighthSecondsInCurrentHalfHourEntry, short remainingPulsesInCurrentHalfHourEntry, DeliveryType deliveryType, Command interlockCommand) { + ProgramInsulinCommand(int address, short sequenceNumber, boolean multiCommandFlag, int nonce, List insulinProgramElements, byte currentSlot, short checksum, short remainingEighthSecondsInCurrentSlot, short remainingPulsesInCurrentSlot, DeliveryType deliveryType) { super(CommandType.PROGRAM_INSULIN, address, sequenceNumber, multiCommandFlag, nonce); this.insulinProgramElements = new ArrayList<>(insulinProgramElements); - this.currentHalfHourEntryIndex = currentHalfHourEntryIndex; + this.currentSlot = currentSlot; this.checksum = checksum; - this.remainingEighthSecondsInCurrentHalfHourEntry = remainingEighthSecondsInCurrentHalfHourEntry; - this.remainingPulsesInCurrentHalfHourEntry = remainingPulsesInCurrentHalfHourEntry; + this.remainingEighthSecondsInCurrentSlot = remainingEighthSecondsInCurrentSlot; + this.remainingPulsesInCurrentSlot = remainingPulsesInCurrentSlot; this.deliveryType = deliveryType; - this.interlockCommand = interlockCommand; } - public short getLength() { + short getLength() { return (short) (insulinProgramElements.size() * 6 + 10); } - public byte getBodyLength() { + byte getBodyLength() { return (byte) (insulinProgramElements.size() * 6 + 8); } @Override public byte[] getEncoded() { - ByteBuffer commandBuffer = ByteBuffer.allocate(this.getLength()) // + ByteBuffer buffer = ByteBuffer.allocate(this.getLength()) // .put(commandType.getValue()) // .put(getBodyLength()) // .putInt(nonce) // .put(deliveryType.getValue()) // .putShort(checksum) // - .put(currentHalfHourEntryIndex) // - .putShort(remainingEighthSecondsInCurrentHalfHourEntry) // - .putShort(remainingPulsesInCurrentHalfHourEntry); + .put(currentSlot) // + .putShort(remainingEighthSecondsInCurrentSlot) // + .putShort(remainingPulsesInCurrentSlot); - for (InsulinProgramElement element : insulinProgramElements) { - commandBuffer.put(element.getEncoded()); + for (ShortInsulinProgramElement element : insulinProgramElements) { + buffer.put(element.getEncoded()); } - byte[] command = commandBuffer.array(); - byte[] interlock = interlockCommand.getEncoded(); - short totalLength = (short) (command.length + interlock.length + HEADER_LENGTH); - - return ByteBuffer.allocate(totalLength) // - .put(encodeHeader(address, sequenceNumber, totalLength, multiCommandFlag)) // - .put(command) // - .put(interlock) // - .array(); + return buffer.array(); } - public static final class Builder extends NonceEnabledCommandBuilder { - private List insulinProgramElements; - private Byte currentHalfOurEntryIndex; - private Short checksum; - private Short remainingEighthSecondsInCurrentHalfHourEntry; - private Short remainingPulsesInCurrentHalfHourEntry; - private DeliveryType deliveryType; - private Command interlockCommand; - - public Builder setInsulinProgramElements(List insulinProgramElements) { - if (insulinProgramElements == null) { - throw new IllegalArgumentException("insulinProgramElements can not be null"); - } - this.insulinProgramElements = new ArrayList<>(insulinProgramElements); - return this; - } - - public Builder setCurrentHalfOurEntryIndex(byte currentHalfOurEntryIndex) { - this.currentHalfOurEntryIndex = currentHalfOurEntryIndex; - return this; - } - - public Builder setChecksum(short checksum) { - this.checksum = checksum; - return this; - } - - public Builder setRemainingEighthSecondsInCurrentHalfHourEntryIndex(short remainingEighthSecondsInCurrentHalfHourEntry) { - this.remainingEighthSecondsInCurrentHalfHourEntry = remainingEighthSecondsInCurrentHalfHourEntry; - return this; - } - - public Builder setRemainingPulsesInCurrentHalfHourEntry(short remainingPulsesInCurrentHalfHourEntry) { - this.remainingPulsesInCurrentHalfHourEntry = remainingPulsesInCurrentHalfHourEntry; - return this; - } - - public Builder setDeliveryType(DeliveryType deliveryType) { - this.deliveryType = deliveryType; - return this; - } - - public Builder 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 (currentHalfOurEntryIndex == null) { - throw new IllegalArgumentException("currentHalfOurEntryIndex can not be null"); - } - if (checksum == null) { - throw new IllegalArgumentException("checksum can not be null"); - } - if (remainingEighthSecondsInCurrentHalfHourEntry == null) { - throw new IllegalArgumentException("remainingEighthSecondsInCurrentHalfHourEntry can not be null"); - } - if (remainingPulsesInCurrentHalfHourEntry == null) { - throw new IllegalArgumentException("remainingPulsesInCurrentHalfHourEntry can not be null"); - } - if (deliveryType == null) { - throw new IllegalArgumentException("deliveryType can not be null"); - } - if (interlockCommand == null) { - throw new IllegalArgumentException("interlockCommand can not be null"); - } - return new ProgramInsulinCommand(address, sequenceNumber, multiCommandFlag, nonce, insulinProgramElements, currentHalfOurEntryIndex, checksum, remainingEighthSecondsInCurrentHalfHourEntry, remainingPulsesInCurrentHalfHourEntry, deliveryType, interlockCommand); - } - } - - public enum DeliveryType { + enum DeliveryType { BASAL((byte) 0x00), TEMP_BASAL((byte) 0x01), BOLUS((byte) 0x02); @@ -167,12 +72,11 @@ public final class ProgramInsulinCommand extends NonceEnabledCommand { @Override public String toString() { return "ProgramInsulinCommand{" + "insulinProgramElements=" + insulinProgramElements + - ", currentHalfHourEntryIndex=" + currentHalfHourEntryIndex + + ", currentSlot=" + currentSlot + ", checksum=" + checksum + - ", remainingEighthSecondsInCurrentHalfHourEntry=" + remainingEighthSecondsInCurrentHalfHourEntry + - ", remainingPulsesInCurrentHalfHourEntry=" + remainingPulsesInCurrentHalfHourEntry + + ", remainingEighthSecondsInCurrentSlot=" + remainingEighthSecondsInCurrentSlot + + ", remainingPulsesInCurrentSlot=" + remainingPulsesInCurrentSlot + ", deliveryType=" + deliveryType + - ", interlockCommand=" + interlockCommand + ", nonce=" + nonce + ", commandType=" + commandType + ", address=" + address + @@ -181,26 +85,4 @@ public final class ProgramInsulinCommand extends NonceEnabledCommand { '}'; } - public static class InsulinProgramElement implements Encodable { - private final byte numberOfHalfOurEntries; // 4 bits - private final short numberOfPulsesPerHalfOurEntry; // 10 bits - private final boolean extraAlternatePulse; - - public InsulinProgramElement(byte numberOfHalfOurEntries, short numberOfPulsesPerHalfOurEntry, boolean extraAlternatePulse) { - this.numberOfHalfOurEntries = numberOfHalfOurEntries; - this.numberOfPulsesPerHalfOurEntry = numberOfPulsesPerHalfOurEntry; - this.extraAlternatePulse = extraAlternatePulse; - } - - @Override public byte[] getEncoded() { - byte firstByte = (byte) ((((numberOfHalfOurEntries - 1) & 0x0f) << 4) // - | ((extraAlternatePulse ? 1 : 0) << 3) // - | ((numberOfPulsesPerHalfOurEntry >>> 8) & 0x03)); - - return ByteBuffer.allocate(2) // - .put(firstByte) // - .put((byte) (numberOfPulsesPerHalfOurEntry & 0xff)) // - .array(); - } - } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommand.java index 7b36a22cd3..bdf7c0fe05 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommand.java @@ -17,7 +17,7 @@ public final class SetUniqueIdCommand extends HeaderEnabledCommand { private final int podSequenceNumber; private final Date initializationTime; - private SetUniqueIdCommand(int address, short sequenceNumber, boolean multiCommandFlag, int lotNumber, int podSequenceNumber, Date initializationTime) { + SetUniqueIdCommand(int address, short sequenceNumber, boolean multiCommandFlag, int lotNumber, int podSequenceNumber, Date initializationTime) { super(CommandType.SET_UNIQUE_ID, address, sequenceNumber, multiCommandFlag); this.lotNumber = lotNumber; this.podSequenceNumber = podSequenceNumber; diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java index b818ff34ad..9fe21103f3 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java @@ -14,7 +14,7 @@ public final class SilenceAlertsCommand extends NonceEnabledCommand { private final SilenceAlertCommandParameters parameters; - private SilenceAlertsCommand(int address, short sequenceNumber, boolean multiCommandFlag, SilenceAlertCommandParameters parameters, int nonce) { + SilenceAlertsCommand(int address, short sequenceNumber, boolean multiCommandFlag, SilenceAlertCommandParameters parameters, int nonce) { super(CommandType.SILENCE_ALERTS, address, sequenceNumber, multiCommandFlag, nonce); this.parameters = parameters; } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java index e4ea66a55f..db6bf0d29f 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java @@ -16,7 +16,7 @@ public final class StopDeliveryCommand extends NonceEnabledCommand { private final DeliveryType deliveryType; private final BeepType beepType; - private StopDeliveryCommand(int address, short sequenceNumber, boolean multiCommandFlag, DeliveryType deliveryType, BeepType beepType, int nonce) { + 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; diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/CurrentSlot.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/CurrentSlot.java new file mode 100644 index 0000000000..71ff653df7 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/CurrentSlot.java @@ -0,0 +1,33 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program; + +public class CurrentSlot { + private byte index; + private short secondsRemaining; + private short pulsesRemaining; + + public CurrentSlot(byte index, short secondsRemaining, short pulsesRemaining) { + this.index = index; + this.secondsRemaining = secondsRemaining; + this.pulsesRemaining = pulsesRemaining; + } + + public byte getIndex() { + return index; + } + + public short getSecondsRemaining() { + return secondsRemaining; + } + + public short getPulsesRemaining() { + return pulsesRemaining; + } + + @Override public String toString() { + return "CurrentSlot{" + + "index=" + index + + ", secondsRemaining=" + secondsRemaining + + ", pulsesRemaining=" + pulsesRemaining + + '}'; + } +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/LongInsulinProgramElement.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/LongInsulinProgramElement.java new file mode 100644 index 0000000000..60c05fa476 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/LongInsulinProgramElement.java @@ -0,0 +1,29 @@ +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 LongInsulinProgramElement implements Encodable { + private final short totalTenthPulses; + private final int delayBetweenTenthPulses; + + public LongInsulinProgramElement(byte totalTenthPulses, short delayBetweenTenthPulses) { + this.totalTenthPulses = totalTenthPulses; + this.delayBetweenTenthPulses = delayBetweenTenthPulses; + } + + @Override public byte[] getEncoded() { + return ByteBuffer.allocate(6) // + .putShort(totalTenthPulses) // + .putInt(delayBetweenTenthPulses) // + .array(); + } + + @Override public String toString() { + return "LongInsulinProgramElement{" + + "totalTenthPulses=" + totalTenthPulses + + ", delayBetweenTenthPulses=" + delayBetweenTenthPulses + + '}'; + } +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ProgramBasalUtil.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ProgramBasalUtil.java new file mode 100644 index 0000000000..54aef93b11 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ProgramBasalUtil.java @@ -0,0 +1,150 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BasalProgram; + +public final class ProgramBasalUtil { + private static final byte NUMBER_OF_BASAL_SLOTS = 48; + private static final byte MAX_NUMBER_OF_SLOTS_IN_SHORT_INSULIN_PROGRAM_ELEMENT = 16; + + private ProgramBasalUtil() { + } + + public static List mapPulsesPerSlotToLongInsulinProgramElements(short[] pulsesPerSlot) { + if (pulsesPerSlot.length != NUMBER_OF_BASAL_SLOTS) { + throw new IllegalArgumentException("Basal program must contain 48 slots"); + } + + // TODO + + return new ArrayList<>(); + } + + public static List mapPulsesPerSlotToShortInsulinProgramElements(short[] pulsesPerSlot) { + if (pulsesPerSlot.length != NUMBER_OF_BASAL_SLOTS) { + throw new IllegalArgumentException("Basal program must contain 48 slots"); + } + + List elements = new ArrayList<>(); + boolean extraAlternatePulse = false; + short previousPulsesPerSlot = 0; + byte numberOfSlotsInCurrentElement = 0; + byte currentTotalNumberOfSlots = 0; + + while (currentTotalNumberOfSlots < NUMBER_OF_BASAL_SLOTS) { + if (currentTotalNumberOfSlots == 0) { + // First slot + + previousPulsesPerSlot = pulsesPerSlot[0]; + currentTotalNumberOfSlots++; + numberOfSlotsInCurrentElement = 1; + } else if (pulsesPerSlot[currentTotalNumberOfSlots] == previousPulsesPerSlot) { + // Subsequent slot in element (same pulses per slot as previous slot) + + if (numberOfSlotsInCurrentElement < MAX_NUMBER_OF_SLOTS_IN_SHORT_INSULIN_PROGRAM_ELEMENT) { + numberOfSlotsInCurrentElement++; + } else { + elements.add(new ShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, false)); + previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots]; + numberOfSlotsInCurrentElement = 1; + extraAlternatePulse = false; + } + + currentTotalNumberOfSlots++; + } else if (numberOfSlotsInCurrentElement == 1 && pulsesPerSlot[currentTotalNumberOfSlots] == previousPulsesPerSlot + 1) { + // Second slot of segment with extra alternate pulse + + boolean expectAlternatePulseForNextSegment = false; + currentTotalNumberOfSlots++; + extraAlternatePulse = true; + while (currentTotalNumberOfSlots < NUMBER_OF_BASAL_SLOTS) { + // Loop rest alternate pulse segment + + if (pulsesPerSlot[currentTotalNumberOfSlots] == previousPulsesPerSlot + (expectAlternatePulseForNextSegment ? 1 : 0)) { + // Still in alternate pulse segment + + currentTotalNumberOfSlots++; + expectAlternatePulseForNextSegment = !expectAlternatePulseForNextSegment; + + if (numberOfSlotsInCurrentElement < MAX_NUMBER_OF_SLOTS_IN_SHORT_INSULIN_PROGRAM_ELEMENT) { + numberOfSlotsInCurrentElement++; + } else { + // End of alternate pulse segment (no slots left in element) + + elements.add(new ShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, true)); + previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots]; + numberOfSlotsInCurrentElement = 1; + extraAlternatePulse = false; + break; + } + } else { + // End of alternate pulse segment (new number of pulses per slot) + + elements.add(new ShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, true)); + previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots]; + numberOfSlotsInCurrentElement = 1; + extraAlternatePulse = false; + currentTotalNumberOfSlots++; + break; + } + } + } else if (previousPulsesPerSlot != pulsesPerSlot[currentTotalNumberOfSlots]) { + // End of segment (new number of pulses per slot) + elements.add(new ShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, false)); + + previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots]; + currentTotalNumberOfSlots++; + extraAlternatePulse = false; + numberOfSlotsInCurrentElement = 1; + } else { + throw new IllegalStateException("Reached illegal point in mapBasalProgramToShortInsulinProgramElements"); + } + } + + elements.add(new ShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse)); + + return elements; + } + + public static short[] mapBasalProgramToPulsesPerSlot(BasalProgram basalProgram) { + short[] pulsesPerSlot = new short[NUMBER_OF_BASAL_SLOTS]; + for (BasalProgram.Segment segment : basalProgram.getSegments()) { + boolean remainingPulse = false; + for (int i = segment.getStartSlotIndex(); i < segment.getEndSlotIndex(); i++) { + pulsesPerSlot[i] = (short) (segment.getPulsesPerHour() / 2); + if (segment.getPulsesPerHour() % 2 == 1) { // Do extra alternate pulse + if (remainingPulse) { + pulsesPerSlot[i] += 1; + } + remainingPulse = !remainingPulse; + } + } + } + + return pulsesPerSlot; + } + + public static CurrentSlot calculateCurrentSlot(short[] pulsesPerSlot, Date currentTime) { + Calendar instance = Calendar.getInstance(); + instance.setTime(currentTime); + + int hourOfDay = instance.get(Calendar.HOUR_OF_DAY); + int minuteOfHour = instance.get(Calendar.MINUTE); + int secondOfMinute = instance.get(Calendar.SECOND); + + byte index = (byte) ((hourOfDay * 60 + minuteOfHour) / 30); + short secondsRemaining = (short) ((index + 1) * 1800 - (secondOfMinute + hourOfDay * 3600 + minuteOfHour * 60)); + short pulsesRemaining = (short) ((double) pulsesPerSlot[index] * secondsRemaining / 1800); + + return new CurrentSlot(index, secondsRemaining, pulsesRemaining); + } + + public static short createChecksum() { + // TODO + return 0; + } +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ShortInsulinProgramElement.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ShortInsulinProgramElement.java new file mode 100644 index 0000000000..08768b684e --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ShortInsulinProgramElement.java @@ -0,0 +1,36 @@ +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 numberOfSlotsMinusOne; // 4 bits + private final short pulsesPerSlot; // 10 bits + private final boolean extraAlternatePulse; + + public ShortInsulinProgramElement(byte numberOfSlotsMinusOne, short pulsesPerSlot, boolean extraAlternatePulse) { + this.numberOfSlotsMinusOne = numberOfSlotsMinusOne; + this.pulsesPerSlot = pulsesPerSlot; + this.extraAlternatePulse = extraAlternatePulse; + } + + @Override public byte[] getEncoded() { + byte firstByte = (byte) ((((numberOfSlotsMinusOne - 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=" + numberOfSlotsMinusOne + + ", pulsesPerSlot=" + pulsesPerSlot + + ", extraAlternatePulse=" + extraAlternatePulse + + '}'; + } +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/BasalProgram.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/BasalProgram.java new file mode 100644 index 0000000000..5019260b0b --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/BasalProgram.java @@ -0,0 +1,92 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class BasalProgram { + private final List segments; + + public BasalProgram(List segments) { + if (segments == null) { + throw new IllegalArgumentException("segments can not be null"); + } + + // TODO validate segments + + this.segments = new ArrayList<>(segments); + } + + public void addSegment(Segment segment) { + segments.add(segment); + } + + public List getSegments() { + return Collections.unmodifiableList(segments); + } + + public boolean isZeroBasal() { + int total = 0; + for (Segment segment : segments) { + total += segment.getBasalRateInHundredthUnitsPerHour(); + } + return total == 0; + } + + public boolean hasZeroUnitSegments() { + for (Segment segment : segments) { + if (segment.getBasalRateInHundredthUnitsPerHour() == 0) { + return true; + } + } + return false; + } + + public static class Segment { + private static final byte PULSES_PER_UNIT = 20; + + private final short startSlotIndex; + private final short endSlotIndex; + private final int basalRateInHundredthUnitsPerHour; + + public Segment(short startSlotIndex, short endSlotIndex, int basalRateInHundredthUnitsPerHour) { + this.startSlotIndex = startSlotIndex; + this.endSlotIndex = endSlotIndex; + this.basalRateInHundredthUnitsPerHour = basalRateInHundredthUnitsPerHour; + } + + public short getStartSlotIndex() { + return startSlotIndex; + } + + public short getEndSlotIndex() { + return endSlotIndex; + } + + public int getBasalRateInHundredthUnitsPerHour() { + return basalRateInHundredthUnitsPerHour; + } + + public short getPulsesPerHour() { + return (short) (basalRateInHundredthUnitsPerHour * PULSES_PER_UNIT / 100); + } + + public short getNumberOfSlots() { + return (short) (endSlotIndex - startSlotIndex); + } + + @Override public String toString() { + return "Segment{" + + "startSlotIndex=" + startSlotIndex + + ", endSlotIndex=" + endSlotIndex + + ", basalRateInHundredthUnitsPerHour=" + basalRateInHundredthUnitsPerHour + + '}'; + } + } + + @Override public String toString() { + return "BasalProgram{" + + "segments=" + segments + + '}'; + } +} diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/response/NakResponseTest.java b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/response/NakResponseTest.java index 8f43916574..06937a0e92 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/response/NakResponseTest.java +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/response/NakResponseTest.java @@ -16,8 +16,8 @@ public class NakResponseTest { @Test public void testValidResponse() throws DecoderException { byte[] encoded = Hex.decodeHex("0603070009"); - NakResponse response = new NakResponse(encoded); + assertArrayEquals(encoded, response.getEncoded()); assertNotSame(encoded, response.getEncoded()); assertEquals(ResponseType.NAK_RESPONSE, response.getResponseType()); From 79c9e9a938357b102496335a500e5eca337dbe5e Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Wed, 17 Feb 2021 14:34:08 +0100 Subject: [PATCH 11/83] More WIP on Omnipod Dash program basal command --- .../pod/command/ProgramBasalCommand.java | 14 +- .../CurrentLongInsulinProgramElement.java | 39 ++++++ .../command/insulin/program/CurrentSlot.java | 16 +-- .../program/LongInsulinProgramElement.java | 34 ++++- .../insulin/program/ProgramBasalUtil.java | 123 ++++++++++++++++-- 5 files changed, 191 insertions(+), 35 deletions(-) create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/CurrentLongInsulinProgramElement.java diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java index f679adde88..7bfb50747e 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java @@ -8,6 +8,7 @@ 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.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; @@ -87,9 +88,6 @@ public final class ProgramBasalCommand extends HeaderEnabledCommand { private Date currentTime; public Builder setBasalProgram(BasalProgram basalProgram) { - if (basalProgram == null) { - throw new IllegalArgumentException("basalProgram can not be null"); - } this.basalProgram = basalProgram; return this; } @@ -120,15 +118,15 @@ public final class ProgramBasalCommand extends HeaderEnabledCommand { List longInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToLongInsulinProgramElements(pulsesPerSlot); List shortInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot); short checksum = ProgramBasalUtil.createChecksum(); - byte currentInsulinProgramElementIndex = 0; // TODO - short remainingTenthPulsesInCurrentInsulinProgramElement = 0; // TODO - int delayUntilNextPulseInUsec = 0; // TODO + CurrentLongInsulinProgramElement currentLongInsulinProgramElement = ProgramBasalUtil.calculateCurrentLongInsulinProgramElement(longInsulinProgramElements, currentTime); ProgramInsulinCommand interlockCommand = new ProgramInsulinCommand(address, sequenceNumber, multiCommandFlag, nonce, - shortInsulinProgramElements, currentSlot.getIndex(), checksum, (short) (currentSlot.getSecondsRemaining() * 8), + shortInsulinProgramElements, currentSlot.getIndex(), checksum, (short) (currentSlot.getEighthSecondsRemaining() * 8), currentSlot.getPulsesRemaining(), ProgramInsulinCommand.DeliveryType.BASAL); - return new ProgramBasalCommand(interlockCommand, address, sequenceNumber, multiCommandFlag, longInsulinProgramElements, programReminder, currentInsulinProgramElementIndex, remainingTenthPulsesInCurrentInsulinProgramElement, delayUntilNextPulseInUsec); + return new ProgramBasalCommand(interlockCommand, address, sequenceNumber, multiCommandFlag, + longInsulinProgramElements, programReminder, currentLongInsulinProgramElement.getIndex(), + currentLongInsulinProgramElement.getRemainingTenthPulses(), currentLongInsulinProgramElement.getDelayUntilNextTenthPulseInUsec()); } } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/CurrentLongInsulinProgramElement.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/CurrentLongInsulinProgramElement.java new file mode 100644 index 0000000000..2c33e8b1bd --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/CurrentLongInsulinProgramElement.java @@ -0,0 +1,39 @@ +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 { + private final byte index; + private final int delayUntilNextTenthPulseInUsec; + private final short remainingTenthPulses; + + public CurrentLongInsulinProgramElement(byte index, int delayUntilNextTenthPulseInUsec, short remainingTenthPulses) { + this.index = index; + this.delayUntilNextTenthPulseInUsec = delayUntilNextTenthPulseInUsec; + this.remainingTenthPulses = remainingTenthPulses; + } + + public byte getIndex() { + return index; + } + + public int getDelayUntilNextTenthPulseInUsec() { + return delayUntilNextTenthPulseInUsec; + } + + public short getRemainingTenthPulses() { + return remainingTenthPulses; + } + + @Override public String toString() { + return "CurrentLongInsulinProgramElement{" + + "index=" + index + + ", delayUntilNextTenthPulseInUsec=" + delayUntilNextTenthPulseInUsec + + ", remainingTenthPulses=" + remainingTenthPulses + + '}'; + } + + @Override public byte[] getEncoded() { + return new byte[0]; + } +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/CurrentSlot.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/CurrentSlot.java index 71ff653df7..1468370b01 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/CurrentSlot.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/CurrentSlot.java @@ -1,13 +1,13 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program; public class CurrentSlot { - private byte index; - private short secondsRemaining; - private short pulsesRemaining; + private final byte index; + private final short eighthSecondsRemaining; + private final short pulsesRemaining; - public CurrentSlot(byte index, short secondsRemaining, short pulsesRemaining) { + public CurrentSlot(byte index, short eighthSecondsRemaining, short pulsesRemaining) { this.index = index; - this.secondsRemaining = secondsRemaining; + this.eighthSecondsRemaining = eighthSecondsRemaining; this.pulsesRemaining = pulsesRemaining; } @@ -15,8 +15,8 @@ public class CurrentSlot { return index; } - public short getSecondsRemaining() { - return secondsRemaining; + public short getEighthSecondsRemaining() { + return eighthSecondsRemaining; } public short getPulsesRemaining() { @@ -26,7 +26,7 @@ public class CurrentSlot { @Override public String toString() { return "CurrentSlot{" + "index=" + index + - ", secondsRemaining=" + secondsRemaining + + ", eighthSecondsRemaining=" + eighthSecondsRemaining + ", pulsesRemaining=" + pulsesRemaining + '}'; } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/LongInsulinProgramElement.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/LongInsulinProgramElement.java index 60c05fa476..f28f4e306b 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/LongInsulinProgramElement.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/LongInsulinProgramElement.java @@ -5,25 +5,47 @@ import java.nio.ByteBuffer; import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable; public class LongInsulinProgramElement implements Encodable { + private final byte startSlotIndex; + private final byte numberOfSlots; private final short totalTenthPulses; - private final int delayBetweenTenthPulses; + private final int delayBetweenTenthPulsesInUsec; - public LongInsulinProgramElement(byte totalTenthPulses, short delayBetweenTenthPulses) { + public LongInsulinProgramElement(byte startSlotIndex, byte numberOfSlots, short totalTenthPulses, int delayBetweenTenthPulsesInUsec) { + this.startSlotIndex = startSlotIndex; + this.numberOfSlots = numberOfSlots; this.totalTenthPulses = totalTenthPulses; - this.delayBetweenTenthPulses = delayBetweenTenthPulses; + this.delayBetweenTenthPulsesInUsec = delayBetweenTenthPulsesInUsec; } @Override public byte[] getEncoded() { return ByteBuffer.allocate(6) // .putShort(totalTenthPulses) // - .putInt(delayBetweenTenthPulses) // + .putInt(delayBetweenTenthPulsesInUsec) // .array(); } + public byte getStartSlotIndex() { + return startSlotIndex; + } + + public byte getNumberOfSlots() { + return numberOfSlots; + } + + public short getTotalTenthPulses() { + return totalTenthPulses; + } + + public int getDelayBetweenTenthPulsesInUsec() { + return delayBetweenTenthPulsesInUsec; + } + @Override public String toString() { return "LongInsulinProgramElement{" + - "totalTenthPulses=" + totalTenthPulses + - ", delayBetweenTenthPulses=" + delayBetweenTenthPulses + + "startSlotIndex=" + startSlotIndex + + ", numberOfSlots=" + numberOfSlots + + ", totalTenthPulses=" + totalTenthPulses + + ", delayBetweenTenthPulsesInUsec=" + delayBetweenTenthPulsesInUsec + '}'; } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ProgramBasalUtil.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ProgramBasalUtil.java index 54aef93b11..e9197f6c10 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ProgramBasalUtil.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ProgramBasalUtil.java @@ -1,5 +1,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; @@ -9,19 +10,39 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definitio public final class ProgramBasalUtil { private static final byte NUMBER_OF_BASAL_SLOTS = 48; - private static final byte MAX_NUMBER_OF_SLOTS_IN_SHORT_INSULIN_PROGRAM_ELEMENT = 16; + private static final byte MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT = 16; + private static final int NUMBER_OF_USEC_IN_SLOT = 1_800_000_000; private ProgramBasalUtil() { } - public static List mapPulsesPerSlotToLongInsulinProgramElements(short[] pulsesPerSlot) { - if (pulsesPerSlot.length != NUMBER_OF_BASAL_SLOTS) { + public static List mapPulsesPerSlotToLongInsulinProgramElements(short[] tenthPulsesPerSlot) { + if (tenthPulsesPerSlot.length != NUMBER_OF_BASAL_SLOTS) { throw new IllegalArgumentException("Basal program must contain 48 slots"); } - // TODO + List elements = new ArrayList<>(); + long previousTenthPulsesPerSlot = 0; + byte numberOfSlotsInCurrentElement = 0; + byte startSlotIndex = 0; - return new ArrayList<>(); + for (int i = 0; i < NUMBER_OF_BASAL_SLOTS; i++) { + 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)))); + + previousTenthPulsesPerSlot = tenthPulsesPerSlot[i]; + numberOfSlotsInCurrentElement = 1; + startSlotIndex += numberOfSlotsInCurrentElement; + } else { + numberOfSlotsInCurrentElement++; + } + } + elements.add(new LongInsulinProgramElement(startSlotIndex, numberOfSlotsInCurrentElement, (short) (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement), (int) ((NUMBER_OF_USEC_IN_SLOT * numberOfSlotsInCurrentElement) / (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement)))); + + return elements; } public static List mapPulsesPerSlotToShortInsulinProgramElements(short[] pulsesPerSlot) { @@ -45,7 +66,7 @@ public final class ProgramBasalUtil { } else if (pulsesPerSlot[currentTotalNumberOfSlots] == previousPulsesPerSlot) { // Subsequent slot in element (same pulses per slot as previous slot) - if (numberOfSlotsInCurrentElement < MAX_NUMBER_OF_SLOTS_IN_SHORT_INSULIN_PROGRAM_ELEMENT) { + if (numberOfSlotsInCurrentElement < MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT) { numberOfSlotsInCurrentElement++; } else { elements.add(new ShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, false)); @@ -70,7 +91,7 @@ public final class ProgramBasalUtil { currentTotalNumberOfSlots++; expectAlternatePulseForNextSegment = !expectAlternatePulseForNextSegment; - if (numberOfSlotsInCurrentElement < MAX_NUMBER_OF_SLOTS_IN_SHORT_INSULIN_PROGRAM_ELEMENT) { + if (numberOfSlotsInCurrentElement < MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT) { numberOfSlotsInCurrentElement++; } else { // End of alternate pulse segment (no slots left in element) @@ -110,6 +131,21 @@ public final class ProgramBasalUtil { return elements; } + public static short[] mapBasalProgramToTenthPulsesPerSlot(BasalProgram basalProgram) { + short[] tenthPulsesPerSlot = new short[NUMBER_OF_BASAL_SLOTS]; + for (BasalProgram.Segment segment : basalProgram.getSegments()) { + for (int i = segment.getStartSlotIndex(); i < segment.getEndSlotIndex(); i++) { + tenthPulsesPerSlot[i] = (short) (roundToHalf(segment.getPulsesPerHour() / 2.0d) * 10); + } + } + + return tenthPulsesPerSlot; + } + + private static double roundToHalf(double d) { + return (double) (short) ((short) (int) (d * 10.0d) / 5 * 5) / 10.0d; + } + public static short[] mapBasalProgramToPulsesPerSlot(BasalProgram basalProgram) { short[] pulsesPerSlot = new short[NUMBER_OF_BASAL_SLOTS]; for (BasalProgram.Segment segment : basalProgram.getSegments()) { @@ -137,14 +173,75 @@ public final class ProgramBasalUtil { int secondOfMinute = instance.get(Calendar.SECOND); byte index = (byte) ((hourOfDay * 60 + minuteOfHour) / 30); - short secondsRemaining = (short) ((index + 1) * 1800 - (secondOfMinute + hourOfDay * 3600 + minuteOfHour * 60)); - short pulsesRemaining = (short) ((double) pulsesPerSlot[index] * secondsRemaining / 1800); + int secondOfDay = secondOfMinute + hourOfDay * 3_600 + minuteOfHour * 60; - return new CurrentSlot(index, secondsRemaining, pulsesRemaining); + short secondsRemaining = (short) ((index + 1) * 1_800 - secondOfDay); + short pulsesRemaining = (short) ((double) pulsesPerSlot[index] * secondsRemaining / 1_800); + + return new CurrentSlot(index, (short) (secondsRemaining * 8), pulsesRemaining); } - public static short createChecksum() { - // TODO - return 0; + public static CurrentLongInsulinProgramElement calculateCurrentLongInsulinProgramElement(List elements, Date currentTime) { + Calendar instance = Calendar.getInstance(); + instance.setTime(currentTime); + + int hourOfDay = instance.get(Calendar.HOUR_OF_DAY); + int minuteOfHour = instance.get(Calendar.MINUTE); + int secondOfMinute = instance.get(Calendar.SECOND); + + int secondOfDay = secondOfMinute + hourOfDay * 3_600 + minuteOfHour * 60; + int startSlotIndex = 0; + + byte index = 0; + for (LongInsulinProgramElement element : elements) { + int startTimeInSeconds = startSlotIndex * 1_800; + int endTimeInSeconds = startTimeInSeconds + element.getNumberOfSlots() * 1_800; + + if (secondOfDay >= startTimeInSeconds && secondOfDay < endTimeInSeconds) { + long totalNumberOfTenThousandthPulsesInSlot = element.getTotalTenthPulses() * 1_000; + if (totalNumberOfTenThousandthPulsesInSlot == 0) { + totalNumberOfTenThousandthPulsesInSlot = element.getNumberOfSlots() * 1_000; + } + + int durationInSeconds = endTimeInSeconds - startTimeInSeconds; + int secondsPassedInCurrentSlot = secondOfDay - startTimeInSeconds; + long remainingTenThousandthPulses = (durationInSeconds - secondsPassedInCurrentSlot) * (long) totalNumberOfTenThousandthPulsesInSlot; + int delayBetweenTenthPulsesInUsec = (int) (durationInSeconds * 1_000_000L * 1_000 / totalNumberOfTenThousandthPulsesInSlot); + int secondsRemaining = secondsPassedInCurrentSlot % 1_800; + int delayUntilNextTenthPulseInUsec = delayBetweenTenthPulsesInUsec; + for (int i = 0; i < secondsRemaining; i++) { + delayUntilNextTenthPulseInUsec = delayUntilNextTenthPulseInUsec - 1_000_000; + while (delayUntilNextTenthPulseInUsec <= 0) { + delayUntilNextTenthPulseInUsec += delayBetweenTenthPulsesInUsec; + } + } + short remainingTenthPulses = (short) ((0 != remainingTenThousandthPulses % 1_000 ? 1 : 0) + remainingTenThousandthPulses / 1_000); + + return new CurrentLongInsulinProgramElement(index, delayUntilNextTenthPulseInUsec, remainingTenthPulses); + } + + index++; + startSlotIndex += element.getNumberOfSlots(); + } + throw new IllegalStateException("Could not determine current long insulin program element"); + } + + public static short createChecksum(short[] pulsesPerSlot, CurrentSlot currentSlot) { + ByteBuffer buffer = ByteBuffer.allocate(1 + 2 + 2 + NUMBER_OF_BASAL_SLOTS * 2) // + .put(currentSlot.getIndex()) // + .putShort(currentSlot.getPulsesRemaining()) // + .putShort(currentSlot.getEighthSecondsRemaining()); + + for (short pulses : pulsesPerSlot) { + buffer.putShort(pulses); + } + + byte[] bytes = buffer.array(); + + short sum = 0; + for (byte b : bytes) { + sum += (short) (b & 0xff); + } + return sum; } } From 8d554fa35b8d1a0f68c2f3df74c4b5471f953c10 Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Wed, 17 Feb 2021 14:42:01 +0100 Subject: [PATCH 12/83] Rename Omnipod Dash address to uniqueId --- .../dash/driver/pod/command/DeactivateCommand.java | 13 +++++++------ .../dash/driver/pod/command/GetVersionCommand.java | 14 +++++++------- .../driver/pod/command/ProgramAlertsCommand.java | 11 ++++++----- .../driver/pod/command/ProgramBasalCommand.java | 14 +++++++------- .../driver/pod/command/ProgramInsulinCommand.java | 6 +++--- .../driver/pod/command/SetUniqueIdCommand.java | 14 +++++++------- .../driver/pod/command/SilenceAlertsCommand.java | 11 ++++++----- .../driver/pod/command/StopDeliveryCommand.java | 11 ++++++----- .../pod/command/base/HeaderEnabledCommand.java | 10 +++++----- .../pod/command/base/NonceEnabledCommand.java | 4 ++-- .../base/builder/HeaderEnabledCommandBuilder.java | 10 +++++----- .../driver/pod/command/DeactivateCommandTest.java | 2 +- .../driver/pod/command/GetVersionCommandTest.java | 2 +- .../pod/command/ProgramAlertsCommandTest.java | 8 ++++---- .../driver/pod/command/SetUniqueIdCommandTest.java | 2 +- .../pod/command/SilenceAlertsCommandTest.java | 2 +- .../pod/command/StopDeliveryCommandTest.java | 4 ++-- 17 files changed, 71 insertions(+), 67 deletions(-) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommand.java index 784e95b40b..3f6ce6d099 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/DeactivateCommand.java @@ -10,13 +10,13 @@ public final class DeactivateCommand extends NonceEnabledCommand { private static final short LENGTH = 6; private static final byte BODY_LENGTH = 4; - DeactivateCommand(int address, short sequenceNumber, boolean multiCommandFlag, int nonce) { - super(CommandType.DEACTIVATE, address, sequenceNumber, multiCommandFlag, nonce); + DeactivateCommand(int uniqueId, short sequenceNumber, boolean multiCommandFlag, int nonce) { + super(CommandType.DEACTIVATE, uniqueId, sequenceNumber, multiCommandFlag, nonce); } @Override public byte[] getEncoded() { return appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) // - .put(encodeHeader(address, sequenceNumber, LENGTH, multiCommandFlag)) // + .put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) // .put(commandType.getValue()) // .put(BODY_LENGTH) // .putInt(nonce) // @@ -25,8 +25,9 @@ public final class DeactivateCommand extends NonceEnabledCommand { @Override public String toString() { return "DeactivateCommand{" + - "commandType=" + commandType + - ", address=" + address + + "nonce=" + nonce + + ", commandType=" + commandType + + ", uniqueId=" + uniqueId + ", sequenceNumber=" + sequenceNumber + ", multiCommandFlag=" + multiCommandFlag + '}'; @@ -34,7 +35,7 @@ public final class DeactivateCommand extends NonceEnabledCommand { public static final class Builder extends NonceEnabledCommandBuilder { @Override protected final DeactivateCommand buildCommand() { - return new DeactivateCommand(Builder.this.address, sequenceNumber, multiCommandFlag, nonce); + return new DeactivateCommand(uniqueId, sequenceNumber, multiCommandFlag, nonce); } } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommand.java index e8cc704efa..4fce0c11a2 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/GetVersionCommand.java @@ -7,28 +7,28 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.b import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.HeaderEnabledCommandBuilder; public final class GetVersionCommand extends HeaderEnabledCommand { - public static final int DEFAULT_ADDRESS = -1; // FIXME move + public static final int DEFAULT_UNIQUE_ID = -1; // FIXME move private static final short LENGTH = 6; private static final byte BODY_LENGTH = 4; - GetVersionCommand(int address, short sequenceNumber, boolean multiCommandFlag) { - super(CommandType.GET_VERSION, address, sequenceNumber, multiCommandFlag); + GetVersionCommand(int uniqueId, short sequenceNumber, boolean multiCommandFlag) { + super(CommandType.GET_VERSION, uniqueId, sequenceNumber, multiCommandFlag); } @Override public byte[] getEncoded() { return appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) // - .put(encodeHeader(address, sequenceNumber, LENGTH, multiCommandFlag)) // + .put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) // .put(commandType.getValue()) // .put(BODY_LENGTH) // - .putInt(address) // + .putInt(uniqueId) // .array()); } @Override public String toString() { return "GetVersionCommand{" + "commandType=" + commandType + - ", address=" + address + + ", uniqueId=" + uniqueId + ", sequenceNumber=" + sequenceNumber + ", multiCommandFlag=" + multiCommandFlag + '}'; @@ -36,7 +36,7 @@ public final class GetVersionCommand extends HeaderEnabledCommand { public static final class Builder extends HeaderEnabledCommandBuilder { @Override protected final GetVersionCommand buildCommand() { - return new GetVersionCommand(address, sequenceNumber, multiCommandFlag); + return new GetVersionCommand(uniqueId, sequenceNumber, multiCommandFlag); } } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.java index 30150a086e..39e850736a 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.java @@ -12,14 +12,14 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definitio public final class ProgramAlertsCommand extends NonceEnabledCommand { private final List alertConfigurations; - ProgramAlertsCommand(int address, short sequenceNumber, boolean multiCommandFlag, List alertConfigurations, int nonce) { - super(CommandType.PROGRAM_ALERTS, address, sequenceNumber, multiCommandFlag, nonce); + ProgramAlertsCommand(int uniqueId, short sequenceNumber, boolean multiCommandFlag, List alertConfigurations, int nonce) { + super(CommandType.PROGRAM_ALERTS, uniqueId, sequenceNumber, multiCommandFlag, nonce); this.alertConfigurations = new ArrayList<>(alertConfigurations); } @Override public byte[] getEncoded() { ByteBuffer byteBuffer = ByteBuffer.allocate(getLength() + HEADER_LENGTH) // - .put(encodeHeader(address, sequenceNumber, getLength(), multiCommandFlag)) // + .put(encodeHeader(uniqueId, sequenceNumber, getLength(), multiCommandFlag)) // .put(commandType.getValue()) // .put(getBodyLength()) // .putInt(nonce); @@ -40,8 +40,9 @@ public final class ProgramAlertsCommand extends NonceEnabledCommand { @Override public String toString() { return "ProgramAlertsCommand{" + "alertConfigurations=" + alertConfigurations + + ", nonce=" + nonce + ", commandType=" + commandType + - ", address=" + address + + ", uniqueId=" + uniqueId + ", sequenceNumber=" + sequenceNumber + ", multiCommandFlag=" + multiCommandFlag + '}'; @@ -59,7 +60,7 @@ public final class ProgramAlertsCommand extends NonceEnabledCommand { if (this.alertConfigurations == null) { throw new IllegalArgumentException("alertConfigurations can not be null"); } - return new ProgramAlertsCommand(address, sequenceNumber, multiCommandFlag, alertConfigurations, nonce); + return new ProgramAlertsCommand(uniqueId, sequenceNumber, multiCommandFlag, alertConfigurations, nonce); } } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java index 7bfb50747e..e111113d81 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java @@ -25,8 +25,8 @@ public final class ProgramBasalCommand extends HeaderEnabledCommand { private final short remainingTenthPulsesInCurrentInsulinProgramElement; private final int delayUntilNextTenthPulseInUsec; - ProgramBasalCommand(ProgramInsulinCommand interlockCommand, int address, short sequenceNumber, boolean multiCommandFlag, List insulinProgramElements, ProgramReminder programReminder, byte currentInsulinProgramElementIndex, short remainingTenthPulsesInCurrentInsulinProgramElement, int delayUntilNextTenthPulseInUsec) { - super(CommandType.PROGRAM_BASAL, address, sequenceNumber, multiCommandFlag); + ProgramBasalCommand(ProgramInsulinCommand interlockCommand, int uniqueId, short sequenceNumber, boolean multiCommandFlag, List insulinProgramElements, ProgramReminder programReminder, byte currentInsulinProgramElementIndex, short remainingTenthPulsesInCurrentInsulinProgramElement, int delayUntilNextTenthPulseInUsec) { + super(CommandType.PROGRAM_BASAL, uniqueId, sequenceNumber, multiCommandFlag); this.interlockCommand = interlockCommand; this.insulinProgramElements = new ArrayList<>(insulinProgramElements); @@ -58,7 +58,7 @@ public final class ProgramBasalCommand extends HeaderEnabledCommand { byte[] bolusCommand = buffer.array(); byte[] interlockCommand = this.interlockCommand.getEncoded(); - byte[] header = encodeHeader(address, 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) // .put(header) // @@ -76,7 +76,7 @@ public final class ProgramBasalCommand extends HeaderEnabledCommand { ", remainingTenthPulsesInCurrentInsulinProgramElement=" + remainingTenthPulsesInCurrentInsulinProgramElement + ", delayUntilNextTenthPulseInUsec=" + delayUntilNextTenthPulseInUsec + ", commandType=" + commandType + - ", address=" + address + + ", uniqueId=" + uniqueId + ", sequenceNumber=" + sequenceNumber + ", multiCommandFlag=" + multiCommandFlag + '}'; @@ -115,16 +115,16 @@ public final class ProgramBasalCommand extends HeaderEnabledCommand { short[] pulsesPerSlot = ProgramBasalUtil.mapBasalProgramToPulsesPerSlot(basalProgram); CurrentSlot currentSlot = ProgramBasalUtil.calculateCurrentSlot(pulsesPerSlot, currentTime); + short checksum = ProgramBasalUtil.createChecksum(pulsesPerSlot, currentSlot); List longInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToLongInsulinProgramElements(pulsesPerSlot); List shortInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot); - short checksum = ProgramBasalUtil.createChecksum(); CurrentLongInsulinProgramElement currentLongInsulinProgramElement = ProgramBasalUtil.calculateCurrentLongInsulinProgramElement(longInsulinProgramElements, currentTime); - ProgramInsulinCommand interlockCommand = new ProgramInsulinCommand(address, sequenceNumber, multiCommandFlag, nonce, + ProgramInsulinCommand interlockCommand = new ProgramInsulinCommand(uniqueId, sequenceNumber, multiCommandFlag, nonce, shortInsulinProgramElements, currentSlot.getIndex(), checksum, (short) (currentSlot.getEighthSecondsRemaining() * 8), currentSlot.getPulsesRemaining(), ProgramInsulinCommand.DeliveryType.BASAL); - return new ProgramBasalCommand(interlockCommand, address, sequenceNumber, multiCommandFlag, + return new ProgramBasalCommand(interlockCommand, uniqueId, sequenceNumber, multiCommandFlag, longInsulinProgramElements, programReminder, currentLongInsulinProgramElement.getIndex(), currentLongInsulinProgramElement.getRemainingTenthPulses(), currentLongInsulinProgramElement.getDelayUntilNextTenthPulseInUsec()); } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java index 6046e17a57..601d8a6122 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java @@ -17,8 +17,8 @@ final class ProgramInsulinCommand extends NonceEnabledCommand { private final short remainingPulsesInCurrentSlot; private final DeliveryType deliveryType; - ProgramInsulinCommand(int address, short sequenceNumber, boolean multiCommandFlag, int nonce, List insulinProgramElements, byte currentSlot, short checksum, short remainingEighthSecondsInCurrentSlot, short remainingPulsesInCurrentSlot, DeliveryType deliveryType) { - super(CommandType.PROGRAM_INSULIN, address, sequenceNumber, multiCommandFlag, nonce); + ProgramInsulinCommand(int uniqueId, short sequenceNumber, boolean multiCommandFlag, int nonce, List insulinProgramElements, byte currentSlot, short checksum, short remainingEighthSecondsInCurrentSlot, short remainingPulsesInCurrentSlot, DeliveryType deliveryType) { + super(CommandType.PROGRAM_INSULIN, uniqueId, sequenceNumber, multiCommandFlag, nonce); this.insulinProgramElements = new ArrayList<>(insulinProgramElements); this.currentSlot = currentSlot; this.checksum = checksum; @@ -79,7 +79,7 @@ final class ProgramInsulinCommand extends NonceEnabledCommand { ", deliveryType=" + deliveryType + ", nonce=" + nonce + ", commandType=" + commandType + - ", address=" + address + + ", uniqueId=" + uniqueId + ", sequenceNumber=" + sequenceNumber + ", multiCommandFlag=" + multiCommandFlag + '}'; diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommand.java index bdf7c0fe05..d43a5fb4be 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SetUniqueIdCommand.java @@ -9,7 +9,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.b import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.HeaderEnabledCommandBuilder; public final class SetUniqueIdCommand extends HeaderEnabledCommand { - private static final int DEFAULT_ADDRESS = -1; + private static final int DEFAULT_UNIQUE_ID = -1; private static final short LENGTH = 21; private static final byte BODY_LENGTH = 19; @@ -17,8 +17,8 @@ public final class SetUniqueIdCommand extends HeaderEnabledCommand { private final int podSequenceNumber; private final Date initializationTime; - SetUniqueIdCommand(int address, short sequenceNumber, boolean multiCommandFlag, int lotNumber, int podSequenceNumber, Date initializationTime) { - super(CommandType.SET_UNIQUE_ID, address, sequenceNumber, multiCommandFlag); + SetUniqueIdCommand(int uniqueId, short sequenceNumber, boolean multiCommandFlag, int lotNumber, int podSequenceNumber, Date initializationTime) { + super(CommandType.SET_UNIQUE_ID, uniqueId, sequenceNumber, multiCommandFlag); this.lotNumber = lotNumber; this.podSequenceNumber = podSequenceNumber; this.initializationTime = initializationTime; @@ -26,10 +26,10 @@ public final class SetUniqueIdCommand extends HeaderEnabledCommand { @Override public byte[] getEncoded() { return appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) // - .put(encodeHeader(DEFAULT_ADDRESS, sequenceNumber, LENGTH, multiCommandFlag)) // + .put(encodeHeader(DEFAULT_UNIQUE_ID, sequenceNumber, LENGTH, multiCommandFlag)) // .put(commandType.getValue()) // .put(BODY_LENGTH) // - .putInt(address) // + .putInt(uniqueId) // .put((byte) 0x14) // FIXME ?? .put((byte) 0x04) // FIXME ?? .put(encodeInitializationTime(initializationTime)) // @@ -57,7 +57,7 @@ public final class SetUniqueIdCommand extends HeaderEnabledCommand { ", podSequenceNumber=" + podSequenceNumber + ", initializationTime=" + initializationTime + ", commandType=" + commandType + - ", address=" + address + + ", uniqueId=" + uniqueId + ", sequenceNumber=" + sequenceNumber + ", multiCommandFlag=" + multiCommandFlag + '}'; @@ -93,7 +93,7 @@ public final class SetUniqueIdCommand extends HeaderEnabledCommand { if (initializationTime == null) { throw new IllegalArgumentException("initializationTime can not be null"); } - return new SetUniqueIdCommand(address, sequenceNumber, multiCommandFlag, lotNumber, podSequenceNumber, initializationTime); + return new SetUniqueIdCommand(uniqueId, sequenceNumber, multiCommandFlag, lotNumber, podSequenceNumber, initializationTime); } } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java index 9fe21103f3..77341967fa 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SilenceAlertsCommand.java @@ -14,14 +14,14 @@ public final class SilenceAlertsCommand extends NonceEnabledCommand { private final SilenceAlertCommandParameters parameters; - SilenceAlertsCommand(int address, short sequenceNumber, boolean multiCommandFlag, SilenceAlertCommandParameters parameters, int nonce) { - super(CommandType.SILENCE_ALERTS, address, sequenceNumber, multiCommandFlag, nonce); + SilenceAlertsCommand(int uniqueId, short sequenceNumber, boolean multiCommandFlag, SilenceAlertCommandParameters parameters, int nonce) { + super(CommandType.SILENCE_ALERTS, uniqueId, sequenceNumber, multiCommandFlag, nonce); this.parameters = parameters; } @Override public byte[] getEncoded() { return appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) // - .put(encodeHeader(address, sequenceNumber, LENGTH, multiCommandFlag)) // + .put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) // .put(commandType.getValue()) // .put(BODY_LENGTH) // .putInt(nonce) // @@ -32,8 +32,9 @@ public final class SilenceAlertsCommand extends NonceEnabledCommand { @Override public String toString() { return "SilenceAlertsCommand{" + "parameters=" + parameters + + ", nonce=" + nonce + ", commandType=" + commandType + - ", address=" + address + + ", uniqueId=" + uniqueId + ", sequenceNumber=" + sequenceNumber + ", multiCommandFlag=" + multiCommandFlag + '}'; @@ -126,7 +127,7 @@ public final class SilenceAlertsCommand extends NonceEnabledCommand { } @Override protected final SilenceAlertsCommand buildCommand() { - return new SilenceAlertsCommand(address, sequenceNumber, multiCommandFlag, new SilenceAlertCommandParameters(silenceAutoOffAlert, silenceMultiCommandAlert, silenceExpirationImminentAlert, silenceUserSetExpirationAlert, silenceLowReservoirAlert, silenceSuspendInProgressAlert, silenceSuspendEndedAlert, silencePodExpirationAlert), nonce); + return new SilenceAlertsCommand(uniqueId, sequenceNumber, multiCommandFlag, new SilenceAlertCommandParameters(silenceAutoOffAlert, silenceMultiCommandAlert, silenceExpirationImminentAlert, silenceUserSetExpirationAlert, silenceLowReservoirAlert, silenceSuspendInProgressAlert, silenceSuspendEndedAlert, silencePodExpirationAlert), nonce); } } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java index db6bf0d29f..9c539c3b4a 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/StopDeliveryCommand.java @@ -16,15 +16,15 @@ public final class StopDeliveryCommand extends NonceEnabledCommand { private final DeliveryType deliveryType; private final BeepType beepType; - StopDeliveryCommand(int address, short sequenceNumber, boolean multiCommandFlag, DeliveryType deliveryType, BeepType beepType, int nonce) { - super(CommandType.STOP_DELIVERY, address, sequenceNumber, multiCommandFlag, nonce); + StopDeliveryCommand(int uniqueId, short sequenceNumber, boolean multiCommandFlag, DeliveryType deliveryType, BeepType beepType, int nonce) { + super(CommandType.STOP_DELIVERY, uniqueId, sequenceNumber, multiCommandFlag, nonce); this.deliveryType = deliveryType; this.beepType = beepType; } @Override public byte[] getEncoded() { return appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) // - .put(encodeHeader(address, sequenceNumber, LENGTH, multiCommandFlag)) // + .put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) // .put(commandType.getValue()) // .put(BODY_LENGTH) // .putInt(nonce) // @@ -36,8 +36,9 @@ public final class StopDeliveryCommand extends NonceEnabledCommand { return "StopDeliveryCommand{" + "deliveryType=" + deliveryType + ", beepType=" + beepType + + ", nonce=" + nonce + ", commandType=" + commandType + - ", address=" + address + + ", uniqueId=" + uniqueId + ", sequenceNumber=" + sequenceNumber + ", multiCommandFlag=" + multiCommandFlag + '}'; @@ -89,7 +90,7 @@ public final class StopDeliveryCommand extends NonceEnabledCommand { if (beepType == null) { throw new IllegalArgumentException("beepType can not be null"); } - return new StopDeliveryCommand(address, sequenceNumber, multiCommandFlag, deliveryType, beepType, nonce); + return new StopDeliveryCommand(uniqueId, sequenceNumber, multiCommandFlag, deliveryType, beepType, nonce); } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/HeaderEnabledCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/HeaderEnabledCommand.java index 219dc48724..6a84f37d7f 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/HeaderEnabledCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/HeaderEnabledCommand.java @@ -8,13 +8,13 @@ public abstract class HeaderEnabledCommand implements Command { protected static final short HEADER_LENGTH = 6; protected final CommandType commandType; - protected final int address; + protected final int uniqueId; protected final short sequenceNumber; protected final boolean multiCommandFlag; - protected HeaderEnabledCommand(CommandType commandType, int address, short sequenceNumber, boolean multiCommandFlag) { + protected HeaderEnabledCommand(CommandType commandType, int uniqueId, short sequenceNumber, boolean multiCommandFlag) { this.commandType = commandType; - this.address = address; + this.uniqueId = uniqueId; this.sequenceNumber = sequenceNumber; this.multiCommandFlag = multiCommandFlag; } @@ -30,9 +30,9 @@ public abstract class HeaderEnabledCommand implements Command { .array(); } - protected static byte[] encodeHeader(int address, short sequenceNumber, short length, boolean multiCommandFlag) { + protected static byte[] encodeHeader(int uniqueId, short sequenceNumber, short length, boolean multiCommandFlag) { return ByteBuffer.allocate(6) // - .putInt(address) // + .putInt(uniqueId) // .putShort((short) (((sequenceNumber & 0x0f) << 10) | length | ((multiCommandFlag ? 1 : 0) << 15))) // .array(); } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/NonceEnabledCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/NonceEnabledCommand.java index 16a136601b..744f7eb1e9 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/NonceEnabledCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/NonceEnabledCommand.java @@ -3,8 +3,8 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command. 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); + protected NonceEnabledCommand(CommandType commandType, int uniqueId, short sequenceNumber, boolean multiCommandFlag, int nonce) { + super(commandType, uniqueId, sequenceNumber, multiCommandFlag); this.nonce = nonce; } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/builder/HeaderEnabledCommandBuilder.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/builder/HeaderEnabledCommandBuilder.java index 92d1f50c92..30dc425cb8 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/builder/HeaderEnabledCommandBuilder.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/builder/HeaderEnabledCommandBuilder.java @@ -3,13 +3,13 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command. import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command; public abstract class HeaderEnabledCommandBuilder, R extends Command> implements CommandBuilder { - protected Integer address; + protected Integer uniqueId; protected Short sequenceNumber; protected boolean multiCommandFlag = false; public R build() { - if (address == null) { - throw new IllegalArgumentException("address can not be null"); + if (uniqueId == null) { + throw new IllegalArgumentException("uniqueId can not be null"); } if (sequenceNumber == null) { throw new IllegalArgumentException("sequenceNumber can not be null"); @@ -17,8 +17,8 @@ public abstract class HeaderEnabledCommandBuilder Date: Wed, 17 Feb 2021 16:10:18 +0100 Subject: [PATCH 13/83] Finished Omnipod Dash program basal command --- .../pod/command/ProgramBasalCommand.java | 16 ++++---- .../pod/command/ProgramInsulinCommand.java | 8 ++-- .../driver/pod/command/base/CommandType.java | 4 +- .../CurrentLongInsulinProgramElement.java | 8 +--- .../insulin/program/ProgramBasalUtil.java | 10 ++--- .../program/ShortInsulinProgramElement.java | 10 ++--- .../pod/definition/ProgramReminder.java | 4 +- .../pod/command/ProgramBasalCommandTest.java | 39 +++++++++++++++++++ 8 files changed, 66 insertions(+), 33 deletions(-) create mode 100644 omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommandTest.java diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java index e111113d81..168ea4d7ea 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java @@ -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 longInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToLongInsulinProgramElements(pulsesPerSlot); + List longInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToLongInsulinProgramElements(ProgramBasalUtil.mapBasalProgramToTenthPulsesPerSlot(basalProgram)); List 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, diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java index 601d8a6122..018bc22f4f 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java @@ -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() { diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/CommandType.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/CommandType.java index 7e520d73c5..bd785e573d 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/CommandType.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/CommandType.java @@ -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), diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/CurrentLongInsulinProgramElement.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/CurrentLongInsulinProgramElement.java index 2c33e8b1bd..5a976a33ee 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/CurrentLongInsulinProgramElement.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/CurrentLongInsulinProgramElement.java @@ -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]; - } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ProgramBasalUtil.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ProgramBasalUtil.java index e9197f6c10..35e37f2054 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ProgramBasalUtil.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ProgramBasalUtil.java @@ -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); } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ShortInsulinProgramElement.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ShortInsulinProgramElement.java index 08768b684e..ab30ccbd85 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ShortInsulinProgramElement.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ShortInsulinProgramElement.java @@ -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 + '}'; diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/ProgramReminder.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/ProgramReminder.java index 22b0402e4d..018986eb36 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/ProgramReminder.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/ProgramReminder.java @@ -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))}; } } diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommandTest.java b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommandTest.java new file mode 100644 index 0000000000..e99e77945d --- /dev/null +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommandTest.java @@ -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 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); + } + +} \ No newline at end of file From cfbd8aeea49d9a341b81f0ecc2e85f4117b087ad Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Wed, 17 Feb 2021 16:10:36 +0100 Subject: [PATCH 14/83] Remove print statement --- .../omnipod/dash/driver/pod/command/ProgramBasalCommandTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommandTest.java b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommandTest.java index e99e77945d..16185fdbc4 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommandTest.java +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommandTest.java @@ -32,7 +32,6 @@ public class ProgramBasalCommandTest { .build() // .getEncoded(); - System.out.println(Hex.encodeHexString(encoded)); assertArrayEquals(Hex.decodeHex("0242000128241A12494E532E0005E81D1708000CF01EF01EF01E130E40001593004C4B403840005B8D80827C"), encoded); } From 23450aee7eb495acab6b1650828c5aa4e867d617 Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Wed, 17 Feb 2021 19:20:27 +0100 Subject: [PATCH 15/83] Add Omnipod Dash bolus command --- .../pod/command/ProgramBasalCommand.java | 20 +-- .../pod/command/ProgramBolusCommand.java | 123 ++++++++++++++++++ .../pod/command/ProgramInsulinCommand.java | 34 +++-- .../command/base/HeaderEnabledCommand.java | 4 +- ...t.java => BasalInsulinProgramElement.java} | 4 +- .../BasalShortInsulinProgramElement.java | 34 +++++ .../BolusShortInsulinProgramElement.java | 19 +++ .../insulin/program/ProgramBasalUtil.java | 31 ++--- .../program/ShortInsulinProgramElement.java | 32 +---- .../util/{CrcUtil.java => MessageUtil.java} | 10 +- .../pod/command/ProgramBolusCommandTest.java | 27 ++++ 11 files changed, 261 insertions(+), 77 deletions(-) create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBolusCommand.java rename omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/{LongInsulinProgramElement.java => BasalInsulinProgramElement.java} (88%) create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/BasalShortInsulinProgramElement.java create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/BolusShortInsulinProgramElement.java rename omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/util/{CrcUtil.java => MessageUtil.java} (92%) create mode 100644 omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBolusCommandTest.java diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java index 168ea4d7ea..47ca0871c8 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java @@ -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 insulinProgramElements; + private final List 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 insulinProgramElements, ProgramReminder programReminder, byte currentInsulinProgramElementIndex, short remainingTenthPulsesInCurrentInsulinProgramElement, int delayUntilNextTenthPulseInUsec) { + ProgramBasalCommand(ProgramInsulinCommand interlockCommand, int uniqueId, short sequenceNumber, boolean multiCommandFlag, List 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 longInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToLongInsulinProgramElements(ProgramBasalUtil.mapBasalProgramToTenthPulsesPerSlot(basalProgram)); + List longInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToLongInsulinProgramElements(ProgramBasalUtil.mapBasalProgramToTenthPulsesPerSlot(basalProgram)); List 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, diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBolusCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBolusCommand.java new file mode 100644 index 0000000000..4431993e56 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBolusCommand.java @@ -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 { + 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()); + } +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java index 018bc22f4f..fe759b1ab4 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java @@ -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 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 insulinProgramElements, byte currentSlot, short checksum, short remainingEighthSecondsInCurrentSlot, short remainingPulsesInCurrentSlot, DeliveryType deliveryType) { + ProgramInsulinCommand(int uniqueId, short sequenceNumber, boolean multiCommandFlag, int nonce, List 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 + diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/HeaderEnabledCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/HeaderEnabledCommand.java index 6a84f37d7f..0a4cc03007 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/HeaderEnabledCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/base/HeaderEnabledCommand.java @@ -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(); } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/LongInsulinProgramElement.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/BasalInsulinProgramElement.java similarity index 88% rename from omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/LongInsulinProgramElement.java rename to omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/BasalInsulinProgramElement.java index f28f4e306b..01359b4586 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/LongInsulinProgramElement.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/BasalInsulinProgramElement.java @@ -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; diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/BasalShortInsulinProgramElement.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/BasalShortInsulinProgramElement.java new file mode 100644 index 0000000000..9a8983f8f3 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/BasalShortInsulinProgramElement.java @@ -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 + + '}'; + } +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/BolusShortInsulinProgramElement.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/BolusShortInsulinProgramElement.java new file mode 100644 index 0000000000..0c23171639 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/BolusShortInsulinProgramElement.java @@ -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(); + } +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ProgramBasalUtil.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ProgramBasalUtil.java index 35e37f2054..13d1c0f395 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ProgramBasalUtil.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ProgramBasalUtil.java @@ -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 mapPulsesPerSlotToLongInsulinProgramElements(short[] tenthPulsesPerSlot) { + public static List mapPulsesPerSlotToLongInsulinProgramElements(short[] tenthPulsesPerSlot) { if (tenthPulsesPerSlot.length != NUMBER_OF_BASAL_SLOTS) { throw new IllegalArgumentException("Basal program must contain 48 slots"); } - List elements = new ArrayList<>(); + List 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 elements, Date currentTime) { + public static CurrentLongInsulinProgramElement calculateCurrentLongInsulinProgramElement(List 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()); } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ShortInsulinProgramElement.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ShortInsulinProgramElement.java index ab30ccbd85..04a5c39864 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ShortInsulinProgramElement.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ShortInsulinProgramElement.java @@ -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 { } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/util/CrcUtil.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/util/MessageUtil.java similarity index 92% rename from omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/util/CrcUtil.java rename to omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/util/MessageUtil.java index 2597c619ff..f67993e3c5 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/util/CrcUtil.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/util/MessageUtil.java @@ -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; + } } diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBolusCommandTest.java b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBolusCommandTest.java new file mode 100644 index 0000000000..2eea08c718 --- /dev/null +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBolusCommandTest.java @@ -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); + } + +} \ No newline at end of file From e961a7990e3a83cc4d0c1f1a0d26958074689fdb Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Wed, 17 Feb 2021 19:34:01 +0100 Subject: [PATCH 16/83] Move Omnipod Dash dependencies to core --- core/core_dependencies.gradle | 1 + omnipod-dash/build.gradle | 7 ++----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/core/core_dependencies.gradle b/core/core_dependencies.gradle index 4d05f7312f..5688e5d957 100644 --- a/core/core_dependencies.gradle +++ b/core/core_dependencies.gradle @@ -46,6 +46,7 @@ dependencies { api "io.reactivex.rxjava2:rxkotlin:$rxkotlin_version" api "io.reactivex.rxjava2:rxandroid:$rxandroid_version" api "org.apache.commons:commons-lang3:$commonslang3_version" + api "commons-codec:commons-codec:$commonscodec_version" //CryptoUtil api 'com.madgag.spongycastle:core:1.58.0.0' diff --git a/omnipod-dash/build.gradle b/omnipod-dash/build.gradle index 8b9f9e4992..85797f8d35 100644 --- a/omnipod-dash/build.gradle +++ b/omnipod-dash/build.gradle @@ -39,15 +39,12 @@ android { } dependencies { + implementation project(':core') + annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version" annotationProcessor "com.google.dagger:dagger-android-processor:$dagger_version" kapt "com.google.dagger:dagger-android-processor:$dagger_version" kapt "com.google.dagger:dagger-compiler:$dagger_version" - - implementation "org.apache.commons:commons-lang3:$commonslang3_version" - implementation "commons-codec:commons-codec:$commonscodec_version" - implementation "androidx.appcompat:appcompat:$appcompat_version" - implementation "com.google.android.material:material:$material_version" testImplementation "junit:junit:$junit_version" androidTestImplementation "androidx.test.ext:junit:$androidx_junit" } \ No newline at end of file From 5347ae4f2deebdf0c4bcc8cf8abf10004f587b41 Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Thu, 18 Feb 2021 00:31:25 +0100 Subject: [PATCH 17/83] WIP on Omnipod program temp basal command --- .../pod/command/ProgramBasalCommand.java | 14 +- .../pod/command/ProgramBolusCommand.java | 6 +- .../pod/command/ProgramInsulinCommand.java | 2 +- .../pod/command/ProgramTempBasalCommand.java | 152 ++++++++++++++++++ .../program/BasalInsulinProgramElement.java | 4 + ...=> CurrentBasalInsulinProgramElement.java} | 4 +- .../TempBasalInsulinProgramElement.java | 35 ++++ .../program/{ => util}/ProgramBasalUtil.java | 49 +++--- .../program/util/ProgramTempBasalUtil.java | 71 ++++++++ .../dash/driver/pod/util/MessageUtil.java | 2 +- .../command/ProgramTempBasalCommandTest.java | 44 +++++ 11 files changed, 351 insertions(+), 32 deletions(-) create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramTempBasalCommand.java rename omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/{CurrentLongInsulinProgramElement.java => CurrentBasalInsulinProgramElement.java} (84%) create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/TempBasalInsulinProgramElement.java rename omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/{ => util}/ProgramBasalUtil.java (77%) create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/util/ProgramTempBasalUtil.java create mode 100644 omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramTempBasalCommandTest.java diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java index 47ca0871c8..a79f7b7374 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBasalCommand.java @@ -9,10 +9,10 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.b 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.CurrentBasalInsulinProgramElement; 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.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.command.insulin.program.util.ProgramBasalUtil; import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BasalProgram; import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ProgramReminder; @@ -115,18 +115,18 @@ public final class ProgramBasalCommand extends HeaderEnabledCommand { short[] pulsesPerSlot = ProgramBasalUtil.mapBasalProgramToPulsesPerSlot(basalProgram); CurrentSlot currentSlot = ProgramBasalUtil.calculateCurrentSlot(pulsesPerSlot, currentTime); - short checksum = ProgramBasalUtil.createChecksum(pulsesPerSlot, currentSlot); - List longInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToLongInsulinProgramElements(ProgramBasalUtil.mapBasalProgramToTenthPulsesPerSlot(basalProgram)); + short checksum = ProgramBasalUtil.calculateChecksum(pulsesPerSlot, currentSlot); + List longInsulinProgramElements = ProgramBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements(ProgramBasalUtil.mapBasalProgramToTenthPulsesPerSlot(basalProgram)); List shortInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot); - CurrentLongInsulinProgramElement currentLongInsulinProgramElement = ProgramBasalUtil.calculateCurrentLongInsulinProgramElement(longInsulinProgramElements, currentTime); + CurrentBasalInsulinProgramElement currentBasalInsulinProgramElement = ProgramBasalUtil.calculateCurrentLongInsulinProgramElement(longInsulinProgramElements, currentTime); ProgramInsulinCommand interlockCommand = new ProgramInsulinCommand(uniqueId, sequenceNumber, multiCommandFlag, nonce, shortInsulinProgramElements, checksum, currentSlot.getIndex(), currentSlot.getEighthSecondsRemaining(), currentSlot.getPulsesRemaining(), ProgramInsulinCommand.DeliveryType.BASAL); return new ProgramBasalCommand(interlockCommand, uniqueId, sequenceNumber, multiCommandFlag, - longInsulinProgramElements, programReminder, currentLongInsulinProgramElement.getIndex(), - currentLongInsulinProgramElement.getRemainingTenthPulses(), currentLongInsulinProgramElement.getDelayUntilNextTenthPulseInUsec()); + longInsulinProgramElements, programReminder, currentBasalInsulinProgramElement.getIndex(), + currentBasalInsulinProgramElement.getRemainingTenthPulses(), currentBasalInsulinProgramElement.getDelayUntilNextTenthPulseInUsec()); } } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBolusCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBolusCommand.java index 4431993e56..7c1e4a80bd 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBolusCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramBolusCommand.java @@ -103,7 +103,7 @@ public final class ProgramBolusCommand extends HeaderEnabledCommand { short byte10And11 = (short) (numberOfPulses * delayBetweenPulsesInEighthSeconds); ProgramInsulinCommand interlockCommand = new ProgramInsulinCommand(uniqueId, sequenceNumber, multiCommandFlag, nonce, - Collections.singletonList(new BolusShortInsulinProgramElement(numberOfPulses)), createChecksum((byte) 0x01, byte10And11, numberOfPulses), + Collections.singletonList(new BolusShortInsulinProgramElement(numberOfPulses)), calculateChecksum((byte) 0x01, byte10And11, numberOfPulses), (byte) 0x01, byte10And11, (short) numberOfPulses, ProgramInsulinCommand.DeliveryType.BOLUS); int delayUntilFirstTenthPulseInUsec = delayBetweenPulsesInEighthSeconds / 8 * 100_000; @@ -112,8 +112,8 @@ public final class ProgramBolusCommand extends HeaderEnabledCommand { } } - private static short createChecksum(byte numberOfSlots, short byte10And11, short numberOfPulses) { - return MessageUtil.createCheckSum(ByteBuffer.allocate(7) // + private static short calculateChecksum(byte numberOfSlots, short byte10And11, short numberOfPulses) { + return MessageUtil.calculateChecksum(ByteBuffer.allocate(7) // .put(numberOfSlots) // .putShort(byte10And11) // .putShort(numberOfPulses) // diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java index fe759b1ab4..ce060000cc 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.java @@ -69,7 +69,7 @@ final class ProgramInsulinCommand extends NonceEnabledCommand { } } - public short createChecksum(byte[] bytes) { + public short calculateChecksum(byte[] bytes) { short sum = 0; for (byte b : bytes) { sum += (short) (b & 0xff); diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramTempBasalCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramTempBasalCommand.java new file mode 100644 index 0000000000..42031a189b --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramTempBasalCommand.java @@ -0,0 +1,152 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command; + +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.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.ShortInsulinProgramElement; +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.util.ProgramBasalUtil; +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.util.ProgramTempBasalUtil; +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ProgramReminder; + +// NOT SUPPORTED: percentage temp basal +public final class ProgramTempBasalCommand extends HeaderEnabledCommand { + private final ProgramInsulinCommand interlockCommand; + private final ProgramReminder programReminder; + private final List insulinProgramElements; + private final TempBasalMethod tempBasalMethod; + + protected ProgramTempBasalCommand(ProgramInsulinCommand interlockCommand, int uniqueId, short sequenceNumber, boolean multiCommandFlag, ProgramReminder programReminder, + List insulinProgramElements, TempBasalMethod tempBasalMethod) { + super(CommandType.PROGRAM_TEMP_BASAL, uniqueId, sequenceNumber, multiCommandFlag); + this.interlockCommand = interlockCommand; + this.programReminder = programReminder; + this.insulinProgramElements = new ArrayList<>(insulinProgramElements); + this.tempBasalMethod = tempBasalMethod; + } + + public TempBasalMethod getTempBasalMethod() { + return tempBasalMethod; + } + + public byte getBodyLength() { + byte bodyLength = (byte) (insulinProgramElements.size() * 6 + 8); + + if (tempBasalMethod == TempBasalMethod.SECOND_METHOD) { + return bodyLength; + } + + // TempBasalMethod.FIRST_METHOD + for (BasalInsulinProgramElement element : insulinProgramElements) { + if (element.getTotalTenthPulses() == 0 && element.getNumberOfSlots() > 1) { + bodyLength = (byte) ((element.getNumberOfSlots() - 1) * 6 + bodyLength); + } + } + + return bodyLength; + } + + public short getLength() { + return (short) (getBodyLength() + 2); + } + + @Override public byte[] getEncoded() { + BasalInsulinProgramElement firstProgramElement = insulinProgramElements.get(0); + + short remainingTenthPulsesInFirstElement; + int delayUntilNextTenthPulseInUsec; + + if (firstProgramElement.getTotalTenthPulses() == 0) { + if (tempBasalMethod == TempBasalMethod.FIRST_METHOD) { + remainingTenthPulsesInFirstElement = 0; + } else { + remainingTenthPulsesInFirstElement = firstProgramElement.getNumberOfSlots(); + } + delayUntilNextTenthPulseInUsec = ProgramBasalUtil.NUMBER_OF_USEC_IN_SLOT; + } else { + remainingTenthPulsesInFirstElement = firstProgramElement.getTotalTenthPulses(); + delayUntilNextTenthPulseInUsec = (int) (firstProgramElement.getNumberOfSlots() * 1_800.0d / remainingTenthPulsesInFirstElement * 1_000_000); + } + + ByteBuffer buffer = ByteBuffer.allocate(getLength()) // + .put(commandType.getValue()) // + .put(getBodyLength()) // + .put(programReminder.getEncoded()) // + .put((byte) 0x00) // Current slot index + .putShort(remainingTenthPulsesInFirstElement) // + .putInt(delayUntilNextTenthPulseInUsec); + + for (BasalInsulinProgramElement element : insulinProgramElements) { + buffer.put(element.getEncoded()); + } + + byte[] tempBasalCommand = buffer.array(); + byte[] interlockCommand = this.interlockCommand.getEncoded(); + byte[] header = encodeHeader(uniqueId, sequenceNumber, (short) (tempBasalCommand.length + interlockCommand.length), multiCommandFlag); + + return appendCrc(ByteBuffer.allocate(header.length + interlockCommand.length + tempBasalCommand.length) // + .put(header) // + .put(interlockCommand) // + .put(tempBasalCommand) // + .array()); + } + + public static class Builder extends NonceEnabledCommandBuilder { + private ProgramReminder programReminder; + private Double rateInUnitsPerHour; + private Short durationInMinutes; + + public Builder setProgramReminder(ProgramReminder programReminder) { + this.programReminder = programReminder; + return this; + } + + public Builder setRateInUnitsPerHour(double rateInUnitsPerHour) { + this.rateInUnitsPerHour = rateInUnitsPerHour; + return this; + } + + public Builder setDurationInMinutes(short durationInMinutes) { + if (durationInMinutes % 30 != 0) { + throw new IllegalArgumentException("durationInMinutes must be dividable by 30"); + } + this.durationInMinutes = durationInMinutes; + return this; + } + + @Override protected ProgramTempBasalCommand buildCommand() { + if (programReminder == null) { + throw new IllegalArgumentException("programReminder can not be null"); + } + if (rateInUnitsPerHour == null) { + throw new IllegalArgumentException("rateInUnitsPerHour can not be null"); + } + if (durationInMinutes == null) { + throw new IllegalArgumentException("durationInMinutes can not be null"); + } + + byte durationInSlots = (byte) (durationInMinutes % 30); + short[] pulsesPerSlot = ProgramTempBasalUtil.mapTempBasalToPulsesPerSlot(durationInSlots, rateInUnitsPerHour); + short[] tenthPulsesPerSlot = ProgramTempBasalUtil.mapTempBasalToTenthPulsesPerSlot(durationInSlots, rateInUnitsPerHour); + TempBasalMethod tempBasalMethod = tenthPulsesPerSlot[0] == 0 ? TempBasalMethod.SECOND_METHOD : TempBasalMethod.FIRST_METHOD; + + List shortInsulinProgramElements = ProgramTempBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot); + List insulinProgramElements = ProgramTempBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot, tempBasalMethod); + + ProgramInsulinCommand interlockCommand = new ProgramInsulinCommand(uniqueId, sequenceNumber, multiCommandFlag, nonce, shortInsulinProgramElements, + ProgramTempBasalUtil.calculateChecksum(durationInSlots, pulsesPerSlot[0], pulsesPerSlot), durationInSlots, + (short) 0x3840, pulsesPerSlot[0], ProgramInsulinCommand.DeliveryType.TEMP_BASAL); + + return new ProgramTempBasalCommand(interlockCommand, uniqueId, sequenceNumber, multiCommandFlag, programReminder, insulinProgramElements, tempBasalMethod); + } + } + + public enum TempBasalMethod { + FIRST_METHOD, + SECOND_METHOD + } +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/BasalInsulinProgramElement.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/BasalInsulinProgramElement.java index 01359b4586..78020c2f6f 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/BasalInsulinProgramElement.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/BasalInsulinProgramElement.java @@ -32,6 +32,10 @@ public class BasalInsulinProgramElement implements Encodable { return numberOfSlots; } + public short getDurationInSeconds() { + return (short) (numberOfSlots * 1_800); + } + public short getTotalTenthPulses() { return totalTenthPulses; } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/CurrentLongInsulinProgramElement.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/CurrentBasalInsulinProgramElement.java similarity index 84% rename from omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/CurrentLongInsulinProgramElement.java rename to omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/CurrentBasalInsulinProgramElement.java index 5a976a33ee..fb7bcd3215 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/CurrentLongInsulinProgramElement.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/CurrentBasalInsulinProgramElement.java @@ -1,11 +1,11 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program; -public class CurrentLongInsulinProgramElement { +public class CurrentBasalInsulinProgramElement { private final byte index; private final int delayUntilNextTenthPulseInUsec; private final short remainingTenthPulses; - public CurrentLongInsulinProgramElement(byte index, int delayUntilNextTenthPulseInUsec, short remainingTenthPulses) { + public CurrentBasalInsulinProgramElement(byte index, int delayUntilNextTenthPulseInUsec, short remainingTenthPulses) { this.index = index; this.delayUntilNextTenthPulseInUsec = delayUntilNextTenthPulseInUsec; this.remainingTenthPulses = remainingTenthPulses; diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/TempBasalInsulinProgramElement.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/TempBasalInsulinProgramElement.java new file mode 100644 index 0000000000..c95203b43d --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/TempBasalInsulinProgramElement.java @@ -0,0 +1,35 @@ +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.command.ProgramTempBasalCommand; + +public class TempBasalInsulinProgramElement extends BasalInsulinProgramElement { + private final ProgramTempBasalCommand.TempBasalMethod tempBasalMethod; + + public TempBasalInsulinProgramElement(byte startSlotIndex, byte numberOfSlots, short totalTenthPulses, int delayBetweenTenthPulsesInUsec, ProgramTempBasalCommand.TempBasalMethod tempBasalMethod) { + super(startSlotIndex, numberOfSlots, totalTenthPulses, delayBetweenTenthPulsesInUsec); + this.tempBasalMethod = tempBasalMethod; + } + + @Override public byte[] getEncoded() { + ByteBuffer buffer = ByteBuffer.allocate(6); + if (getTotalTenthPulses() == 0) { + if (tempBasalMethod == ProgramTempBasalCommand.TempBasalMethod.FIRST_METHOD) { + for (int i = 0; i < getNumberOfSlots(); i++) { + buffer.putShort((short) 0) // + .putInt((int) ((long) getDurationInSeconds() * 1_000_000d / getNumberOfSlots())); + } + } else { + // Zero basal and temp basal second method + buffer.putShort(getNumberOfSlots()) // + .putInt((int) ((long) getDurationInSeconds() * 1_000_000d / getNumberOfSlots())); + } + } else { + buffer.putShort(getTotalTenthPulses()) // + .putInt(getDelayBetweenTenthPulsesInUsec()); + } + return buffer.array(); + } + +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ProgramBasalUtil.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/util/ProgramBasalUtil.java similarity index 77% rename from omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ProgramBasalUtil.java rename to omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/util/ProgramBasalUtil.java index 13d1c0f395..a238554714 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/ProgramBasalUtil.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/util/ProgramBasalUtil.java @@ -1,4 +1,4 @@ -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.util; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -6,20 +6,33 @@ import java.util.Calendar; import java.util.Date; import java.util.List; +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.BasalShortInsulinProgramElement; +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.CurrentBasalInsulinProgramElement; +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.ShortInsulinProgramElement; 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; - private static final byte MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT = 16; - private static final int NUMBER_OF_USEC_IN_SLOT = 1_800_000_000; + public static final int NUMBER_OF_USEC_IN_SLOT = 1_800_000_000; + public static final byte NUMBER_OF_BASAL_SLOTS = 48; + public static final byte MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT = 16; private ProgramBasalUtil() { } - public static List mapPulsesPerSlotToLongInsulinProgramElements(short[] tenthPulsesPerSlot) { - if (tenthPulsesPerSlot.length != NUMBER_OF_BASAL_SLOTS) { - throw new IllegalArgumentException("Basal program must contain 48 slots"); + public interface BasalInsulinProgramElementFactory { + T create(byte startSlotIndex, byte numberOfSlots, short totalTenthPulses, int delayBetweenTenthPulsesInUsec); + } + + public static List mapTenthPulsesPerSlotToLongInsulinProgramElements(short[] tenthPulsesPerSlot) { + return mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot, BasalInsulinProgramElement::new); + } + + public static List mapTenthPulsesPerSlotToLongInsulinProgramElements(short[] tenthPulsesPerSlot, BasalInsulinProgramElementFactory insulinProgramElementFactory) { + if (tenthPulsesPerSlot.length > NUMBER_OF_BASAL_SLOTS) { + throw new IllegalArgumentException("Basal program must contain at most 48 slots"); } List elements = new ArrayList<>(); @@ -27,12 +40,12 @@ public final class ProgramBasalUtil { byte numberOfSlotsInCurrentElement = 0; byte startSlotIndex = 0; - for (int i = 0; i < NUMBER_OF_BASAL_SLOTS; i++) { + for (int i = 0; i < tenthPulsesPerSlot.length; i++) { if (i == 0) { previousTenthPulsesPerSlot = tenthPulsesPerSlot[i]; numberOfSlotsInCurrentElement = 1; } else if (previousTenthPulsesPerSlot != tenthPulsesPerSlot[i] || (numberOfSlotsInCurrentElement + 1) * previousTenthPulsesPerSlot > 65_534) { - elements.add(new BasalInsulinProgramElement(startSlotIndex, numberOfSlotsInCurrentElement, (short) (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement), (int) (((long) NUMBER_OF_USEC_IN_SLOT * numberOfSlotsInCurrentElement) / (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement)))); + elements.add(insulinProgramElementFactory.create(startSlotIndex, numberOfSlotsInCurrentElement, (short) (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement), (int) (((long) NUMBER_OF_USEC_IN_SLOT * numberOfSlotsInCurrentElement) / (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement)))); previousTenthPulsesPerSlot = tenthPulsesPerSlot[i]; numberOfSlotsInCurrentElement = 1; @@ -41,14 +54,14 @@ public final class ProgramBasalUtil { numberOfSlotsInCurrentElement++; } } - elements.add(new BasalInsulinProgramElement(startSlotIndex, numberOfSlotsInCurrentElement, (short) (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement), (int) (((long) NUMBER_OF_USEC_IN_SLOT * numberOfSlotsInCurrentElement) / (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement)))); + elements.add(insulinProgramElementFactory.create(startSlotIndex, numberOfSlotsInCurrentElement, (short) (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement), (int) (((long) NUMBER_OF_USEC_IN_SLOT * numberOfSlotsInCurrentElement) / (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement)))); return elements; } public static List mapPulsesPerSlotToShortInsulinProgramElements(short[] pulsesPerSlot) { - if (pulsesPerSlot.length != NUMBER_OF_BASAL_SLOTS) { - throw new IllegalArgumentException("Basal program must contain 48 slots"); + if (pulsesPerSlot.length > NUMBER_OF_BASAL_SLOTS) { + throw new IllegalArgumentException("Basal program must contain at most 48 slots"); } List elements = new ArrayList<>(); @@ -57,7 +70,7 @@ public final class ProgramBasalUtil { byte numberOfSlotsInCurrentElement = 0; byte currentTotalNumberOfSlots = 0; - while (currentTotalNumberOfSlots < NUMBER_OF_BASAL_SLOTS) { + while (currentTotalNumberOfSlots < pulsesPerSlot.length) { if (currentTotalNumberOfSlots == 0) { // First slot @@ -83,7 +96,7 @@ public final class ProgramBasalUtil { boolean expectAlternatePulseForNextSegment = false; currentTotalNumberOfSlots++; extraAlternatePulse = true; - while (currentTotalNumberOfSlots < NUMBER_OF_BASAL_SLOTS) { + while (currentTotalNumberOfSlots < pulsesPerSlot.length) { // Loop rest alternate pulse segment if (pulsesPerSlot[currentTotalNumberOfSlots] == previousPulsesPerSlot + (expectAlternatePulseForNextSegment ? 1 : 0)) { @@ -182,7 +195,7 @@ public final class ProgramBasalUtil { return new CurrentSlot(index, (short) (secondsRemaining * 8), pulsesRemaining); } - public static CurrentLongInsulinProgramElement calculateCurrentLongInsulinProgramElement(List elements, Date currentTime) { + public static CurrentBasalInsulinProgramElement calculateCurrentLongInsulinProgramElement(List elements, Date currentTime) { Calendar instance = Calendar.getInstance(); instance.setTime(currentTime); @@ -218,7 +231,7 @@ public final class ProgramBasalUtil { } short remainingTenthPulses = (short) ((remainingTenThousandthPulses % 1_000 != 0 ? 1 : 0) + remainingTenThousandthPulses / 1_000); - return new CurrentLongInsulinProgramElement(index, delayUntilNextTenthPulseInUsec, remainingTenthPulses); + return new CurrentBasalInsulinProgramElement(index, delayUntilNextTenthPulseInUsec, remainingTenthPulses); } index++; @@ -227,7 +240,7 @@ public final class ProgramBasalUtil { throw new IllegalStateException("Could not determine current long insulin program element"); } - public static short createChecksum(short[] pulsesPerSlot, CurrentSlot currentSlot) { + public static short calculateChecksum(short[] pulsesPerSlot, CurrentSlot currentSlot) { ByteBuffer buffer = ByteBuffer.allocate(1 + 2 + 2 + NUMBER_OF_BASAL_SLOTS * 2) // .put(currentSlot.getIndex()) // .putShort(currentSlot.getPulsesRemaining()) // @@ -237,6 +250,6 @@ public final class ProgramBasalUtil { buffer.putShort(pulses); } - return MessageUtil.createCheckSum(buffer.array()); + return MessageUtil.calculateChecksum(buffer.array()); } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/util/ProgramTempBasalUtil.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/util/ProgramTempBasalUtil.java new file mode 100644 index 0000000000..29b9172397 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/util/ProgramTempBasalUtil.java @@ -0,0 +1,71 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.util; + +import java.nio.ByteBuffer; +import java.util.List; + +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.ProgramTempBasalCommand; +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.ShortInsulinProgramElement; +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.TempBasalInsulinProgramElement; +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.MessageUtil; + +public final class ProgramTempBasalUtil { + private ProgramTempBasalUtil() { + } + + public static List mapTenthPulsesPerSlotToLongInsulinProgramElements(short[] tenthPulsesPerSlot, ProgramTempBasalCommand.TempBasalMethod tempBasalMethod) { + return ProgramBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot, + (startSlotIndex, numberOfSlots, totalTenthPulses, delayBetweenTenthPulsesInUsec) -> + new TempBasalInsulinProgramElement(startSlotIndex, numberOfSlots, totalTenthPulses, delayBetweenTenthPulsesInUsec, tempBasalMethod)); + } + + public static short[] mapTempBasalToTenthPulsesPerSlot(int durationInSlots, double rateInUnitsPerHour) { + short pulsesPerHour = (short) Math.round(rateInUnitsPerHour * 20); + + short[] tenthPulsesPerSlot = new short[durationInSlots]; + for (int i = 0; durationInSlots > i; i++) { + tenthPulsesPerSlot[i] = (short) (roundToHalf(pulsesPerHour / 2.0d) * 10); + } + + return tenthPulsesPerSlot; + } + + private static double roundToHalf(double d) { + return (double) (short) ((short) (int) (d * 10.0d) / 5 * 5) / 10.0d; + } + + public static short[] mapTempBasalToPulsesPerSlot(byte durationInSlots, double rateInUnitsPerHour) { + short pulsesPerHour = (short) Math.round(rateInUnitsPerHour * 20); + short[] pulsesPerSlot = new short[durationInSlots]; + + boolean remainingPulse = false; + + for (int i = 0; durationInSlots > i; i++) { + pulsesPerSlot[i] = (short) (pulsesPerHour / 2); + if (pulsesPerHour % 2 == 1) { // Do extra alternate pulse + if (remainingPulse) { + pulsesPerSlot[i] += 1; + } + remainingPulse = !remainingPulse; + } + } + + return pulsesPerSlot; + } + + public static short calculateChecksum(byte totalNumberOfSlots, short pulsesInFirstSlot, short[] pulsesPerSlot) { + ByteBuffer buffer = ByteBuffer.allocate(1 + 2 + 2 + 2 * pulsesPerSlot.length) // + .put(totalNumberOfSlots) // + .putShort((short) 0x3840) // + .putShort(pulsesInFirstSlot); + for (short pulses : pulsesPerSlot) { + buffer.putShort(pulses); + } + + return MessageUtil.calculateChecksum(buffer.array()); + } + + public static List mapPulsesPerSlotToShortInsulinProgramElements(short[] pulsesPerSlot) { + return ProgramBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot); + } +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/util/MessageUtil.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/util/MessageUtil.java index f67993e3c5..6d9297f12a 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/util/MessageUtil.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/util/MessageUtil.java @@ -30,7 +30,7 @@ public class MessageUtil { return s; } - public static short createCheckSum(byte[] bytes) { + public static short calculateChecksum(byte[] bytes) { short sum = 0; for (byte b : bytes) { sum += (short) (b & 0xff); diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramTempBasalCommandTest.java b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramTempBasalCommandTest.java new file mode 100644 index 0000000000..d239f0ab2f --- /dev/null +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramTempBasalCommandTest.java @@ -0,0 +1,44 @@ +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; +import static org.junit.Assert.assertEquals; + +public class ProgramTempBasalCommandTest { + @Test + public void testFirstTempBasalMethod() throws DecoderException { + ProgramTempBasalCommand command = new ProgramTempBasalCommand.Builder() // + .setUniqueId(37879809) // + .setNonce(1229869870) // + .setSequenceNumber((short) 3) // + .setRateInUnitsPerHour(5d) // + .setDurationInMinutes((short) 60) // + .setProgramReminder(new ProgramReminder(false, true, (byte) 0)) // + .build(); + + assertEquals(ProgramTempBasalCommand.TempBasalMethod.SECOND_METHOD, command.getTempBasalMethod()); + + assertArrayEquals(Hex.decodeHex("024200010C201A0E494E532E01014303384000322032160E400005DC0036EE8005DC0036EE808396"), command.getEncoded()); + } + + @Test + public void testSecondTempBasalMethod() throws DecoderException { + ProgramTempBasalCommand command = new ProgramTempBasalCommand.Builder() // + .setUniqueId(37879809) // + .setNonce(1229869870) // + .setSequenceNumber((short) 13) // + .setRateInUnitsPerHour(0.0) // + .setDurationInMinutes((short) 60) // + .setProgramReminder(new ProgramReminder(true, true, (byte) 0)) // + .build(); + + assertEquals(ProgramTempBasalCommand.TempBasalMethod.SECOND_METHOD, command.getTempBasalMethod()); + + assertArrayEquals(Hex.decodeHex("0242000134201A0E494E532E01007B03384000002000160EC00000036B49D2000003EB49D2000223"), command.getEncoded()); + } +} \ No newline at end of file From d142da37e8c3c1efd225ce95467f8940ec309345 Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Thu, 18 Feb 2021 10:42:50 +0100 Subject: [PATCH 18/83] Finish program temp basal command for Omnipod Dash --- omnipod-dash/build.gradle | 5 ++ .../pod/command/ProgramTempBasalCommand.java | 47 ++++--------------- .../program/BasalInsulinProgramElement.java | 15 +++--- .../TempBasalInsulinProgramElement.java | 22 ++------- .../program/util/ProgramBasalUtil.java | 18 +++---- .../program/util/ProgramTempBasalUtil.java | 7 +-- .../command/ProgramTempBasalCommandTest.java | 21 ++++----- 7 files changed, 48 insertions(+), 87 deletions(-) diff --git a/omnipod-dash/build.gradle b/omnipod-dash/build.gradle index 85797f8d35..7007afea06 100644 --- a/omnipod-dash/build.gradle +++ b/omnipod-dash/build.gradle @@ -41,6 +41,11 @@ android { dependencies { implementation project(':core') + implementation "org.apache.commons:commons-lang3:$commonslang3_version" + implementation "commons-codec:commons-codec:$commonscodec_version" + implementation "androidx.appcompat:appcompat:$appcompat_version" + implementation "com.google.android.material:material:$material_version" + annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version" annotationProcessor "com.google.dagger:dagger-android-processor:$dagger_version" kapt "com.google.dagger:dagger-android-processor:$dagger_version" diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramTempBasalCommand.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramTempBasalCommand.java index 42031a189b..9d4f1f547a 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramTempBasalCommand.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramTempBasalCommand.java @@ -18,36 +18,17 @@ public final class ProgramTempBasalCommand extends HeaderEnabledCommand { private final ProgramInsulinCommand interlockCommand; private final ProgramReminder programReminder; private final List insulinProgramElements; - private final TempBasalMethod tempBasalMethod; - protected ProgramTempBasalCommand(ProgramInsulinCommand interlockCommand, int uniqueId, short sequenceNumber, boolean multiCommandFlag, ProgramReminder programReminder, - List insulinProgramElements, TempBasalMethod tempBasalMethod) { + protected ProgramTempBasalCommand(ProgramInsulinCommand interlockCommand, int uniqueId, short sequenceNumber, boolean multiCommandFlag, + ProgramReminder programReminder, List insulinProgramElements) { super(CommandType.PROGRAM_TEMP_BASAL, uniqueId, sequenceNumber, multiCommandFlag); this.interlockCommand = interlockCommand; this.programReminder = programReminder; this.insulinProgramElements = new ArrayList<>(insulinProgramElements); - this.tempBasalMethod = tempBasalMethod; - } - - public TempBasalMethod getTempBasalMethod() { - return tempBasalMethod; } public byte getBodyLength() { - byte bodyLength = (byte) (insulinProgramElements.size() * 6 + 8); - - if (tempBasalMethod == TempBasalMethod.SECOND_METHOD) { - return bodyLength; - } - - // TempBasalMethod.FIRST_METHOD - for (BasalInsulinProgramElement element : insulinProgramElements) { - if (element.getTotalTenthPulses() == 0 && element.getNumberOfSlots() > 1) { - bodyLength = (byte) ((element.getNumberOfSlots() - 1) * 6 + bodyLength); - } - } - - return bodyLength; + return (byte) (insulinProgramElements.size() * 6 + 8); } public short getLength() { @@ -61,15 +42,11 @@ public final class ProgramTempBasalCommand extends HeaderEnabledCommand { int delayUntilNextTenthPulseInUsec; if (firstProgramElement.getTotalTenthPulses() == 0) { - if (tempBasalMethod == TempBasalMethod.FIRST_METHOD) { - remainingTenthPulsesInFirstElement = 0; - } else { - remainingTenthPulsesInFirstElement = firstProgramElement.getNumberOfSlots(); - } - delayUntilNextTenthPulseInUsec = ProgramBasalUtil.NUMBER_OF_USEC_IN_SLOT; + remainingTenthPulsesInFirstElement = firstProgramElement.getNumberOfSlots(); + delayUntilNextTenthPulseInUsec = ProgramBasalUtil.MAX_DELAY_BETWEEN_TENTH_PULSES_IN_USEC_AND_USECS_IN_BASAL_SLOT; } else { remainingTenthPulsesInFirstElement = firstProgramElement.getTotalTenthPulses(); - delayUntilNextTenthPulseInUsec = (int) (firstProgramElement.getNumberOfSlots() * 1_800.0d / remainingTenthPulsesInFirstElement * 1_000_000); + delayUntilNextTenthPulseInUsec = (int) ((long) firstProgramElement.getNumberOfSlots() * 1_800.0d / remainingTenthPulsesInFirstElement * 1_000_000); } ByteBuffer buffer = ByteBuffer.allocate(getLength()) // @@ -129,24 +106,18 @@ public final class ProgramTempBasalCommand extends HeaderEnabledCommand { throw new IllegalArgumentException("durationInMinutes can not be null"); } - byte durationInSlots = (byte) (durationInMinutes % 30); + byte durationInSlots = (byte) (durationInMinutes / 30); short[] pulsesPerSlot = ProgramTempBasalUtil.mapTempBasalToPulsesPerSlot(durationInSlots, rateInUnitsPerHour); short[] tenthPulsesPerSlot = ProgramTempBasalUtil.mapTempBasalToTenthPulsesPerSlot(durationInSlots, rateInUnitsPerHour); - TempBasalMethod tempBasalMethod = tenthPulsesPerSlot[0] == 0 ? TempBasalMethod.SECOND_METHOD : TempBasalMethod.FIRST_METHOD; List shortInsulinProgramElements = ProgramTempBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot); - List insulinProgramElements = ProgramTempBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot, tempBasalMethod); + List insulinProgramElements = ProgramTempBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot); ProgramInsulinCommand interlockCommand = new ProgramInsulinCommand(uniqueId, sequenceNumber, multiCommandFlag, nonce, shortInsulinProgramElements, ProgramTempBasalUtil.calculateChecksum(durationInSlots, pulsesPerSlot[0], pulsesPerSlot), durationInSlots, (short) 0x3840, pulsesPerSlot[0], ProgramInsulinCommand.DeliveryType.TEMP_BASAL); - return new ProgramTempBasalCommand(interlockCommand, uniqueId, sequenceNumber, multiCommandFlag, programReminder, insulinProgramElements, tempBasalMethod); + return new ProgramTempBasalCommand(interlockCommand, uniqueId, sequenceNumber, multiCommandFlag, programReminder, insulinProgramElements); } } - - public enum TempBasalMethod { - FIRST_METHOD, - SECOND_METHOD - } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/BasalInsulinProgramElement.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/BasalInsulinProgramElement.java index 78020c2f6f..4ddcc6347a 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/BasalInsulinProgramElement.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/BasalInsulinProgramElement.java @@ -4,23 +4,23 @@ import java.nio.ByteBuffer; import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable; +import static info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.util.ProgramBasalUtil.MAX_DELAY_BETWEEN_TENTH_PULSES_IN_USEC_AND_USECS_IN_BASAL_SLOT; + public class BasalInsulinProgramElement implements Encodable { private final byte startSlotIndex; private final byte numberOfSlots; private final short totalTenthPulses; - private final int delayBetweenTenthPulsesInUsec; - public BasalInsulinProgramElement(byte startSlotIndex, byte numberOfSlots, short totalTenthPulses, int delayBetweenTenthPulsesInUsec) { + public BasalInsulinProgramElement(byte startSlotIndex, byte numberOfSlots, short totalTenthPulses) { this.startSlotIndex = startSlotIndex; this.numberOfSlots = numberOfSlots; this.totalTenthPulses = totalTenthPulses; - this.delayBetweenTenthPulsesInUsec = delayBetweenTenthPulsesInUsec; } @Override public byte[] getEncoded() { return ByteBuffer.allocate(6) // .putShort(totalTenthPulses) // - .putInt(delayBetweenTenthPulsesInUsec) // + .putInt(totalTenthPulses == 0 ? Integer.MIN_VALUE | getDelayBetweenTenthPulsesInUsec() : getDelayBetweenTenthPulsesInUsec()) // .array(); } @@ -41,7 +41,10 @@ public class BasalInsulinProgramElement implements Encodable { } public int getDelayBetweenTenthPulsesInUsec() { - return delayBetweenTenthPulsesInUsec; + if (totalTenthPulses == 0) { + return MAX_DELAY_BETWEEN_TENTH_PULSES_IN_USEC_AND_USECS_IN_BASAL_SLOT; + } + return (int) (((long) MAX_DELAY_BETWEEN_TENTH_PULSES_IN_USEC_AND_USECS_IN_BASAL_SLOT * numberOfSlots) / (double) totalTenthPulses); } @Override public String toString() { @@ -49,7 +52,7 @@ public class BasalInsulinProgramElement implements Encodable { "startSlotIndex=" + startSlotIndex + ", numberOfSlots=" + numberOfSlots + ", totalTenthPulses=" + totalTenthPulses + - ", delayBetweenTenthPulsesInUsec=" + delayBetweenTenthPulsesInUsec + + ", delayBetweenTenthPulsesInUsec=" + getDelayBetweenTenthPulsesInUsec() + '}'; } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/TempBasalInsulinProgramElement.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/TempBasalInsulinProgramElement.java index c95203b43d..b43b148ea3 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/TempBasalInsulinProgramElement.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/TempBasalInsulinProgramElement.java @@ -2,29 +2,17 @@ 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.command.ProgramTempBasalCommand; - public class TempBasalInsulinProgramElement extends BasalInsulinProgramElement { - private final ProgramTempBasalCommand.TempBasalMethod tempBasalMethod; - - public TempBasalInsulinProgramElement(byte startSlotIndex, byte numberOfSlots, short totalTenthPulses, int delayBetweenTenthPulsesInUsec, ProgramTempBasalCommand.TempBasalMethod tempBasalMethod) { - super(startSlotIndex, numberOfSlots, totalTenthPulses, delayBetweenTenthPulsesInUsec); - this.tempBasalMethod = tempBasalMethod; + public TempBasalInsulinProgramElement(byte startSlotIndex, byte numberOfSlots, short totalTenthPulses) { + super(startSlotIndex, numberOfSlots, totalTenthPulses); } @Override public byte[] getEncoded() { ByteBuffer buffer = ByteBuffer.allocate(6); if (getTotalTenthPulses() == 0) { - if (tempBasalMethod == ProgramTempBasalCommand.TempBasalMethod.FIRST_METHOD) { - for (int i = 0; i < getNumberOfSlots(); i++) { - buffer.putShort((short) 0) // - .putInt((int) ((long) getDurationInSeconds() * 1_000_000d / getNumberOfSlots())); - } - } else { - // Zero basal and temp basal second method - buffer.putShort(getNumberOfSlots()) // - .putInt((int) ((long) getDurationInSeconds() * 1_000_000d / getNumberOfSlots())); - } + int i = ((int) ((((double) getDurationInSeconds()) * 1_000_000.0d) / ((double) getNumberOfSlots()))) | Integer.MIN_VALUE; + buffer.putShort(getNumberOfSlots()) // + .putInt(i); } else { buffer.putShort(getTotalTenthPulses()) // .putInt(getDelayBetweenTenthPulsesInUsec()); diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/util/ProgramBasalUtil.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/util/ProgramBasalUtil.java index a238554714..0c02799d02 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/util/ProgramBasalUtil.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/util/ProgramBasalUtil.java @@ -15,7 +15,8 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definitio import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.MessageUtil; public final class ProgramBasalUtil { - public static final int NUMBER_OF_USEC_IN_SLOT = 1_800_000_000; + public static final int MAX_DELAY_BETWEEN_TENTH_PULSES_IN_USEC_AND_USECS_IN_BASAL_SLOT = 1_800_000_000; + public static final byte NUMBER_OF_BASAL_SLOTS = 48; public static final byte MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT = 16; @@ -23,7 +24,7 @@ public final class ProgramBasalUtil { } public interface BasalInsulinProgramElementFactory { - T create(byte startSlotIndex, byte numberOfSlots, short totalTenthPulses, int delayBetweenTenthPulsesInUsec); + T create(byte startSlotIndex, byte numberOfSlots, short totalTenthPulses); } public static List mapTenthPulsesPerSlotToLongInsulinProgramElements(short[] tenthPulsesPerSlot) { @@ -45,7 +46,7 @@ public final class ProgramBasalUtil { previousTenthPulsesPerSlot = tenthPulsesPerSlot[i]; numberOfSlotsInCurrentElement = 1; } else if (previousTenthPulsesPerSlot != tenthPulsesPerSlot[i] || (numberOfSlotsInCurrentElement + 1) * previousTenthPulsesPerSlot > 65_534) { - elements.add(insulinProgramElementFactory.create(startSlotIndex, numberOfSlotsInCurrentElement, (short) (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement), (int) (((long) NUMBER_OF_USEC_IN_SLOT * numberOfSlotsInCurrentElement) / (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement)))); + elements.add(insulinProgramElementFactory.create(startSlotIndex, numberOfSlotsInCurrentElement, (short) (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement))); previousTenthPulsesPerSlot = tenthPulsesPerSlot[i]; numberOfSlotsInCurrentElement = 1; @@ -54,7 +55,7 @@ public final class ProgramBasalUtil { numberOfSlotsInCurrentElement++; } } - elements.add(insulinProgramElementFactory.create(startSlotIndex, numberOfSlotsInCurrentElement, (short) (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement), (int) (((long) NUMBER_OF_USEC_IN_SLOT * numberOfSlotsInCurrentElement) / (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement)))); + elements.add(insulinProgramElementFactory.create(startSlotIndex, numberOfSlotsInCurrentElement, (short) (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement))); return elements; } @@ -83,7 +84,7 @@ public final class ProgramBasalUtil { if (numberOfSlotsInCurrentElement < MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT) { numberOfSlotsInCurrentElement++; } else { - elements.add(new BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, false)); + elements.add(new BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse)); previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots]; numberOfSlotsInCurrentElement = 1; extraAlternatePulse = false; @@ -95,6 +96,7 @@ public final class ProgramBasalUtil { boolean expectAlternatePulseForNextSegment = false; currentTotalNumberOfSlots++; + numberOfSlotsInCurrentElement++; extraAlternatePulse = true; while (currentTotalNumberOfSlots < pulsesPerSlot.length) { // Loop rest alternate pulse segment @@ -110,7 +112,7 @@ public final class ProgramBasalUtil { } else { // End of alternate pulse segment (no slots left in element) - elements.add(new BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, true)); + elements.add(new BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse)); previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots]; numberOfSlotsInCurrentElement = 1; extraAlternatePulse = false; @@ -119,7 +121,7 @@ public final class ProgramBasalUtil { } else { // End of alternate pulse segment (new number of pulses per slot) - elements.add(new BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, true)); + elements.add(new BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse)); previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots]; numberOfSlotsInCurrentElement = 1; extraAlternatePulse = false; @@ -129,7 +131,7 @@ public final class ProgramBasalUtil { } } else if (previousPulsesPerSlot != pulsesPerSlot[currentTotalNumberOfSlots]) { // End of segment (new number of pulses per slot) - elements.add(new BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, false)); + elements.add(new BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse)); previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots]; currentTotalNumberOfSlots++; diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/util/ProgramTempBasalUtil.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/util/ProgramTempBasalUtil.java index 29b9172397..f60a5b3e8e 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/util/ProgramTempBasalUtil.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/insulin/program/util/ProgramTempBasalUtil.java @@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command. import java.nio.ByteBuffer; import java.util.List; -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.ProgramTempBasalCommand; 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.ShortInsulinProgramElement; import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.TempBasalInsulinProgramElement; @@ -13,10 +12,8 @@ public final class ProgramTempBasalUtil { private ProgramTempBasalUtil() { } - public static List mapTenthPulsesPerSlotToLongInsulinProgramElements(short[] tenthPulsesPerSlot, ProgramTempBasalCommand.TempBasalMethod tempBasalMethod) { - return ProgramBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot, - (startSlotIndex, numberOfSlots, totalTenthPulses, delayBetweenTenthPulsesInUsec) -> - new TempBasalInsulinProgramElement(startSlotIndex, numberOfSlots, totalTenthPulses, delayBetweenTenthPulsesInUsec, tempBasalMethod)); + public static List mapTenthPulsesPerSlotToLongInsulinProgramElements(short[] tenthPulsesPerSlot) { + return ProgramBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot, TempBasalInsulinProgramElement::new); } public static short[] mapTempBasalToTenthPulsesPerSlot(int durationInSlots, double rateInUnitsPerHour) { diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramTempBasalCommandTest.java b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramTempBasalCommandTest.java index d239f0ab2f..5dc5e738c4 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramTempBasalCommandTest.java +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramTempBasalCommandTest.java @@ -7,38 +7,33 @@ import org.junit.Test; import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ProgramReminder; import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; public class ProgramTempBasalCommandTest { @Test - public void testFirstTempBasalMethod() throws DecoderException { + public void testAlternateSegmentTempBasal() throws DecoderException { ProgramTempBasalCommand command = new ProgramTempBasalCommand.Builder() // .setUniqueId(37879809) // .setNonce(1229869870) // - .setSequenceNumber((short) 3) // - .setRateInUnitsPerHour(5d) // + .setSequenceNumber((short) 15) // + .setRateInUnitsPerHour(5.05d) // .setDurationInMinutes((short) 60) // .setProgramReminder(new ProgramReminder(false, true, (byte) 0)) // .build(); - assertEquals(ProgramTempBasalCommand.TempBasalMethod.SECOND_METHOD, command.getTempBasalMethod()); - - assertArrayEquals(Hex.decodeHex("024200010C201A0E494E532E01014303384000322032160E400005DC0036EE8005DC0036EE808396"), command.getEncoded()); + assertArrayEquals(Hex.decodeHex("024200013C201A0E494E532E01011102384000321832160E400003F20036634403F20036634482A6"), command.getEncoded()); } @Test - public void testSecondTempBasalMethod() throws DecoderException { + public void testZeroTempBasal() throws DecoderException { ProgramTempBasalCommand command = new ProgramTempBasalCommand.Builder() // .setUniqueId(37879809) // .setNonce(1229869870) // - .setSequenceNumber((short) 13) // + .setSequenceNumber((short) 7) // .setRateInUnitsPerHour(0.0) // - .setDurationInMinutes((short) 60) // + .setDurationInMinutes((short) 300) // .setProgramReminder(new ProgramReminder(true, true, (byte) 0)) // .build(); - assertEquals(ProgramTempBasalCommand.TempBasalMethod.SECOND_METHOD, command.getTempBasalMethod()); - - assertArrayEquals(Hex.decodeHex("0242000134201A0E494E532E01007B03384000002000160EC00000036B49D2000003EB49D2000223"), command.getEncoded()); + assertArrayEquals(Hex.decodeHex("024200011C201A0E494E532E0100820A384000009000160EC000000A6B49D200000AEB49D20001DE"), command.getEncoded()); } } \ No newline at end of file From 9d21338f105321eaac7d311a192688946fef57d5 Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Thu, 18 Feb 2021 10:51:29 +0100 Subject: [PATCH 19/83] Rename --- omnipod-dash/build.gradle | 5 ----- .../dash/driver/pod/command/ProgramTempBasalCommandTest.java | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/omnipod-dash/build.gradle b/omnipod-dash/build.gradle index 7007afea06..85797f8d35 100644 --- a/omnipod-dash/build.gradle +++ b/omnipod-dash/build.gradle @@ -41,11 +41,6 @@ android { dependencies { implementation project(':core') - implementation "org.apache.commons:commons-lang3:$commonslang3_version" - implementation "commons-codec:commons-codec:$commonscodec_version" - implementation "androidx.appcompat:appcompat:$appcompat_version" - implementation "com.google.android.material:material:$material_version" - annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version" annotationProcessor "com.google.dagger:dagger-android-processor:$dagger_version" kapt "com.google.dagger:dagger-android-processor:$dagger_version" diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramTempBasalCommandTest.java b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramTempBasalCommandTest.java index 5dc5e738c4..b622174379 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramTempBasalCommandTest.java +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramTempBasalCommandTest.java @@ -10,7 +10,7 @@ import static org.junit.Assert.assertArrayEquals; public class ProgramTempBasalCommandTest { @Test - public void testAlternateSegmentTempBasal() throws DecoderException { + public void testExtraAlternateSegmentPulseTempBasal() throws DecoderException { ProgramTempBasalCommand command = new ProgramTempBasalCommand.Builder() // .setUniqueId(37879809) // .setNonce(1229869870) // From 2a385784394e145b314a17758445fd857f77a879 Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Thu, 18 Feb 2021 23:31:31 +0100 Subject: [PATCH 20/83] Add empty omnipod-common module --- app/build.gradle | 1 + crowdin.yml | 2 + omnipod-common/.gitignore | 1 + omnipod-common/build.gradle | 50 +++++++++++++++++++ omnipod-common/consumer-rules.pro | 0 omnipod-common/proguard-rules.pro | 21 ++++++++ omnipod-common/src/main/AndroidManifest.xml | 5 ++ .../pump/omnipod/common/PlaceHolder.java | 4 ++ omnipod-dash/build.gradle | 1 + omnipod-eros/build.gradle | 1 + settings.gradle | 2 +- 11 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 omnipod-common/.gitignore create mode 100644 omnipod-common/build.gradle create mode 100644 omnipod-common/consumer-rules.pro create mode 100644 omnipod-common/proguard-rules.pro create mode 100644 omnipod-common/src/main/AndroidManifest.xml create mode 100644 omnipod-common/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/common/PlaceHolder.java diff --git a/app/build.gradle b/app/build.gradle index 2f474c8590..44a1a55ec2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -239,6 +239,7 @@ dependencies { implementation project(':danar') implementation project(':rileylink') implementation project(':medtronic') + implementation project(':omnipod-common') implementation project(':omnipod-eros') implementation project(':omnipod-dash') diff --git a/crowdin.yml b/crowdin.yml index d4bddbb642..7339e43604 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -19,6 +19,8 @@ files: translation: /dana/src/main/res/values-%android_code%/strings.xml - source: /medtronic/src/main/res/values/strings.xml translation: /medtronic/src/main/res/values-%android_code%/strings.xml + - source: /omnipod-common/src/main/res/values/strings.xml + translation: /omnipod-common/src/main/res/values-%android_code%/strings.xml - source: /omnipod-dash/src/main/res/values/strings.xml translation: /omnipod-dash/src/main/res/values-%android_code%/strings.xml - source: /omnipod-eros/src/main/res/values/strings.xml diff --git a/omnipod-common/.gitignore b/omnipod-common/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/omnipod-common/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/omnipod-common/build.gradle b/omnipod-common/build.gradle new file mode 100644 index 0000000000..85797f8d35 --- /dev/null +++ b/omnipod-common/build.gradle @@ -0,0 +1,50 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-kapt' + +android { + compileSdkVersion 28 + + defaultConfig { + minSdkVersion 24 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + } + + kotlinOptions { + jvmTarget = '1.8' + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + debug { + testCoverageEnabled(project.hasProperty('coverage')) + } + firebaseDisable { + System.setProperty("disableFirebase", "true") + ext.enableCrashlytics = false + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + implementation project(':core') + + annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version" + annotationProcessor "com.google.dagger:dagger-android-processor:$dagger_version" + kapt "com.google.dagger:dagger-android-processor:$dagger_version" + kapt "com.google.dagger:dagger-compiler:$dagger_version" + testImplementation "junit:junit:$junit_version" + androidTestImplementation "androidx.test.ext:junit:$androidx_junit" +} \ No newline at end of file diff --git a/omnipod-common/consumer-rules.pro b/omnipod-common/consumer-rules.pro new file mode 100644 index 0000000000..e69de29bb2 diff --git a/omnipod-common/proguard-rules.pro b/omnipod-common/proguard-rules.pro new file mode 100644 index 0000000000..481bb43481 --- /dev/null +++ b/omnipod-common/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/omnipod-common/src/main/AndroidManifest.xml b/omnipod-common/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..2ad7b616f1 --- /dev/null +++ b/omnipod-common/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/omnipod-common/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/common/PlaceHolder.java b/omnipod-common/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/common/PlaceHolder.java new file mode 100644 index 0000000000..4053d8f105 --- /dev/null +++ b/omnipod-common/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/common/PlaceHolder.java @@ -0,0 +1,4 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.common; + +public class PlaceHolder { +} diff --git a/omnipod-dash/build.gradle b/omnipod-dash/build.gradle index 85797f8d35..1a0f73a300 100644 --- a/omnipod-dash/build.gradle +++ b/omnipod-dash/build.gradle @@ -40,6 +40,7 @@ android { dependencies { implementation project(':core') + implementation project(':omnipod-common') annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version" annotationProcessor "com.google.dagger:dagger-android-processor:$dagger_version" diff --git a/omnipod-eros/build.gradle b/omnipod-eros/build.gradle index 5f95aa675c..439c3d26a8 100644 --- a/omnipod-eros/build.gradle +++ b/omnipod-eros/build.gradle @@ -43,6 +43,7 @@ android { dependencies { implementation project(':core') + implementation project(':omnipod-common') implementation project(':rileylink') annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version" diff --git a/settings.gradle b/settings.gradle index 2090bffc04..c1f4057c12 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,2 @@ -include ':app', ':database', ':wear', ':core', ':dana', ':danar', ':danars', ':rileylink', ':medtronic', ':omnipod-eros', ':omnipod-dash' +include ':app', ':database', ':wear', ':core', ':dana', ':danar', ':danars', ':rileylink', ':medtronic', ':omnipod-common', ':omnipod-eros', ':omnipod-dash' From ad1f450820b39f52a437b89a091b1b8baf9d4d2c Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Fri, 19 Feb 2021 00:26:05 +0100 Subject: [PATCH 21/83] Move a bunch of resources from omnipod-eros to omnipod-common --- ...ic_omnipod_overview_acknowledge_alerts.xml | 0 .../ic_omnipod_overview_pod_management.xml | 0 ...ic_omnipod_overview_refresh_pod_status.xml | 0 .../ic_omnipod_overview_resume_delivery.xml | 0 .../drawable/ic_omnipod_overview_set_time.xml | 0 .../ic_omnipod_overview_suspend_delivery.xml | 0 .../drawable/ic_omnipod_wizard_success.xml | 0 .../src/main/res/drawable/ic_pod.xml | 0 .../src/main/res/drawable/ic_pod_128.xml | 0 .../ic_pod_management_activate_pod.xml | 0 .../ic_pod_management_deactivate_pod.xml | 0 .../ic_pod_management_discard_pod.xml | 0 .../ic_pod_management_play_test_beep.xml | 0 .../ic_pod_management_pod_history.xml | 0 .../drawable/ic_pod_management_pulse_log.xml | 0 ...omnipod_pod_activation_wizard_activity.xml | 0 ...nipod_pod_deactivation_wizard_activity.xml | 0 .../omnipod_wizard_action_page_fragment.xml | 6 +-- .../layout/omnipod_wizard_base_fragment.xml | 0 .../omnipod_wizard_info_page_fragment.xml | 0 .../res/layout/omnipod_wizard_nav_buttons.xml | 4 +- .../omnipod_wizard_progress_indication.xml | 0 ...pod_activation_wizard_navigation_graph.xml | 0 ...d_deactivation_wizard_navigation_graph.xml | 0 omnipod-common/src/main/res/values/colors.xml | 39 +++++++++++++++++++ .../src/main/res/values/dimens.xml | 0 .../src/main/res/values/strings.xml | 12 ++++++ .../src/main/res/values/styles.xml | 0 .../activity/OmnipodWizardActivityBase.kt | 4 +- .../common/fragment/WizardFragmentBase.kt | 2 +- .../src/main/res/values-bg-rBG/strings.xml | 16 ++++---- .../src/main/res/values-cs-rCZ/strings.xml | 16 ++++---- .../src/main/res/values-de-rDE/strings.xml | 16 ++++---- .../src/main/res/values-es-rES/strings.xml | 16 ++++---- .../src/main/res/values-fr-rFR/strings.xml | 16 ++++---- .../src/main/res/values-ga-rIE/strings.xml | 4 +- .../src/main/res/values-it-rIT/strings.xml | 16 ++++---- .../src/main/res/values-iw-rIL/strings.xml | 16 ++++---- .../src/main/res/values-lt-rLT/strings.xml | 16 ++++---- .../src/main/res/values-nl-rNL/strings.xml | 16 ++++---- .../src/main/res/values-no-rNO/strings.xml | 16 ++++---- .../src/main/res/values-pl-rPL/strings.xml | 16 ++++---- .../src/main/res/values-pt-rPT/strings.xml | 16 ++++---- .../src/main/res/values-ro-rRO/strings.xml | 16 ++++---- .../src/main/res/values-ru-rRU/strings.xml | 16 ++++---- .../src/main/res/values-sk-rSK/strings.xml | 16 ++++---- .../src/main/res/values-sv-rSE/strings.xml | 16 ++++---- omnipod-eros/src/main/res/values/colors.xml | 34 ---------------- omnipod-eros/src/main/res/values/strings.xml | 10 ----- 49 files changed, 189 insertions(+), 182 deletions(-) rename {omnipod-eros => omnipod-common}/src/main/res/drawable/ic_omnipod_overview_acknowledge_alerts.xml (100%) rename {omnipod-eros => omnipod-common}/src/main/res/drawable/ic_omnipod_overview_pod_management.xml (100%) rename {omnipod-eros => omnipod-common}/src/main/res/drawable/ic_omnipod_overview_refresh_pod_status.xml (100%) rename {omnipod-eros => omnipod-common}/src/main/res/drawable/ic_omnipod_overview_resume_delivery.xml (100%) rename {omnipod-eros => omnipod-common}/src/main/res/drawable/ic_omnipod_overview_set_time.xml (100%) rename {omnipod-eros => omnipod-common}/src/main/res/drawable/ic_omnipod_overview_suspend_delivery.xml (100%) rename {omnipod-eros => omnipod-common}/src/main/res/drawable/ic_omnipod_wizard_success.xml (100%) rename {omnipod-eros => omnipod-common}/src/main/res/drawable/ic_pod.xml (100%) rename {omnipod-eros => omnipod-common}/src/main/res/drawable/ic_pod_128.xml (100%) rename {omnipod-eros => omnipod-common}/src/main/res/drawable/ic_pod_management_activate_pod.xml (100%) rename {omnipod-eros => omnipod-common}/src/main/res/drawable/ic_pod_management_deactivate_pod.xml (100%) rename {omnipod-eros => omnipod-common}/src/main/res/drawable/ic_pod_management_discard_pod.xml (100%) rename {omnipod-eros => omnipod-common}/src/main/res/drawable/ic_pod_management_play_test_beep.xml (100%) rename {omnipod-eros => omnipod-common}/src/main/res/drawable/ic_pod_management_pod_history.xml (100%) rename {omnipod-eros => omnipod-common}/src/main/res/drawable/ic_pod_management_pulse_log.xml (100%) rename {omnipod-eros => omnipod-common}/src/main/res/layout/omnipod_pod_activation_wizard_activity.xml (100%) rename {omnipod-eros => omnipod-common}/src/main/res/layout/omnipod_pod_deactivation_wizard_activity.xml (100%) rename {omnipod-eros => omnipod-common}/src/main/res/layout/omnipod_wizard_action_page_fragment.xml (93%) rename {omnipod-eros => omnipod-common}/src/main/res/layout/omnipod_wizard_base_fragment.xml (100%) rename {omnipod-eros => omnipod-common}/src/main/res/layout/omnipod_wizard_info_page_fragment.xml (100%) rename {omnipod-eros => omnipod-common}/src/main/res/layout/omnipod_wizard_nav_buttons.xml (80%) rename {omnipod-eros => omnipod-common}/src/main/res/layout/omnipod_wizard_progress_indication.xml (100%) rename {omnipod-eros => omnipod-common}/src/main/res/navigation/omnipod_pod_activation_wizard_navigation_graph.xml (100%) rename {omnipod-eros => omnipod-common}/src/main/res/navigation/omnipod_pod_deactivation_wizard_navigation_graph.xml (100%) create mode 100644 omnipod-common/src/main/res/values/colors.xml rename {omnipod-eros => omnipod-common}/src/main/res/values/dimens.xml (100%) create mode 100644 omnipod-common/src/main/res/values/strings.xml rename {omnipod-eros => omnipod-common}/src/main/res/values/styles.xml (100%) diff --git a/omnipod-eros/src/main/res/drawable/ic_omnipod_overview_acknowledge_alerts.xml b/omnipod-common/src/main/res/drawable/ic_omnipod_overview_acknowledge_alerts.xml similarity index 100% rename from omnipod-eros/src/main/res/drawable/ic_omnipod_overview_acknowledge_alerts.xml rename to omnipod-common/src/main/res/drawable/ic_omnipod_overview_acknowledge_alerts.xml diff --git a/omnipod-eros/src/main/res/drawable/ic_omnipod_overview_pod_management.xml b/omnipod-common/src/main/res/drawable/ic_omnipod_overview_pod_management.xml similarity index 100% rename from omnipod-eros/src/main/res/drawable/ic_omnipod_overview_pod_management.xml rename to omnipod-common/src/main/res/drawable/ic_omnipod_overview_pod_management.xml diff --git a/omnipod-eros/src/main/res/drawable/ic_omnipod_overview_refresh_pod_status.xml b/omnipod-common/src/main/res/drawable/ic_omnipod_overview_refresh_pod_status.xml similarity index 100% rename from omnipod-eros/src/main/res/drawable/ic_omnipod_overview_refresh_pod_status.xml rename to omnipod-common/src/main/res/drawable/ic_omnipod_overview_refresh_pod_status.xml diff --git a/omnipod-eros/src/main/res/drawable/ic_omnipod_overview_resume_delivery.xml b/omnipod-common/src/main/res/drawable/ic_omnipod_overview_resume_delivery.xml similarity index 100% rename from omnipod-eros/src/main/res/drawable/ic_omnipod_overview_resume_delivery.xml rename to omnipod-common/src/main/res/drawable/ic_omnipod_overview_resume_delivery.xml diff --git a/omnipod-eros/src/main/res/drawable/ic_omnipod_overview_set_time.xml b/omnipod-common/src/main/res/drawable/ic_omnipod_overview_set_time.xml similarity index 100% rename from omnipod-eros/src/main/res/drawable/ic_omnipod_overview_set_time.xml rename to omnipod-common/src/main/res/drawable/ic_omnipod_overview_set_time.xml diff --git a/omnipod-eros/src/main/res/drawable/ic_omnipod_overview_suspend_delivery.xml b/omnipod-common/src/main/res/drawable/ic_omnipod_overview_suspend_delivery.xml similarity index 100% rename from omnipod-eros/src/main/res/drawable/ic_omnipod_overview_suspend_delivery.xml rename to omnipod-common/src/main/res/drawable/ic_omnipod_overview_suspend_delivery.xml diff --git a/omnipod-eros/src/main/res/drawable/ic_omnipod_wizard_success.xml b/omnipod-common/src/main/res/drawable/ic_omnipod_wizard_success.xml similarity index 100% rename from omnipod-eros/src/main/res/drawable/ic_omnipod_wizard_success.xml rename to omnipod-common/src/main/res/drawable/ic_omnipod_wizard_success.xml diff --git a/omnipod-eros/src/main/res/drawable/ic_pod.xml b/omnipod-common/src/main/res/drawable/ic_pod.xml similarity index 100% rename from omnipod-eros/src/main/res/drawable/ic_pod.xml rename to omnipod-common/src/main/res/drawable/ic_pod.xml diff --git a/omnipod-eros/src/main/res/drawable/ic_pod_128.xml b/omnipod-common/src/main/res/drawable/ic_pod_128.xml similarity index 100% rename from omnipod-eros/src/main/res/drawable/ic_pod_128.xml rename to omnipod-common/src/main/res/drawable/ic_pod_128.xml diff --git a/omnipod-eros/src/main/res/drawable/ic_pod_management_activate_pod.xml b/omnipod-common/src/main/res/drawable/ic_pod_management_activate_pod.xml similarity index 100% rename from omnipod-eros/src/main/res/drawable/ic_pod_management_activate_pod.xml rename to omnipod-common/src/main/res/drawable/ic_pod_management_activate_pod.xml diff --git a/omnipod-eros/src/main/res/drawable/ic_pod_management_deactivate_pod.xml b/omnipod-common/src/main/res/drawable/ic_pod_management_deactivate_pod.xml similarity index 100% rename from omnipod-eros/src/main/res/drawable/ic_pod_management_deactivate_pod.xml rename to omnipod-common/src/main/res/drawable/ic_pod_management_deactivate_pod.xml diff --git a/omnipod-eros/src/main/res/drawable/ic_pod_management_discard_pod.xml b/omnipod-common/src/main/res/drawable/ic_pod_management_discard_pod.xml similarity index 100% rename from omnipod-eros/src/main/res/drawable/ic_pod_management_discard_pod.xml rename to omnipod-common/src/main/res/drawable/ic_pod_management_discard_pod.xml diff --git a/omnipod-eros/src/main/res/drawable/ic_pod_management_play_test_beep.xml b/omnipod-common/src/main/res/drawable/ic_pod_management_play_test_beep.xml similarity index 100% rename from omnipod-eros/src/main/res/drawable/ic_pod_management_play_test_beep.xml rename to omnipod-common/src/main/res/drawable/ic_pod_management_play_test_beep.xml diff --git a/omnipod-eros/src/main/res/drawable/ic_pod_management_pod_history.xml b/omnipod-common/src/main/res/drawable/ic_pod_management_pod_history.xml similarity index 100% rename from omnipod-eros/src/main/res/drawable/ic_pod_management_pod_history.xml rename to omnipod-common/src/main/res/drawable/ic_pod_management_pod_history.xml diff --git a/omnipod-eros/src/main/res/drawable/ic_pod_management_pulse_log.xml b/omnipod-common/src/main/res/drawable/ic_pod_management_pulse_log.xml similarity index 100% rename from omnipod-eros/src/main/res/drawable/ic_pod_management_pulse_log.xml rename to omnipod-common/src/main/res/drawable/ic_pod_management_pulse_log.xml diff --git a/omnipod-eros/src/main/res/layout/omnipod_pod_activation_wizard_activity.xml b/omnipod-common/src/main/res/layout/omnipod_pod_activation_wizard_activity.xml similarity index 100% rename from omnipod-eros/src/main/res/layout/omnipod_pod_activation_wizard_activity.xml rename to omnipod-common/src/main/res/layout/omnipod_pod_activation_wizard_activity.xml diff --git a/omnipod-eros/src/main/res/layout/omnipod_pod_deactivation_wizard_activity.xml b/omnipod-common/src/main/res/layout/omnipod_pod_deactivation_wizard_activity.xml similarity index 100% rename from omnipod-eros/src/main/res/layout/omnipod_pod_deactivation_wizard_activity.xml rename to omnipod-common/src/main/res/layout/omnipod_pod_deactivation_wizard_activity.xml diff --git a/omnipod-eros/src/main/res/layout/omnipod_wizard_action_page_fragment.xml b/omnipod-common/src/main/res/layout/omnipod_wizard_action_page_fragment.xml similarity index 93% rename from omnipod-eros/src/main/res/layout/omnipod_wizard_action_page_fragment.xml rename to omnipod-common/src/main/res/layout/omnipod_wizard_action_page_fragment.xml index 54061c7d07..4d0ef0a2ed 100644 --- a/omnipod-eros/src/main/res/layout/omnipod_wizard_action_page_fragment.xml +++ b/omnipod-common/src/main/res/layout/omnipod_wizard_action_page_fragment.xml @@ -56,7 +56,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="10dp" - android:text="@string/omnipod_wizard_button_deactivate_pod" + android:text="@string/omnipod_common_wizard_button_deactivate_pod" android:visibility="gone" />