Add Omnipod Dash GetStatusCommand and ProgramBeepsCommand

This commit is contained in:
Bart Sopers 2021-02-26 14:41:18 +01:00
parent f2922057c0
commit 69c0b5afa7
14 changed files with 225 additions and 29 deletions

View file

@ -1,8 +1,11 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BasalProgram
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.event.PodEvent
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertConfiguration
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertSlot
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BasalProgram
import io.reactivex.Observable
import java.util.*
interface OmnipodDashManager {
@ -26,7 +29,11 @@ interface OmnipodDashManager {
fun cancelBolus(): Observable<PodEvent>
fun silenceAlerts(): Observable<PodEvent>
fun programBeeps(): Observable<PodEvent>
fun programAlerts(alertConfigurations: List<AlertConfiguration>): Observable<PodEvent>
fun silenceAlerts(alerts: EnumSet<AlertSlot>): Observable<PodEvent>
fun deactivatePod(): Observable<PodEvent>
}

View file

@ -2,10 +2,13 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.OmnipodDashBleManager
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BasalProgram
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.event.PodEvent
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertConfiguration
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertSlot
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BasalProgram
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
import io.reactivex.Observable
import java.util.*
import javax.inject.Inject
import javax.inject.Singleton
@ -66,7 +69,17 @@ class OmnipodDashManagerImpl @Inject constructor(
return Observable.empty()
}
override fun silenceAlerts(): Observable<PodEvent> {
override fun programBeeps(): Observable<PodEvent> {
// TODO
return Observable.empty()
}
override fun programAlerts(alertConfigurations: List<AlertConfiguration>): Observable<PodEvent> {
// TODO
return Observable.empty()
}
override fun silenceAlerts(alerts: EnumSet<AlertSlot>): Observable<PodEvent> {
// TODO
return Observable.empty()
}

View file

@ -0,0 +1,46 @@
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 info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.ResponseType
import java.nio.ByteBuffer
class GetStatusCommand(
uniqueId: Int,
sequenceNumber: Short,
multiCommandFlag: Boolean,
private val statusResponseType: ResponseType.StatusResponseType
) : HeaderEnabledCommand(CommandType.GET_STATUS, uniqueId, sequenceNumber, multiCommandFlag) {
override val encoded: ByteArray
get() = appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) //
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
.put(commandType.value) //
.put(BODY_LENGTH) //
.put(statusResponseType.value) //
.array())
class Builder : HeaderEnabledCommandBuilder<Builder, GetStatusCommand>() {
private var statusResponseType: ResponseType.StatusResponseType? = null
fun setStatusResponseType(statusResponseType: ResponseType.StatusResponseType): Builder {
this.statusResponseType = statusResponseType
return this
}
override fun buildCommand(): GetStatusCommand {
requireNotNull(statusResponseType) { "immediateBeepType can not be null" }
return GetStatusCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, statusResponseType!!)
}
}
companion object {
private const val LENGTH: Short = 3
private const val BODY_LENGTH: Byte = 1
}
}

View file

@ -0,0 +1,73 @@
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 info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ProgramReminder
import java.nio.ByteBuffer
class ProgramBeepsCommand internal constructor(
uniqueId: Int,
sequenceNumber: Short,
multiCommandFlag: Boolean,
private val immediateBeepType: BeepType,
private val basalReminder: ProgramReminder,
private val tempBasalReminder: ProgramReminder,
private val bolusReminder: ProgramReminder
) : HeaderEnabledCommand(CommandType.PROGRAM_BEEPS, uniqueId, sequenceNumber, multiCommandFlag) {
override val encoded: ByteArray
get() = appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) //
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
.put(commandType.value) //
.put(BODY_LENGTH) //
.put(immediateBeepType.value) //
.put(basalReminder.encoded) //
.put(tempBasalReminder.encoded) //
.put(bolusReminder.encoded) //
.array())
class Builder : HeaderEnabledCommandBuilder<Builder, ProgramBeepsCommand>() {
private var immediateBeepType: BeepType? = null
private var basalReminder: ProgramReminder? = null
private var tempBasalReminder: ProgramReminder? = null
private var bolusReminder: ProgramReminder? = null
fun setImmediateBeepType(beepType: BeepType): Builder {
this.immediateBeepType = beepType
return this
}
fun setBasalReminder(programReminder: ProgramReminder): Builder {
this.basalReminder = programReminder
return this
}
fun setTempBasalReminder(programReminder: ProgramReminder): Builder {
this.tempBasalReminder = programReminder
return this
}
fun setBolusReminder(programReminder: ProgramReminder): Builder {
this.bolusReminder = programReminder
return this
}
override fun buildCommand(): ProgramBeepsCommand {
requireNotNull(immediateBeepType) { "immediateBeepType can not be null" }
requireNotNull(basalReminder) { "basalReminder can not be null" }
requireNotNull(tempBasalReminder) { "tempBasalReminder can not be null" }
requireNotNull(bolusReminder) { "bolusReminder can not be null" }
return ProgramBeepsCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, immediateBeepType!!, basalReminder!!, tempBasalReminder!!, bolusReminder!!)
}
}
companion object {
private const val LENGTH: Short = 6
private const val BODY_LENGTH: Byte = 4
}
}

