Merge remote-tracking branch 'origin/adrian/kotlinify-driver-pod' into dash-mgr
This commit is contained in:
commit
d5679e51dd
99 changed files with 2366 additions and 3098 deletions
|
@ -1,41 +0,0 @@
|
||||||
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.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;
|
|
||||||
private static final byte BODY_LENGTH = 4;
|
|
||||||
|
|
||||||
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(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
|
|
||||||
.put(commandType.getValue()) //
|
|
||||||
.put(BODY_LENGTH) //
|
|
||||||
.putInt(nonce) //
|
|
||||||
.array());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String toString() {
|
|
||||||
return "DeactivateCommand{" +
|
|
||||||
"nonce=" + nonce +
|
|
||||||
", commandType=" + commandType +
|
|
||||||
", uniqueId=" + uniqueId +
|
|
||||||
", sequenceNumber=" + sequenceNumber +
|
|
||||||
", multiCommandFlag=" + multiCommandFlag +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class Builder extends NonceEnabledCommandBuilder<Builder, DeactivateCommand> {
|
|
||||||
@Override protected final DeactivateCommand buildCommand() {
|
|
||||||
return new DeactivateCommand(uniqueId, sequenceNumber, multiCommandFlag, nonce);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.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 java.nio.ByteBuffer
|
||||||
|
|
||||||
|
class DeactivateCommand internal constructor(uniqueId: Int, sequenceNumber: Short, multiCommandFlag: Boolean, nonce: Int) : NonceEnabledCommand(CommandType.DEACTIVATE, uniqueId, sequenceNumber, multiCommandFlag, nonce) {
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
override val encoded: ByteArray
|
||||||
|
get() = appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) //
|
||||||
|
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
|
||||||
|
.put(commandType.value) //
|
||||||
|
.put(BODY_LENGTH) //
|
||||||
|
.putInt(nonce) //
|
||||||
|
.array())
|
||||||
|
|
||||||
|
override fun toString(): String = "DeactivateCommand{" +
|
||||||
|
"nonce=" + nonce +
|
||||||
|
", commandType=" + commandType +
|
||||||
|
", uniqueId=" + uniqueId +
|
||||||
|
", sequenceNumber=" + sequenceNumber +
|
||||||
|
", multiCommandFlag=" + multiCommandFlag +
|
||||||
|
'}'
|
||||||
|
|
||||||
|
class Builder : NonceEnabledCommandBuilder<Builder, DeactivateCommand>() {
|
||||||
|
|
||||||
|
override fun buildCommand(): DeactivateCommand =
|
||||||
|
DeactivateCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, nonce!!) // TODO this might crash if not all are set
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val LENGTH: Short = 6
|
||||||
|
private const val BODY_LENGTH: Byte = 4
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,42 +0,0 @@
|
||||||
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.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_UNIQUE_ID = -1; // FIXME move
|
|
||||||
|
|
||||||
private static final short LENGTH = 6;
|
|
||||||
private static final byte BODY_LENGTH = 4;
|
|
||||||
|
|
||||||
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(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
|
|
||||||
.put(commandType.getValue()) //
|
|
||||||
.put(BODY_LENGTH) //
|
|
||||||
.putInt(uniqueId) //
|
|
||||||
.array());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String toString() {
|
|
||||||
return "GetVersionCommand{" +
|
|
||||||
"commandType=" + commandType +
|
|
||||||
", uniqueId=" + uniqueId +
|
|
||||||
", sequenceNumber=" + sequenceNumber +
|
|
||||||
", multiCommandFlag=" + multiCommandFlag +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class Builder extends HeaderEnabledCommandBuilder<Builder, GetVersionCommand> {
|
|
||||||
@Override protected final GetVersionCommand buildCommand() {
|
|
||||||
return new GetVersionCommand(uniqueId, sequenceNumber, multiCommandFlag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.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.command.base.builder.HeaderEnabledCommandBuilder
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
|
class GetVersionCommand internal constructor(uniqueId: Int, sequenceNumber: Short, multiCommandFlag: Boolean) : HeaderEnabledCommand(CommandType.GET_VERSION, uniqueId, sequenceNumber, multiCommandFlag) {
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
override val encoded: ByteArray
|
||||||
|
get() = HeaderEnabledCommand.Companion.appendCrc(ByteBuffer.allocate(LENGTH + HeaderEnabledCommand.Companion.HEADER_LENGTH) //
|
||||||
|
.put(HeaderEnabledCommand.Companion.encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
|
||||||
|
.put(commandType.value) //
|
||||||
|
.put(BODY_LENGTH) //
|
||||||
|
.putInt(uniqueId) //
|
||||||
|
.array())
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "GetVersionCommand{" +
|
||||||
|
"commandType=" + commandType +
|
||||||
|
", uniqueId=" + uniqueId +
|
||||||
|
", sequenceNumber=" + sequenceNumber +
|
||||||
|
", multiCommandFlag=" + multiCommandFlag +
|
||||||
|
'}'
|
||||||
|
}
|
||||||
|
|
||||||
|
class Builder : HeaderEnabledCommandBuilder<Builder, GetVersionCommand>() {
|
||||||
|
|
||||||
|
override fun buildCommand(): GetVersionCommand {
|
||||||
|
return GetVersionCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
const val DEFAULT_UNIQUE_ID = -1 // FIXME move
|
||||||
|
private const val LENGTH: Short = 6
|
||||||
|
private const val BODY_LENGTH: Byte = 4
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,66 +0,0 @@
|
||||||
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.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 {
|
|
||||||
private final List<AlertConfiguration> alertConfigurations;
|
|
||||||
|
|
||||||
ProgramAlertsCommand(int uniqueId, short sequenceNumber, boolean multiCommandFlag, List<AlertConfiguration> 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(uniqueId, sequenceNumber, getLength(), multiCommandFlag)) //
|
|
||||||
.put(commandType.getValue()) //
|
|
||||||
.put(getBodyLength()) //
|
|
||||||
.putInt(nonce);
|
|
||||||
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 +
|
|
||||||
", nonce=" + nonce +
|
|
||||||
", commandType=" + commandType +
|
|
||||||
", uniqueId=" + uniqueId +
|
|
||||||
", sequenceNumber=" + sequenceNumber +
|
|
||||||
", multiCommandFlag=" + multiCommandFlag +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class Builder extends NonceEnabledCommandBuilder<Builder, ProgramAlertsCommand> {
|
|
||||||
private List<AlertConfiguration> alertConfigurations;
|
|
||||||
|
|
||||||
public Builder setAlertConfigurations(List<AlertConfiguration> alertConfigurations) {
|
|
||||||
this.alertConfigurations = alertConfigurations;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override protected final ProgramAlertsCommand buildCommand() {
|
|
||||||
if (this.alertConfigurations == null) {
|
|
||||||
throw new IllegalArgumentException("alertConfigurations can not be null");
|
|
||||||
}
|
|
||||||
return new ProgramAlertsCommand(uniqueId, sequenceNumber, multiCommandFlag, alertConfigurations, nonce);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.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.AlertConfiguration
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class ProgramAlertsCommand internal constructor(uniqueId: Int, sequenceNumber: Short, multiCommandFlag: Boolean, alertConfigurations: List<AlertConfiguration>?, nonce: Int) : NonceEnabledCommand(CommandType.PROGRAM_ALERTS, uniqueId, sequenceNumber, multiCommandFlag, nonce) {
|
||||||
|
|
||||||
|
private val alertConfigurations: List<AlertConfiguration>
|
||||||
|
|
||||||
|
private fun getLength(): Short {
|
||||||
|
return (alertConfigurations.size * 6 + 6).toShort()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getBodyLength(): Byte {
|
||||||
|
return (alertConfigurations.size * 6 + 4).toByte()
|
||||||
|
}
|
||||||
|
|
||||||
|
override val encoded: ByteArray
|
||||||
|
get() {
|
||||||
|
val byteBuffer: ByteBuffer = ByteBuffer.allocate(getLength() + HEADER_LENGTH) //
|
||||||
|
.put(encodeHeader(uniqueId, sequenceNumber, getLength(), multiCommandFlag)) //
|
||||||
|
.put(commandType.value) //
|
||||||
|
.put(getBodyLength()) //
|
||||||
|
.putInt(nonce)
|
||||||
|
for (configuration in alertConfigurations) {
|
||||||
|
byteBuffer.put(configuration.encoded)
|
||||||
|
}
|
||||||
|
return appendCrc(byteBuffer.array())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "ProgramAlertsCommand{" +
|
||||||
|
"alertConfigurations=" + alertConfigurations +
|
||||||
|
", nonce=" + nonce +
|
||||||
|
", commandType=" + commandType +
|
||||||
|
", uniqueId=" + uniqueId +
|
||||||
|
", sequenceNumber=" + sequenceNumber +
|
||||||
|
", multiCommandFlag=" + multiCommandFlag +
|
||||||
|
'}'
|
||||||
|
}
|
||||||
|
|
||||||
|
class Builder : NonceEnabledCommandBuilder<Builder, ProgramAlertsCommand>() {
|
||||||
|
|
||||||
|
private var alertConfigurations: List<AlertConfiguration>? = null
|
||||||
|
fun setAlertConfigurations(alertConfigurations: List<AlertConfiguration>?): Builder {
|
||||||
|
this.alertConfigurations = alertConfigurations
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildCommand(): ProgramAlertsCommand {
|
||||||
|
requireNotNull(alertConfigurations) { "alertConfigurations can not be null" } // !!?
|
||||||
|
return ProgramAlertsCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, alertConfigurations, nonce!!) // TODO this might crash if not all are set
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
this.alertConfigurations = ArrayList(alertConfigurations)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,132 +0,0 @@
|
||||||
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.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.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.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;
|
|
||||||
|
|
||||||
// Always preceded by 0x1a ProgramInsulinCommand
|
|
||||||
public final class ProgramBasalCommand extends HeaderEnabledCommand {
|
|
||||||
private final ProgramInsulinCommand interlockCommand;
|
|
||||||
private final List<BasalInsulinProgramElement> 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<BasalInsulinProgramElement> insulinProgramElements, ProgramReminder programReminder, byte currentInsulinProgramElementIndex, short remainingTenthPulsesInCurrentInsulinProgramElement, int delayUntilNextTenthPulseInUsec) {
|
|
||||||
super(CommandType.PROGRAM_BASAL, uniqueId, sequenceNumber, multiCommandFlag);
|
|
||||||
|
|
||||||
this.interlockCommand = interlockCommand;
|
|
||||||
this.insulinProgramElements = new ArrayList<>(insulinProgramElements);
|
|
||||||
this.programReminder = programReminder;
|
|
||||||
this.currentInsulinProgramElementIndex = currentInsulinProgramElementIndex;
|
|
||||||
this.remainingTenthPulsesInCurrentInsulinProgramElement = remainingTenthPulsesInCurrentInsulinProgramElement;
|
|
||||||
this.delayUntilNextTenthPulseInUsec = delayUntilNextTenthPulseInUsec;
|
|
||||||
}
|
|
||||||
|
|
||||||
short getLength() {
|
|
||||||
return (short) (insulinProgramElements.size() * 6 + 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
byte getBodyLength() {
|
|
||||||
return (byte) (insulinProgramElements.size() * 6 + 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public byte[] getEncoded() {
|
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(getLength()) //
|
|
||||||
.put(getCommandType().getValue()) //
|
|
||||||
.put(getBodyLength()) //
|
|
||||||
.put(programReminder.getEncoded()) //
|
|
||||||
.put(currentInsulinProgramElementIndex) //
|
|
||||||
.putShort(remainingTenthPulsesInCurrentInsulinProgramElement) //
|
|
||||||
.putInt(delayUntilNextTenthPulseInUsec);
|
|
||||||
for (BasalInsulinProgramElement insulinProgramElement : insulinProgramElements) {
|
|
||||||
buffer.put(insulinProgramElement.getEncoded());
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] basalCommand = buffer.array();
|
|
||||||
byte[] interlockCommand = this.interlockCommand.getEncoded();
|
|
||||||
byte[] header = encodeHeader(uniqueId, sequenceNumber, (short) (basalCommand.length + interlockCommand.length), multiCommandFlag);
|
|
||||||
|
|
||||||
return appendCrc(ByteBuffer.allocate(basalCommand.length + interlockCommand.length + header.length) //
|
|
||||||
.put(header) //
|
|
||||||
.put(interlockCommand) //
|
|
||||||
.put(basalCommand) //
|
|
||||||
.array());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String toString() {
|
|
||||||
return "ProgramBasalCommand{" +
|
|
||||||
"interlockCommand=" + interlockCommand +
|
|
||||||
", insulinProgramElements=" + insulinProgramElements +
|
|
||||||
", programReminder=" + programReminder +
|
|
||||||
", currentInsulinProgramElementIndex=" + currentInsulinProgramElementIndex +
|
|
||||||
", remainingTenthPulsesInCurrentInsulinProgramElement=" + remainingTenthPulsesInCurrentInsulinProgramElement +
|
|
||||||
", delayUntilNextTenthPulseInUsec=" + delayUntilNextTenthPulseInUsec +
|
|
||||||
", commandType=" + commandType +
|
|
||||||
", uniqueId=" + uniqueId +
|
|
||||||
", sequenceNumber=" + sequenceNumber +
|
|
||||||
", multiCommandFlag=" + multiCommandFlag +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class Builder extends NonceEnabledCommandBuilder<Builder, ProgramBasalCommand> {
|
|
||||||
private BasalProgram basalProgram;
|
|
||||||
private ProgramReminder programReminder;
|
|
||||||
private Date currentTime;
|
|
||||||
|
|
||||||
public Builder setBasalProgram(BasalProgram basalProgram) {
|
|
||||||
this.basalProgram = basalProgram;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder setProgramReminder(ProgramReminder programReminder) {
|
|
||||||
this.programReminder = programReminder;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder setCurrentTime(Date currentTime) {
|
|
||||||
this.currentTime = currentTime;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@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 (currentTime == null) {
|
|
||||||
throw new IllegalArgumentException("currentTime can not be null");
|
|
||||||
}
|
|
||||||
|
|
||||||
short[] pulsesPerSlot = ProgramBasalUtil.mapBasalProgramToPulsesPerSlot(basalProgram);
|
|
||||||
CurrentSlot currentSlot = ProgramBasalUtil.calculateCurrentSlot(pulsesPerSlot, currentTime);
|
|
||||||
short checksum = ProgramBasalUtil.calculateChecksum(pulsesPerSlot, currentSlot);
|
|
||||||
List<BasalInsulinProgramElement> longInsulinProgramElements = ProgramBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements(ProgramBasalUtil.mapBasalProgramToTenthPulsesPerSlot(basalProgram));
|
|
||||||
List<ShortInsulinProgramElement> shortInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot);
|
|
||||||
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, currentBasalInsulinProgramElement.getIndex(),
|
|
||||||
currentBasalInsulinProgramElement.getRemainingTenthPulses(), currentBasalInsulinProgramElement.getDelayUntilNextTenthPulseInUsec());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.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.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.util.ProgramBasalUtil
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.util.ProgramTempBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements
|
||||||
|
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 java.nio.ByteBuffer
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
// Always preceded by 0x1a ProgramInsulinCommand
|
||||||
|
class ProgramBasalCommand internal constructor(private val interlockCommand: ProgramInsulinCommand, uniqueId: Int, sequenceNumber: Short, multiCommandFlag: Boolean, insulinProgramElements: List<BasalInsulinProgramElement>?, programReminder: ProgramReminder, currentInsulinProgramElementIndex: Byte, remainingTenthPulsesInCurrentInsulinProgramElement: Short, delayUntilNextTenthPulseInUsec: Int) : HeaderEnabledCommand(CommandType.PROGRAM_BASAL, uniqueId, sequenceNumber, multiCommandFlag) {
|
||||||
|
|
||||||
|
private val insulinProgramElements: List<BasalInsulinProgramElement>
|
||||||
|
private val programReminder: ProgramReminder
|
||||||
|
private val currentInsulinProgramElementIndex: Byte
|
||||||
|
private val remainingTenthPulsesInCurrentInsulinProgramElement: Short
|
||||||
|
private val delayUntilNextTenthPulseInUsec: Int
|
||||||
|
val length: Short
|
||||||
|
get() = (insulinProgramElements.size * 6 + 10).toShort()
|
||||||
|
val bodyLength: Byte
|
||||||
|
get() = (insulinProgramElements.size * 6 + 8).toByte()//
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
override val encoded: ByteArray
|
||||||
|
get() {
|
||||||
|
val buffer = ByteBuffer.allocate(length.toInt()) //
|
||||||
|
.put(commandType.value) //
|
||||||
|
.put(bodyLength) //
|
||||||
|
.put(programReminder.encoded) //
|
||||||
|
.put(currentInsulinProgramElementIndex) //
|
||||||
|
.putShort(remainingTenthPulsesInCurrentInsulinProgramElement) //
|
||||||
|
.putInt(delayUntilNextTenthPulseInUsec)
|
||||||
|
for (insulinProgramElement in insulinProgramElements) {
|
||||||
|
buffer.put(insulinProgramElement.encoded)
|
||||||
|
}
|
||||||
|
val basalCommand = buffer.array()
|
||||||
|
val interlockCommand = interlockCommand.encoded
|
||||||
|
val header: ByteArray = HeaderEnabledCommand.Companion.encodeHeader(uniqueId, sequenceNumber, (basalCommand.size + interlockCommand!!.size).toShort(), multiCommandFlag)
|
||||||
|
return HeaderEnabledCommand.appendCrc(ByteBuffer.allocate(basalCommand.size + interlockCommand.size + header.size) //
|
||||||
|
.put(header) //
|
||||||
|
.put(interlockCommand) //
|
||||||
|
.put(basalCommand) //
|
||||||
|
.array())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "ProgramBasalCommand{" +
|
||||||
|
"interlockCommand=" + interlockCommand +
|
||||||
|
", insulinProgramElements=" + insulinProgramElements +
|
||||||
|
", programReminder=" + programReminder +
|
||||||
|
", currentInsulinProgramElementIndex=" + currentInsulinProgramElementIndex +
|
||||||
|
", remainingTenthPulsesInCurrentInsulinProgramElement=" + remainingTenthPulsesInCurrentInsulinProgramElement +
|
||||||
|
", delayUntilNextTenthPulseInUsec=" + delayUntilNextTenthPulseInUsec +
|
||||||
|
", commandType=" + commandType +
|
||||||
|
", uniqueId=" + uniqueId +
|
||||||
|
", sequenceNumber=" + sequenceNumber +
|
||||||
|
", multiCommandFlag=" + multiCommandFlag +
|
||||||
|
'}'
|
||||||
|
}
|
||||||
|
|
||||||
|
class Builder : NonceEnabledCommandBuilder<Builder, ProgramBasalCommand>() {
|
||||||
|
|
||||||
|
private var basalProgram: BasalProgram? = null
|
||||||
|
private var programReminder: ProgramReminder? = null
|
||||||
|
private var currentTime: Date? = null
|
||||||
|
fun setBasalProgram(basalProgram: BasalProgram?): Builder {
|
||||||
|
this.basalProgram = basalProgram
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setProgramReminder(programReminder: ProgramReminder?): Builder {
|
||||||
|
this.programReminder = programReminder
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setCurrentTime(currentTime: Date?): Builder {
|
||||||
|
this.currentTime = currentTime
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildCommand(): ProgramBasalCommand {
|
||||||
|
requireNotNull(basalProgram) { "basalProgram can not be null" }
|
||||||
|
requireNotNull(programReminder) { "programReminder can not be null" }
|
||||||
|
requireNotNull(currentTime) { "currentTime can not be null" }
|
||||||
|
val pulsesPerSlot = ProgramBasalUtil.mapBasalProgramToPulsesPerSlot(basalProgram!!)
|
||||||
|
val currentSlot = ProgramBasalUtil.calculateCurrentSlot(pulsesPerSlot, currentTime)
|
||||||
|
val checksum = ProgramBasalUtil.calculateChecksum(pulsesPerSlot, currentSlot)
|
||||||
|
val longInsulinProgramElements: List<BasalInsulinProgramElement> = mapTenthPulsesPerSlotToLongInsulinProgramElements(ProgramBasalUtil.mapBasalProgramToTenthPulsesPerSlot(basalProgram!!))
|
||||||
|
val shortInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot)
|
||||||
|
val currentBasalInsulinProgramElement = ProgramBasalUtil.calculateCurrentLongInsulinProgramElement(longInsulinProgramElements, currentTime)
|
||||||
|
val interlockCommand = ProgramInsulinCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, nonce!!,
|
||||||
|
shortInsulinProgramElements, checksum, currentSlot.index, currentSlot.eighthSecondsRemaining,
|
||||||
|
currentSlot.pulsesRemaining, ProgramInsulinCommand.DeliveryType.BASAL)
|
||||||
|
return ProgramBasalCommand(interlockCommand, uniqueId!!, sequenceNumber!!, multiCommandFlag,
|
||||||
|
longInsulinProgramElements, programReminder!!, currentBasalInsulinProgramElement.index,
|
||||||
|
currentBasalInsulinProgramElement.remainingTenthPulses, currentBasalInsulinProgramElement.delayUntilNextTenthPulseInUsec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
this.insulinProgramElements = ArrayList(insulinProgramElements)
|
||||||
|
this.programReminder = programReminder
|
||||||
|
this.currentInsulinProgramElementIndex = currentInsulinProgramElementIndex
|
||||||
|
this.remainingTenthPulsesInCurrentInsulinProgramElement = remainingTenthPulsesInCurrentInsulinProgramElement
|
||||||
|
this.delayUntilNextTenthPulseInUsec = delayUntilNextTenthPulseInUsec
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,123 +0,0 @@
|
||||||
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<Builder, ProgramBolusCommand> {
|
|
||||||
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)), calculateChecksum((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 calculateChecksum(byte numberOfSlots, short byte10And11, short numberOfPulses) {
|
|
||||||
return MessageUtil.calculateChecksum(ByteBuffer.allocate(7) //
|
|
||||||
.put(numberOfSlots) //
|
|
||||||
.putShort(byte10And11) //
|
|
||||||
.putShort(numberOfPulses) //
|
|
||||||
.putShort(numberOfPulses) //
|
|
||||||
.array());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.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.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
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
|
// NOT SUPPORTED: extended bolus
|
||||||
|
class ProgramBolusCommand internal constructor(private val interlockCommand: ProgramInsulinCommand, uniqueId: Int, sequenceNumber: Short, multiCommandFlag: Boolean, private val programReminder: ProgramReminder, private val numberOfTenthPulses: Short, //
|
||||||
|
private val delayUntilFirstTenthPulseInUsec: Int) : HeaderEnabledCommand(CommandType.PROGRAM_BOLUS, uniqueId, sequenceNumber, multiCommandFlag) {
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Extended bolus pulses
|
||||||
|
// Delay between tenth extended pulses in usec
|
||||||
|
override val encoded: ByteArray
|
||||||
|
get() {
|
||||||
|
val bolusCommand = ByteBuffer.allocate(LENGTH.toInt()) //
|
||||||
|
.put(commandType.value) //
|
||||||
|
.put(BODY_LENGTH) //
|
||||||
|
.put(programReminder.encoded) //
|
||||||
|
.putShort(numberOfTenthPulses) //
|
||||||
|
.putInt(delayUntilFirstTenthPulseInUsec) //
|
||||||
|
.putShort(0.toShort()) // Extended bolus pulses
|
||||||
|
.putInt(0) // Delay between tenth extended pulses in usec
|
||||||
|
.array()
|
||||||
|
val interlockCommand = interlockCommand.encoded
|
||||||
|
val header: ByteArray = HeaderEnabledCommand.Companion.encodeHeader(uniqueId, sequenceNumber, (bolusCommand.size + interlockCommand!!.size).toShort(), multiCommandFlag)
|
||||||
|
return HeaderEnabledCommand.Companion.appendCrc(ByteBuffer.allocate(header.size + interlockCommand.size + bolusCommand.size) //
|
||||||
|
.put(header) //
|
||||||
|
.put(interlockCommand) //
|
||||||
|
.put(bolusCommand) //
|
||||||
|
.array())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "ProgramBolusCommand{" +
|
||||||
|
"interlockCommand=" + interlockCommand +
|
||||||
|
", programReminder=" + programReminder +
|
||||||
|
", numberOfTenthPulses=" + numberOfTenthPulses +
|
||||||
|
", delayUntilFirstTenthPulseInUsec=" + delayUntilFirstTenthPulseInUsec +
|
||||||
|
", commandType=" + commandType +
|
||||||
|
", uniqueId=" + uniqueId +
|
||||||
|
", sequenceNumber=" + sequenceNumber +
|
||||||
|
", multiCommandFlag=" + multiCommandFlag +
|
||||||
|
'}'
|
||||||
|
}
|
||||||
|
|
||||||
|
class Builder : NonceEnabledCommandBuilder<Builder, ProgramBolusCommand>() {
|
||||||
|
|
||||||
|
private var numberOfUnits: Double? = null
|
||||||
|
private var delayBetweenPulsesInEighthSeconds: Byte? = null
|
||||||
|
private var programReminder: ProgramReminder? = null
|
||||||
|
fun setNumberOfUnits(numberOfUnits: Double): Builder {
|
||||||
|
require(numberOfUnits > 0.0) { "Number of units should be greater than zero" }
|
||||||
|
require((numberOfUnits * 1000).toInt() % 50 == 0) { "Number of units must be dividable by 0.05" }
|
||||||
|
this.numberOfUnits = (numberOfUnits * 100).toInt() / 100.0
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setDelayBetweenPulsesInEighthSeconds(delayBetweenPulsesInEighthSeconds: Byte): Builder {
|
||||||
|
this.delayBetweenPulsesInEighthSeconds = delayBetweenPulsesInEighthSeconds
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setProgramReminder(programReminder: ProgramReminder?): Builder {
|
||||||
|
this.programReminder = programReminder
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildCommand(): ProgramBolusCommand {
|
||||||
|
requireNotNull(numberOfUnits) { "numberOfUnits can not be null" }
|
||||||
|
requireNotNull(delayBetweenPulsesInEighthSeconds) { "delayBetweenPulsesInEighthSeconds can not be null" }
|
||||||
|
requireNotNull(programReminder) { "programReminder can not be null" }
|
||||||
|
val numberOfPulses = Math.round(numberOfUnits!! * 20).toShort()
|
||||||
|
val byte10And11 = (numberOfPulses * delayBetweenPulsesInEighthSeconds!!).toShort()
|
||||||
|
val interlockCommand = ProgramInsulinCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, nonce!!, listOf(BolusShortInsulinProgramElement(numberOfPulses)), calculateChecksum(0x01.toByte(), byte10And11, numberOfPulses),
|
||||||
|
0x01.toByte(), byte10And11, numberOfPulses, ProgramInsulinCommand.DeliveryType.BOLUS)
|
||||||
|
val delayUntilFirstTenthPulseInUsec = delayBetweenPulsesInEighthSeconds!! / 8 * 100000
|
||||||
|
return ProgramBolusCommand(interlockCommand, uniqueId!!, sequenceNumber!!, multiCommandFlag, programReminder!!, (numberOfPulses * 10).toShort(), delayUntilFirstTenthPulseInUsec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val LENGTH: Short = 15
|
||||||
|
private const val BODY_LENGTH: Byte = 13
|
||||||
|
private fun calculateChecksum(numberOfSlots: Byte, byte10And11: Short, numberOfPulses: Short): Short {
|
||||||
|
return MessageUtil.calculateChecksum(ByteBuffer.allocate(7) //
|
||||||
|
.put(numberOfSlots) //
|
||||||
|
.putShort(byte10And11) //
|
||||||
|
.putShort(numberOfPulses) //
|
||||||
|
.putShort(numberOfPulses) //
|
||||||
|
.array())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,96 +0,0 @@
|
||||||
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.NonceEnabledCommand;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.ShortInsulinProgramElement;
|
|
||||||
|
|
||||||
// Always followed by one of: 0x13, 0x16, 0x17
|
|
||||||
final class ProgramInsulinCommand extends NonceEnabledCommand {
|
|
||||||
private final List<ShortInsulinProgramElement> insulinProgramElements;
|
|
||||||
private final short checksum;
|
|
||||||
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<ShortInsulinProgramElement> 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.checksum = checksum;
|
|
||||||
this.byte9 = byte9;
|
|
||||||
this.byte10And11 = byte10And11;
|
|
||||||
this.byte12And13 = byte12And13;
|
|
||||||
this.deliveryType = deliveryType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getLength() {
|
|
||||||
return (short) (insulinProgramElements.size() * 2 + 14);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getBodyLength() {
|
|
||||||
return (byte) (insulinProgramElements.size() * 2 + 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public byte[] getEncoded() {
|
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(this.getLength()) //
|
|
||||||
.put(commandType.getValue()) //
|
|
||||||
.put(getBodyLength()) //
|
|
||||||
.putInt(nonce) //
|
|
||||||
.put(deliveryType.getValue()) //
|
|
||||||
.putShort(checksum) //
|
|
||||||
.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());
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer.array();
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public short calculateChecksum(byte[] bytes) {
|
|
||||||
short sum = 0;
|
|
||||||
for (byte b : bytes) {
|
|
||||||
sum += (short) (b & 0xff);
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String toString() {
|
|
||||||
return "ProgramInsulinCommand{" +
|
|
||||||
"insulinProgramElements=" + insulinProgramElements +
|
|
||||||
", checksum=" + checksum +
|
|
||||||
", byte9=" + byte9 +
|
|
||||||
", byte10And11=" + byte10And11 +
|
|
||||||
", byte12And13=" + byte12And13 +
|
|
||||||
", deliveryType=" + deliveryType +
|
|
||||||
", nonce=" + nonce +
|
|
||||||
", commandType=" + commandType +
|
|
||||||
", uniqueId=" + uniqueId +
|
|
||||||
", sequenceNumber=" + sequenceNumber +
|
|
||||||
", multiCommandFlag=" + multiCommandFlag +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.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.insulin.program.ShortInsulinProgramElement
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
// Always followed by one of: 0x13, 0x16, 0x17
|
||||||
|
class ProgramInsulinCommand(uniqueId: Int, sequenceNumber: Short, multiCommandFlag: Boolean, nonce: Int, insulinProgramElements: List<ShortInsulinProgramElement>, private val checksum: Short, private val byte9: Byte, private val byte10And11: Short, private val byte12And13: Short, private val deliveryType: DeliveryType) : NonceEnabledCommand(CommandType.PROGRAM_INSULIN, uniqueId, sequenceNumber, multiCommandFlag, nonce) {
|
||||||
|
|
||||||
|
private val insulinProgramElements: List<ShortInsulinProgramElement> = ArrayList(insulinProgramElements)
|
||||||
|
|
||||||
|
fun getLength(): Short = (insulinProgramElements.size * 2 + 14).toShort()
|
||||||
|
|
||||||
|
fun getBodyLength(): Byte = (insulinProgramElements.size * 2 + 12).toByte()
|
||||||
|
|
||||||
|
enum class DeliveryType(private val value: Byte) {
|
||||||
|
BASAL(0x00.toByte()), TEMP_BASAL(0x01.toByte()), BOLUS(0x02.toByte());
|
||||||
|
|
||||||
|
fun getValue(): Byte {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun calculateChecksum(bytes: ByteArray): Short {
|
||||||
|
var sum: Short = 0
|
||||||
|
for (b in bytes) {
|
||||||
|
sum = ((b.toInt() and 0xff) + sum).toShort() // TODO Adrian: int conversion ok?
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
|
||||||
|
override val encoded: ByteArray
|
||||||
|
get() {
|
||||||
|
val buffer = ByteBuffer.allocate(getLength().toInt()) //
|
||||||
|
.put(commandType.value) //
|
||||||
|
.put(getBodyLength()) //
|
||||||
|
.putInt(nonce) //
|
||||||
|
.put(deliveryType.getValue()) //
|
||||||
|
.putShort(checksum) //
|
||||||
|
.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 (element in insulinProgramElements) {
|
||||||
|
buffer.put(element.encoded)
|
||||||
|
}
|
||||||
|
return buffer.array()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "ProgramInsulinCommand{" +
|
||||||
|
"insulinProgramElements=" + insulinProgramElements +
|
||||||
|
", checksum=" + checksum +
|
||||||
|
", byte9=" + byte9 +
|
||||||
|
", byte10And11=" + byte10And11 +
|
||||||
|
", byte12And13=" + byte12And13 +
|
||||||
|
", deliveryType=" + deliveryType +
|
||||||
|
", nonce=" + nonce +
|
||||||
|
", commandType=" + commandType +
|
||||||
|
", uniqueId=" + uniqueId +
|
||||||
|
", sequenceNumber=" + sequenceNumber +
|
||||||
|
", multiCommandFlag=" + multiCommandFlag +
|
||||||
|
'}'
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,123 +0,0 @@
|
||||||
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<BasalInsulinProgramElement> insulinProgramElements;
|
|
||||||
|
|
||||||
protected ProgramTempBasalCommand(ProgramInsulinCommand interlockCommand, int uniqueId, short sequenceNumber, boolean multiCommandFlag,
|
|
||||||
ProgramReminder programReminder, List<BasalInsulinProgramElement> insulinProgramElements) {
|
|
||||||
super(CommandType.PROGRAM_TEMP_BASAL, uniqueId, sequenceNumber, multiCommandFlag);
|
|
||||||
this.interlockCommand = interlockCommand;
|
|
||||||
this.programReminder = programReminder;
|
|
||||||
this.insulinProgramElements = new ArrayList<>(insulinProgramElements);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getBodyLength() {
|
|
||||||
return (byte) (insulinProgramElements.size() * 6 + 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getLength() {
|
|
||||||
return (short) (getBodyLength() + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public byte[] getEncoded() {
|
|
||||||
BasalInsulinProgramElement firstProgramElement = insulinProgramElements.get(0);
|
|
||||||
|
|
||||||
short remainingTenthPulsesInFirstElement;
|
|
||||||
int delayUntilNextTenthPulseInUsec;
|
|
||||||
|
|
||||||
if (firstProgramElement.getTotalTenthPulses() == 0) {
|
|
||||||
remainingTenthPulsesInFirstElement = firstProgramElement.getNumberOfSlots();
|
|
||||||
delayUntilNextTenthPulseInUsec = ProgramBasalUtil.MAX_DELAY_BETWEEN_TENTH_PULSES_IN_USEC_AND_USECS_IN_BASAL_SLOT;
|
|
||||||
} else {
|
|
||||||
remainingTenthPulsesInFirstElement = firstProgramElement.getTotalTenthPulses();
|
|
||||||
delayUntilNextTenthPulseInUsec = (int) ((long) 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<Builder, ProgramTempBasalCommand> {
|
|
||||||
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);
|
|
||||||
|
|
||||||
List<ShortInsulinProgramElement> shortInsulinProgramElements = ProgramTempBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot);
|
|
||||||
List<BasalInsulinProgramElement> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.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.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.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
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
// NOT SUPPORTED: percentage temp basal
|
||||||
|
class ProgramTempBasalCommand protected constructor(private val interlockCommand: ProgramInsulinCommand, uniqueId: Int, sequenceNumber: Short, multiCommandFlag: Boolean,
|
||||||
|
private val programReminder: ProgramReminder, insulinProgramElements: List<BasalInsulinProgramElement>) : HeaderEnabledCommand(CommandType.PROGRAM_TEMP_BASAL, uniqueId, sequenceNumber, multiCommandFlag) {
|
||||||
|
|
||||||
|
private val insulinProgramElements: List<BasalInsulinProgramElement>
|
||||||
|
fun getBodyLength(): Byte = (insulinProgramElements.size * 6 + 8).toByte()
|
||||||
|
|
||||||
|
fun getLength(): Short = (getBodyLength() + 2).toShort()
|
||||||
|
|
||||||
|
class Builder : NonceEnabledCommandBuilder<Builder, ProgramTempBasalCommand>() {
|
||||||
|
|
||||||
|
private var programReminder: ProgramReminder? = null
|
||||||
|
private var rateInUnitsPerHour: Double? = null
|
||||||
|
private var durationInMinutes: Short? = null
|
||||||
|
fun setProgramReminder(programReminder: ProgramReminder?): Builder {
|
||||||
|
this.programReminder = programReminder
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setRateInUnitsPerHour(rateInUnitsPerHour: Double): Builder {
|
||||||
|
this.rateInUnitsPerHour = rateInUnitsPerHour
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setDurationInMinutes(durationInMinutes: Short): Builder {
|
||||||
|
require(durationInMinutes % 30 == 0) { "durationInMinutes must be dividable by 30" }
|
||||||
|
this.durationInMinutes = durationInMinutes
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildCommand(): ProgramTempBasalCommand {
|
||||||
|
requireNotNull(programReminder) { "programReminder can not be null" }
|
||||||
|
requireNotNull(rateInUnitsPerHour) { "rateInUnitsPerHour can not be null" }
|
||||||
|
requireNotNull(durationInMinutes) { "durationInMinutes can not be null" }
|
||||||
|
val durationInSlots = (durationInMinutes!! / 30).toByte()
|
||||||
|
val pulsesPerSlot = ProgramTempBasalUtil.mapTempBasalToPulsesPerSlot(durationInSlots, rateInUnitsPerHour!!)
|
||||||
|
val tenthPulsesPerSlot = ProgramTempBasalUtil.mapTempBasalToTenthPulsesPerSlot(durationInSlots.toInt(), rateInUnitsPerHour!!)
|
||||||
|
val shortInsulinProgramElements = ProgramTempBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot)
|
||||||
|
val insulinProgramElements = ProgramTempBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot)
|
||||||
|
val interlockCommand = ProgramInsulinCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, nonce!!, shortInsulinProgramElements,
|
||||||
|
ProgramTempBasalUtil.calculateChecksum(durationInSlots, pulsesPerSlot!![0], pulsesPerSlot), durationInSlots,
|
||||||
|
0x3840.toShort(), pulsesPerSlot[0], ProgramInsulinCommand.DeliveryType.TEMP_BASAL)
|
||||||
|
return ProgramTempBasalCommand(interlockCommand, uniqueId!!, sequenceNumber!!, multiCommandFlag, programReminder!!, insulinProgramElements)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
this.insulinProgramElements = ArrayList(insulinProgramElements)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val encoded: ByteArray
|
||||||
|
get() {
|
||||||
|
val firstProgramElement = insulinProgramElements[0]
|
||||||
|
val remainingTenthPulsesInFirstElement: Short
|
||||||
|
val delayUntilNextTenthPulseInUsec: Int
|
||||||
|
if (firstProgramElement.totalTenthPulses.toInt() == 0) {
|
||||||
|
remainingTenthPulsesInFirstElement = firstProgramElement.numberOfSlots.toShort()
|
||||||
|
delayUntilNextTenthPulseInUsec = ProgramBasalUtil.MAX_DELAY_BETWEEN_TENTH_PULSES_IN_USEC_AND_USECS_IN_BASAL_SLOT
|
||||||
|
} else {
|
||||||
|
remainingTenthPulsesInFirstElement = firstProgramElement.totalTenthPulses
|
||||||
|
delayUntilNextTenthPulseInUsec = (firstProgramElement.numberOfSlots.toLong() * 1800.0 / remainingTenthPulsesInFirstElement * 1000000).toInt()
|
||||||
|
}
|
||||||
|
val buffer = ByteBuffer.allocate(getLength().toInt()) //
|
||||||
|
.put(commandType.value) //
|
||||||
|
.put(getBodyLength()) //
|
||||||
|
.put(programReminder.encoded) //
|
||||||
|
.put(0x00.toByte()) // Current slot index
|
||||||
|
.putShort(remainingTenthPulsesInFirstElement) //
|
||||||
|
.putInt(delayUntilNextTenthPulseInUsec)
|
||||||
|
for (element in insulinProgramElements) {
|
||||||
|
buffer.put(element.encoded)
|
||||||
|
}
|
||||||
|
val tempBasalCommand = buffer.array()
|
||||||
|
val interlockCommand = interlockCommand.encoded
|
||||||
|
val header: ByteArray = HeaderEnabledCommand.Companion.encodeHeader(uniqueId, sequenceNumber, (tempBasalCommand.size + interlockCommand!!.size).toShort(), multiCommandFlag)
|
||||||
|
return HeaderEnabledCommand.Companion.appendCrc(ByteBuffer.allocate(header.size + interlockCommand.size + tempBasalCommand.size) //
|
||||||
|
.put(header) //
|
||||||
|
.put(interlockCommand) //
|
||||||
|
.put(tempBasalCommand) //
|
||||||
|
.array())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,99 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.Calendar;
|
|
||||||
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_UNIQUE_ID = -1;
|
|
||||||
private static final short LENGTH = 21;
|
|
||||||
private static final byte BODY_LENGTH = 19;
|
|
||||||
|
|
||||||
private final int lotNumber;
|
|
||||||
private final int podSequenceNumber;
|
|
||||||
private final Date initializationTime;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public byte[] getEncoded() {
|
|
||||||
return appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) //
|
|
||||||
.put(encodeHeader(DEFAULT_UNIQUE_ID, sequenceNumber, LENGTH, multiCommandFlag)) //
|
|
||||||
.put(commandType.getValue()) //
|
|
||||||
.put(BODY_LENGTH) //
|
|
||||||
.putInt(uniqueId) //
|
|
||||||
.put((byte) 0x14) // FIXME ??
|
|
||||||
.put((byte) 0x04) // FIXME ??
|
|
||||||
.put(encodeInitializationTime(initializationTime)) //
|
|
||||||
.putInt(lotNumber) //
|
|
||||||
.putInt(podSequenceNumber) //
|
|
||||||
.array());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] encodeInitializationTime(Date date) {
|
|
||||||
Calendar instance = Calendar.getInstance();
|
|
||||||
instance.setTime(date);
|
|
||||||
|
|
||||||
return new byte[]{ //
|
|
||||||
(byte) (instance.get(Calendar.MONTH) + 1), //
|
|
||||||
(byte) instance.get(Calendar.DATE), //
|
|
||||||
(byte) (instance.get(Calendar.YEAR) % 100), //
|
|
||||||
(byte) instance.get(Calendar.HOUR_OF_DAY), //
|
|
||||||
(byte) instance.get(Calendar.MINUTE) //
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String toString() {
|
|
||||||
return "SetUniqueIdCommand{" +
|
|
||||||
"lotNumber=" + lotNumber +
|
|
||||||
", podSequenceNumber=" + podSequenceNumber +
|
|
||||||
", initializationTime=" + initializationTime +
|
|
||||||
", commandType=" + commandType +
|
|
||||||
", uniqueId=" + uniqueId +
|
|
||||||
", sequenceNumber=" + sequenceNumber +
|
|
||||||
", multiCommandFlag=" + multiCommandFlag +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class Builder extends HeaderEnabledCommandBuilder<Builder, SetUniqueIdCommand> {
|
|
||||||
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 protected 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(uniqueId, sequenceNumber, multiCommandFlag, lotNumber, podSequenceNumber, initializationTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.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.command.base.builder.HeaderEnabledCommandBuilder
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class SetUniqueIdCommand internal constructor(uniqueId: Int, sequenceNumber: Short, multiCommandFlag: Boolean, private val lotNumber: Int, private val podSequenceNumber: Int, private val initializationTime: Date) : HeaderEnabledCommand(CommandType.SET_UNIQUE_ID, uniqueId, sequenceNumber, multiCommandFlag) {
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// FIXME ??
|
||||||
|
// FIXME ??
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
override val encoded: ByteArray
|
||||||
|
get() = HeaderEnabledCommand.Companion.appendCrc(ByteBuffer.allocate(LENGTH + HeaderEnabledCommand.Companion.HEADER_LENGTH) //
|
||||||
|
.put(HeaderEnabledCommand.Companion.encodeHeader(DEFAULT_UNIQUE_ID, sequenceNumber, LENGTH, multiCommandFlag)) //
|
||||||
|
.put(commandType.value) //
|
||||||
|
.put(BODY_LENGTH) //
|
||||||
|
.putInt(uniqueId) //
|
||||||
|
.put(0x14.toByte()) // FIXME ??
|
||||||
|
.put(0x04.toByte()) // FIXME ??
|
||||||
|
.put(encodeInitializationTime(initializationTime)) //
|
||||||
|
.putInt(lotNumber) //
|
||||||
|
.putInt(podSequenceNumber) //
|
||||||
|
.array())
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "SetUniqueIdCommand{" +
|
||||||
|
"lotNumber=" + lotNumber +
|
||||||
|
", podSequenceNumber=" + podSequenceNumber +
|
||||||
|
", initializationTime=" + initializationTime +
|
||||||
|
", commandType=" + commandType +
|
||||||
|
", uniqueId=" + uniqueId +
|
||||||
|
", sequenceNumber=" + sequenceNumber +
|
||||||
|
", multiCommandFlag=" + multiCommandFlag +
|
||||||
|
'}'
|
||||||
|
}
|
||||||
|
|
||||||
|
class Builder : HeaderEnabledCommandBuilder<Builder, SetUniqueIdCommand>() {
|
||||||
|
|
||||||
|
private var lotNumber: Int? = null
|
||||||
|
private var podSequenceNumber: Int? = null
|
||||||
|
private var initializationTime: Date? = null
|
||||||
|
fun setLotNumber(lotNumber: Int): Builder {
|
||||||
|
this.lotNumber = lotNumber
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setPodSequenceNumber(podSequenceNumber: Int): Builder {
|
||||||
|
this.podSequenceNumber = podSequenceNumber
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setInitializationTime(initializationTime: Date?): Builder {
|
||||||
|
this.initializationTime = initializationTime
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildCommand(): SetUniqueIdCommand {
|
||||||
|
requireNotNull(lotNumber) { "lotNumber can not be null" }
|
||||||
|
requireNotNull(podSequenceNumber) { "podSequenceNumber can not be null" }
|
||||||
|
requireNotNull(initializationTime) { "initializationTime can not be null" }
|
||||||
|
return SetUniqueIdCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, lotNumber!!, podSequenceNumber!!, initializationTime!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val DEFAULT_UNIQUE_ID = -1
|
||||||
|
private const val LENGTH: Short = 21
|
||||||
|
private const val BODY_LENGTH: Byte = 19
|
||||||
|
private fun encodeInitializationTime(date: Date): ByteArray {
|
||||||
|
val instance = Calendar.getInstance()
|
||||||
|
instance.time = date
|
||||||
|
return byteArrayOf( //
|
||||||
|
(instance[Calendar.MONTH] + 1).toByte(), //
|
||||||
|
instance[Calendar.DATE].toByte(), //
|
||||||
|
(instance[Calendar.YEAR] % 100).toByte(), //
|
||||||
|
instance[Calendar.HOUR_OF_DAY].toByte(), //
|
||||||
|
instance[Calendar.MINUTE].toByte() //
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,133 +0,0 @@
|
||||||
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.command.base.builder.NonceEnabledCommandBuilder;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
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(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
|
|
||||||
.put(commandType.getValue()) //
|
|
||||||
.put(BODY_LENGTH) //
|
|
||||||
.putInt(nonce) //
|
|
||||||
.put(parameters.getEncoded()) //
|
|
||||||
.array());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String toString() {
|
|
||||||
return "SilenceAlertsCommand{" +
|
|
||||||
"parameters=" + parameters +
|
|
||||||
", nonce=" + nonce +
|
|
||||||
", commandType=" + commandType +
|
|
||||||
", uniqueId=" + uniqueId +
|
|
||||||
", sequenceNumber=" + sequenceNumber +
|
|
||||||
", multiCommandFlag=" + multiCommandFlag +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class SilenceAlertCommandParameters implements Encodable {
|
|
||||||
private final boolean silenceAutoOffAlert;
|
|
||||||
private final boolean silenceMultiCommandAlert;
|
|
||||||
private final boolean silenceExpirationImminentAlert;
|
|
||||||
private final boolean silenceUserSetExpirationAlert;
|
|
||||||
private final boolean silenceLowReservoirAlert;
|
|
||||||
private final boolean silenceSuspendInProgressAlert;
|
|
||||||
private final boolean silenceSuspendEndedAlert;
|
|
||||||
private final 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;
|
|
||||||
this.silenceUserSetExpirationAlert = silenceUserSetExpirationAlert;
|
|
||||||
this.silenceLowReservoirAlert = silenceLowReservoirAlert;
|
|
||||||
this.silenceSuspendInProgressAlert = silenceSuspendInProgressAlert;
|
|
||||||
this.silenceSuspendEndedAlert = silenceSuspendEndedAlert;
|
|
||||||
this.silencePodExpirationAlert = silencePodExpirationAlert;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] getEncoded() {
|
|
||||||
BitSet bitSet = new BitSet(8);
|
|
||||||
bitSet.set(0, this.silenceAutoOffAlert);
|
|
||||||
bitSet.set(1, this.silenceMultiCommandAlert);
|
|
||||||
bitSet.set(2, this.silenceExpirationImminentAlert);
|
|
||||||
bitSet.set(3, this.silenceUserSetExpirationAlert);
|
|
||||||
bitSet.set(4, this.silenceLowReservoirAlert);
|
|
||||||
bitSet.set(5, this.silenceSuspendInProgressAlert);
|
|
||||||
bitSet.set(6, this.silenceSuspendEndedAlert);
|
|
||||||
bitSet.set(7, this.silencePodExpirationAlert);
|
|
||||||
return bitSet.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Builder extends NonceEnabledCommandBuilder<Builder, SilenceAlertsCommand> {
|
|
||||||
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 protected final SilenceAlertsCommand buildCommand() {
|
|
||||||
return new SilenceAlertsCommand(uniqueId, sequenceNumber, multiCommandFlag, new SilenceAlertCommandParameters(silenceAutoOffAlert, silenceMultiCommandAlert, silenceExpirationImminentAlert, silenceUserSetExpirationAlert, silenceLowReservoirAlert, silenceSuspendInProgressAlert, silenceSuspendEndedAlert, silencePodExpirationAlert), nonce);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.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.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 java.nio.ByteBuffer
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class SilenceAlertsCommand internal constructor(uniqueId: Int, sequenceNumber: Short, multiCommandFlag: Boolean, private val parameters: SilenceAlertCommandParameters, nonce: Int) : NonceEnabledCommand(CommandType.SILENCE_ALERTS, uniqueId, sequenceNumber, multiCommandFlag, nonce) {
|
||||||
|
|
||||||
|
override val encoded: ByteArray
|
||||||
|
get() =
|
||||||
|
HeaderEnabledCommand.Companion.appendCrc(ByteBuffer.allocate(LENGTH + HeaderEnabledCommand.Companion.HEADER_LENGTH) //
|
||||||
|
.put(HeaderEnabledCommand.Companion.encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
|
||||||
|
.put(commandType.value) //
|
||||||
|
.put(BODY_LENGTH) //
|
||||||
|
.putInt(nonce) //
|
||||||
|
.put(parameters.encoded) //
|
||||||
|
.array())
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "SilenceAlertsCommand{" +
|
||||||
|
"parameters=" + parameters +
|
||||||
|
", nonce=" + nonce +
|
||||||
|
", commandType=" + commandType +
|
||||||
|
", uniqueId=" + uniqueId +
|
||||||
|
", sequenceNumber=" + sequenceNumber +
|
||||||
|
", multiCommandFlag=" + multiCommandFlag +
|
||||||
|
'}'
|
||||||
|
}
|
||||||
|
|
||||||
|
class SilenceAlertCommandParameters(private val silenceAutoOffAlert: Boolean, private val silenceMultiCommandAlert: Boolean, private val silenceExpirationImminentAlert: Boolean, private val silenceUserSetExpirationAlert: Boolean, private val silenceLowReservoirAlert: Boolean, private val silenceSuspendInProgressAlert: Boolean, private val silenceSuspendEndedAlert: Boolean, private val silencePodExpirationAlert: Boolean) : Encodable {
|
||||||
|
|
||||||
|
override val encoded: ByteArray
|
||||||
|
get() {
|
||||||
|
val bitSet = BitSet(8)
|
||||||
|
bitSet[0] = silenceAutoOffAlert
|
||||||
|
bitSet[1] = silenceMultiCommandAlert
|
||||||
|
bitSet[2] = silenceExpirationImminentAlert
|
||||||
|
bitSet[3] = silenceUserSetExpirationAlert
|
||||||
|
bitSet[4] = silenceLowReservoirAlert
|
||||||
|
bitSet[5] = silenceSuspendInProgressAlert
|
||||||
|
bitSet[6] = silenceSuspendEndedAlert
|
||||||
|
bitSet[7] = silencePodExpirationAlert
|
||||||
|
return bitSet.toByteArray()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Builder : NonceEnabledCommandBuilder<Builder, SilenceAlertsCommand>() {
|
||||||
|
|
||||||
|
private var silenceAutoOffAlert = false
|
||||||
|
private var silenceMultiCommandAlert = false
|
||||||
|
private var silenceExpirationImminentAlert = false
|
||||||
|
private var silenceUserSetExpirationAlert = false
|
||||||
|
private var silenceLowReservoirAlert = false
|
||||||
|
private var silenceSuspendInProgressAlert = false
|
||||||
|
private var silenceSuspendEndedAlert = false
|
||||||
|
private var silencePodExpirationAlert = false
|
||||||
|
fun setSilenceAutoOffAlert(silenceAutoOffAlert: Boolean): Builder {
|
||||||
|
this.silenceAutoOffAlert = silenceAutoOffAlert
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setSilenceMultiCommandAlert(silenceMultiCommandAlert: Boolean): Builder {
|
||||||
|
this.silenceMultiCommandAlert = silenceMultiCommandAlert
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setSilenceExpirationImminentAlert(silenceExpirationImminentAlert: Boolean): Builder {
|
||||||
|
this.silenceExpirationImminentAlert = silenceExpirationImminentAlert
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setSilenceUserSetExpirationAlert(silenceUserSetExpirationAlert: Boolean): Builder {
|
||||||
|
this.silenceUserSetExpirationAlert = silenceUserSetExpirationAlert
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setSilenceLowReservoirAlert(silenceLowReservoirAlert: Boolean): Builder {
|
||||||
|
this.silenceLowReservoirAlert = silenceLowReservoirAlert
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setSilenceSuspendInProgressAlert(silenceSuspendInProgressAlert: Boolean): Builder {
|
||||||
|
this.silenceSuspendInProgressAlert = silenceSuspendInProgressAlert
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setSilenceSuspendEndedAlert(silenceSuspendEndedAlert: Boolean): Builder {
|
||||||
|
this.silenceSuspendEndedAlert = silenceSuspendEndedAlert
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setSilencePodExpirationAlert(silencePodExpirationAlert: Boolean): Builder {
|
||||||
|
this.silencePodExpirationAlert = silencePodExpirationAlert
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildCommand(): SilenceAlertsCommand {
|
||||||
|
return SilenceAlertsCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, SilenceAlertCommandParameters(silenceAutoOffAlert, silenceMultiCommandAlert, silenceExpirationImminentAlert, silenceUserSetExpirationAlert, silenceLowReservoirAlert, silenceSuspendInProgressAlert, silenceSuspendEndedAlert, silencePodExpirationAlert), nonce!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val LENGTH = 7.toShort()
|
||||||
|
private const val BODY_LENGTH = 5.toByte()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,97 +0,0 @@
|
||||||
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.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;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
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(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
|
|
||||||
.put(commandType.getValue()) //
|
|
||||||
.put(BODY_LENGTH) //
|
|
||||||
.putInt(nonce) //
|
|
||||||
.put((byte) ((beepType.getValue() << 4) | deliveryType.getEncoded()[0])) //
|
|
||||||
.array());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String toString() {
|
|
||||||
return "StopDeliveryCommand{" +
|
|
||||||
"deliveryType=" + deliveryType +
|
|
||||||
", beepType=" + beepType +
|
|
||||||
", nonce=" + nonce +
|
|
||||||
", commandType=" + commandType +
|
|
||||||
", uniqueId=" + uniqueId +
|
|
||||||
", sequenceNumber=" + sequenceNumber +
|
|
||||||
", multiCommandFlag=" + multiCommandFlag +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum DeliveryType implements Encodable {
|
|
||||||
BASAL(true, false, false),
|
|
||||||
TEMP_BASAL(false, true, false),
|
|
||||||
BOLUS(false, false, true),
|
|
||||||
ALL(true, true, true);
|
|
||||||
|
|
||||||
private final boolean basal;
|
|
||||||
private final boolean tempBasal;
|
|
||||||
private final boolean bolus;
|
|
||||||
|
|
||||||
DeliveryType(boolean basal, boolean tempBasal, boolean bolus) {
|
|
||||||
this.basal = basal;
|
|
||||||
this.tempBasal = tempBasal;
|
|
||||||
this.bolus = bolus;
|
|
||||||
}
|
|
||||||
|
|
||||||
@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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class Builder extends NonceEnabledCommandBuilder<Builder, StopDeliveryCommand> {
|
|
||||||
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 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(uniqueId, sequenceNumber, multiCommandFlag, deliveryType, beepType, nonce);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.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.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
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class StopDeliveryCommand internal constructor(uniqueId: Int, sequenceNumber: Short, multiCommandFlag: Boolean, private val deliveryType: DeliveryType, private val beepType: BeepType, nonce: Int) : NonceEnabledCommand(CommandType.STOP_DELIVERY, uniqueId, sequenceNumber, multiCommandFlag, nonce) {
|
||||||
|
|
||||||
|
override val encoded: ByteArray
|
||||||
|
get() {
|
||||||
|
return HeaderEnabledCommand.Companion.appendCrc(ByteBuffer.allocate(LENGTH + HeaderEnabledCommand.Companion.HEADER_LENGTH) //
|
||||||
|
.put(HeaderEnabledCommand.Companion.encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
|
||||||
|
.put(commandType.value) //
|
||||||
|
.put(BODY_LENGTH) //
|
||||||
|
.putInt(nonce) //
|
||||||
|
.put((beepType.value.toInt() shl 4 or deliveryType.encoded[0].toInt()).toByte()) // TODO bitstuff
|
||||||
|
.array())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "StopDeliveryCommand{" +
|
||||||
|
"deliveryType=" + deliveryType +
|
||||||
|
", beepType=" + beepType +
|
||||||
|
", nonce=" + nonce +
|
||||||
|
", commandType=" + commandType +
|
||||||
|
", uniqueId=" + uniqueId +
|
||||||
|
", sequenceNumber=" + sequenceNumber +
|
||||||
|
", multiCommandFlag=" + multiCommandFlag +
|
||||||
|
'}'
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class DeliveryType(private val basal: Boolean, private val tempBasal: Boolean, private val bolus: Boolean) : Encodable {
|
||||||
|
BASAL(true, false, false), TEMP_BASAL(false, true, false), BOLUS(false, false, true), ALL(true, true, true);
|
||||||
|
|
||||||
|
override val encoded: ByteArray
|
||||||
|
get() {
|
||||||
|
val bitSet = BitSet(8)
|
||||||
|
bitSet[0] = basal
|
||||||
|
bitSet[1] = tempBasal
|
||||||
|
bitSet[2] = bolus
|
||||||
|
return bitSet.toByteArray()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Builder : NonceEnabledCommandBuilder<Builder, StopDeliveryCommand>() {
|
||||||
|
|
||||||
|
private var deliveryType: DeliveryType? = null
|
||||||
|
private var beepType: BeepType? = BeepType.LONG_SINGLE_BEEP
|
||||||
|
fun setDeliveryType(deliveryType: DeliveryType?): Builder {
|
||||||
|
this.deliveryType = deliveryType
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setBeepType(beepType: BeepType?): Builder {
|
||||||
|
this.beepType = beepType
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildCommand(): StopDeliveryCommand {
|
||||||
|
requireNotNull(deliveryType) { "deliveryType can not be null" }
|
||||||
|
requireNotNull(beepType) { "beepType can not be null" }
|
||||||
|
return StopDeliveryCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, deliveryType!!, beepType!!, nonce!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val LENGTH: Short = 7
|
||||||
|
private const val BODY_LENGTH: Byte = 5
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable;
|
|
||||||
|
|
||||||
public interface Command extends Encodable {
|
|
||||||
CommandType getCommandType();
|
|
||||||
}
|
|
|
@ -1,6 +1,8 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program;
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base
|
||||||
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable;
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable
|
||||||
|
|
||||||
public interface ShortInsulinProgramElement extends Encodable {
|
interface Command : Encodable {
|
||||||
|
|
||||||
|
val commandType: CommandType
|
||||||
}
|
}
|
|
@ -1,26 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base;
|
|
||||||
|
|
||||||
public enum CommandType {
|
|
||||||
SET_UNIQUE_ID((byte) 0x03),
|
|
||||||
GET_VERSION((byte) 0x07),
|
|
||||||
GET_STATUS((byte) 0x0e),
|
|
||||||
SILENCE_ALERTS((byte) 0x11),
|
|
||||||
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),
|
|
||||||
PROGRAM_INSULIN((byte) 0x1a), // Always followed by one of: 0x13, 0x16, 0x17
|
|
||||||
DEACTIVATE((byte) 0x1c),
|
|
||||||
PROGRAM_BEEPS((byte) 0x1e),
|
|
||||||
STOP_DELIVERY((byte) 0x1f);
|
|
||||||
|
|
||||||
byte value;
|
|
||||||
|
|
||||||
CommandType(byte value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base
|
||||||
|
|
||||||
|
enum class CommandType(var value: Byte) {
|
||||||
|
SET_UNIQUE_ID(0x03.toByte()),
|
||||||
|
GET_VERSION(0x07.toByte()),
|
||||||
|
GET_STATUS(0x0e.toByte()),
|
||||||
|
SILENCE_ALERTS(0x11.toByte()),
|
||||||
|
PROGRAM_BASAL(0x13.toByte()), // Always preceded by 0x1a
|
||||||
|
PROGRAM_TEMP_BASAL(0x16.toByte()), // Always preceded by 0x1a
|
||||||
|
PROGRAM_BOLUS(0x17.toByte()), // Always preceded by 0x1a
|
||||||
|
PROGRAM_ALERTS(0x19.toByte()),
|
||||||
|
PROGRAM_INSULIN(0x1a.toByte()), // Always followed by one of: 0x13, 0x16, 0x17
|
||||||
|
DEACTIVATE(0x1c.toByte()),
|
||||||
|
PROGRAM_BEEPS(0x1e.toByte()),
|
||||||
|
STOP_DELIVERY(0x1f.toByte());
|
||||||
|
}
|
|
@ -1,40 +0,0 @@
|
||||||
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.MessageUtil;
|
|
||||||
|
|
||||||
public abstract class HeaderEnabledCommand implements Command {
|
|
||||||
protected static final short HEADER_LENGTH = 6;
|
|
||||||
|
|
||||||
protected final CommandType commandType;
|
|
||||||
protected final int uniqueId;
|
|
||||||
protected final short sequenceNumber;
|
|
||||||
protected final boolean multiCommandFlag;
|
|
||||||
|
|
||||||
protected HeaderEnabledCommand(CommandType commandType, int uniqueId, short sequenceNumber, boolean multiCommandFlag) {
|
|
||||||
this.commandType = commandType;
|
|
||||||
this.uniqueId = uniqueId;
|
|
||||||
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(MessageUtil.createCrc(command)) //
|
|
||||||
.array();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static byte[] encodeHeader(int uniqueId, short sequenceNumber, short length, boolean multiCommandFlag) {
|
|
||||||
return ByteBuffer.allocate(6) //
|
|
||||||
.putInt(uniqueId) //
|
|
||||||
.putShort((short) (((sequenceNumber & 0x0f) << 10) | length | ((multiCommandFlag ? 1 : 0) << 15))) //
|
|
||||||
.array();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.MessageUtil
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
|
abstract class HeaderEnabledCommand protected constructor(
|
||||||
|
override val commandType: CommandType,
|
||||||
|
protected val uniqueId: Int,
|
||||||
|
protected val sequenceNumber: Short,
|
||||||
|
protected val multiCommandFlag: Boolean
|
||||||
|
) : Command {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
internal fun appendCrc(command: ByteArray): ByteArray =
|
||||||
|
ByteBuffer.allocate(command.size + 2) //
|
||||||
|
.put(command) //
|
||||||
|
.putShort(MessageUtil.createCrc(command)) //
|
||||||
|
.array()
|
||||||
|
|
||||||
|
internal fun encodeHeader(uniqueId: Int, sequenceNumber: Short, length: Short, multiCommandFlag: Boolean): ByteArray =
|
||||||
|
ByteBuffer.allocate(6) //
|
||||||
|
.putInt(uniqueId) //
|
||||||
|
.putShort((sequenceNumber.toInt() and 0x0f shl 10 or length.toInt() or ((if (multiCommandFlag) 1 else 0) shl 15)).toShort()) //
|
||||||
|
.array()
|
||||||
|
|
||||||
|
internal const val HEADER_LENGTH: Short = 6
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +0,0 @@
|
||||||
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 uniqueId, short sequenceNumber, boolean multiCommandFlag, int nonce) {
|
|
||||||
super(commandType, uniqueId, sequenceNumber, multiCommandFlag);
|
|
||||||
this.nonce = nonce;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base
|
||||||
|
|
||||||
|
abstract class NonceEnabledCommand protected constructor(
|
||||||
|
commandType: CommandType,
|
||||||
|
uniqueId: Int,
|
||||||
|
sequenceNumber: Short,
|
||||||
|
multiCommandFlag: Boolean,
|
||||||
|
protected val nonce: Int
|
||||||
|
) : HeaderEnabledCommand(commandType, uniqueId, sequenceNumber, multiCommandFlag)
|
|
@ -1,7 +1,8 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder;
|
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;
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command
|
||||||
|
|
||||||
public interface CommandBuilder<R extends Command> {
|
interface CommandBuilder<R : Command> {
|
||||||
R build();
|
|
||||||
|
fun build(): R
|
||||||
}
|
}
|
|
@ -1,36 +0,0 @@
|
||||||
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<T extends HeaderEnabledCommandBuilder<T, R>, R extends Command> implements CommandBuilder<R> {
|
|
||||||
protected Integer uniqueId;
|
|
||||||
protected Short sequenceNumber;
|
|
||||||
protected boolean multiCommandFlag = false;
|
|
||||||
|
|
||||||
public R build() {
|
|
||||||
if (uniqueId == null) {
|
|
||||||
throw new IllegalArgumentException("uniqueId can not be null");
|
|
||||||
}
|
|
||||||
if (sequenceNumber == null) {
|
|
||||||
throw new IllegalArgumentException("sequenceNumber can not be null");
|
|
||||||
}
|
|
||||||
return buildCommand();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final T setUniqueId(int uniqueId) {
|
|
||||||
this.uniqueId = uniqueId;
|
|
||||||
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();
|
|
||||||
}
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
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
|
||||||
|
|
||||||
|
abstract class HeaderEnabledCommandBuilder<T : HeaderEnabledCommandBuilder<T, R>, R : Command> : CommandBuilder<R> {
|
||||||
|
|
||||||
|
protected var uniqueId: Int? = null
|
||||||
|
protected var sequenceNumber: Short? = null
|
||||||
|
protected var multiCommandFlag = false
|
||||||
|
override fun build(): R {
|
||||||
|
requireNotNull(uniqueId) { "uniqueId can not be null" }
|
||||||
|
requireNotNull(sequenceNumber) { "sequenceNumber can not be null" }
|
||||||
|
return buildCommand()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setUniqueId(uniqueId: Int): T {
|
||||||
|
this.uniqueId = uniqueId
|
||||||
|
return this as T
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setSequenceNumber(sequenceNumber: Short): T {
|
||||||
|
this.sequenceNumber = sequenceNumber
|
||||||
|
return this as T
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setMultiCommandFlag(multiCommandFlag: Boolean): T {
|
||||||
|
this.multiCommandFlag = multiCommandFlag
|
||||||
|
return this as T
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun buildCommand(): R
|
||||||
|
}
|
|
@ -1,19 +0,0 @@
|
||||||
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<T extends NonceEnabledCommandBuilder<T, R>, R extends Command> extends HeaderEnabledCommandBuilder<T, R> {
|
|
||||||
protected Integer nonce;
|
|
||||||
|
|
||||||
public final R build() {
|
|
||||||
if (nonce == null) {
|
|
||||||
throw new IllegalArgumentException("nonce can not be null");
|
|
||||||
}
|
|
||||||
return super.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final T setNonce(int nonce) {
|
|
||||||
this.nonce = nonce;
|
|
||||||
return (T) this;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
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
|
||||||
|
|
||||||
|
abstract class NonceEnabledCommandBuilder<T : NonceEnabledCommandBuilder<T, R>, R : Command> : HeaderEnabledCommandBuilder<T, R>() {
|
||||||
|
|
||||||
|
protected var nonce: Int? = null
|
||||||
|
override fun build(): R {
|
||||||
|
requireNotNull(nonce) { "nonce can not be null" }
|
||||||
|
return super.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setNonce(nonce: Int): T {
|
||||||
|
this.nonce = nonce
|
||||||
|
return this as T
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,58 +0,0 @@
|
||||||
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;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
public BasalInsulinProgramElement(byte startSlotIndex, byte numberOfSlots, short totalTenthPulses) {
|
|
||||||
this.startSlotIndex = startSlotIndex;
|
|
||||||
this.numberOfSlots = numberOfSlots;
|
|
||||||
this.totalTenthPulses = totalTenthPulses;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public byte[] getEncoded() {
|
|
||||||
return ByteBuffer.allocate(6) //
|
|
||||||
.putShort(totalTenthPulses) //
|
|
||||||
.putInt(totalTenthPulses == 0 ? Integer.MIN_VALUE | getDelayBetweenTenthPulsesInUsec() : getDelayBetweenTenthPulsesInUsec()) //
|
|
||||||
.array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getStartSlotIndex() {
|
|
||||||
return startSlotIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getNumberOfSlots() {
|
|
||||||
return numberOfSlots;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getDurationInSeconds() {
|
|
||||||
return (short) (numberOfSlots * 1_800);
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getTotalTenthPulses() {
|
|
||||||
return totalTenthPulses;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getDelayBetweenTenthPulsesInUsec() {
|
|
||||||
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() {
|
|
||||||
return "LongInsulinProgramElement{" +
|
|
||||||
"startSlotIndex=" + startSlotIndex +
|
|
||||||
", numberOfSlots=" + numberOfSlots +
|
|
||||||
", totalTenthPulses=" + totalTenthPulses +
|
|
||||||
", delayBetweenTenthPulsesInUsec=" + getDelayBetweenTenthPulsesInUsec() +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program
|
||||||
|
|
||||||
|
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.Encodable
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
|
open class BasalInsulinProgramElement(val startSlotIndex: Byte, val numberOfSlots: Byte, val totalTenthPulses: Short) : Encodable {
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
override val encoded: ByteArray
|
||||||
|
get() = ByteBuffer.allocate(6) //
|
||||||
|
.putShort(totalTenthPulses) //
|
||||||
|
.putInt(if (totalTenthPulses.toInt() == 0) Int.MIN_VALUE or delayBetweenTenthPulsesInUsec else delayBetweenTenthPulsesInUsec) //
|
||||||
|
.array()
|
||||||
|
val durationInSeconds: Short
|
||||||
|
get() = (numberOfSlots * 1800).toShort()
|
||||||
|
val delayBetweenTenthPulsesInUsec: Int
|
||||||
|
get() = if (totalTenthPulses.toInt() == 0) {
|
||||||
|
ProgramBasalUtil.MAX_DELAY_BETWEEN_TENTH_PULSES_IN_USEC_AND_USECS_IN_BASAL_SLOT
|
||||||
|
} else (ProgramBasalUtil.MAX_DELAY_BETWEEN_TENTH_PULSES_IN_USEC_AND_USECS_IN_BASAL_SLOT.toLong() * numberOfSlots / totalTenthPulses.toDouble()).toInt()
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "LongInsulinProgramElement{" +
|
||||||
|
"startSlotIndex=" + startSlotIndex +
|
||||||
|
", numberOfSlots=" + numberOfSlots +
|
||||||
|
", totalTenthPulses=" + totalTenthPulses +
|
||||||
|
", delayBetweenTenthPulsesInUsec=" + delayBetweenTenthPulsesInUsec +
|
||||||
|
'}'
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,34 +0,0 @@
|
||||||
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 +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import kotlin.experimental.and
|
||||||
|
|
||||||
|
class BasalShortInsulinProgramElement(// 4 bits
|
||||||
|
private val numberOfSlots: Byte, // 10 bits
|
||||||
|
private val pulsesPerSlot: Short, //
|
||||||
|
private val extraAlternatePulse: Boolean) : ShortInsulinProgramElement {
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
override val encoded: ByteArray
|
||||||
|
get() {
|
||||||
|
val firstByte = (numberOfSlots - 1 and 0x0f shl 4 //
|
||||||
|
or ((if (extraAlternatePulse) 1 else 0) shl 3) //
|
||||||
|
or (pulsesPerSlot.toInt() ushr 8 and 0x03)).toByte()
|
||||||
|
return ByteBuffer.allocate(2) //
|
||||||
|
.put(firstByte) //
|
||||||
|
.put((pulsesPerSlot and 0xff).toByte()) //
|
||||||
|
.array()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "ShortInsulinProgramElement{" +
|
||||||
|
"numberOfSlotsMinusOne=" + numberOfSlots +
|
||||||
|
", pulsesPerSlot=" + pulsesPerSlot +
|
||||||
|
", extraAlternatePulse=" + extraAlternatePulse +
|
||||||
|
'}'
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +0,0 @@
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
|
class BolusShortInsulinProgramElement(private val numberOfPulses: Short) : ShortInsulinProgramElement {
|
||||||
|
|
||||||
|
override val encoded: ByteArray
|
||||||
|
get() = ByteBuffer.allocate(2).putShort(numberOfPulses).array()
|
||||||
|
}
|
|
@ -1,33 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program;
|
|
||||||
|
|
||||||
public class CurrentBasalInsulinProgramElement {
|
|
||||||
private final byte index;
|
|
||||||
private final int delayUntilNextTenthPulseInUsec;
|
|
||||||
private final short remainingTenthPulses;
|
|
||||||
|
|
||||||
public CurrentBasalInsulinProgramElement(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 +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program
|
||||||
|
|
||||||
|
class CurrentBasalInsulinProgramElement(val index: Byte, val delayUntilNextTenthPulseInUsec: Int, val remainingTenthPulses: Short) {
|
||||||
|
|
||||||
|
override fun toString(): String = "CurrentLongInsulinProgramElement{" +
|
||||||
|
"index=" + index +
|
||||||
|
", delayUntilNextTenthPulseInUsec=" + delayUntilNextTenthPulseInUsec +
|
||||||
|
", remainingTenthPulses=" + remainingTenthPulses +
|
||||||
|
'}'
|
||||||
|
}
|
|
@ -1,33 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program;
|
|
||||||
|
|
||||||
public class CurrentSlot {
|
|
||||||
private final byte index;
|
|
||||||
private final short eighthSecondsRemaining;
|
|
||||||
private final short pulsesRemaining;
|
|
||||||
|
|
||||||
public CurrentSlot(byte index, short eighthSecondsRemaining, short pulsesRemaining) {
|
|
||||||
this.index = index;
|
|
||||||
this.eighthSecondsRemaining = eighthSecondsRemaining;
|
|
||||||
this.pulsesRemaining = pulsesRemaining;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getIndex() {
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getEighthSecondsRemaining() {
|
|
||||||
return eighthSecondsRemaining;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getPulsesRemaining() {
|
|
||||||
return pulsesRemaining;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String toString() {
|
|
||||||
return "CurrentSlot{" +
|
|
||||||
"index=" + index +
|
|
||||||
", eighthSecondsRemaining=" + eighthSecondsRemaining +
|
|
||||||
", pulsesRemaining=" + pulsesRemaining +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program
|
||||||
|
|
||||||
|
class CurrentSlot(val index: Byte, val eighthSecondsRemaining: Short, val pulsesRemaining: Short) {
|
||||||
|
|
||||||
|
override fun toString(): String = "CurrentSlot{" +
|
||||||
|
"index=" + index +
|
||||||
|
", eighthSecondsRemaining=" + eighthSecondsRemaining +
|
||||||
|
", pulsesRemaining=" + pulsesRemaining +
|
||||||
|
'}'
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
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
|
||||||
|
|
||||||
|
interface ShortInsulinProgramElement : Encodable
|
|
@ -1,23 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
public class TempBasalInsulinProgramElement extends BasalInsulinProgramElement {
|
|
||||||
public TempBasalInsulinProgramElement(byte startSlotIndex, byte numberOfSlots, short totalTenthPulses) {
|
|
||||||
super(startSlotIndex, numberOfSlots, totalTenthPulses);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public byte[] getEncoded() {
|
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(6);
|
|
||||||
if (getTotalTenthPulses() == 0) {
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
return buffer.array();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
|
class TempBasalInsulinProgramElement(startSlotIndex: Byte, numberOfSlots: Byte, totalTenthPulses: Short) : BasalInsulinProgramElement(startSlotIndex, numberOfSlots, totalTenthPulses) {
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
override val encoded: ByteArray
|
||||||
|
get() {
|
||||||
|
val buffer = ByteBuffer.allocate(6)
|
||||||
|
if (totalTenthPulses.toInt() == 0) {
|
||||||
|
val i = (durationInSeconds.toDouble() * 1000000.0 / numberOfSlots.toDouble()).toInt() or Int.MIN_VALUE
|
||||||
|
buffer.putShort(numberOfSlots.toShort()) //
|
||||||
|
.putInt(i)
|
||||||
|
} else {
|
||||||
|
buffer.putShort(totalTenthPulses) //
|
||||||
|
.putInt(delayBetweenTenthPulsesInUsec)
|
||||||
|
}
|
||||||
|
return buffer.array()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,257 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.util;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
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.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 {
|
|
||||||
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;
|
|
||||||
|
|
||||||
private ProgramBasalUtil() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface BasalInsulinProgramElementFactory<T extends BasalInsulinProgramElement> {
|
|
||||||
T create(byte startSlotIndex, byte numberOfSlots, short totalTenthPulses);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<BasalInsulinProgramElement> mapTenthPulsesPerSlotToLongInsulinProgramElements(short[] tenthPulsesPerSlot) {
|
|
||||||
return mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot, BasalInsulinProgramElement::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T extends BasalInsulinProgramElement> List<BasalInsulinProgramElement> mapTenthPulsesPerSlotToLongInsulinProgramElements(short[] tenthPulsesPerSlot, BasalInsulinProgramElementFactory<T> insulinProgramElementFactory) {
|
|
||||||
if (tenthPulsesPerSlot.length > NUMBER_OF_BASAL_SLOTS) {
|
|
||||||
throw new IllegalArgumentException("Basal program must contain at most 48 slots");
|
|
||||||
}
|
|
||||||
|
|
||||||
List<BasalInsulinProgramElement> elements = new ArrayList<>();
|
|
||||||
long previousTenthPulsesPerSlot = 0;
|
|
||||||
byte numberOfSlotsInCurrentElement = 0;
|
|
||||||
byte startSlotIndex = 0;
|
|
||||||
|
|
||||||
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(insulinProgramElementFactory.create(startSlotIndex, numberOfSlotsInCurrentElement, (short) (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement)));
|
|
||||||
|
|
||||||
previousTenthPulsesPerSlot = tenthPulsesPerSlot[i];
|
|
||||||
numberOfSlotsInCurrentElement = 1;
|
|
||||||
startSlotIndex += numberOfSlotsInCurrentElement;
|
|
||||||
} else {
|
|
||||||
numberOfSlotsInCurrentElement++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
elements.add(insulinProgramElementFactory.create(startSlotIndex, numberOfSlotsInCurrentElement, (short) (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement)));
|
|
||||||
|
|
||||||
return elements;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<ShortInsulinProgramElement> mapPulsesPerSlotToShortInsulinProgramElements(short[] pulsesPerSlot) {
|
|
||||||
if (pulsesPerSlot.length > NUMBER_OF_BASAL_SLOTS) {
|
|
||||||
throw new IllegalArgumentException("Basal program must contain at most 48 slots");
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ShortInsulinProgramElement> elements = new ArrayList<>();
|
|
||||||
boolean extraAlternatePulse = false;
|
|
||||||
short previousPulsesPerSlot = 0;
|
|
||||||
byte numberOfSlotsInCurrentElement = 0;
|
|
||||||
byte currentTotalNumberOfSlots = 0;
|
|
||||||
|
|
||||||
while (currentTotalNumberOfSlots < pulsesPerSlot.length) {
|
|
||||||
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_INSULIN_PROGRAM_ELEMENT) {
|
|
||||||
numberOfSlotsInCurrentElement++;
|
|
||||||
} else {
|
|
||||||
elements.add(new BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse));
|
|
||||||
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++;
|
|
||||||
numberOfSlotsInCurrentElement++;
|
|
||||||
extraAlternatePulse = true;
|
|
||||||
while (currentTotalNumberOfSlots < pulsesPerSlot.length) {
|
|
||||||
// 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_INSULIN_PROGRAM_ELEMENT) {
|
|
||||||
numberOfSlotsInCurrentElement++;
|
|
||||||
} else {
|
|
||||||
// End of alternate pulse segment (no slots left in element)
|
|
||||||
|
|
||||||
elements.add(new BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse));
|
|
||||||
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots];
|
|
||||||
numberOfSlotsInCurrentElement = 1;
|
|
||||||
extraAlternatePulse = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// End of alternate pulse segment (new number of pulses per slot)
|
|
||||||
|
|
||||||
elements.add(new BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse));
|
|
||||||
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 BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse));
|
|
||||||
|
|
||||||
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots];
|
|
||||||
currentTotalNumberOfSlots++;
|
|
||||||
extraAlternatePulse = false;
|
|
||||||
numberOfSlotsInCurrentElement = 1;
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Reached illegal point in mapBasalProgramToShortInsulinProgramElements");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
elements.add(new BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse));
|
|
||||||
|
|
||||||
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()) {
|
|
||||||
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);
|
|
||||||
int secondOfDay = secondOfMinute + hourOfDay * 3_600 + minuteOfHour * 60;
|
|
||||||
|
|
||||||
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 CurrentBasalInsulinProgramElement calculateCurrentLongInsulinProgramElement(List<BasalInsulinProgramElement> 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 (BasalInsulinProgramElement 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 = (long) ((durationInSeconds - secondsPassedInCurrentSlot) / (double) durationInSeconds * 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) ((remainingTenThousandthPulses % 1_000 != 0 ? 1 : 0) + remainingTenThousandthPulses / 1_000);
|
|
||||||
|
|
||||||
return new CurrentBasalInsulinProgramElement(index, delayUntilNextTenthPulseInUsec, remainingTenthPulses);
|
|
||||||
}
|
|
||||||
|
|
||||||
index++;
|
|
||||||
startSlotIndex += element.getNumberOfSlots();
|
|
||||||
}
|
|
||||||
throw new IllegalStateException("Could not determine current long insulin program element");
|
|
||||||
}
|
|
||||||
|
|
||||||
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()) //
|
|
||||||
.putShort(currentSlot.getEighthSecondsRemaining());
|
|
||||||
|
|
||||||
for (short pulses : pulsesPerSlot) {
|
|
||||||
buffer.putShort(pulses);
|
|
||||||
}
|
|
||||||
|
|
||||||
return MessageUtil.calculateChecksum(buffer.array());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,208 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.util
|
||||||
|
|
||||||
|
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
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
object ProgramBasalUtil {
|
||||||
|
|
||||||
|
const val MAX_DELAY_BETWEEN_TENTH_PULSES_IN_USEC_AND_USECS_IN_BASAL_SLOT = 1800000000
|
||||||
|
private const val NUMBER_OF_BASAL_SLOTS: Byte = 48
|
||||||
|
private const val MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT: Byte = 16
|
||||||
|
|
||||||
|
fun mapTenthPulsesPerSlotToLongInsulinProgramElements(
|
||||||
|
tenthPulsesPerSlot: ShortArray?,
|
||||||
|
insulinProgramElementFactory: (Byte, Byte, Short) -> BasalInsulinProgramElement = ::BasalInsulinProgramElement
|
||||||
|
): List<BasalInsulinProgramElement> {
|
||||||
|
require(tenthPulsesPerSlot!!.size <= NUMBER_OF_BASAL_SLOTS) { "Basal program must contain at most 48 slots" }
|
||||||
|
val elements: MutableList<BasalInsulinProgramElement> = ArrayList()
|
||||||
|
var previousTenthPulsesPerSlot: Short = 0
|
||||||
|
var numberOfSlotsInCurrentElement: Byte = 0
|
||||||
|
var startSlotIndex: Byte = 0
|
||||||
|
for (i in tenthPulsesPerSlot.indices) {
|
||||||
|
if (i == 0) {
|
||||||
|
previousTenthPulsesPerSlot = tenthPulsesPerSlot[i]
|
||||||
|
numberOfSlotsInCurrentElement = 1
|
||||||
|
} else if (previousTenthPulsesPerSlot != tenthPulsesPerSlot[i] || (numberOfSlotsInCurrentElement + 1) * previousTenthPulsesPerSlot > 65534) {
|
||||||
|
elements.add(insulinProgramElementFactory(startSlotIndex, numberOfSlotsInCurrentElement, (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement).toShort()))
|
||||||
|
previousTenthPulsesPerSlot = tenthPulsesPerSlot[i]
|
||||||
|
numberOfSlotsInCurrentElement = 1
|
||||||
|
startSlotIndex = (numberOfSlotsInCurrentElement + startSlotIndex).toByte()
|
||||||
|
} else {
|
||||||
|
numberOfSlotsInCurrentElement++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elements.add(insulinProgramElementFactory(startSlotIndex, numberOfSlotsInCurrentElement, (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement).toShort()))
|
||||||
|
return elements
|
||||||
|
}
|
||||||
|
|
||||||
|
fun mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot: ShortArray?): List<ShortInsulinProgramElement> {
|
||||||
|
require(pulsesPerSlot!!.size <= NUMBER_OF_BASAL_SLOTS) { "Basal program must contain at most 48 slots" }
|
||||||
|
val elements: MutableList<ShortInsulinProgramElement> = ArrayList()
|
||||||
|
var extraAlternatePulse = false
|
||||||
|
var previousPulsesPerSlot: Short = 0
|
||||||
|
var numberOfSlotsInCurrentElement: Byte = 0
|
||||||
|
var currentTotalNumberOfSlots: Byte = 0
|
||||||
|
while (currentTotalNumberOfSlots < pulsesPerSlot.size) {
|
||||||
|
if (currentTotalNumberOfSlots.toInt() == 0) {
|
||||||
|
// First slot
|
||||||
|
previousPulsesPerSlot = pulsesPerSlot[0]
|
||||||
|
currentTotalNumberOfSlots++
|
||||||
|
numberOfSlotsInCurrentElement = 1
|
||||||
|
} else if (pulsesPerSlot[currentTotalNumberOfSlots.toInt()] == previousPulsesPerSlot) {
|
||||||
|
// Subsequent slot in element (same pulses per slot as previous slot)
|
||||||
|
if (numberOfSlotsInCurrentElement < MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT) {
|
||||||
|
numberOfSlotsInCurrentElement++
|
||||||
|
} else {
|
||||||
|
elements.add(BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse))
|
||||||
|
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots.toInt()]
|
||||||
|
numberOfSlotsInCurrentElement = 1
|
||||||
|
extraAlternatePulse = false
|
||||||
|
}
|
||||||
|
currentTotalNumberOfSlots++
|
||||||
|
} else if (numberOfSlotsInCurrentElement.toInt() == 1 && pulsesPerSlot[currentTotalNumberOfSlots.toInt()].toInt() == previousPulsesPerSlot + 1) {
|
||||||
|
// Second slot of segment with extra alternate pulse
|
||||||
|
var expectAlternatePulseForNextSegment = false
|
||||||
|
currentTotalNumberOfSlots++
|
||||||
|
numberOfSlotsInCurrentElement++
|
||||||
|
extraAlternatePulse = true
|
||||||
|
while (currentTotalNumberOfSlots < pulsesPerSlot.size) {
|
||||||
|
// Loop rest alternate pulse segment
|
||||||
|
if (pulsesPerSlot[currentTotalNumberOfSlots.toInt()].toInt() == previousPulsesPerSlot + (if (expectAlternatePulseForNextSegment) 1 else 0)) {
|
||||||
|
// Still in alternate pulse segment
|
||||||
|
currentTotalNumberOfSlots++
|
||||||
|
expectAlternatePulseForNextSegment = !expectAlternatePulseForNextSegment
|
||||||
|
if (numberOfSlotsInCurrentElement < MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT) {
|
||||||
|
numberOfSlotsInCurrentElement++
|
||||||
|
} else {
|
||||||
|
// End of alternate pulse segment (no slots left in element)
|
||||||
|
elements.add(BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse))
|
||||||
|
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots.toInt()]
|
||||||
|
numberOfSlotsInCurrentElement = 1
|
||||||
|
extraAlternatePulse = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// End of alternate pulse segment (new number of pulses per slot)
|
||||||
|
elements.add(BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse))
|
||||||
|
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots.toInt()]
|
||||||
|
numberOfSlotsInCurrentElement = 1
|
||||||
|
extraAlternatePulse = false
|
||||||
|
currentTotalNumberOfSlots++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (previousPulsesPerSlot != pulsesPerSlot[currentTotalNumberOfSlots.toInt()]) {
|
||||||
|
// End of segment (new number of pulses per slot)
|
||||||
|
elements.add(BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse))
|
||||||
|
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots.toInt()]
|
||||||
|
currentTotalNumberOfSlots++
|
||||||
|
extraAlternatePulse = false
|
||||||
|
numberOfSlotsInCurrentElement = 1
|
||||||
|
} else {
|
||||||
|
throw IllegalStateException("Reached illegal point in mapBasalProgramToShortInsulinProgramElements")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elements.add(BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse))
|
||||||
|
return elements
|
||||||
|
}
|
||||||
|
|
||||||
|
fun mapBasalProgramToTenthPulsesPerSlot(basalProgram: BasalProgram): ShortArray {
|
||||||
|
val tenthPulsesPerSlot = ShortArray(NUMBER_OF_BASAL_SLOTS.toInt())
|
||||||
|
for (segment in basalProgram.segments) {
|
||||||
|
for (i in segment.startSlotIndex until segment.endSlotIndex) {
|
||||||
|
tenthPulsesPerSlot[i] = (roundToHalf(segment.getPulsesPerHour() / 2.0) * 10).toInt().toShort() // TODO Adrian: int conversion ok?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tenthPulsesPerSlot
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun roundToHalf(d: Double): Double {
|
||||||
|
return ((d * 10.0).toInt().toShort() / 5 * 5).toShort().toDouble() / 10.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fun mapBasalProgramToPulsesPerSlot(basalProgram: BasalProgram): ShortArray {
|
||||||
|
val pulsesPerSlot = ShortArray(NUMBER_OF_BASAL_SLOTS.toInt())
|
||||||
|
for (segment in basalProgram.segments) {
|
||||||
|
var remainingPulse = false
|
||||||
|
for (i in segment.startSlotIndex until segment.endSlotIndex) {
|
||||||
|
pulsesPerSlot[i] = (segment.getPulsesPerHour() / 2).toShort()
|
||||||
|
if (segment.getPulsesPerHour() % 2 == 1) { // Do extra alternate pulse
|
||||||
|
if (remainingPulse) {
|
||||||
|
pulsesPerSlot[i] = (pulsesPerSlot[i] + 1).toShort()
|
||||||
|
}
|
||||||
|
remainingPulse = !remainingPulse
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pulsesPerSlot
|
||||||
|
}
|
||||||
|
|
||||||
|
fun calculateCurrentSlot(pulsesPerSlot: ShortArray?, currentTime: Date?): CurrentSlot {
|
||||||
|
val instance = Calendar.getInstance()
|
||||||
|
instance.time = currentTime
|
||||||
|
val hourOfDay = instance[Calendar.HOUR_OF_DAY]
|
||||||
|
val minuteOfHour = instance[Calendar.MINUTE]
|
||||||
|
val secondOfMinute = instance[Calendar.SECOND]
|
||||||
|
val index = ((hourOfDay * 60 + minuteOfHour) / 30).toByte()
|
||||||
|
val secondOfDay = secondOfMinute + hourOfDay * 3600 + minuteOfHour * 60
|
||||||
|
val secondsRemaining = ((index + 1) * 1800 - secondOfDay).toShort()
|
||||||
|
val pulsesRemaining = (pulsesPerSlot!![index.toInt()].toDouble() * secondsRemaining / 1800).toShort()
|
||||||
|
return CurrentSlot(index, (secondsRemaining * 8).toShort(), pulsesRemaining)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun calculateCurrentLongInsulinProgramElement(elements: List<BasalInsulinProgramElement>, currentTime: Date?): CurrentBasalInsulinProgramElement {
|
||||||
|
val instance = Calendar.getInstance()
|
||||||
|
instance.time = currentTime
|
||||||
|
val hourOfDay = instance[Calendar.HOUR_OF_DAY]
|
||||||
|
val minuteOfHour = instance[Calendar.MINUTE]
|
||||||
|
val secondOfMinute = instance[Calendar.SECOND]
|
||||||
|
val secondOfDay = secondOfMinute + hourOfDay * 3600 + minuteOfHour * 60
|
||||||
|
var startSlotIndex = 0
|
||||||
|
var index: Byte = 0
|
||||||
|
for (element in elements) {
|
||||||
|
val startTimeInSeconds = startSlotIndex * 1800
|
||||||
|
val endTimeInSeconds = startTimeInSeconds + element.numberOfSlots * 1800
|
||||||
|
if (secondOfDay in startTimeInSeconds until endTimeInSeconds) { // TODO Adrian Range check ok
|
||||||
|
var totalNumberOfTenThousandthPulsesInSlot = (element.totalTenthPulses * 1000).toLong()
|
||||||
|
if (totalNumberOfTenThousandthPulsesInSlot == 0L) {
|
||||||
|
totalNumberOfTenThousandthPulsesInSlot = (element.numberOfSlots * 1000).toLong()
|
||||||
|
}
|
||||||
|
val durationInSeconds = endTimeInSeconds - startTimeInSeconds
|
||||||
|
val secondsPassedInCurrentSlot = secondOfDay - startTimeInSeconds
|
||||||
|
val remainingTenThousandthPulses = ((durationInSeconds - secondsPassedInCurrentSlot) / durationInSeconds.toDouble() * totalNumberOfTenThousandthPulsesInSlot).toLong()
|
||||||
|
val delayBetweenTenthPulsesInUsec = (durationInSeconds * 1000000L * 1000 / totalNumberOfTenThousandthPulsesInSlot).toInt()
|
||||||
|
val secondsRemaining = secondsPassedInCurrentSlot % 1800
|
||||||
|
var delayUntilNextTenthPulseInUsec = delayBetweenTenthPulsesInUsec
|
||||||
|
for (i in 0 until secondsRemaining) {
|
||||||
|
delayUntilNextTenthPulseInUsec -= 1000000
|
||||||
|
while (delayUntilNextTenthPulseInUsec <= 0) {
|
||||||
|
delayUntilNextTenthPulseInUsec += delayBetweenTenthPulsesInUsec
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val remainingTenthPulses = ((if (remainingTenThousandthPulses % 1000 != 0L) 1 else 0) + remainingTenThousandthPulses / 1000).toShort()
|
||||||
|
return CurrentBasalInsulinProgramElement(index, delayUntilNextTenthPulseInUsec, remainingTenthPulses)
|
||||||
|
}
|
||||||
|
index++
|
||||||
|
startSlotIndex += element.numberOfSlots.toInt()
|
||||||
|
}
|
||||||
|
throw IllegalStateException("Could not determine current long insulin program element")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun calculateChecksum(pulsesPerSlot: ShortArray?, currentSlot: CurrentSlot): Short {
|
||||||
|
val buffer = ByteBuffer.allocate(1 + 2 + 2 + NUMBER_OF_BASAL_SLOTS * 2) //
|
||||||
|
.put(currentSlot.index) //
|
||||||
|
.putShort(currentSlot.pulsesRemaining) //
|
||||||
|
.putShort(currentSlot.eighthSecondsRemaining)
|
||||||
|
for (pulses in pulsesPerSlot!!) {
|
||||||
|
buffer.putShort(pulses)
|
||||||
|
}
|
||||||
|
return MessageUtil.calculateChecksum(buffer.array())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,68 +0,0 @@
|
||||||
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.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<BasalInsulinProgramElement> mapTenthPulsesPerSlotToLongInsulinProgramElements(short[] tenthPulsesPerSlot) {
|
|
||||||
return ProgramBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot, TempBasalInsulinProgramElement::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
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<ShortInsulinProgramElement> mapPulsesPerSlotToShortInsulinProgramElements(short[] pulsesPerSlot) {
|
|
||||||
return ProgramBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.util
|
||||||
|
|
||||||
|
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
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
object ProgramTempBasalUtil {
|
||||||
|
|
||||||
|
fun mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot: ShortArray?): List<BasalInsulinProgramElement> {
|
||||||
|
return ProgramBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot) { startSlotIndex: Byte, numberOfSlots: Byte, totalTenthPulses: Short -> TempBasalInsulinProgramElement(startSlotIndex, numberOfSlots, totalTenthPulses) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun mapTempBasalToTenthPulsesPerSlot(durationInSlots: Int, rateInUnitsPerHour: Double): ShortArray {
|
||||||
|
val pulsesPerHour = (rateInUnitsPerHour * 20).roundToInt().toShort()
|
||||||
|
val tenthPulsesPerSlot = ShortArray(durationInSlots)
|
||||||
|
var i = 0
|
||||||
|
while (durationInSlots > i) {
|
||||||
|
tenthPulsesPerSlot[i] = (roundToHalf(pulsesPerHour / 2.0) * 10).toShort()
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return tenthPulsesPerSlot
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun roundToHalf(d: Double): Double {
|
||||||
|
return ((d * 10.0).toInt().toShort() / 5 * 5).toShort().toDouble() / 10.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fun mapTempBasalToPulsesPerSlot(durationInSlots: Byte, rateInUnitsPerHour: Double): ShortArray {
|
||||||
|
val pulsesPerHour = (rateInUnitsPerHour * 20).roundToInt().toShort()
|
||||||
|
val pulsesPerSlot = ShortArray(durationInSlots.toInt())
|
||||||
|
var remainingPulse = false
|
||||||
|
var i = 0
|
||||||
|
while (durationInSlots > i) {
|
||||||
|
pulsesPerSlot[i] = (pulsesPerHour / 2).toShort()
|
||||||
|
if (pulsesPerHour % 2 == 1) { // Do extra alternate pulse
|
||||||
|
if (remainingPulse) {
|
||||||
|
pulsesPerSlot[i] = (pulsesPerSlot[i] + 1).toShort()
|
||||||
|
}
|
||||||
|
remainingPulse = !remainingPulse
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return pulsesPerSlot
|
||||||
|
}
|
||||||
|
|
||||||
|
fun calculateChecksum(totalNumberOfSlots: Byte, pulsesInFirstSlot: Short, pulsesPerSlot: ShortArray?): Short {
|
||||||
|
val buffer = ByteBuffer.allocate(1 + 2 + 2 + 2 * pulsesPerSlot!!.size) //
|
||||||
|
.put(totalNumberOfSlots) //
|
||||||
|
.putShort(0x3840.toShort()) //
|
||||||
|
.putShort(pulsesInFirstSlot)
|
||||||
|
for (pulses in pulsesPerSlot) {
|
||||||
|
buffer.putShort(pulses)
|
||||||
|
}
|
||||||
|
return MessageUtil.calculateChecksum(buffer.array())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot: ShortArray?): List<ShortInsulinProgramElement> =
|
||||||
|
ProgramBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot)
|
||||||
|
}
|
|
@ -1,174 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
|
||||||
|
|
||||||
public enum AlarmType {
|
|
||||||
NONE((byte) 0x00),
|
|
||||||
ALARM_PW_FLASH_ERASE((byte) 0x01),
|
|
||||||
ALARM_PW_FLASH_WRITE((byte) 0x02),
|
|
||||||
ALARM_BASAL_CKSUM((byte) 0x03),
|
|
||||||
ALARM_BASAL_PPULSE((byte) 0x04),
|
|
||||||
ALARM_BASAL_STEP((byte) 0x05),
|
|
||||||
ALARM_AUTO_WAKEUP_TIMEOUT((byte) 0x06),
|
|
||||||
ALARM_WIRE_OVERDRIVEN((byte) 0x07),
|
|
||||||
ALARM_BEEP_REP_INVALID_INDEX((byte) 0x08),
|
|
||||||
ALARM_INVALID_REP_PATTERN((byte) 0x09),
|
|
||||||
ALARM_TEMP_BASAL_STEP((byte) 0x0a),
|
|
||||||
ALARM_TEMP_BASAL_CKSUM((byte) 0x0b),
|
|
||||||
ALARM_BOLUS_OVERFLOW((byte) 0x0c),
|
|
||||||
ALARM_COP_RESET((byte) 0x0d),
|
|
||||||
ALARM_ILOP_RESET((byte) 0x0e),
|
|
||||||
ALARM_ILAD_RESET((byte) 0x0f),
|
|
||||||
ALARM_SAWCOP_RESET((byte) 0x10),
|
|
||||||
ALARM_BOLUS_STEP((byte) 0x11),
|
|
||||||
ALARM_LVD_RESET((byte) 0x12),
|
|
||||||
ALARM_INVALID_RF_MSG_LENGTH((byte) 0x13),
|
|
||||||
ALARM_OCCLUDED((byte) 0x14),
|
|
||||||
ALARM_BOLUSPROG_CHKSUM((byte) 0x15),
|
|
||||||
ALARM_BOLUS_LOG((byte) 0x16),
|
|
||||||
ALARM_CRITICAL_VAR((byte) 0x17),
|
|
||||||
ALARM_EMPTY_RESERVOIR((byte) 0x18),
|
|
||||||
ALARM_LOADERR((byte) 0x19),
|
|
||||||
ALARM_PSA_FAILURE((byte) 0x1a),
|
|
||||||
ALARM_TICKCNT_NOT_CLEARED((byte) 0x1b),
|
|
||||||
ALARM_PUMP_EXPIRED((byte) 0x1c),
|
|
||||||
ALARM_COMD_BIT_NOT_SET((byte) 0x1d),
|
|
||||||
ALARM_INVALID_COMD_SET((byte) 0x1e),
|
|
||||||
ALARM_ALERTS_ARRAY_CKSM((byte) 0x1f),
|
|
||||||
ALARM_UNIT_TEST((byte) 0x20),
|
|
||||||
ALARM_TICK_TIME_ERROR((byte) 0x21),
|
|
||||||
ALARM_CRITICAL_HAZARD((byte) 0x22),
|
|
||||||
ALARM_PIEZO_FREQ((byte) 0x23),
|
|
||||||
ALARM_TICKCNT_ERROR_RTC((byte) 0x24),
|
|
||||||
ALARM_TICK_FAILURE((byte) 0x25),
|
|
||||||
ALARM_INVALID((byte) 0x26),
|
|
||||||
ALARM_LUMP_ALERT_PROGRAM((byte) 0x27),
|
|
||||||
ALARM_INVALID_PASS_CODE((byte) 0x28),
|
|
||||||
ALARM_ALERT0((byte) 0x29),
|
|
||||||
ALARM_ALERT1((byte) 0x2a),
|
|
||||||
ALARM_ALERT2((byte) 0x2b),
|
|
||||||
ALARM_ALERT3((byte) 0x2c),
|
|
||||||
ALARM_ALERT4((byte) 0x2d),
|
|
||||||
ALARM_ALERT5((byte) 0x2e),
|
|
||||||
ALARM_ALERT6((byte) 0x2f),
|
|
||||||
ALARM_ALERT7((byte) 0x30),
|
|
||||||
ALARM_ILLEGAL_PUMP_STATE((byte) 0x31),
|
|
||||||
ALARM_COP_TEST_FAILURE((byte) 0x32),
|
|
||||||
ALARM_MCTF((byte) 0x33),
|
|
||||||
ALARM_ILLEGAL_RESET((byte) 0x34),
|
|
||||||
ALARM_VETO_NOT_SET((byte) 0x35),
|
|
||||||
ALARM_ILLEGAL_PIN_RESET((byte) 0x36),
|
|
||||||
ALARM_INVALID_BEEP_PATTERN((byte) 0x37),
|
|
||||||
ALARM_WIRE_STATE_MACHINE((byte) 0x38),
|
|
||||||
ALARM_VETO_TEST_DEFAULT((byte) 0x39),
|
|
||||||
ALARM_ALERT_INVALID_INDEX((byte) 0x3a),
|
|
||||||
ALARM_SAWCOP_TEST_FAIL((byte) 0x3b),
|
|
||||||
ALARM_MCUCOP_TEST_FAIL((byte) 0x3c),
|
|
||||||
ALARM_STEP_SENSOR_SHORTED((byte) 0x3d),
|
|
||||||
ALARM_FLASH_FAILURE((byte) 0x3e),
|
|
||||||
ALARM_SPARE63((byte) 0x3f),
|
|
||||||
ALARM_SS_OPEN_CNT_EXCEEDED((byte) 0x40),
|
|
||||||
ALARM_SS_EXCESSIVE_SUMMED((byte) 0x41),
|
|
||||||
ALARM_SS_MIN_PULSE_TRANSITION((byte) 0x42),
|
|
||||||
ALARM_SS_DEFAULT((byte) 0x43),
|
|
||||||
ALARM_OPEN_WIRE1((byte) 0x44),
|
|
||||||
ALARM_OPEN_WIRE2((byte) 0x45),
|
|
||||||
ALARM_LOADERR_FAILURE((byte) 0x46),
|
|
||||||
ALARM_SAW_VETO_FAILURE((byte) 0x47),
|
|
||||||
ALARM_BAD_RFM_CLOCK((byte) 0x48),
|
|
||||||
ALARM_BAD_TICK_HIGH((byte) 0x49),
|
|
||||||
ALARM_BAD_TICK_PERIOD((byte) 0x4a),
|
|
||||||
ALARM_BAD_TRIM_VALUE((byte) 0x4b),
|
|
||||||
ALARM_BAD_BUS_CLOCK((byte) 0x4c),
|
|
||||||
ALARM_BAD_CAL_MODE((byte) 0x4d),
|
|
||||||
ALARM_SAW_TRIM_ERROR((byte) 0x4e),
|
|
||||||
ALARM_RFM_CRYSTAL_ERROR((byte) 0x4f),
|
|
||||||
ALARM_CALST_TIMEOUT((byte) 0x50),
|
|
||||||
ALARM_TICKCNT_ERROR((byte) 0x51),
|
|
||||||
ALARM_BAD_RFM_XTAL_START((byte) 0x52),
|
|
||||||
ALARM_BAD_RX_SENSENSITIVITY((byte) 0x53),
|
|
||||||
ALARM_BAD_TX_PKT_SIZE((byte) 0x54),
|
|
||||||
ALARM_TICK_LOW_PHASE_EXCEEDED((byte) 0x55),
|
|
||||||
ALARM_TICK_HIGH_PHASE_EXCEEDED((byte) 0x56),
|
|
||||||
ALARM_OCCL_CRITVAR_FAIL((byte) 0x57),
|
|
||||||
ALARM_OCCL_PARAM((byte) 0x58),
|
|
||||||
ALARM_PROG_OCCL_FAIL((byte) 0x59),
|
|
||||||
ALARM_PW_TO_HIGH_FOR_OCCL_DET((byte) 0x5a),
|
|
||||||
ALARM_OCCL_CSUM((byte) 0x5b),
|
|
||||||
ALARM_PRIME_OPEN_CNT_TO_LOW((byte) 0x5c),
|
|
||||||
ALARM_BAD_RF_CDTHR((byte) 0x5d),
|
|
||||||
ALARM_FLASH_NOT_SECURE((byte) 0x5e),
|
|
||||||
ALARM_WIRE_TEST_OPEN_GROUND((byte) 0x5f),
|
|
||||||
ALARM_OCCL_STARTUP1((byte) 0x60),
|
|
||||||
ALARM_OCCL_STARTUP2((byte) 0x61),
|
|
||||||
ALARM_OCCL_EXCESS_TIMEOUTS1((byte) 0x62),
|
|
||||||
ALARM_SPARE99((byte) 0x63),
|
|
||||||
ALARM_SPARE100((byte) 0x64),
|
|
||||||
ALARM_SPARE101((byte) 0x65),
|
|
||||||
ALARM_OCCL_EXCESS_TIMEOUTS2((byte) 0x66),
|
|
||||||
ALARM_OCCL_EXCESS_TIMEOUTS3((byte) 0x67),
|
|
||||||
ALARM_OCCL_NOISY_PULSE_WIDTHS((byte) 0x68),
|
|
||||||
ALARM_OCCL_AT_BOLUS_END((byte) 0x69),
|
|
||||||
ALARM_OCCL_ABOVE_THRESHOLD((byte) 0x6a),
|
|
||||||
ALARM_BASAL_UNDERINFUSION((byte) 0x80),
|
|
||||||
ALARM_BASAL_OVERINFUSION((byte) 0x81),
|
|
||||||
ALARM_TEMP_UNDERINFUSION((byte) 0x82),
|
|
||||||
ALARM_TEMP_OVERINFUSION((byte) 0x83),
|
|
||||||
ALARM_BOLUS_UNDERINFUSION((byte) 0x84),
|
|
||||||
ALARM_BOLUS_OVERINFUSION((byte) 0x85),
|
|
||||||
ALARM_BASAL_OVERINFUSION_PULSE((byte) 0x86),
|
|
||||||
ALARM_TEMP_OVERINFUSION_PULSE((byte) 0x87),
|
|
||||||
ALARM_BOLUS_OVERINFUSION_PULSE((byte) 0x88),
|
|
||||||
ALARM_IMMBOLUS_UNDERINFUSION_PULSE((byte) 0x89),
|
|
||||||
ALARM_EXTBOLUS_OVERINFUSION_PULSE((byte) 0x8a),
|
|
||||||
ALARM_PROGRAM_CSUM((byte) 0x8b),
|
|
||||||
ALARM_UNUSED_140((byte) 0x8c),
|
|
||||||
ALARM_UNRECOGNIZED_PULSE((byte) 0x8d),
|
|
||||||
ALARM_SYNC_WITHOUT_TEMP_ACTIVE((byte) 0x8e),
|
|
||||||
ALARM_INTERLOCK_LOAD((byte) 0x8f),
|
|
||||||
ALARM_ILLEGAL_CHAN_PARAM((byte) 0x90),
|
|
||||||
ALARM_BASAL_PULSE_CHAN_INACTIVE((byte) 0x91),
|
|
||||||
ALARM_TEMP_PULSE_CHAN_INACTIVE((byte) 0x92),
|
|
||||||
ALARM_BOLUS_PULSE_CHAN_INACTIVE((byte) 0x93),
|
|
||||||
ALARM_INT_SEMAPHORE_NOT_SET((byte) 0x94),
|
|
||||||
ALARM_ILLEGAL_INTERLOCK_CHAN((byte) 0x95),
|
|
||||||
ALARM_TERMINATE_BOLUS((byte) 0x96),
|
|
||||||
ALARM_OPEN_TRANSITIONS_COUNT((byte) 0x97),
|
|
||||||
ALARM_BLE_TO((byte) 0xa0),
|
|
||||||
ALARM_BLE_INITIATED((byte) 0xa1),
|
|
||||||
ALARM_BLE_UNK_ALARM((byte) 0xa2),
|
|
||||||
ALARM_UNUSED_163((byte) 0xa3),
|
|
||||||
ALARM_UNUSED_164((byte) 0xa4),
|
|
||||||
ALARM_UNUSED_165((byte) 0xa5),
|
|
||||||
ALARM_BLE_IAAS((byte) 0xa6),
|
|
||||||
ALARM_UNUSED_167((byte) 0xa7),
|
|
||||||
ALARM_CRC_FAILURE((byte) 0xa8),
|
|
||||||
ALARM_BLE_WD_PING_TIMEOUT((byte) 0xa9),
|
|
||||||
ALARM_BLE_EXCESSIVE_RESETS((byte) 0xaa),
|
|
||||||
ALARM_BLE_NAK_ERROR((byte) 0xab),
|
|
||||||
ALARM_BLE_REQ_HIGH_TIMEOUT((byte) 0xac),
|
|
||||||
ALARM_BLE_UNKNOWN_RESP((byte) 0xad),
|
|
||||||
ALARM_BLE_UNUSED_174((byte) 0xae),
|
|
||||||
ALARM_BLE_REQ_STUCK_HIGH((byte) 0xaf),
|
|
||||||
ALARM_BLE_STATE_MACHINE_1((byte) 0xb1),
|
|
||||||
ALARM_BLE_STATE_MACHINE_2((byte) 0xb2),
|
|
||||||
ALARM_BLE_UNUSED_179((byte) 0xb3),
|
|
||||||
ALARM_BLE_ARB_LOST((byte) 0xb4),
|
|
||||||
ALARM_BLE_ER48_DUAL_NACK((byte) 0xc0),
|
|
||||||
ALARM_BLE_QN_EXCEED_MAX_RETRY((byte) 0xc1),
|
|
||||||
ALARM_BLE_QN_CRIT_VAR_FAIL((byte) 0xc2),
|
|
||||||
UNKNOWN((byte) 0xff);
|
|
||||||
|
|
||||||
private byte value;
|
|
||||||
|
|
||||||
AlarmType(byte value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AlarmType byValue(byte value) {
|
|
||||||
for (AlarmType type : values()) {
|
|
||||||
if (type.value == value) {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return UNKNOWN;
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because one or more lines are too long
|
@ -1,61 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
public class AlertConfiguration implements Encodable {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override 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 +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import kotlin.experimental.or
|
||||||
|
|
||||||
|
class AlertConfiguration(private val slot: AlertSlot, private val enabled: Boolean, private val durationInMinutes: Short, private val autoOff: Boolean, private val triggerType: AlertTriggerType, private val offsetInMinutesOrThresholdInMicroLiters: Short, private val beepType: BeepType, private val beepRepetition: BeepRepetitionType) : Encodable {
|
||||||
|
|
||||||
|
|
||||||
|
override val encoded: ByteArray
|
||||||
|
get() {
|
||||||
|
var firstByte = (slot.value.toInt() shl 4).toByte()
|
||||||
|
if (enabled) {
|
||||||
|
firstByte = firstByte or (1 shl 3)
|
||||||
|
}
|
||||||
|
if (triggerType == AlertTriggerType.RESERVOIR_VOLUME_TRIGGER) {
|
||||||
|
firstByte = firstByte or (1 shl 2)
|
||||||
|
}
|
||||||
|
if (autoOff) {
|
||||||
|
firstByte = firstByte or (1 shl 1)
|
||||||
|
}
|
||||||
|
firstByte = firstByte or ((durationInMinutes.toInt() shr 8 and 0x01).toByte()) //Todo bitstuff
|
||||||
|
return ByteBuffer.allocate(6) //
|
||||||
|
.put(firstByte)
|
||||||
|
.put(durationInMinutes.toByte()) //
|
||||||
|
.putShort(offsetInMinutesOrThresholdInMicroLiters) //
|
||||||
|
.put(beepRepetition.value) //
|
||||||
|
.put(beepType.value) //
|
||||||
|
.array()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "AlertConfiguration{" +
|
||||||
|
"slot=" + slot +
|
||||||
|
", enabled=" + enabled +
|
||||||
|
", durationInMinutes=" + durationInMinutes +
|
||||||
|
", autoOff=" + autoOff +
|
||||||
|
", triggerType=" + triggerType +
|
||||||
|
", offsetInMinutesOrThresholdInMicroLiters=" + offsetInMinutesOrThresholdInMicroLiters +
|
||||||
|
", beepType=" + beepType +
|
||||||
|
", beepRepetition=" + beepRepetition +
|
||||||
|
'}'
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,32 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
|
||||||
|
|
||||||
public enum AlertSlot {
|
|
||||||
AUTO_OFF((byte) 0x00),
|
|
||||||
MULTI_COMMAND((byte) 0x01),
|
|
||||||
EXPIRATION_IMMINENT((byte) 0x02),
|
|
||||||
USER_SET_EXPIRATION((byte) 0x03),
|
|
||||||
LOW_RESERVOIR((byte) 0x04),
|
|
||||||
SUSPEND_IN_PROGRESS((byte) 0x05),
|
|
||||||
SUSPEND_ENDED((byte) 0x06),
|
|
||||||
EXPIRATION((byte) 0x07),
|
|
||||||
UNKNOWN((byte) 0xff);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||||
|
|
||||||
|
enum class AlertSlot(val value: Byte) {
|
||||||
|
AUTO_OFF(0x00.toByte()), MULTI_COMMAND(0x01.toByte()), EXPIRATION_IMMINENT(0x02.toByte()), USER_SET_EXPIRATION(0x03.toByte()), LOW_RESERVOIR(0x04.toByte()), SUSPEND_IN_PROGRESS(0x05.toByte()), SUSPEND_ENDED(0x06.toByte()), EXPIRATION(0x07.toByte()), UNKNOWN(0xff.toByte());
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun byValue(value: Byte): AlertSlot {
|
||||||
|
for (slot in values()) {
|
||||||
|
if (slot.value == value) {
|
||||||
|
return slot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
|
||||||
|
|
||||||
public enum AlertTriggerType {
|
|
||||||
TIME_TRIGGER,
|
|
||||||
RESERVOIR_VOLUME_TRIGGER
|
|
||||||
}
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||||
|
|
||||||
|
enum class AlertTriggerType {
|
||||||
|
TIME_TRIGGER, RESERVOIR_VOLUME_TRIGGER
|
||||||
|
}
|
|
@ -1,92 +0,0 @@
|
||||||
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<Segment> segments;
|
|
||||||
|
|
||||||
public BasalProgram(List<Segment> 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<Segment> 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 +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||||
|
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class BasalProgram(segments: List<Segment>) {
|
||||||
|
|
||||||
|
val segments: MutableList<Segment> = segments.toMutableList()
|
||||||
|
get() = Collections.unmodifiableList(field) // TODO Adrian: moved method here
|
||||||
|
|
||||||
|
fun addSegment(segment: Segment) {
|
||||||
|
segments.add(segment)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hasZeroUnitSegments() = segments.any { it.basalRateInHundredthUnitsPerHour == 0 }
|
||||||
|
|
||||||
|
fun isZeroBasal() = segments.sumBy(Segment::basalRateInHundredthUnitsPerHour) == 0
|
||||||
|
|
||||||
|
class Segment(val startSlotIndex: Short, val endSlotIndex: Short, val basalRateInHundredthUnitsPerHour: Int) {
|
||||||
|
|
||||||
|
fun getPulsesPerHour(): Short {
|
||||||
|
return (basalRateInHundredthUnitsPerHour * PULSES_PER_UNIT / 100).toShort()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getNumberOfSlots(): Short {
|
||||||
|
return (endSlotIndex - startSlotIndex).toShort()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "Segment{" +
|
||||||
|
"startSlotIndex=" + startSlotIndex +
|
||||||
|
", endSlotIndex=" + endSlotIndex +
|
||||||
|
", basalRateInHundredthUnitsPerHour=" + basalRateInHundredthUnitsPerHour +
|
||||||
|
'}'
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val PULSES_PER_UNIT: Byte = 20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "BasalProgram{" +
|
||||||
|
"segments=" + segments +
|
||||||
|
'}'
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,20 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||||
|
|
||||||
|
// FIXME names
|
||||||
|
enum class BeepRepetitionType( // Used in lump of coal alert
|
||||||
|
val value: Byte) {
|
||||||
|
|
||||||
|
XXX(0x01.toByte()), // Used in low reservoir alert
|
||||||
|
XXX2(0x03.toByte()), // Used in user pod expiration alert
|
||||||
|
XXX3(0x05.toByte()), // Used in pod expiration alert
|
||||||
|
XXX4(0x06.toByte()), // Used in imminent pod expiration alert
|
||||||
|
XXX5(0x08.toByte());
|
||||||
|
|
||||||
|
}
|
|
@ -1,17 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
|
||||||
|
|
||||||
public enum BeepType {
|
|
||||||
SILENT((byte) 0x00),
|
|
||||||
FOUR_TIMES_BIP_BEEP((byte) 0x02), // Used in low reservoir alert, user expiration alert, expiration alert, imminent expiration alert, lump of coal alert
|
|
||||||
LONG_SINGLE_BEEP((byte) 0x06); // Used in stop delivery command
|
|
||||||
|
|
||||||
private byte value;
|
|
||||||
|
|
||||||
BeepType(byte value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||||
|
|
||||||
|
enum class BeepType( // Used in stop delivery command
|
||||||
|
val value: Byte) {
|
||||||
|
|
||||||
|
SILENT(0x00.toByte()), FOUR_TIMES_BIP_BEEP(0x02.toByte()), // Used in low reservoir alert, user expiration alert, expiration alert, imminent expiration alert, lump of coal alert
|
||||||
|
LONG_SINGLE_BEEP(0x06.toByte());
|
||||||
|
}
|
|
@ -1,26 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
|
||||||
|
|
||||||
public enum DeliveryStatus {
|
|
||||||
SUSPENDED((byte) 0x00),
|
|
||||||
BASAL_ACTIVE((byte) 0x01),
|
|
||||||
TEMP_BASAL_ACTIVE((byte) 0x02),
|
|
||||||
PRIMING((byte) 0x04),
|
|
||||||
BOLUS_AND_BASAL_ACTIVE((byte) 0x05),
|
|
||||||
BOLUS_AND_TEMP_BASAL_ACTIVE((byte) 0x06),
|
|
||||||
UNKNOWN((byte) 0xff);
|
|
||||||
|
|
||||||
private byte value;
|
|
||||||
|
|
||||||
DeliveryStatus(byte value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DeliveryStatus byValue(byte value) {
|
|
||||||
for (DeliveryStatus status : values()) {
|
|
||||||
if (status.value == value) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return UNKNOWN;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||||
|
|
||||||
|
enum class DeliveryStatus(private val value: Byte) {
|
||||||
|
SUSPENDED(0x00.toByte()), BASAL_ACTIVE(0x01.toByte()), TEMP_BASAL_ACTIVE(0x02.toByte()), PRIMING(0x04.toByte()), BOLUS_AND_BASAL_ACTIVE(0x05.toByte()), BOLUS_AND_TEMP_BASAL_ACTIVE(0x06.toByte()), UNKNOWN(0xff.toByte());
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun byValue(value: Byte): DeliveryStatus {
|
||||||
|
for (status in values()) {
|
||||||
|
if (status.value == value) {
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
|
||||||
|
|
||||||
public interface Encodable {
|
|
||||||
byte[] getEncoded();
|
|
||||||
}
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||||
|
|
||||||
|
interface Encodable {
|
||||||
|
|
||||||
|
val encoded: ByteArray
|
||||||
|
}
|
|
@ -1,49 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
|
||||||
|
|
||||||
public enum NakErrorType {
|
|
||||||
FLASH_WRITE((byte) 0x01),
|
|
||||||
FLASH_ERASE((byte) 0x02),
|
|
||||||
FLASH_OPERATION((byte) 0x03),
|
|
||||||
FLASH_ADDR((byte) 0x04),
|
|
||||||
POD_STATE((byte) 0x05),
|
|
||||||
CRITICAL_VARIABLE((byte) 0x06),
|
|
||||||
ILLEGAL_PARAM((byte) 0x07),
|
|
||||||
BOLUS_CRITICAL_VAR((byte) 0x08),
|
|
||||||
INT_ILLEGAL_PARAM((byte) 0x09),
|
|
||||||
ILLEGAL_CHECKSUM((byte) 0x0a),
|
|
||||||
INVALID_MSG_LEN((byte) 0x0b),
|
|
||||||
PUMP_STATE((byte) 0x0c),
|
|
||||||
ILLEGAL_COMMAND((byte) 0x0d),
|
|
||||||
ILLEGAL_FILL_STATE((byte) 0x0e),
|
|
||||||
MAX_READWRITE_SIZE((byte) 0x0f),
|
|
||||||
ILLEGAL_READ_ADDRESS((byte) 0x10),
|
|
||||||
ILLEGAL_READ_MEM_TYPE((byte) 0x11),
|
|
||||||
INIT_POD((byte) 0x12),
|
|
||||||
ILLEGAL_CMD_STATE((byte) 0x13),
|
|
||||||
ILLEGAL_SECURITY_CODE((byte) 0x14),
|
|
||||||
POD_IN_ALARM((byte) 0x15),
|
|
||||||
COMD_NOT_SET((byte) 0x16),
|
|
||||||
ILLEGAL_RX_SENS_VALUE((byte) 0x17),
|
|
||||||
ILLEGAL_TX_PKT_SIZE((byte) 0x18),
|
|
||||||
OCCL_PARAMS_ALREADY_SET((byte) 0x19),
|
|
||||||
OCCL_PARAM((byte) 0x1a),
|
|
||||||
ILLEGAL_CDTHR_VALUE((byte) 0x1b),
|
|
||||||
IGNORE_COMMAND((byte) 0x1c),
|
|
||||||
INVALID_CRC((byte) 0x1d),
|
|
||||||
UNKNOWN((byte) 0xff);
|
|
||||||
|
|
||||||
private byte value;
|
|
||||||
|
|
||||||
NakErrorType(byte value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static NakErrorType byValue(byte value) {
|
|
||||||
for (NakErrorType type : values()) {
|
|
||||||
if (type.value == value) {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return UNKNOWN;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||||
|
|
||||||
|
enum class NakErrorType(private val value: Byte) {
|
||||||
|
FLASH_WRITE(0x01.toByte()), FLASH_ERASE(0x02.toByte()), FLASH_OPERATION(0x03.toByte()), FLASH_ADDR(0x04.toByte()), POD_STATE(0x05.toByte()), CRITICAL_VARIABLE(0x06.toByte()), ILLEGAL_PARAM(0x07.toByte()), BOLUS_CRITICAL_VAR(0x08.toByte()), INT_ILLEGAL_PARAM(0x09.toByte()), ILLEGAL_CHECKSUM(0x0a.toByte()), INVALID_MSG_LEN(0x0b.toByte()), PUMP_STATE(0x0c.toByte()), ILLEGAL_COMMAND(0x0d.toByte()), ILLEGAL_FILL_STATE(0x0e.toByte()), MAX_READWRITE_SIZE(0x0f.toByte()), ILLEGAL_READ_ADDRESS(0x10.toByte()), ILLEGAL_READ_MEM_TYPE(0x11.toByte()), INIT_POD(0x12.toByte()), ILLEGAL_CMD_STATE(0x13.toByte()), ILLEGAL_SECURITY_CODE(0x14.toByte()), POD_IN_ALARM(0x15.toByte()), COMD_NOT_SET(0x16.toByte()), ILLEGAL_RX_SENS_VALUE(0x17.toByte()), ILLEGAL_TX_PKT_SIZE(0x18.toByte()), OCCL_PARAMS_ALREADY_SET(0x19.toByte()), OCCL_PARAM(0x1a.toByte()), ILLEGAL_CDTHR_VALUE(0x1b.toByte()), IGNORE_COMMAND(0x1c.toByte()), INVALID_CRC(0x1d.toByte()), UNKNOWN(0xff.toByte());
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun byValue(value: Byte): NakErrorType {
|
||||||
|
for (type in values()) {
|
||||||
|
if (type.value == value) {
|
||||||
|
return type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,26 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
|
||||||
|
|
||||||
public class OmnipodEvent {
|
|
||||||
public enum OmnipodEventType {
|
|
||||||
CONNECTED,
|
|
||||||
ALREADY_CONNECTED,
|
|
||||||
FAILED_TO_CONNECT,
|
|
||||||
DISCONNECTED,
|
|
||||||
COMMAND_SENT,
|
|
||||||
GOT_POD_VERSION,
|
|
||||||
SET_UNIQUE_ID,
|
|
||||||
PRIMED_PUMP,
|
|
||||||
FINISHED_ACTIVATION_1,
|
|
||||||
PROGRAMMED_BASAL,
|
|
||||||
PROGRAMMED_ALERTS,
|
|
||||||
SET_BEEPS,
|
|
||||||
INSERTED_CANNULA,
|
|
||||||
FINISHED_ACTIVATION_2,
|
|
||||||
PROGRAMMED_TEMP_BASAL,
|
|
||||||
STARTED_BOLUS,
|
|
||||||
STOPPED_DELIVERY,
|
|
||||||
SILENCED_ALERTS,
|
|
||||||
DEACTIVATED,
|
|
||||||
COMMAND_SENDING,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||||
|
|
||||||
|
class OmnipodEvent {
|
||||||
|
enum class OmnipodEventType {
|
||||||
|
CONNECTED, ALREADY_CONNECTED, FAILED_TO_CONNECT, DISCONNECTED, COMMAND_SENT, GOT_POD_VERSION, SET_UNIQUE_ID, PRIMED_PUMP, FINISHED_ACTIVATION_1, PROGRAMMED_BASAL, PROGRAMMED_ALERTS, SET_BEEPS, INSERTED_CANNULA, FINISHED_ACTIVATION_2, PROGRAMMED_TEMP_BASAL, STARTED_BOLUS, STOPPED_DELIVERY, SILENCED_ALERTS, DEACTIVATED, COMMAND_SENDING
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,36 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
|
||||||
|
|
||||||
public enum PodStatus {
|
|
||||||
UNINITIALIZED((byte) 0x00),
|
|
||||||
MFG_TEST((byte) 0x01),
|
|
||||||
FILLED((byte) 0x02),
|
|
||||||
UID_SET((byte) 0x03),
|
|
||||||
ENGAGING_CLUTCH_DRIVE((byte) 0x04),
|
|
||||||
CLUTCH_DRIVE_ENGAGED((byte) 0x05),
|
|
||||||
BASAL_PROGRAM_RUNNING((byte) 0x06),
|
|
||||||
PRIMING((byte) 0x07),
|
|
||||||
RUNNING_ABOVE_MIN_VOLUME((byte) 0x08),
|
|
||||||
RUNNING_BELOW_MIN_VOLUME((byte) 0x09),
|
|
||||||
UNUSED_10((byte) 0x0a),
|
|
||||||
UNUSED_11((byte) 0x0b),
|
|
||||||
UNUSED_12((byte) 0x0c),
|
|
||||||
ALARM((byte) 0x0d),
|
|
||||||
LUMP_OF_COAL((byte) 0x0e),
|
|
||||||
DEACTIVATED((byte) 0x0f),
|
|
||||||
UNKNOWN((byte) 0xff);
|
|
||||||
|
|
||||||
private byte value;
|
|
||||||
|
|
||||||
PodStatus(byte value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PodStatus byValue(byte value) {
|
|
||||||
for (PodStatus status : values()) {
|
|
||||||
if (status.value == value) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return UNKNOWN;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||||
|
|
||||||
|
enum class PodStatus(private val value: Byte) {
|
||||||
|
UNINITIALIZED(0x00.toByte()), MFG_TEST(0x01.toByte()), FILLED(0x02.toByte()), UID_SET(0x03.toByte()), ENGAGING_CLUTCH_DRIVE(0x04.toByte()), CLUTCH_DRIVE_ENGAGED(0x05.toByte()), BASAL_PROGRAM_RUNNING(0x06.toByte()), PRIMING(0x07.toByte()), RUNNING_ABOVE_MIN_VOLUME(0x08.toByte()), RUNNING_BELOW_MIN_VOLUME(0x09.toByte()), UNUSED_10(0x0a.toByte()), UNUSED_11(0x0b.toByte()), UNUSED_12(0x0c.toByte()), ALARM(0x0d.toByte()), LUMP_OF_COAL(0x0e.toByte()), DEACTIVATED(0x0f.toByte()), UNKNOWN(0xff.toByte());
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun byValue(value: Byte): PodStatus {
|
||||||
|
for (status in values()) {
|
||||||
|
if (status.value == value) {
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
|
||||||
|
|
||||||
public class ProgramReminder implements Encodable {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public byte[] getEncoded() {
|
|
||||||
return new byte[]{(byte) (((this.atStart ? 1 : 0) << 7)
|
|
||||||
| ((this.atEnd ? 1 : 0) << 6)
|
|
||||||
| (this.atInterval & 0x3f))};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||||
|
|
||||||
|
import kotlin.experimental.and
|
||||||
|
|
||||||
|
class ProgramReminder(private val atStart: Boolean, private val atEnd: Boolean, private val atInterval: Byte) : Encodable {
|
||||||
|
|
||||||
|
override val encoded: ByteArray
|
||||||
|
get() = byteArrayOf(((if (atStart) 1 else 0) shl 7
|
||||||
|
or ((if (atEnd) 1 else 0) shl 6)
|
||||||
|
or ((atInterval and 0x3f).toInt())).toByte())
|
||||||
|
}
|
|
@ -1,14 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response;
|
|
||||||
|
|
||||||
abstract class ActivationResponseBase extends ResponseBase {
|
|
||||||
final ResponseType.ActivationResponseType activationResponseType;
|
|
||||||
|
|
||||||
ActivationResponseBase(ResponseType.ActivationResponseType activationResponseType, byte[] encoded) {
|
|
||||||
super(ResponseType.ACTIVATION_RESPONSE, encoded);
|
|
||||||
this.activationResponseType = activationResponseType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResponseType.ActivationResponseType getActivationResponseType() {
|
|
||||||
return activationResponseType;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.ResponseType.ActivationResponseType
|
||||||
|
|
||||||
|
abstract class ActivationResponseBase(val activationResponseType: ActivationResponseType, encoded: ByteArray) : ResponseBase(ResponseType.ACTIVATION_RESPONSE, encoded)
|
|
@ -1,14 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response;
|
|
||||||
|
|
||||||
public class AdditionalStatusResponseBase extends ResponseBase {
|
|
||||||
final ResponseType.AdditionalStatusResponseType statusResponseType;
|
|
||||||
|
|
||||||
AdditionalStatusResponseBase(ResponseType.AdditionalStatusResponseType statusResponseType, byte[] encoded) {
|
|
||||||
super(ResponseType.ADDITIONAL_STATUS_RESPONSE, encoded);
|
|
||||||
this.statusResponseType = statusResponseType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResponseType.AdditionalStatusResponseType getStatusResponseType() {
|
|
||||||
return statusResponseType;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.ResponseType.AdditionalStatusResponseType
|
||||||
|
|
||||||
|
open class AdditionalStatusResponseBase internal constructor(val statusResponseType: AdditionalStatusResponseType, encoded: ByteArray) : ResponseBase(ResponseType.ADDITIONAL_STATUS_RESPONSE, encoded)
|
|
@ -1,240 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlarmType;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.DeliveryStatus;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus;
|
|
||||||
|
|
||||||
public class AlarmStatusResponse extends AdditionalStatusResponseBase {
|
|
||||||
private final byte messageType;
|
|
||||||
private final short messageLength;
|
|
||||||
private final byte additionalStatusResponseType;
|
|
||||||
private final PodStatus podStatus;
|
|
||||||
private final DeliveryStatus deliveryStatus;
|
|
||||||
private final short bolusPulsesRemaining;
|
|
||||||
private final short sequenceNumberOfLastProgrammingCommand;
|
|
||||||
private final short totalPulsesDelivered;
|
|
||||||
private final AlarmType alarmType;
|
|
||||||
private final short alarmTime;
|
|
||||||
private final short reservoirPulsesRemaining;
|
|
||||||
private final short minutesSinceActivation;
|
|
||||||
private final boolean alert0Active;
|
|
||||||
private final boolean alert1Active;
|
|
||||||
private final boolean alert2Active;
|
|
||||||
private final boolean alert3Active;
|
|
||||||
private final boolean alert4Active;
|
|
||||||
private final boolean alert5Active;
|
|
||||||
private final boolean alert6Active;
|
|
||||||
private final boolean alert7Active;
|
|
||||||
private final boolean occlusionAlarm;
|
|
||||||
private final boolean pulseInfoInvalid;
|
|
||||||
private final PodStatus podStatusWhenAlarmOccurred;
|
|
||||||
private final boolean immediateBolusWhenAlarmOccurred;
|
|
||||||
private final byte occlusionType;
|
|
||||||
private final boolean occurredWhenFetchingImmediateBolusActiveInformation;
|
|
||||||
private final short rssi;
|
|
||||||
private final short receiverLowerGain;
|
|
||||||
private final PodStatus podStatusWhenAlarmOccurred2;
|
|
||||||
private final short returnAddressOfPodAlarmHandlerCaller;
|
|
||||||
|
|
||||||
public AlarmStatusResponse(byte[] encoded) {
|
|
||||||
super(ResponseType.AdditionalStatusResponseType.ALARM_STATUS, encoded);
|
|
||||||
messageType = encoded[0];
|
|
||||||
messageLength = (short) (encoded[1] & 0xff);
|
|
||||||
additionalStatusResponseType = encoded[2];
|
|
||||||
podStatus = PodStatus.byValue((byte) (encoded[3] & 0x0f));
|
|
||||||
deliveryStatus = DeliveryStatus.byValue((byte) (encoded[4] & 0x0f));
|
|
||||||
bolusPulsesRemaining = (short) (ByteBuffer.wrap(new byte[]{encoded[5], encoded[6]}).getShort() & 2047);
|
|
||||||
sequenceNumberOfLastProgrammingCommand = (short) (encoded[7] & 0x0f);
|
|
||||||
totalPulsesDelivered = ByteBuffer.wrap(new byte[]{encoded[8], encoded[9]}).getShort();
|
|
||||||
alarmType = AlarmType.byValue(encoded[10]);
|
|
||||||
alarmTime = ByteBuffer.wrap(new byte[]{encoded[11], encoded[12]}).getShort();
|
|
||||||
reservoirPulsesRemaining = ByteBuffer.wrap(new byte[]{encoded[13], encoded[14]}).getShort();
|
|
||||||
minutesSinceActivation = ByteBuffer.wrap(new byte[]{encoded[15], encoded[16]}).getShort();
|
|
||||||
|
|
||||||
byte activeAlerts = encoded[17];
|
|
||||||
alert0Active = (activeAlerts & 1) == 1;
|
|
||||||
alert1Active = ((activeAlerts >>> 1) & 1) == 1;
|
|
||||||
alert2Active = ((activeAlerts >>> 2) & 1) == 1;
|
|
||||||
alert3Active = ((activeAlerts >>> 3) & 1) == 1;
|
|
||||||
alert4Active = ((activeAlerts >>> 4) & 1) == 1;
|
|
||||||
alert5Active = ((activeAlerts >>> 5) & 1) == 1;
|
|
||||||
alert6Active = ((activeAlerts >>> 6) & 1) == 1;
|
|
||||||
alert7Active = ((activeAlerts >>> 7) & 1) == 1;
|
|
||||||
|
|
||||||
byte alarmFlags = encoded[18];
|
|
||||||
occlusionAlarm = (alarmFlags & 1) == 1;
|
|
||||||
pulseInfoInvalid = ((alarmFlags >> 1) & 1) == 1;
|
|
||||||
|
|
||||||
byte byte19 = encoded[19];
|
|
||||||
byte byte20 = encoded[20];
|
|
||||||
podStatusWhenAlarmOccurred = PodStatus.byValue((byte) (byte19 & 0x0f));
|
|
||||||
immediateBolusWhenAlarmOccurred = ((byte19 >> 4) & 1) == 1;
|
|
||||||
occlusionType = (byte) ((byte19 >> 5) & 3);
|
|
||||||
occurredWhenFetchingImmediateBolusActiveInformation = ((byte19 >> 7) & 1) == 1;
|
|
||||||
rssi = (short) (byte20 & 0x3f);
|
|
||||||
receiverLowerGain = (short) ((byte20 >> 6) & 0x03);
|
|
||||||
podStatusWhenAlarmOccurred2 = PodStatus.byValue((byte) (encoded[21] & 0x0f));
|
|
||||||
returnAddressOfPodAlarmHandlerCaller = ByteBuffer.wrap(new byte[]{encoded[22], encoded[23]}).getShort();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getMessageType() {
|
|
||||||
return messageType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getMessageLength() {
|
|
||||||
return messageLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getAdditionalStatusResponseType() {
|
|
||||||
return additionalStatusResponseType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PodStatus getPodStatus() {
|
|
||||||
return podStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DeliveryStatus getDeliveryStatus() {
|
|
||||||
return deliveryStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getBolusPulsesRemaining() {
|
|
||||||
return bolusPulsesRemaining;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getSequenceNumberOfLastProgrammingCommand() {
|
|
||||||
return sequenceNumberOfLastProgrammingCommand;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getTotalPulsesDelivered() {
|
|
||||||
return totalPulsesDelivered;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AlarmType getAlarmType() {
|
|
||||||
return alarmType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getAlarmTime() {
|
|
||||||
return alarmTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getReservoirPulsesRemaining() {
|
|
||||||
return reservoirPulsesRemaining;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getMinutesSinceActivation() {
|
|
||||||
return minutesSinceActivation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAlert0Active() {
|
|
||||||
return alert0Active;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAlert1Active() {
|
|
||||||
return alert1Active;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAlert2Active() {
|
|
||||||
return alert2Active;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAlert3Active() {
|
|
||||||
return alert3Active;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAlert4Active() {
|
|
||||||
return alert4Active;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAlert5Active() {
|
|
||||||
return alert5Active;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAlert6Active() {
|
|
||||||
return alert6Active;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAlert7Active() {
|
|
||||||
return alert7Active;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOcclusionAlarm() {
|
|
||||||
return occlusionAlarm;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPulseInfoInvalid() {
|
|
||||||
return pulseInfoInvalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PodStatus getPodStatusWhenAlarmOccurred() {
|
|
||||||
return podStatusWhenAlarmOccurred;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isImmediateBolusWhenAlarmOccurred() {
|
|
||||||
return immediateBolusWhenAlarmOccurred;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getOcclusionType() {
|
|
||||||
return occlusionType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOccurredWhenFetchingImmediateBolusActiveInformation() {
|
|
||||||
return occurredWhenFetchingImmediateBolusActiveInformation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getRssi() {
|
|
||||||
return rssi;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getReceiverLowerGain() {
|
|
||||||
return receiverLowerGain;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PodStatus getPodStatusWhenAlarmOccurred2() {
|
|
||||||
return podStatusWhenAlarmOccurred2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getReturnAddressOfPodAlarmHandlerCaller() {
|
|
||||||
return returnAddressOfPodAlarmHandlerCaller;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String toString() {
|
|
||||||
return "AlarmStatusResponse{" +
|
|
||||||
"messageType=" + messageType +
|
|
||||||
", messageLength=" + messageLength +
|
|
||||||
", additionalStatusResponseType=" + additionalStatusResponseType +
|
|
||||||
", podStatus=" + podStatus +
|
|
||||||
", deliveryStatus=" + deliveryStatus +
|
|
||||||
", bolusPulsesRemaining=" + bolusPulsesRemaining +
|
|
||||||
", sequenceNumberOfLastProgrammingCommand=" + sequenceNumberOfLastProgrammingCommand +
|
|
||||||
", totalPulsesDelivered=" + totalPulsesDelivered +
|
|
||||||
", alarmType=" + alarmType +
|
|
||||||
", alarmTime=" + alarmTime +
|
|
||||||
", reservoirPulsesRemaining=" + reservoirPulsesRemaining +
|
|
||||||
", minutesSinceActivation=" + minutesSinceActivation +
|
|
||||||
", alert0Active=" + alert0Active +
|
|
||||||
", alert1Active=" + alert1Active +
|
|
||||||
", alert2Active=" + alert2Active +
|
|
||||||
", alert3Active=" + alert3Active +
|
|
||||||
", alert4Active=" + alert4Active +
|
|
||||||
", alert5Active=" + alert5Active +
|
|
||||||
", alert6Active=" + alert6Active +
|
|
||||||
", alert7Active=" + alert7Active +
|
|
||||||
", occlusionAlarm=" + occlusionAlarm +
|
|
||||||
", pulseInfoInvalid=" + pulseInfoInvalid +
|
|
||||||
", podStatusWhenAlarmOccurred=" + podStatusWhenAlarmOccurred +
|
|
||||||
", immediateBolusWhenAlarmOccurred=" + immediateBolusWhenAlarmOccurred +
|
|
||||||
", occlusionType=" + occlusionType +
|
|
||||||
", occurredWhenFetchingImmediateBolusActiveInformation=" + occurredWhenFetchingImmediateBolusActiveInformation +
|
|
||||||
", rssi=" + rssi +
|
|
||||||
", receiverLowerGain=" + receiverLowerGain +
|
|
||||||
", podStatusWhenAlarmOccurred2=" + podStatusWhenAlarmOccurred2 +
|
|
||||||
", returnAddressOfPodAlarmHandlerCaller=" + returnAddressOfPodAlarmHandlerCaller +
|
|
||||||
", statusResponseType=" + statusResponseType +
|
|
||||||
", responseType=" + responseType +
|
|
||||||
", encoded=" + Arrays.toString(encoded) +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,243 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.*
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.ResponseType.AdditionalStatusResponseType
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.experimental.and
|
||||||
|
|
||||||
|
class AlarmStatusResponse(encoded: ByteArray) : AdditionalStatusResponseBase(AdditionalStatusResponseType.ALARM_STATUS, encoded) {
|
||||||
|
|
||||||
|
private val messageType: Byte
|
||||||
|
private val messageLength: Short
|
||||||
|
private val additionalStatusResponseType: Byte
|
||||||
|
private val podStatus: PodStatus
|
||||||
|
private val deliveryStatus: DeliveryStatus
|
||||||
|
private val bolusPulsesRemaining: Short
|
||||||
|
private val sequenceNumberOfLastProgrammingCommand: Short
|
||||||
|
private val totalPulsesDelivered: Short
|
||||||
|
private val alarmType: AlarmType
|
||||||
|
private val alarmTime: Short
|
||||||
|
private val reservoirPulsesRemaining: Short
|
||||||
|
private val minutesSinceActivation: Short
|
||||||
|
private val alert0Active: Boolean
|
||||||
|
private val alert1Active: Boolean
|
||||||
|
private val alert2Active: Boolean
|
||||||
|
private val alert3Active: Boolean
|
||||||
|
private val alert4Active: Boolean
|
||||||
|
private val alert5Active: Boolean
|
||||||
|
private val alert6Active: Boolean
|
||||||
|
private val alert7Active: Boolean
|
||||||
|
private val occlusionAlarm: Boolean
|
||||||
|
private val pulseInfoInvalid: Boolean
|
||||||
|
private val podStatusWhenAlarmOccurred: PodStatus
|
||||||
|
private val immediateBolusWhenAlarmOccurred: Boolean
|
||||||
|
private val occlusionType: Byte
|
||||||
|
private val occurredWhenFetchingImmediateBolusActiveInformation: Boolean
|
||||||
|
private val rssi: Short
|
||||||
|
private val receiverLowerGain: Short
|
||||||
|
private val podStatusWhenAlarmOccurred2: PodStatus
|
||||||
|
private val returnAddressOfPodAlarmHandlerCaller: Short
|
||||||
|
fun getMessageType(): Byte {
|
||||||
|
return messageType
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMessageLength(): Short {
|
||||||
|
return messageLength
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAdditionalStatusResponseType(): Byte {
|
||||||
|
return additionalStatusResponseType
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPodStatus(): PodStatus {
|
||||||
|
return podStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDeliveryStatus(): DeliveryStatus {
|
||||||
|
return deliveryStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBolusPulsesRemaining(): Short {
|
||||||
|
return bolusPulsesRemaining
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSequenceNumberOfLastProgrammingCommand(): Short {
|
||||||
|
return sequenceNumberOfLastProgrammingCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getTotalPulsesDelivered(): Short {
|
||||||
|
return totalPulsesDelivered
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAlarmType(): AlarmType {
|
||||||
|
return alarmType
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAlarmTime(): Short {
|
||||||
|
return alarmTime
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getReservoirPulsesRemaining(): Short {
|
||||||
|
return reservoirPulsesRemaining
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMinutesSinceActivation(): Short {
|
||||||
|
return minutesSinceActivation
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isAlert0Active(): Boolean {
|
||||||
|
return alert0Active
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isAlert1Active(): Boolean {
|
||||||
|
return alert1Active
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isAlert2Active(): Boolean {
|
||||||
|
return alert2Active
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isAlert3Active(): Boolean {
|
||||||
|
return alert3Active
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isAlert4Active(): Boolean {
|
||||||
|
return alert4Active
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isAlert5Active(): Boolean {
|
||||||
|
return alert5Active
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isAlert6Active(): Boolean {
|
||||||
|
return alert6Active
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isAlert7Active(): Boolean {
|
||||||
|
return alert7Active
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isOcclusionAlarm(): Boolean {
|
||||||
|
return occlusionAlarm
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isPulseInfoInvalid(): Boolean {
|
||||||
|
return pulseInfoInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPodStatusWhenAlarmOccurred(): PodStatus {
|
||||||
|
return podStatusWhenAlarmOccurred
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isImmediateBolusWhenAlarmOccurred(): Boolean {
|
||||||
|
return immediateBolusWhenAlarmOccurred
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getOcclusionType(): Byte {
|
||||||
|
return occlusionType
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isOccurredWhenFetchingImmediateBolusActiveInformation(): Boolean {
|
||||||
|
return occurredWhenFetchingImmediateBolusActiveInformation
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getRssi(): Short {
|
||||||
|
return rssi
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getReceiverLowerGain(): Short {
|
||||||
|
return receiverLowerGain
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPodStatusWhenAlarmOccurred2(): PodStatus {
|
||||||
|
return podStatusWhenAlarmOccurred2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getReturnAddressOfPodAlarmHandlerCaller(): Short {
|
||||||
|
return returnAddressOfPodAlarmHandlerCaller
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "AlarmStatusResponse{" +
|
||||||
|
"messageType=" + messageType +
|
||||||
|
", messageLength=" + messageLength +
|
||||||
|
", additionalStatusResponseType=" + additionalStatusResponseType +
|
||||||
|
", podStatus=" + podStatus +
|
||||||
|
", deliveryStatus=" + deliveryStatus +
|
||||||
|
", bolusPulsesRemaining=" + bolusPulsesRemaining +
|
||||||
|
", sequenceNumberOfLastProgrammingCommand=" + sequenceNumberOfLastProgrammingCommand +
|
||||||
|
", totalPulsesDelivered=" + totalPulsesDelivered +
|
||||||
|
", alarmType=" + alarmType +
|
||||||
|
", alarmTime=" + alarmTime +
|
||||||
|
", reservoirPulsesRemaining=" + reservoirPulsesRemaining +
|
||||||
|
", minutesSinceActivation=" + minutesSinceActivation +
|
||||||
|
", alert0Active=" + alert0Active +
|
||||||
|
", alert1Active=" + alert1Active +
|
||||||
|
", alert2Active=" + alert2Active +
|
||||||
|
", alert3Active=" + alert3Active +
|
||||||
|
", alert4Active=" + alert4Active +
|
||||||
|
", alert5Active=" + alert5Active +
|
||||||
|
", alert6Active=" + alert6Active +
|
||||||
|
", alert7Active=" + alert7Active +
|
||||||
|
", occlusionAlarm=" + occlusionAlarm +
|
||||||
|
", pulseInfoInvalid=" + pulseInfoInvalid +
|
||||||
|
", podStatusWhenAlarmOccurred=" + podStatusWhenAlarmOccurred +
|
||||||
|
", immediateBolusWhenAlarmOccurred=" + immediateBolusWhenAlarmOccurred +
|
||||||
|
", occlusionType=" + occlusionType +
|
||||||
|
", occurredWhenFetchingImmediateBolusActiveInformation=" + occurredWhenFetchingImmediateBolusActiveInformation +
|
||||||
|
", rssi=" + rssi +
|
||||||
|
", receiverLowerGain=" + receiverLowerGain +
|
||||||
|
", podStatusWhenAlarmOccurred2=" + podStatusWhenAlarmOccurred2 +
|
||||||
|
", returnAddressOfPodAlarmHandlerCaller=" + returnAddressOfPodAlarmHandlerCaller +
|
||||||
|
", statusResponseType=" + statusResponseType +
|
||||||
|
", responseType=" + responseType +
|
||||||
|
", encoded=" + Arrays.toString(encoded) +
|
||||||
|
'}'
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
messageType = encoded[0]
|
||||||
|
messageLength = (encoded[1].toInt() and 0xff).toShort()
|
||||||
|
additionalStatusResponseType = encoded[2]
|
||||||
|
podStatus = PodStatus.byValue((encoded[3] and 0x0f))
|
||||||
|
deliveryStatus = DeliveryStatus.Companion.byValue((encoded[4] and 0x0f))
|
||||||
|
bolusPulsesRemaining = (ByteBuffer.wrap(byteArrayOf(encoded[5], encoded[6])).short and 2047)
|
||||||
|
sequenceNumberOfLastProgrammingCommand = (encoded[7] and 0x0f).toShort()
|
||||||
|
totalPulsesDelivered = ByteBuffer.wrap(byteArrayOf(encoded[8], encoded[9])).short
|
||||||
|
alarmType = AlarmType.Companion.byValue(encoded[10])
|
||||||
|
alarmTime = ByteBuffer.wrap(byteArrayOf(encoded[11], encoded[12])).short
|
||||||
|
reservoirPulsesRemaining = ByteBuffer.wrap(byteArrayOf(encoded[13], encoded[14])).short
|
||||||
|
minutesSinceActivation = ByteBuffer.wrap(byteArrayOf(encoded[15], encoded[16])).short
|
||||||
|
val activeAlerts = encoded[17].toInt() // TODO: toInt()?
|
||||||
|
alert0Active = activeAlerts and 1 == 1
|
||||||
|
alert1Active = activeAlerts ushr 1 and 1 == 1
|
||||||
|
alert2Active = activeAlerts ushr 2 and 1 == 1
|
||||||
|
alert3Active = activeAlerts ushr 3 and 1 == 1
|
||||||
|
alert4Active = activeAlerts ushr 4 and 1 == 1
|
||||||
|
alert5Active = activeAlerts ushr 5 and 1 == 1
|
||||||
|
alert6Active = activeAlerts ushr 6 and 1 == 1
|
||||||
|
alert7Active = activeAlerts ushr 7 and 1 == 1
|
||||||
|
val alarmFlags = encoded[18]
|
||||||
|
occlusionAlarm = (alarmFlags.toInt() and 1) == 1
|
||||||
|
pulseInfoInvalid = alarmFlags shr 1 and 1 == 1
|
||||||
|
val byte19 = encoded[19]
|
||||||
|
val byte20 = encoded[20]
|
||||||
|
podStatusWhenAlarmOccurred = PodStatus.byValue((byte19 and 0x0f))
|
||||||
|
immediateBolusWhenAlarmOccurred = byte19 shr 4 and 1 == 1
|
||||||
|
occlusionType = ((byte19 shr 5 and 3).toByte())
|
||||||
|
occurredWhenFetchingImmediateBolusActiveInformation = byte19 shr 7 and 1 == 1
|
||||||
|
rssi = (byte20 and 0x3f).toShort()
|
||||||
|
receiverLowerGain = ((byte20 shr 6 and 0x03).toShort())
|
||||||
|
podStatusWhenAlarmOccurred2 = PodStatus.byValue((encoded[21] and 0x0f))
|
||||||
|
returnAddressOfPodAlarmHandlerCaller = ByteBuffer.wrap(byteArrayOf(encoded[22], encoded[23])).short
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO autoconvert to Int ok?
|
||||||
|
private infix fun Byte.ushr(i: Int) = toInt() ushr i
|
||||||
|
private infix fun Short.shr(i: Int): Int = toInt() shr i
|
||||||
|
private infix fun Byte.shl(i: Int): Int = toInt() shl i
|
||||||
|
private infix fun Byte.shr(i: Int): Int = toInt() shr i
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,136 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.DeliveryStatus;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus;
|
|
||||||
|
|
||||||
public class DefaultStatusResponse extends ResponseBase {
|
|
||||||
private final byte messageType;
|
|
||||||
private final DeliveryStatus deliveryStatus;
|
|
||||||
private final PodStatus podStatus;
|
|
||||||
private final short totalPulsesDelivered;
|
|
||||||
private final short sequenceNumberOfLastProgrammingCommand;
|
|
||||||
private final short bolusPulsesRemaining;
|
|
||||||
private final boolean occlusionAlertActive;
|
|
||||||
private final boolean alert1Active;
|
|
||||||
private final boolean alert2Active;
|
|
||||||
private final boolean alert3Active;
|
|
||||||
private final boolean alert4Active;
|
|
||||||
private final boolean alert5Active;
|
|
||||||
private final boolean alert6Active;
|
|
||||||
private final boolean alert7Active;
|
|
||||||
private final short minutesSinceActivation;
|
|
||||||
private final short reservoirPulsesRemaining;
|
|
||||||
|
|
||||||
public DefaultStatusResponse(byte[] encoded) {
|
|
||||||
super(ResponseType.DEFAULT_STATUS_RESPONSE, encoded);
|
|
||||||
|
|
||||||
messageType = encoded[0];
|
|
||||||
deliveryStatus = DeliveryStatus.byValue((byte) ((encoded[1] >> 4) & 0x0f));
|
|
||||||
podStatus = PodStatus.byValue((byte) (encoded[1] & 0x0f));
|
|
||||||
totalPulsesDelivered = (short) (((encoded[2] & 0x0f) << 12) | ((encoded[3] & 0xff) << 1) | ((encoded[4] & 0xff) >>> 7));
|
|
||||||
sequenceNumberOfLastProgrammingCommand = (byte) ((encoded[4] >>> 3) & 0x0f);
|
|
||||||
bolusPulsesRemaining = (short) ((((encoded[4] & 0x07) << 10) | (encoded[5] & 0xff)) & 2047);
|
|
||||||
|
|
||||||
short activeAlerts = (short) (((encoded[6] & 0xff) << 1) | (encoded[7] >>> 7));
|
|
||||||
occlusionAlertActive = (activeAlerts & 1) == 1;
|
|
||||||
alert1Active = ((activeAlerts >> 1) & 1) == 1;
|
|
||||||
alert2Active = ((activeAlerts >> 2) & 1) == 1;
|
|
||||||
alert3Active = ((activeAlerts >> 3) & 1) == 1;
|
|
||||||
alert4Active = ((activeAlerts >> 4) & 1) == 1;
|
|
||||||
alert5Active = ((activeAlerts >> 5) & 1) == 1;
|
|
||||||
alert6Active = ((activeAlerts >> 6) & 1) == 1;
|
|
||||||
alert7Active = ((activeAlerts >> 7) & 1) == 1;
|
|
||||||
|
|
||||||
minutesSinceActivation = (short) (((encoded[7] & 0x7f) << 6) | (((encoded[8] & 0xff) >>> 2) & 0x3f));
|
|
||||||
reservoirPulsesRemaining = (short) (((encoded[8] << 8) | encoded[9]) & 0x3ff);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getMessageType() {
|
|
||||||
return messageType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DeliveryStatus getDeliveryStatus() {
|
|
||||||
return deliveryStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PodStatus getPodStatus() {
|
|
||||||
return podStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getTotalPulsesDelivered() {
|
|
||||||
return totalPulsesDelivered;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getSequenceNumberOfLastProgrammingCommand() {
|
|
||||||
return sequenceNumberOfLastProgrammingCommand;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getBolusPulsesRemaining() {
|
|
||||||
return bolusPulsesRemaining;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOcclusionAlertActive() {
|
|
||||||
return occlusionAlertActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAlert1Active() {
|
|
||||||
return alert1Active;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAlert2Active() {
|
|
||||||
return alert2Active;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAlert3Active() {
|
|
||||||
return alert3Active;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAlert4Active() {
|
|
||||||
return alert4Active;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAlert5Active() {
|
|
||||||
return alert5Active;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAlert6Active() {
|
|
||||||
return alert6Active;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAlert7Active() {
|
|
||||||
return alert7Active;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getMinutesSinceActivation() {
|
|
||||||
return minutesSinceActivation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getReservoirPulsesRemaining() {
|
|
||||||
return reservoirPulsesRemaining;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String toString() {
|
|
||||||
return "DefaultStatusResponse{" +
|
|
||||||
"messageType=" + messageType +
|
|
||||||
", deliveryStatus=" + deliveryStatus +
|
|
||||||
", podStatus=" + podStatus +
|
|
||||||
", totalPulsesDelivered=" + totalPulsesDelivered +
|
|
||||||
", sequenceNumberOfLastProgrammingCommand=" + sequenceNumberOfLastProgrammingCommand +
|
|
||||||
", bolusPulsesRemaining=" + bolusPulsesRemaining +
|
|
||||||
", occlusionAlertActive=" + occlusionAlertActive +
|
|
||||||
", alert1Active=" + alert1Active +
|
|
||||||
", alert2Active=" + alert2Active +
|
|
||||||
", alert3Active=" + alert3Active +
|
|
||||||
", alert4Active=" + alert4Active +
|
|
||||||
", alert5Active=" + alert5Active +
|
|
||||||
", alert6Active=" + alert6Active +
|
|
||||||
", alert7Active=" + alert7Active +
|
|
||||||
", minutesSinceActivation=" + minutesSinceActivation +
|
|
||||||
", reservoirPulsesRemaining=" + reservoirPulsesRemaining +
|
|
||||||
", responseType=" + responseType +
|
|
||||||
", encoded=" + Arrays.toString(encoded) +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.DeliveryStatus
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus
|
||||||
|
import kotlin.experimental.and
|
||||||
|
|
||||||
|
class DefaultStatusResponse(encoded: ByteArray) : ResponseBase(ResponseType.DEFAULT_STATUS_RESPONSE, encoded) {
|
||||||
|
|
||||||
|
// TODO: Here is a lot of bitshifting that had to be changed. we should go over it.
|
||||||
|
private val messageType: Byte = encoded[0]
|
||||||
|
private val deliveryStatus: DeliveryStatus = DeliveryStatus.byValue((encoded[1].toInt() shr 4 and 0x0f).toByte())
|
||||||
|
private val podStatus: PodStatus = PodStatus.Companion.byValue((encoded[1] and 0x0f) as Byte)
|
||||||
|
private val totalPulsesDelivered: Short = ((encoded[2] and 0x0f shl 12 or (encoded[3].toInt() and 0xff shl 1) or (encoded[4].toInt() and 0xff ushr 7)).toShort())
|
||||||
|
private val sequenceNumberOfLastProgrammingCommand: Short = (encoded[4] ushr 3 and 0x0f).toShort()
|
||||||
|
private val bolusPulsesRemaining: Short = ((encoded[4] and 0x07 shl 10 or (encoded[5].toInt() and 0xff) and 2047).toShort())
|
||||||
|
private val activeAlerts = (encoded[6].toInt() and 0xff shl 1 or (encoded[7] ushr 7)).toShort()
|
||||||
|
private val occlusionAlertActive: Boolean = (activeAlerts and 1).toInt() == 1
|
||||||
|
private val alert1Active: Boolean = activeAlerts shr 1 and 1 == 1
|
||||||
|
private val alert2Active: Boolean = activeAlerts shr 2 and 1 == 1
|
||||||
|
private val alert3Active: Boolean = activeAlerts shr 3 and 1 == 1
|
||||||
|
private val alert4Active: Boolean = activeAlerts shr 4 and 1 == 1
|
||||||
|
private val alert5Active: Boolean = activeAlerts shr 5 and 1 == 1
|
||||||
|
private val alert6Active: Boolean = activeAlerts shr 6 and 1 == 1
|
||||||
|
private val alert7Active: Boolean = activeAlerts shr 7 and 1 == 1
|
||||||
|
private val minutesSinceActivation: Short = (encoded[7] and 0x7f shl 6 or (encoded[8].toInt() and 0xff ushr 2 and 0x3f)).toShort()
|
||||||
|
private val reservoirPulsesRemaining: Short = (encoded[8] shl 8 or encoded[9].toInt() and 0x3ff).toShort()
|
||||||
|
fun getMessageType(): Byte {
|
||||||
|
return messageType
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDeliveryStatus(): DeliveryStatus {
|
||||||
|
return deliveryStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPodStatus(): PodStatus {
|
||||||
|
return podStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getTotalPulsesDelivered(): Short {
|
||||||
|
return totalPulsesDelivered
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSequenceNumberOfLastProgrammingCommand(): Short {
|
||||||
|
return sequenceNumberOfLastProgrammingCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBolusPulsesRemaining(): Short {
|
||||||
|
return bolusPulsesRemaining
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isOcclusionAlertActive(): Boolean {
|
||||||
|
return occlusionAlertActive
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isAlert1Active(): Boolean {
|
||||||
|
return alert1Active
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isAlert2Active(): Boolean {
|
||||||
|
return alert2Active
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isAlert3Active(): Boolean {
|
||||||
|
return alert3Active
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isAlert4Active(): Boolean {
|
||||||
|
return alert4Active
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isAlert5Active(): Boolean {
|
||||||
|
return alert5Active
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isAlert6Active(): Boolean {
|
||||||
|
return alert6Active
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isAlert7Active(): Boolean {
|
||||||
|
return alert7Active
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMinutesSinceActivation(): Short {
|
||||||
|
return minutesSinceActivation
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getReservoirPulsesRemaining(): Short {
|
||||||
|
return reservoirPulsesRemaining
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "DefaultStatusResponse{" +
|
||||||
|
"messageType=" + messageType +
|
||||||
|
", deliveryStatus=" + deliveryStatus +
|
||||||
|
", podStatus=" + podStatus +
|
||||||
|
", totalPulsesDelivered=" + totalPulsesDelivered +
|
||||||
|
", sequenceNumberOfLastProgrammingCommand=" + sequenceNumberOfLastProgrammingCommand +
|
||||||
|
", bolusPulsesRemaining=" + bolusPulsesRemaining +
|
||||||
|
", occlusionAlertActive=" + occlusionAlertActive +
|
||||||
|
", alert1Active=" + alert1Active +
|
||||||
|
", alert2Active=" + alert2Active +
|
||||||
|
", alert3Active=" + alert3Active +
|
||||||
|
", alert4Active=" + alert4Active +
|
||||||
|
", alert5Active=" + alert5Active +
|
||||||
|
", alert6Active=" + alert6Active +
|
||||||
|
", alert7Active=" + alert7Active +
|
||||||
|
", minutesSinceActivation=" + minutesSinceActivation +
|
||||||
|
", reservoirPulsesRemaining=" + reservoirPulsesRemaining +
|
||||||
|
", responseType=" + responseType +
|
||||||
|
", encoded=" + encoded.contentToString() +
|
||||||
|
'}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO autoconvert to Int ok?
|
||||||
|
private infix fun Byte.ushr(i: Int) = toInt() ushr i
|
||||||
|
private infix fun Short.shr(i: Int): Int = toInt() shr i
|
||||||
|
private infix fun Byte.shl(i: Int): Int = toInt() shl i
|
|
@ -1,71 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlarmType;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.NakErrorType;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus;
|
|
||||||
|
|
||||||
public class NakResponse extends ResponseBase {
|
|
||||||
private final byte messageType;
|
|
||||||
private final short messageLength;
|
|
||||||
private final NakErrorType nakErrorType;
|
|
||||||
private final AlarmType alarmType;
|
|
||||||
private final PodStatus podStatus;
|
|
||||||
private final short securityNakSyncCount;
|
|
||||||
|
|
||||||
public NakResponse(byte[] encoded) {
|
|
||||||
super(ResponseType.NAK_RESPONSE, encoded);
|
|
||||||
this.messageType = encoded[0];
|
|
||||||
this.messageLength = encoded[1];
|
|
||||||
this.nakErrorType = NakErrorType.byValue(encoded[2]);
|
|
||||||
byte byte3 = encoded[3];
|
|
||||||
byte byte4 = encoded[4];
|
|
||||||
if (nakErrorType == NakErrorType.ILLEGAL_SECURITY_CODE) {
|
|
||||||
this.securityNakSyncCount = (short) ((byte3 << 8) | byte4);
|
|
||||||
this.alarmType = null;
|
|
||||||
this.podStatus = null;
|
|
||||||
} else {
|
|
||||||
this.securityNakSyncCount = 0;
|
|
||||||
this.alarmType = AlarmType.byValue(byte3);
|
|
||||||
this.podStatus = PodStatus.byValue(byte4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getMessageType() {
|
|
||||||
return messageType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getMessageLength() {
|
|
||||||
return messageLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
public NakErrorType getNakErrorType() {
|
|
||||||
return nakErrorType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AlarmType getAlarmType() {
|
|
||||||
return alarmType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PodStatus getPodStatus() {
|
|
||||||
return podStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getSecurityNakSyncCount() {
|
|
||||||
return securityNakSyncCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String toString() {
|
|
||||||
return "NakResponse{" +
|
|
||||||
"messageType=" + messageType +
|
|
||||||
", messageLength=" + messageLength +
|
|
||||||
", nakErrorType=" + nakErrorType +
|
|
||||||
", alarmType=" + alarmType +
|
|
||||||
", podStatus=" + podStatus +
|
|
||||||
", securityNakSyncCount=" + securityNakSyncCount +
|
|
||||||
", responseType=" + responseType +
|
|
||||||
", encoded=" + Arrays.toString(encoded) +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlarmType
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.NakErrorType
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class NakResponse(encoded: ByteArray) : ResponseBase(ResponseType.NAK_RESPONSE, encoded) {
|
||||||
|
|
||||||
|
private val messageType: Byte // TODO directly assign here
|
||||||
|
private val messageLength: Short
|
||||||
|
private val nakErrorType: NakErrorType
|
||||||
|
private var alarmType: AlarmType? = null
|
||||||
|
private var podStatus: PodStatus? = null
|
||||||
|
private var securityNakSyncCount: Short = 0
|
||||||
|
fun getMessageType(): Byte {
|
||||||
|
return messageType
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMessageLength(): Short {
|
||||||
|
return messageLength
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getNakErrorType(): NakErrorType { // TODO make public, a val cannot be reassigned, same for other Responses
|
||||||
|
return nakErrorType
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAlarmType(): AlarmType? {
|
||||||
|
return alarmType
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPodStatus(): PodStatus? {
|
||||||
|
return podStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSecurityNakSyncCount(): Short {
|
||||||
|
return securityNakSyncCount
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "NakResponse{" +
|
||||||
|
"messageType=" + messageType +
|
||||||
|
", messageLength=" + messageLength +
|
||||||
|
", nakErrorType=" + nakErrorType +
|
||||||
|
", alarmType=" + alarmType +
|
||||||
|
", podStatus=" + podStatus +
|
||||||
|
", securityNakSyncCount=" + securityNakSyncCount +
|
||||||
|
", responseType=" + responseType +
|
||||||
|
", encoded=" + encoded.contentToString() +
|
||||||
|
'}'
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
messageType = encoded[0]
|
||||||
|
messageLength = encoded[1].toShort()
|
||||||
|
nakErrorType = NakErrorType.Companion.byValue(encoded[2])
|
||||||
|
val byte3 = encoded[3]
|
||||||
|
val byte4 = encoded[4]
|
||||||
|
if (nakErrorType == NakErrorType.ILLEGAL_SECURITY_CODE) {
|
||||||
|
securityNakSyncCount = ((byte3.toInt() shl 8 or byte4.toInt()).toShort()) // TODO: toInt()
|
||||||
|
alarmType = null
|
||||||
|
podStatus = null
|
||||||
|
} else {
|
||||||
|
securityNakSyncCount = 0
|
||||||
|
alarmType = AlarmType.byValue(byte3)
|
||||||
|
podStatus = PodStatus.byValue(byte4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response;
|
|
||||||
|
|
||||||
public interface Response {
|
|
||||||
ResponseType getResponseType();
|
|
||||||
|
|
||||||
byte[] getEncoded();
|
|
||||||
}
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response
|
||||||
|
|
||||||
|
interface Response {
|
||||||
|
|
||||||
|
val responseType: ResponseType
|
||||||
|
val encoded: ByteArray
|
||||||
|
}
|
|
@ -1,22 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
abstract class ResponseBase implements Response {
|
|
||||||
final ResponseType responseType;
|
|
||||||
final byte[] encoded;
|
|
||||||
|
|
||||||
ResponseBase(ResponseType responseType, byte[] encoded) {
|
|
||||||
this.responseType = responseType;
|
|
||||||
this.encoded = Arrays.copyOf(encoded, encoded.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public ResponseType getResponseType() {
|
|
||||||
return responseType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] getEncoded() {
|
|
||||||
return encoded;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response
|
||||||
|
|
||||||
|
abstract class ResponseBase(override val responseType: ResponseType, encoded: ByteArray) : Response {
|
||||||
|
|
||||||
|
override val encoded: ByteArray = encoded.copyOf(encoded.size)
|
||||||
|
|
||||||
|
}
|
|
@ -1,80 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response;
|
|
||||||
|
|
||||||
public enum ResponseType {
|
|
||||||
ACTIVATION_RESPONSE((byte) 0x01),
|
|
||||||
DEFAULT_STATUS_RESPONSE((byte) 0x1d),
|
|
||||||
ADDITIONAL_STATUS_RESPONSE((byte) 0x02),
|
|
||||||
NAK_RESPONSE((byte) 0x06),
|
|
||||||
UNKNOWN((byte) 0xff);
|
|
||||||
|
|
||||||
private byte value;
|
|
||||||
|
|
||||||
ResponseType(byte value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ResponseType byValue(byte value) {
|
|
||||||
for (ResponseType type : values()) {
|
|
||||||
if (type.value == value) {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum AdditionalStatusResponseType {
|
|
||||||
STATUS_RESPONSE_PAGE_1((byte) 0x01),
|
|
||||||
ALARM_STATUS((byte) 0x02),
|
|
||||||
STATUS_RESPONSE_PAGE_3((byte) 0x03),
|
|
||||||
STATUS_RESPONSE_PAGE_5((byte) 0x05),
|
|
||||||
STATUS_RESPONSE_PAGE_6((byte) 0x06),
|
|
||||||
STATUS_RESPONSE_PAGE_70((byte) 0x46),
|
|
||||||
STATUS_RESPONSE_PAGE_80((byte) 0x50),
|
|
||||||
STATUS_RESPONSE_PAGE_81((byte) 0x51),
|
|
||||||
UNKNOWN((byte) 0xff);
|
|
||||||
|
|
||||||
private byte value;
|
|
||||||
|
|
||||||
AdditionalStatusResponseType(byte value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AdditionalStatusResponseType byValue(byte value) {
|
|
||||||
for (AdditionalStatusResponseType type : values()) {
|
|
||||||
if (type.value == value) {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ActivationResponseType {
|
|
||||||
GET_VERSION_RESPONSE((byte) 0x15),
|
|
||||||
SET_UNIQUE_ID_RESPONSE((byte) 0x1b),
|
|
||||||
UNKNOWN((byte) 0xff);
|
|
||||||
|
|
||||||
private byte length;
|
|
||||||
|
|
||||||
ActivationResponseType(byte length) {
|
|
||||||
this.length = length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ActivationResponseType byLength(byte length) {
|
|
||||||
for (ActivationResponseType type : values()) {
|
|
||||||
if (type.length == length) {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return UNKNOWN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response
|
||||||
|
|
||||||
|
enum class ResponseType(private val value: Byte) {
|
||||||
|
ACTIVATION_RESPONSE(0x01.toByte()), DEFAULT_STATUS_RESPONSE(0x1d.toByte()), ADDITIONAL_STATUS_RESPONSE(0x02.toByte()), NAK_RESPONSE(0x06.toByte()), UNKNOWN(0xff.toByte());
|
||||||
|
|
||||||
|
fun getValue(): Byte {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class AdditionalStatusResponseType(private val value: Byte) {
|
||||||
|
STATUS_RESPONSE_PAGE_1(0x01.toByte()), ALARM_STATUS(0x02.toByte()), STATUS_RESPONSE_PAGE_3(0x03.toByte()), STATUS_RESPONSE_PAGE_5(0x05.toByte()), STATUS_RESPONSE_PAGE_6(0x06.toByte()), STATUS_RESPONSE_PAGE_70(0x46.toByte()), STATUS_RESPONSE_PAGE_80(0x50.toByte()), STATUS_RESPONSE_PAGE_81(0x51.toByte()), UNKNOWN(0xff.toByte());
|
||||||
|
|
||||||
|
fun getValue(): Byte {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun byValue(value: Byte): AdditionalStatusResponseType {
|
||||||
|
for (type in values()) {
|
||||||
|
if (type.value == value) {
|
||||||
|
return type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class ActivationResponseType(private val length: Byte) {
|
||||||
|
GET_VERSION_RESPONSE(0x15.toByte()), SET_UNIQUE_ID_RESPONSE(0x1b.toByte()), UNKNOWN(0xff.toByte());
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun byLength(length: Byte): ActivationResponseType {
|
||||||
|
for (type in values()) {
|
||||||
|
if (type.length == length) {
|
||||||
|
return type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun byValue(value: Byte): ResponseType {
|
||||||
|
for (type in values()) {
|
||||||
|
if (type.value == value) {
|
||||||
|
return type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,155 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus;
|
|
||||||
|
|
||||||
public final class SetUniqueIdResponse extends ActivationResponseBase {
|
|
||||||
private byte messageType;
|
|
||||||
private short messageLength;
|
|
||||||
private short pulseVolumeInTenThousandthMicroLiter;
|
|
||||||
private short pumpRate;
|
|
||||||
private short primePumpRate;
|
|
||||||
private short numberOfEngagingClutchDrivePulses;
|
|
||||||
private short numberOfPrimePulses;
|
|
||||||
private short podExpirationTimeInHours;
|
|
||||||
private short firmwareVersionMajor;
|
|
||||||
private short firmwareVersionMinor;
|
|
||||||
private short firmwareVersionInterim;
|
|
||||||
private short bleVersionMajor;
|
|
||||||
private short bleVersionMinor;
|
|
||||||
private short bleVersionInterim;
|
|
||||||
private short productId;
|
|
||||||
private PodStatus podStatus;
|
|
||||||
private long lotNumber;
|
|
||||||
private long podSequenceNumber;
|
|
||||||
private long uniqueIdReceivedInCommand;
|
|
||||||
|
|
||||||
public SetUniqueIdResponse(byte[] encoded) {
|
|
||||||
super(ResponseType.ActivationResponseType.SET_UNIQUE_ID_RESPONSE, encoded);
|
|
||||||
|
|
||||||
messageType = encoded[0];
|
|
||||||
messageLength = (short) (encoded[1] & 0xff);
|
|
||||||
pulseVolumeInTenThousandthMicroLiter = ByteBuffer.wrap(new byte[]{encoded[2], encoded[3]}).getShort();
|
|
||||||
pumpRate = (short) (encoded[4] & 0xff);
|
|
||||||
primePumpRate = (short) (encoded[5] & 0xff);
|
|
||||||
numberOfEngagingClutchDrivePulses = (short) (encoded[6] & 0xff);
|
|
||||||
numberOfPrimePulses = (short) (encoded[7] & 0xff);
|
|
||||||
podExpirationTimeInHours = (short) (encoded[8] & 0xff);
|
|
||||||
firmwareVersionMajor = (short) (encoded[9] & 0xff);
|
|
||||||
firmwareVersionMinor = (short) (encoded[10] & 0xff);
|
|
||||||
firmwareVersionInterim = (short) (encoded[11] & 0xff);
|
|
||||||
bleVersionMajor = (short) (encoded[12] & 0xff);
|
|
||||||
bleVersionMinor = (short) (encoded[13] & 0xff);
|
|
||||||
bleVersionInterim = (short) (encoded[14] & 0xff);
|
|
||||||
productId = (short) (encoded[15] & 0xff);
|
|
||||||
podStatus = PodStatus.byValue(encoded[16]);
|
|
||||||
lotNumber = ByteBuffer.wrap(new byte[]{0, 0, 0, 0, encoded[17], encoded[18], encoded[19], encoded[20]}).getLong();
|
|
||||||
podSequenceNumber = ByteBuffer.wrap(new byte[]{0, 0, 0, 0, encoded[21], encoded[22], encoded[23], encoded[24]}).getLong();
|
|
||||||
uniqueIdReceivedInCommand = ByteBuffer.wrap(new byte[]{0, 0, 0, 0, encoded[25], encoded[26], encoded[27], encoded[28]}).getLong();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getMessageType() {
|
|
||||||
return messageType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getMessageLength() {
|
|
||||||
return messageLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getPulseVolumeInTenThousandthMicroLiter() {
|
|
||||||
return pulseVolumeInTenThousandthMicroLiter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getDeliveryRate() {
|
|
||||||
return pumpRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getPrimeRate() {
|
|
||||||
return primePumpRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getNumberOfEngagingClutchDrivePulses() {
|
|
||||||
return numberOfEngagingClutchDrivePulses;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getNumberOfPrimePulses() {
|
|
||||||
return numberOfPrimePulses;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getPodExpirationTimeInHours() {
|
|
||||||
return podExpirationTimeInHours;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getFirmwareVersionMajor() {
|
|
||||||
return firmwareVersionMajor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getFirmwareVersionMinor() {
|
|
||||||
return firmwareVersionMinor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getFirmwareVersionInterim() {
|
|
||||||
return firmwareVersionInterim;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getBleVersionMajor() {
|
|
||||||
return bleVersionMajor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getBleVersionMinor() {
|
|
||||||
return bleVersionMinor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getBleVersionInterim() {
|
|
||||||
return bleVersionInterim;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getProductId() {
|
|
||||||
return productId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PodStatus getPodStatus() {
|
|
||||||
return podStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getLotNumber() {
|
|
||||||
return lotNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getPodSequenceNumber() {
|
|
||||||
return podSequenceNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getUniqueIdReceivedInCommand() {
|
|
||||||
return uniqueIdReceivedInCommand;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String toString() {
|
|
||||||
return "SetUniqueIdResponse{" +
|
|
||||||
"messageType=" + messageType +
|
|
||||||
", messageLength=" + messageLength +
|
|
||||||
", pulseVolume=" + pulseVolumeInTenThousandthMicroLiter +
|
|
||||||
", pumpRate=" + pumpRate +
|
|
||||||
", primePumpRate=" + primePumpRate +
|
|
||||||
", numberOfEngagingClutchDrivePulses=" + numberOfEngagingClutchDrivePulses +
|
|
||||||
", numberOfPrimePulses=" + numberOfPrimePulses +
|
|
||||||
", podExpirationTimeInHours=" + podExpirationTimeInHours +
|
|
||||||
", softwareVersionMajor=" + firmwareVersionMajor +
|
|
||||||
", softwareVersionMinor=" + firmwareVersionMinor +
|
|
||||||
", softwareVersionInterim=" + firmwareVersionInterim +
|
|
||||||
", bleVersionMajor=" + bleVersionMajor +
|
|
||||||
", bleVersionMinor=" + bleVersionMinor +
|
|
||||||
", bleVersionInterim=" + bleVersionInterim +
|
|
||||||
", productId=" + productId +
|
|
||||||
", podStatus=" + podStatus +
|
|
||||||
", lotNumber=" + lotNumber +
|
|
||||||
", podSequenceNumber=" + podSequenceNumber +
|
|
||||||
", uniqueIdReceivedInCommand=" + uniqueIdReceivedInCommand +
|
|
||||||
", activationResponseType=" + activationResponseType +
|
|
||||||
", responseType=" + responseType +
|
|
||||||
", encoded=" + Arrays.toString(encoded) +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,154 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.ResponseType.ActivationResponseType
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.experimental.and
|
||||||
|
|
||||||
|
class SetUniqueIdResponse(encoded: ByteArray) : ActivationResponseBase(ActivationResponseType.SET_UNIQUE_ID_RESPONSE, encoded) {
|
||||||
|
|
||||||
|
private val messageType: Byte // TODO directly assign here
|
||||||
|
private val messageLength: Short
|
||||||
|
private val pulseVolumeInTenThousandthMicroLiter: Short
|
||||||
|
private val pumpRate: Short
|
||||||
|
private val primePumpRate: Short
|
||||||
|
private val numberOfEngagingClutchDrivePulses: Short
|
||||||
|
private val numberOfPrimePulses: Short
|
||||||
|
private val podExpirationTimeInHours: Short
|
||||||
|
private val firmwareVersionMajor: Short
|
||||||
|
private val firmwareVersionMinor: Short
|
||||||
|
private val firmwareVersionInterim: Short
|
||||||
|
private val bleVersionMajor: Short
|
||||||
|
private val bleVersionMinor: Short
|
||||||
|
private val bleVersionInterim: Short
|
||||||
|
private val productId: Short
|
||||||
|
private val podStatus: PodStatus
|
||||||
|
private val lotNumber: Long
|
||||||
|
private val podSequenceNumber: Long
|
||||||
|
private val uniqueIdReceivedInCommand: Long
|
||||||
|
fun getMessageType(): Byte {
|
||||||
|
return messageType
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMessageLength(): Short { // TODO value getters
|
||||||
|
return messageLength
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPulseVolumeInTenThousandthMicroLiter(): Short {
|
||||||
|
return pulseVolumeInTenThousandthMicroLiter
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDeliveryRate(): Short {
|
||||||
|
return pumpRate
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPrimeRate(): Short {
|
||||||
|
return primePumpRate
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getNumberOfEngagingClutchDrivePulses(): Short {
|
||||||
|
return numberOfEngagingClutchDrivePulses
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getNumberOfPrimePulses(): Short {
|
||||||
|
return numberOfPrimePulses
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPodExpirationTimeInHours(): Short {
|
||||||
|
return podExpirationTimeInHours
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFirmwareVersionMajor(): Short {
|
||||||
|
return firmwareVersionMajor
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFirmwareVersionMinor(): Short {
|
||||||
|
return firmwareVersionMinor
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFirmwareVersionInterim(): Short {
|
||||||
|
return firmwareVersionInterim
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBleVersionMajor(): Short {
|
||||||
|
return bleVersionMajor
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBleVersionMinor(): Short {
|
||||||
|
return bleVersionMinor
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBleVersionInterim(): Short {
|
||||||
|
return bleVersionInterim
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getProductId(): Short {
|
||||||
|
return productId
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPodStatus(): PodStatus {
|
||||||
|
return podStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLotNumber(): Long {
|
||||||
|
return lotNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPodSequenceNumber(): Long {
|
||||||
|
return podSequenceNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getUniqueIdReceivedInCommand(): Long {
|
||||||
|
return uniqueIdReceivedInCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "SetUniqueIdResponse{" +
|
||||||
|
"messageType=" + messageType +
|
||||||
|
", messageLength=" + messageLength +
|
||||||
|
", pulseVolume=" + pulseVolumeInTenThousandthMicroLiter +
|
||||||
|
", pumpRate=" + pumpRate +
|
||||||
|
", primePumpRate=" + primePumpRate +
|
||||||
|
", numberOfEngagingClutchDrivePulses=" + numberOfEngagingClutchDrivePulses +
|
||||||
|
", numberOfPrimePulses=" + numberOfPrimePulses +
|
||||||
|
", podExpirationTimeInHours=" + podExpirationTimeInHours +
|
||||||
|
", softwareVersionMajor=" + firmwareVersionMajor +
|
||||||
|
", softwareVersionMinor=" + firmwareVersionMinor +
|
||||||
|
", softwareVersionInterim=" + firmwareVersionInterim +
|
||||||
|
", bleVersionMajor=" + bleVersionMajor +
|
||||||
|
", bleVersionMinor=" + bleVersionMinor +
|
||||||
|
", bleVersionInterim=" + bleVersionInterim +
|
||||||
|
", productId=" + productId +
|
||||||
|
", podStatus=" + podStatus +
|
||||||
|
", lotNumber=" + lotNumber +
|
||||||
|
", podSequenceNumber=" + podSequenceNumber +
|
||||||
|
", uniqueIdReceivedInCommand=" + uniqueIdReceivedInCommand +
|
||||||
|
", activationResponseType=" + activationResponseType +
|
||||||
|
", responseType=" + responseType +
|
||||||
|
", encoded=" + encoded.contentToString() +
|
||||||
|
'}'
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
messageType = encoded[0]
|
||||||
|
messageLength = (encoded[1].toInt() and 0xff) .toShort()
|
||||||
|
pulseVolumeInTenThousandthMicroLiter = ByteBuffer.wrap(byteArrayOf(encoded[2], encoded[3])).short
|
||||||
|
pumpRate = (encoded[4].toInt() and 0xff) .toShort()
|
||||||
|
primePumpRate = (encoded[5].toInt() and 0xff) .toShort()
|
||||||
|
numberOfEngagingClutchDrivePulses = (encoded[6].toInt() and 0xff) .toShort()
|
||||||
|
numberOfPrimePulses = (encoded[7].toInt() and 0xff) .toShort()
|
||||||
|
podExpirationTimeInHours = (encoded[8].toInt() and 0xff) .toShort()
|
||||||
|
firmwareVersionMajor = (encoded[9].toInt() and 0xff) .toShort()
|
||||||
|
firmwareVersionMinor = (encoded[10].toInt() and 0xff) .toShort()
|
||||||
|
firmwareVersionInterim = (encoded[11].toInt() and 0xff) .toShort()
|
||||||
|
bleVersionMajor = (encoded[12].toInt() and 0xff) .toShort()
|
||||||
|
bleVersionMinor = (encoded[13].toInt() and 0xff) .toShort()
|
||||||
|
bleVersionInterim = (encoded[14].toInt() and 0xff) .toShort()
|
||||||
|
productId = (encoded[15].toInt() and 0xff) .toShort()
|
||||||
|
podStatus = PodStatus.byValue(encoded[16])
|
||||||
|
lotNumber = ByteBuffer.wrap(byteArrayOf(0, 0, 0, 0, encoded[17], encoded[18], encoded[19], encoded[20])).long
|
||||||
|
podSequenceNumber = ByteBuffer.wrap(byteArrayOf(0, 0, 0, 0, encoded[21], encoded[22], encoded[23], encoded[24])).long
|
||||||
|
uniqueIdReceivedInCommand = ByteBuffer.wrap(byteArrayOf(0, 0, 0, 0, encoded[25], encoded[26], encoded[27], encoded[28])).long
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,128 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus;
|
|
||||||
|
|
||||||
public final class VersionResponse extends ActivationResponseBase {
|
|
||||||
|
|
||||||
private final byte messageType;
|
|
||||||
private final short messageLength;
|
|
||||||
private final short firmwareVersionMajor;
|
|
||||||
private final short firmwareVersionMinor;
|
|
||||||
private final short firmwareVersionInterim;
|
|
||||||
private final short bleVersionMajor;
|
|
||||||
private final short bleVersionMinor;
|
|
||||||
private final short bleVersionInterim;
|
|
||||||
private final short productId;
|
|
||||||
private final PodStatus podStatus;
|
|
||||||
private final long lotNumber;
|
|
||||||
private final long podSequenceNumber;
|
|
||||||
private final byte rssi;
|
|
||||||
private final byte receiverLowerGain;
|
|
||||||
private final long uniqueIdReceivedInCommand;
|
|
||||||
|
|
||||||
public VersionResponse(byte[] encoded) {
|
|
||||||
super(ResponseType.ActivationResponseType.GET_VERSION_RESPONSE, encoded);
|
|
||||||
|
|
||||||
messageType = encoded[0];
|
|
||||||
messageLength = (short) (encoded[1] & 0xff);
|
|
||||||
firmwareVersionMajor = (short) (encoded[2] & 0xff);
|
|
||||||
firmwareVersionMinor = (short) (encoded[3] & 0xff);
|
|
||||||
firmwareVersionInterim = (short) (encoded[4] & 0xff);
|
|
||||||
bleVersionMajor = (short) (encoded[5] & 0xff);
|
|
||||||
bleVersionMinor = (short) (encoded[6] & 0xff);
|
|
||||||
bleVersionInterim = (short) (encoded[7] & 0xff);
|
|
||||||
productId = (short) (encoded[8] & 0xff);
|
|
||||||
podStatus = PodStatus.byValue((byte) (encoded[9] & 0xf));
|
|
||||||
lotNumber = ByteBuffer.wrap(new byte[]{0, 0, 0, 0, encoded[10], encoded[11], encoded[12], encoded[13]}).getLong();
|
|
||||||
podSequenceNumber = ByteBuffer.wrap(new byte[]{0, 0, 0, 0, encoded[14], encoded[15], encoded[16], encoded[17]}).getLong();
|
|
||||||
rssi = (byte) (encoded[18] & 0x3f);
|
|
||||||
receiverLowerGain = (byte) ((encoded[18] >> 6) & 0x03);
|
|
||||||
uniqueIdReceivedInCommand = ByteBuffer.wrap(new byte[]{0, 0, 0, 0, encoded[19], encoded[20], encoded[21], encoded[22]}).getLong();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getMessageType() {
|
|
||||||
return messageType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getMessageLength() {
|
|
||||||
return messageLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getFirmwareVersionMajor() {
|
|
||||||
return firmwareVersionMajor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getFirmwareVersionMinor() {
|
|
||||||
return firmwareVersionMinor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getFirmwareVersionInterim() {
|
|
||||||
return firmwareVersionInterim;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getBleVersionMajor() {
|
|
||||||
return bleVersionMajor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getBleVersionMinor() {
|
|
||||||
return bleVersionMinor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getBleVersionInterim() {
|
|
||||||
return bleVersionInterim;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getProductId() {
|
|
||||||
return productId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PodStatus getPodStatus() {
|
|
||||||
return podStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getLotNumber() {
|
|
||||||
return lotNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getPodSequenceNumber() {
|
|
||||||
return podSequenceNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getRssi() {
|
|
||||||
return rssi;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getReceiverLowerGain() {
|
|
||||||
return receiverLowerGain;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getUniqueIdReceivedInCommand() {
|
|
||||||
return uniqueIdReceivedInCommand;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String toString() {
|
|
||||||
return "VersionResponse{" +
|
|
||||||
"messageType=" + messageType +
|
|
||||||
", messageLength=" + messageLength +
|
|
||||||
", firmwareVersionMajor=" + firmwareVersionMajor +
|
|
||||||
", firmwareVersionMinor=" + firmwareVersionMinor +
|
|
||||||
", firmwareVersionInterim=" + firmwareVersionInterim +
|
|
||||||
", bleVersionMajor=" + bleVersionMajor +
|
|
||||||
", bleVersionMinor=" + bleVersionMinor +
|
|
||||||
", bleVersionInterim=" + bleVersionInterim +
|
|
||||||
", productId=" + productId +
|
|
||||||
", podStatus=" + podStatus +
|
|
||||||
", lotNumber=" + lotNumber +
|
|
||||||
", podSequenceNumber=" + podSequenceNumber +
|
|
||||||
", rssi=" + rssi +
|
|
||||||
", receiverLowerGain=" + receiverLowerGain +
|
|
||||||
", uniqueIdReceivedInCommand=" + uniqueIdReceivedInCommand +
|
|
||||||
", activationResponseType=" + activationResponseType +
|
|
||||||
", responseType=" + responseType +
|
|
||||||
", encoded=" + Arrays.toString(encoded) +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.ResponseType.ActivationResponseType
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.experimental.and
|
||||||
|
|
||||||
|
class VersionResponse(encoded: ByteArray) : ActivationResponseBase(ActivationResponseType.GET_VERSION_RESPONSE, encoded) {
|
||||||
|
|
||||||
|
private val messageType: Byte = encoded[0]
|
||||||
|
private val messageLength: Short = (encoded[1].toInt() and 0xff) .toShort()
|
||||||
|
private val firmwareVersionMajor: Short = (encoded[2].toInt() and 0xff) .toShort()
|
||||||
|
private val firmwareVersionMinor: Short = (encoded[3].toInt() and 0xff) .toShort()
|
||||||
|
private val firmwareVersionInterim: Short = (encoded[4].toInt() and 0xff) .toShort()
|
||||||
|
private val bleVersionMajor: Short = (encoded[5].toInt() and 0xff) .toShort()
|
||||||
|
private val bleVersionMinor: Short = (encoded[6].toInt() and 0xff) .toShort()
|
||||||
|
private val bleVersionInterim: Short = (encoded[7].toInt() and 0xff) .toShort()
|
||||||
|
private val productId: Short = (encoded[8].toInt() and 0xff) .toShort()
|
||||||
|
private val podStatus: PodStatus = PodStatus.byValue((encoded[9] and 0xf))
|
||||||
|
private val lotNumber: Long = ByteBuffer.wrap(byteArrayOf(0, 0, 0, 0, encoded[10], encoded[11], encoded[12], encoded[13])).long
|
||||||
|
private val podSequenceNumber: Long = ByteBuffer.wrap(byteArrayOf(0, 0, 0, 0, encoded[14], encoded[15], encoded[16], encoded[17])).long
|
||||||
|
private val rssi: Byte = (encoded[18] and 0x3f)
|
||||||
|
private val receiverLowerGain: Byte = ((encoded[18].toInt() shr 6 and 0x03).toByte())
|
||||||
|
private val uniqueIdReceivedInCommand: Long = ByteBuffer.wrap(byteArrayOf(0, 0, 0, 0, encoded[19], encoded[20], encoded[21], encoded[22])).long
|
||||||
|
fun getMessageType(): Byte {
|
||||||
|
return messageType
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMessageLength(): Short {
|
||||||
|
return messageLength
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFirmwareVersionMajor(): Short {
|
||||||
|
return firmwareVersionMajor
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFirmwareVersionMinor(): Short {
|
||||||
|
return firmwareVersionMinor
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFirmwareVersionInterim(): Short {
|
||||||
|
return firmwareVersionInterim
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBleVersionMajor(): Short {
|
||||||
|
return bleVersionMajor
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBleVersionMinor(): Short {
|
||||||
|
return bleVersionMinor
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBleVersionInterim(): Short {
|
||||||
|
return bleVersionInterim
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getProductId(): Short {
|
||||||
|
return productId
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPodStatus(): PodStatus {
|
||||||
|
return podStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLotNumber(): Long {
|
||||||
|
return lotNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPodSequenceNumber(): Long {
|
||||||
|
return podSequenceNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getRssi(): Byte {
|
||||||
|
return rssi
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getReceiverLowerGain(): Byte {
|
||||||
|
return receiverLowerGain
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getUniqueIdReceivedInCommand(): Long {
|
||||||
|
return uniqueIdReceivedInCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "VersionResponse{" +
|
||||||
|
"messageType=" + messageType +
|
||||||
|
", messageLength=" + messageLength +
|
||||||
|
", firmwareVersionMajor=" + firmwareVersionMajor +
|
||||||
|
", firmwareVersionMinor=" + firmwareVersionMinor +
|
||||||
|
", firmwareVersionInterim=" + firmwareVersionInterim +
|
||||||
|
", bleVersionMajor=" + bleVersionMajor +
|
||||||
|
", bleVersionMinor=" + bleVersionMinor +
|
||||||
|
", bleVersionInterim=" + bleVersionInterim +
|
||||||
|
", productId=" + productId +
|
||||||
|
", podStatus=" + podStatus +
|
||||||
|
", lotNumber=" + lotNumber +
|
||||||
|
", podSequenceNumber=" + podSequenceNumber +
|
||||||
|
", rssi=" + rssi +
|
||||||
|
", receiverLowerGain=" + receiverLowerGain +
|
||||||
|
", uniqueIdReceivedInCommand=" + uniqueIdReceivedInCommand +
|
||||||
|
", activationResponseType=" + activationResponseType +
|
||||||
|
", responseType=" + responseType +
|
||||||
|
", encoded=" + Arrays.toString(encoded) +
|
||||||
|
'}'
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state;
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state
|
||||||
|
|
||||||
public interface OmnipodDashPodStateManager {
|
interface OmnipodDashPodStateManager
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util;
|
|
||||||
|
|
||||||
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};
|
|
||||||
|
|
||||||
public static int createCrc(short[] sArr) {
|
|
||||||
int i = 0;
|
|
||||||
for (short s = 0; s < sArr.length; s = (short) (s + 1)) {
|
|
||||||
byte b = (byte) sArr[s];
|
|
||||||
short s2 = b;
|
|
||||||
if (b < 0) {
|
|
||||||
s2 = (short) (((byte) (b & Byte.MAX_VALUE)) + 128);
|
|
||||||
}
|
|
||||||
i += s2;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static short createCrc(byte[] bArr) {
|
|
||||||
short s = 0;
|
|
||||||
for (byte b : bArr) {
|
|
||||||
byte b2 = (byte) (b ^ (s & 255));
|
|
||||||
short s2 = b2;
|
|
||||||
if (b2 < 0) {
|
|
||||||
s2 = (short) (((byte) (b2 & Byte.MAX_VALUE)) + 128);
|
|
||||||
}
|
|
||||||
s = (short) (((short) (((short) (s >> 8)) & 255)) ^ crc16table[s2]);
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static short calculateChecksum(byte[] bytes) {
|
|
||||||
short sum = 0;
|
|
||||||
for (byte b : bytes) {
|
|
||||||
sum += (short) (b & 0xff);
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util
|
||||||
|
|
||||||
|
import kotlin.experimental.and
|
||||||
|
import kotlin.experimental.xor
|
||||||
|
|
||||||
|
object MessageUtil {
|
||||||
|
|
||||||
|
private val crc16table = shortArrayOf(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)
|
||||||
|
|
||||||
|
fun createCrc(sArr: ShortArray): Int {
|
||||||
|
var i = 0
|
||||||
|
var s: Short = 0
|
||||||
|
while (s < sArr.size) {
|
||||||
|
val b = sArr[s.toInt()].toByte()
|
||||||
|
var s2 = b.toShort()
|
||||||
|
if (b < 0) {
|
||||||
|
s2 = ((b and Byte.MAX_VALUE) as Byte + 128).toShort()
|
||||||
|
}
|
||||||
|
i += s2.toInt()
|
||||||
|
s = (s + 1).toShort()
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createCrc(bArr: ByteArray): Short {
|
||||||
|
var s: Short = 0
|
||||||
|
for (b in bArr) {
|
||||||
|
val b2 = (b xor (s and 255).toByte()) // TODO byte conversion ok?
|
||||||
|
var s2 = b2.toShort()
|
||||||
|
if (b2 < 0) {
|
||||||
|
s2 = ((b2 and Byte.MAX_VALUE) as Byte + 128).toShort()
|
||||||
|
}
|
||||||
|
s = (((s.toInt() shr 8).toShort() and 255) xor crc16table[s2.toInt()])
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
fun calculateChecksum(bytes: ByteArray): Short {
|
||||||
|
var sum: Short = 0
|
||||||
|
for (b in bytes) {
|
||||||
|
sum = (sum + (b.toInt() and 0xff)).toShort()
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue