Add ProgramAlertsCommand

This commit is contained in:
Bart Sopers 2021-02-10 18:00:34 +01:00
parent af35253f0b
commit eb46c973a3
11 changed files with 254 additions and 87 deletions

View file

@ -78,7 +78,7 @@ abstract class CommandBase implements Command {
static byte[] encodeHeader(int address, short sequenceNumber, short length, boolean unknown) {
return ByteBuffer.allocate(6) //
.putInt(address) //
.putShort((short) (((sequenceNumber & 15) << 10) | length | (((unknown ? 1 : 0) & 1) << 15))) //
.putShort((short) (((sequenceNumber & 0x0f) << 10) | length | ((unknown ? 1 : 0) << 15))) //
.array();
}
}

View file

@ -18,4 +18,13 @@ public class DeactivateCommand extends CommandBase {
.putInt(1229869870) // FIXME ?? was: byte array of int 777211465 converted to little endian
.array());
}
@Override public String toString() {
return "DeactivateCommand{" +
"commandType=" + commandType +
", address=" + address +
", sequenceNumber=" + sequenceNumber +
", unknown=" + unknown +
'}';
}
}

View file

@ -23,4 +23,13 @@ public class GetVersionCommand extends CommandBase {
.putInt(address) //
.array());
}
@Override public String toString() {
return "GetVersionCommand{" +
"commandType=" + commandType +
", address=" + address +
", sequenceNumber=" + sequenceNumber +
", unknown=" + unknown +
'}';
}
}

View file

@ -0,0 +1,46 @@
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.definition.AlertConfiguration;
public class ProgramAlertsCommand extends CommandBase {
private final List<AlertConfiguration> alertConfigurations;
ProgramAlertsCommand(int address, short sequenceNumber, boolean unknown, List<AlertConfiguration> alertConfigurations) {
super(CommandType.PROGRAM_ALERTS, address, sequenceNumber, unknown);
this.alertConfigurations = new ArrayList<>(alertConfigurations);
}
@Override public byte[] getEncoded() {
ByteBuffer byteBuffer = ByteBuffer.allocate(getLength() + HEADER_LENGTH) //
.put(encodeHeader(address, sequenceNumber, getLength(), unknown)) //
.put(commandType.getValue()) //
.put(getBodyLength()) //
.putInt(1229869870); // FIXME ?? was: byte array of int 777211465 converted to little endian
for (AlertConfiguration configuration : alertConfigurations) {
byteBuffer.put(configuration.getEncoded());
}
return appendCrc(byteBuffer.array());
}
private short getLength() {
return (short) (alertConfigurations.size() * 6 + 6);
}
private byte getBodyLength() {
return (byte) (alertConfigurations.size() * 6 + 4);
}
@Override public String toString() {
return "ProgramAlertsCommand{" +
"alertConfigurations=" + alertConfigurations +
", commandType=" + commandType +
", address=" + address +
", sequenceNumber=" + sequenceNumber +
", unknown=" + unknown +
'}';
}
}

View file

@ -47,4 +47,16 @@ public class SetUniqueIdCommand extends CommandBase {
(byte) instance.get(Calendar.MINUTE) //
};
}
@Override public String toString() {
return "SetUniqueIdCommand{" +
"lotNumber=" + lotNumber +
", podSequenceNumber=" + podSequenceNumber +
", initializationTime=" + initializationTime +
", commandType=" + commandType +
", address=" + address +
", sequenceNumber=" + sequenceNumber +
", unknown=" + unknown +
'}';
}
}

View file

@ -0,0 +1,62 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
import java.nio.ByteBuffer;
public class AlertConfiguration {
private AlertSlot slot;
private boolean enabled;
private short durationInMinutes;
private boolean autoOff;
private AlertTriggerType triggerType;
private short offsetInMinutesOrThresholdInMicroLiters;
private BeepType beepType;
private BeepRepetitionType beepRepetition;
public AlertConfiguration(AlertSlot slot, boolean enabled, short durationInMinutes, boolean autoOff, AlertTriggerType triggerType, short offsetInMinutesOrThresholdInMicroLiters, BeepType beepType, BeepRepetitionType beepRepetition) {
this.slot = slot;
this.enabled = enabled;
this.durationInMinutes = durationInMinutes;
this.autoOff = autoOff;
this.triggerType = triggerType;
this.offsetInMinutesOrThresholdInMicroLiters = offsetInMinutesOrThresholdInMicroLiters;
this.beepType = beepType;
this.beepRepetition = beepRepetition;
}
/* renamed from: d */
public byte[] getEncoded() {
byte firstByte = (byte) (slot.getValue() << 4);
if (enabled) {
firstByte |= 1 << 3;
}
if (triggerType == AlertTriggerType.RESERVOIR_VOLUME_TRIGGER) {
firstByte |= 1 << 2;
}
if (autoOff) {
firstByte |= 1 << 1;
}
firstByte |= ((durationInMinutes >> 8) & 0x01);
return ByteBuffer.allocate(6) //
.put(firstByte)
.put((byte) durationInMinutes) //
.putShort(offsetInMinutesOrThresholdInMicroLiters) //
.put(beepRepetition.getValue()) //
.put(beepType.getValue()) //
.array();
}
@Override public String toString() {
return "AlertConfiguration{" +
"slot=" + slot +
", enabled=" + enabled +
", durationInMinutes=" + durationInMinutes +
", autoOff=" + autoOff +
", triggerType=" + triggerType +
", offsetInMinutesOrThresholdInMicroLiters=" + offsetInMinutesOrThresholdInMicroLiters +
", beepType=" + beepType +
", beepRepetition=" + beepRepetition +
'}';
}
}