View file

@ -1,8 +1,8 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.ResponseType.AdditionalStatusResponseType
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.ResponseType.StatusResponseType
open class AdditionalStatusResponseBase internal constructor(
val statusResponseType: AdditionalStatusResponseType,
val statusResponseType: StatusResponseType,
encoded: ByteArray
) : ResponseBase(ResponseType.ADDITIONAL_STATUS_RESPONSE, encoded)

View file

@ -3,14 +3,14 @@ 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.DeliveryStatus
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.ResponseType.AdditionalStatusResponseType
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.ResponseType.StatusResponseType
import java.nio.ByteBuffer
import java.util.*
import kotlin.experimental.and
class AlarmStatusResponse(
encoded: ByteArray
) : AdditionalStatusResponseBase(AdditionalStatusResponseType.ALARM_STATUS, encoded) {
) : AdditionalStatusResponseBase(StatusResponseType.ALARM_STATUS, encoded) {
private val messageType: Byte
private val messageLength: Short

View file

@ -1,7 +1,7 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response
enum class ResponseType(
private val value: Byte
val value: Byte
) {
ACTIVATION_RESPONSE(0x01.toByte()),
@ -10,20 +10,25 @@ enum class ResponseType(
NAK_RESPONSE(0x06.toByte()),
UNKNOWN(0xff.toByte());
fun getValue(): Byte {
return value
}
enum class StatusResponseType(
val value: Byte
) {
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
}
DEFAULT_STATUS_RESPONSE(0x00.toByte()),
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());
companion object {
fun byValue(value: Byte): AdditionalStatusResponseType {
@JvmStatic
fun byValue(value: Byte): StatusResponseType {
for (type in values()) {
if (type.value == value) {
return type
@ -34,11 +39,17 @@ enum class ResponseType(
}
}
enum class ActivationResponseType(private val length: Byte) {
GET_VERSION_RESPONSE(0x15.toByte()), SET_UNIQUE_ID_RESPONSE(0x1b.toByte()), UNKNOWN(0xff.toByte());
enum class ActivationResponseType(
val length: Byte
) {
GET_VERSION_RESPONSE(0x15.toByte()),
SET_UNIQUE_ID_RESPONSE(0x1b.toByte()),
UNKNOWN(0xff.toByte());
companion object {
@JvmStatic
fun byLength(length: Byte): ActivationResponseType {
for (type in values()) {
if (type.length == length) {
@ -52,6 +63,7 @@ enum class ResponseType(
companion object {
@JvmStatic
fun byValue(value: Byte): ResponseType {
for (type in values()) {
if (type.value == value) {

View file

@ -0,0 +1,21 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.ResponseType
import org.apache.commons.codec.DecoderException
import org.apache.commons.codec.binary.Hex
import org.junit.Assert
import org.junit.Test
class GetStatusCommandTest {
@Test @Throws(DecoderException::class) fun testGetDefaultStatusResponse() {
val encoded = GetStatusCommand.Builder() //
.setUniqueId(37879810) //
.setSequenceNumber(15.toShort()) //
.setStatusResponseType(ResponseType.StatusResponseType.DEFAULT_STATUS_RESPONSE) //
.build() //
.encoded
Assert.assertArrayEquals(Hex.decodeHex("024200023C030E0100024C"), encoded)
}
}

View file

@ -0,0 +1,25 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ProgramReminder
import org.apache.commons.codec.DecoderException
import org.apache.commons.codec.binary.Hex
import org.junit.Assert
import org.junit.Test
class ProgramBeepsCommandTest {
@Test @Throws(DecoderException::class) fun testPlayTestBeep() {
val encoded = ProgramBeepsCommand.Builder() //
.setUniqueId(37879810) //
.setSequenceNumber(11.toShort()) //
.setImmediateBeepType(BeepType.FOUR_TIMES_BIP_BEEP) //
.setBasalReminder(ProgramReminder(false, false, 0.toByte())) //
.setTempBasalReminder(ProgramReminder(false, false, 0.toByte())) //
.setBolusReminder(ProgramReminder(false, false, 0.toByte())) //
.build() //
.encoded
Assert.assertArrayEquals(Hex.decodeHex("024200022C061E0402000000800F"), encoded)
}
}

View file

@ -3,7 +3,6 @@ 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.DeliveryStatus
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.ResponseType
import org.apache.commons.codec.DecoderException
import org.apache.commons.codec.binary.Hex
import org.junit.Assert
@ -18,9 +17,9 @@ class AlarmStatusResponseTest {
Assert.assertArrayEquals(encoded, response.encoded)
Assert.assertNotSame(encoded, response.encoded)
Assert.assertEquals(ResponseType.ADDITIONAL_STATUS_RESPONSE, response.responseType)
Assert.assertEquals(ResponseType.ADDITIONAL_STATUS_RESPONSE.getValue(), response.getMessageType())
Assert.assertEquals(ResponseType.AdditionalStatusResponseType.ALARM_STATUS, response.statusResponseType)
Assert.assertEquals(ResponseType.AdditionalStatusResponseType.ALARM_STATUS.getValue(), response.getAdditionalStatusResponseType())
Assert.assertEquals(ResponseType.ADDITIONAL_STATUS_RESPONSE.value, response.getMessageType())
Assert.assertEquals(ResponseType.StatusResponseType.ALARM_STATUS, response.statusResponseType)
Assert.assertEquals(ResponseType.StatusResponseType.ALARM_STATUS.value, response.getAdditionalStatusResponseType())
Assert.assertEquals(PodStatus.RUNNING_ABOVE_MIN_VOLUME, response.getPodStatus())
Assert.assertEquals(DeliveryStatus.BASAL_ACTIVE, response.getDeliveryStatus())
Assert.assertEquals(0.toShort(), response.getBolusPulsesRemaining())

View file

@ -16,7 +16,7 @@ class DefaultStatusResponseTest {
Assert.assertArrayEquals(encoded, response.encoded)
Assert.assertNotSame(encoded, response.encoded)
Assert.assertEquals(ResponseType.DEFAULT_STATUS_RESPONSE, response.responseType)
Assert.assertEquals(ResponseType.DEFAULT_STATUS_RESPONSE.getValue(), response.getMessageType())
Assert.assertEquals(ResponseType.DEFAULT_STATUS_RESPONSE.value, response.getMessageType())
Assert.assertEquals(DeliveryStatus.BASAL_ACTIVE, response.getDeliveryStatus())
Assert.assertEquals(PodStatus.RUNNING_ABOVE_MIN_VOLUME, response.getPodStatus())
Assert.assertEquals(320.toShort(), response.getTotalPulsesDelivered())

View file

@ -18,7 +18,7 @@ class NakResponseTest {
Assert.assertArrayEquals(encoded, response.encoded)
Assert.assertNotSame(encoded, response.encoded)
Assert.assertEquals(ResponseType.NAK_RESPONSE, response.responseType)
Assert.assertEquals(ResponseType.NAK_RESPONSE.getValue(), response.getMessageType())
Assert.assertEquals(ResponseType.NAK_RESPONSE.value, response.getMessageType())
Assert.assertEquals(NakErrorType.ILLEGAL_PARAM, response.getNakErrorType())
Assert.assertEquals(AlarmType.NONE, response.getAlarmType())
Assert.assertEquals(PodStatus.RUNNING_BELOW_MIN_VOLUME, response.getPodStatus())

View file

@ -17,7 +17,7 @@ class SetUniqueIdResponseTest {
Assert.assertNotSame(encoded, response.encoded)
Assert.assertEquals(ResponseType.ACTIVATION_RESPONSE, response.responseType)
Assert.assertEquals(ResponseType.ActivationResponseType.SET_UNIQUE_ID_RESPONSE, response.activationResponseType)
Assert.assertEquals(ResponseType.ACTIVATION_RESPONSE.getValue(), response.getMessageType())
Assert.assertEquals(ResponseType.ACTIVATION_RESPONSE.value, response.getMessageType())
Assert.assertEquals(27.toShort(), response.getMessageLength())
Assert.assertEquals(5000.toShort(), response.getPulseVolumeInTenThousandthMicroLiter())
Assert.assertEquals(16.toShort(), response.getDeliveryRate())

View file

@ -17,7 +17,7 @@ class VersionResponseTest {
Assert.assertNotSame(encoded, response.encoded)
Assert.assertEquals(ResponseType.ACTIVATION_RESPONSE, response.responseType)
Assert.assertEquals(ResponseType.ActivationResponseType.GET_VERSION_RESPONSE, response.activationResponseType)
Assert.assertEquals(ResponseType.ACTIVATION_RESPONSE.getValue(), response.getMessageType())
Assert.assertEquals(ResponseType.ACTIVATION_RESPONSE.value, response.getMessageType())
Assert.assertEquals(21.toShort(), response.getMessageLength())
Assert.assertEquals(4.toShort(), response.getFirmwareVersionMajor())
Assert.assertEquals(10.toShort(), response.getFirmwareVersionMinor())