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