Merge remote-tracking branch 'origin/adrian/kotlinify-driver-pod' into dash-mgr

This commit is contained in:
Bart Sopers 2021-02-25 23:22:16 +01:00
commit d5679e51dd
99 changed files with 2366 additions and 3098 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 +
'}';
}
}

View file

@ -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 +
'}'
}
}

View file

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

View file

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

View file

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

View file

@ -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() //
)
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 +
'}'
}
}

View file

@ -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 +
'}';
}
}

View file

@ -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 +
'}'
}
}

View file

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

View file

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

View file

@ -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 +
'}';
}
}

View file

@ -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 +
'}'
}

View file

@ -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 +
'}';
}
}

View file

@ -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 +
'}'
}

View file

@ -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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 +
'}';
}
}

View file

@ -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 +
'}'
}
}

View file

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

View file

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

View file

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

View file

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

View file

@ -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 +
'}';
}
}

View file

@ -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 +
'}'
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +0,0 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
public interface Encodable {
byte[] getEncoded();
}

View file

@ -0,0 +1,6 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
interface Encodable {
val encoded: ByteArray
}

View file

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

View file

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

View file

@ -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,
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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

View file

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

View file

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

View file

@ -1,7 +0,0 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response;
public interface Response {
ResponseType getResponseType();
byte[] getEncoded();
}

View file

@ -0,0 +1,7 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response
interface Response {
val responseType: ResponseType
val encoded: ByteArray
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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) +
'}'
}
}

View file

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

View file

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

View file

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