View file

@ -0,0 +1,28 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
public enum AlertSlot {
EXPIRATION_IMMINENT((byte) 0x02),
LOW_RESERVOIR((byte) 0x04),
USER_POD_EXPIRATION((byte) 0x03),
LUMP_OF_COAL_AND_EXPIRATION((byte) 0x07),
UNKNOWN((byte) 255);
private byte value;
AlertSlot(byte value) {
this.value = value;
}
public static AlertSlot byValue(byte value) {
for (AlertSlot slot : values()) {
if (slot.value == value) {
return slot;
}
}
return UNKNOWN;
}
public byte getValue() {
return value;
}
}

View file

@ -0,0 +1,6 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
public enum AlertTriggerType {
TIME_TRIGGER,
RESERVOIR_VOLUME_TRIGGER
}

View file

@ -0,0 +1,20 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
// FIXME names
public enum BeepRepetitionType {
XXX((byte) 0x01), // Used in low reservoir alert
XXX2((byte) 0x03), // Used in user pod expiration alert
XXX3((byte) 0x05), // Used in pod expiration alert
XXX4((byte) 0x06), // Used in imminent pod expiration alert
XXX5((byte) 0x08); // Used in lump of coal alert
private byte value;
BeepRepetitionType(byte value) {
this.value = value;
}
public byte getValue() {
return value;
}
}

View file

@ -0,0 +1,17 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
// FIXME names
public enum BeepType {
SILENT((byte) 0x00),
XXX((byte) 0x02); //// Used in low reservoir alert, user expiration alert, expiration alert, imminent expiration alert, lump of coal alert
private byte value;
BeepType(byte value) {
this.value = value;
}
public byte getValue() {
return value;
}
}

View file

@ -1,102 +1,60 @@
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.ArrayList;
import java.util.List;
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertConfiguration;
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertSlot;
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertTriggerType;
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepRepetitionType;
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType;
import static org.junit.Assert.assertArrayEquals;
public class ProgramAlertsCommandTest {
// TODO
@Test
public void testExpirationAlerts() throws DecoderException {
List<AlertConfiguration> configurations = new ArrayList<>();
configurations.add(new AlertConfiguration(AlertSlot.LUMP_OF_COAL_AND_EXPIRATION, true, (short) 420, false, AlertTriggerType.TIME_TRIGGER, (short) 4305, BeepType.XXX, BeepRepetitionType.XXX3));
configurations.add(new AlertConfiguration(AlertSlot.EXPIRATION_IMMINENT, true, (short) 0, false, AlertTriggerType.TIME_TRIGGER, (short) 4725, BeepType.XXX, BeepRepetitionType.XXX4));
// Address for all captures below: 37879811
byte[] encoded = new ProgramAlertsCommand(37879811, (short) 3, true, configurations).getEncoded();
/*
Pod expiration alerts
assertArrayEquals(Hex.decodeHex("024200038C121910494E532E79A410D1050228001275060280F5"), encoded);
}
V/PodComm: *** encode() CALLED ON ProgramAlertsCommandEncoder
*** encode() CALLED ON HeaderEncoder
V/PodComm: *** encode() RESULT FOR HeaderEncoder: 02:42:00:03:8C:12 FROM HeaderEncoder{lengthSequenceNumberAndFlags=-29678, f6666a=[], encoded=[2, 66, 0, 3, -116, 18], headerEncoder=null, commandId=0, f6671f=0, commandBodyLength=0}
*** encode() RESULT FOR ProgramAlertsCommandEncoder: 02:42:00:03:8C:12:19:10:49:4E:53:2E:79:A4:10:D1:05:02:28:00:12:75:06:02:80:F5 FROM ProgramAlertsCommandEncoder{parameters=ProgramAlertsCommandParameters{configurations=[AlertConfigurationEncoder{slot=7, enabled=true, durationInMinutes=420, autoOff=false, timeTrigger=false, offsetInMinutes=4305, beepType=2, beepRepetition=5}, AlertConfigurationEncoder{slot=2, enabled=true, durationInMinutes=0, autoOff=false, timeTrigger=false, offsetInMinutes=4725, beepType=2, beepRepetition=6}]}, f6666a=[], encoded=[2, 66, 0, 3, -116, 18, 25, 16, 73, 78, 83, 46, 121, -92, 16, -47, 5, 2, 40, 0, 18, 117, 6, 2, -128, -11], headerEncoder=HeaderEncoder{lengthSequenceNumberAndFlags=-29678, f6666a=[], encoded=[2, 66, 0, 3, -116, 18], headerEncoder=null, commandId=0, f6671f=0, commandBodyLength=0}, commandId=25, f6671f=0, commandBodyLength=16}
@Test
public void testLowReservoirAlert() throws DecoderException {
List<AlertConfiguration> configurations = new ArrayList<>();
configurations.add(new AlertConfiguration(AlertSlot.LOW_RESERVOIR, true, (short) 0, false, AlertTriggerType.RESERVOIR_VOLUME_TRIGGER, (short) 200, BeepType.XXX, BeepRepetitionType.XXX));
I/PodComm: pod command: 024200038C121910494E532E79A410D1050228001275060280F5
V/PodComm: flags: seqNum=3 ack=false mctf=true
Program Alert:
length:16, number of alerts:2
-------------------------------------
alert index: 7 (lump of coal/pod expiration)
enabled: true
duration: 420 minutes
set alarm: false
V/PodComm: type: time - trigger after 4305 minutes (71.75 hrs)
beep type: 2
beep repetition: 5
-------------------------------------
alert index: 2 (imminent pod expiration)
enabled: true
duration: 0 minutes
set alarm: false
type: time - trigger after 4725 minutes (78.75 hrs)
beep type: 2
beep repetition: 6
byte[] encoded = new ProgramAlertsCommand(37879811, (short) 8, false, configurations).getEncoded();
*/
assertArrayEquals(Hex.decodeHex("02420003200C190A494E532E4C0000C801020149"), encoded);
}
/*
Low reservoir
@Test
public void testUserExpirationAlert() throws DecoderException {
List<AlertConfiguration> configurations = new ArrayList<>();
configurations.add(new AlertConfiguration(AlertSlot.USER_POD_EXPIRATION, true, (short) 0, false, AlertTriggerType.TIME_TRIGGER, (short) 4079, BeepType.XXX, BeepRepetitionType.XXX2));
V/PodComm: *** encode() RESULT FOR HeaderEncoder: 02:42:00:03:20:0C FROM HeaderEncoder{lengthSequenceNumberAndFlags=8204, f6666a=[], encoded=[2, 66, 0, 3, 32, 12], headerEncoder=null, commandId=0, f6671f=0, commandBodyLength=0}
V/PodComm: *** encode() RESULT FOR ProgramAlertsCommandEncoder: 02:42:00:03:20:0C:19:0A:49:4E:53:2E:4C:00:00:C8:01:02:01:49 FROM ProgramAlertsCommandEncoder{parameters=ProgamAlertsCommandParameters{configurations=[AlertConfigurationEncoder{slot=4, enabled=true, durationInMinutes=0, autoOff=false, timeTrigger=true, offsetInMinutes=200, beepType=2, beepRepetition=1}]}, f6666a=[], encoded=[2, 66, 0, 3, 32, 12, 25, 10, 73, 78, 83, 46, 76, 0, 0, -56, 1, 2, 1, 73], headerEncoder=HeaderEncoder{lengthSequenceNumberAndFlags=8204, f6666a=[], encoded=[2, 66, 0, 3, 32, 12], headerEncoder=null, commandId=0, f6671f=0, commandBodyLength=0}, commandId=25, f6671f=0, commandBodyLength=10}
byte[] encoded = new ProgramAlertsCommand(37879811, (short) 15, false, configurations).getEncoded();
V/PodComm: flags: seqNum=8 ack=false mctf=false
Program Alert:
length:10, number of alerts:1
-------------------------------------
alert index: 4 (low reservoir)
enabled: true
duration: 0 minutes
set alarm: false
type: volume - trigger at 200 micro liter
beep type: 2
beep repetition: 1
*/
/*
User Pod expiration
V/PodComm: *** encode() CALLED ON ProgramAlertsCommandEncoder
*** encode() CALLED ON HeaderEncoder
V/PodComm: *** encode() RESULT FOR HeaderEncoder: 02:42:00:03:3C:0C FROM HeaderEncoder{lengthSequenceNumberAndFlags=15372, f6666a=[], encoded=[2, 66, 0, 3, 60, 12], headerEncoder=null, commandId=0, f6671f=0, commandBodyLength=0}
V/PodComm: *** encode() RESULT FOR ProgramAlertsCommandEncoder: 02:42:00:03:3C:0C:19:0A:49:4E:53:2E:38:00:0F:EF:03:02:03:E2 FROM ProgramAlertsCommandEncoder{parameters=ProgramAlertsCommandParameters{configurations=[AlertConfigurationEncoder{slot=3, enabled=true, durationInMinutes=0, autoOff=false, timeTrigger=false, offsetInMinutes=4079, beepType=2, beepRepetition=3}]}, f6666a=[], encoded=[2, 66, 0, 3, 60, 12, 25, 10, 73, 78, 83, 46, 56, 0, 15, -17, 3, 2, 3, -30], headerEncoder=HeaderEncoder{lengthSequenceNumberAndFlags=15372, f6666a=[], encoded=[2, 66, 0, 3, 60, 12], headerEncoder=null, commandId=0, f6671f=0, commandBodyLength=0}, commandId=25, f6671f=0, commandBodyLength=10}
I/PodComm: pod command: 024200033C0C190A494E532E38000FEF030203E2
V/PodComm: flags: seqNum=15 ack=false mctf=false
Program Alert:
length:10, number of alerts:1
-------------------------------------
alert index: 3 (user pod expiration)
enabled: true
duration: 0 minutes
set alarm: false
type: time - trigger after 4079 minutes (67.98 hrs)
beep type: 2
beep repetition: 3
*/
assertArrayEquals(Hex.decodeHex("024200033C0C190A494E532E38000FEF030203E2"), encoded);
}
/*
Lump of coal
@Test
public void testLumpOfCoalAlert() throws DecoderException {
List<AlertConfiguration> configurations = new ArrayList<>();
configurations.add(new AlertConfiguration(AlertSlot.LUMP_OF_COAL_AND_EXPIRATION, true, (short) 55, false, AlertTriggerType.TIME_TRIGGER, (short) 5, BeepType.XXX, BeepRepetitionType.XXX5));
V/PodComm: *** encode() CALLED ON ProgramAlertsCommandEncoder
*** encode() CALLED ON HeaderEncoder
*** encode() RESULT FOR HeaderEncoder: 02:42:00:03:28:0C FROM HeaderEncoder{lengthSequenceNumberAndFlags=10252, f6666a=[], encoded=[2, 66, 0, 3, 40, 12], headerEncoder=null, commandId=0, f6671f=0, commandBodyLength=0}
D/MainActivity: Pod Activation 1: got Pod Event
V/PodComm: *** encode() RESULT FOR ProgramAlertsCommandEncoder: 02:42:00:03:28:0C:19:0A:49:4E:53:2E:78:37:00:05:08:02:03:56 FROM ProgramAlertsCommandEncoder{parameters=ProgramAlertsCommandParameters{configurations=[AlertConfigurationEncoder{slot=7, enabled=true, durationInMinutes=55, autoOff=false, timeTrigger=false, offsetInMinutes=5, beepType=2, beepRepetition=8}]}, f6666a=[], encoded=[2, 66, 0, 3, 40, 12, 25, 10, 73, 78, 83, 46, 120, 55, 0, 5, 8, 2, 3, 86], headerEncoder=HeaderEncoder{lengthSequenceNumberAndFlags=10252, f6666a=[], encoded=[2, 66, 0, 3, 40, 12], headerEncoder=null, commandId=0, f6671f=0, commandBodyLength=0}, commandId=25, f6671f=0, commandBodyLength=10}
byte[] encoded = new ProgramAlertsCommand(37879811, (short) 10, false, configurations).getEncoded();
V/PodComm: flags: seqNum=10 ack=false mctf=false
Program Alert:
length:10, number of alerts:1
-------------------------------------
V/PodComm: alert index: 7 (lump of coal/pod expiration)
enabled: true
duration: 55 minutes
set alarm: false
type: time - trigger after 5 minutes (0.08 hrs)
beep type: 2
beep repetition: 8
*/
assertArrayEquals(Hex.decodeHex("02420003280C190A494E532E7837000508020356"), encoded);
}
}