commit
f8ca7592ae
|
@ -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>
|
||||
}
|
|
@ -2,10 +2,16 @@ 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.command.GetVersionCommand
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.GetVersionCommand.Companion.DEFAULT_UNIQUE_ID
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ActivationProgress
|
||||
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
|
||||
|
||||
|
@ -16,9 +22,37 @@ class OmnipodDashManagerImpl @Inject constructor(
|
|||
private val bleManager: OmnipodDashBleManager
|
||||
) : OmnipodDashManager {
|
||||
|
||||
private val observePodReadyForActivationPart1: Observable<PodEvent>
|
||||
get() {
|
||||
if (podStateManager.activationProgress.isBefore(ActivationProgress.PHASE_1_COMPLETED)) {
|
||||
return Observable.empty()
|
||||
}
|
||||
return Observable.error(IllegalStateException("Pod is in an incorrect state"))
|
||||
}
|
||||
|
||||
private val observeConnectToPod: Observable<PodEvent>
|
||||
get() {
|
||||
return Observable.defer {
|
||||
bleManager.connect()
|
||||
Observable.just(PodEvent.Connected(0)) // TODO should be returned in BleManager
|
||||
}
|
||||
}
|
||||
|
||||
override fun activatePodPart1(): Observable<PodEvent> {
|
||||
// TODO
|
||||
return Observable.empty()
|
||||
val command = GetVersionCommand.Builder() //
|
||||
.setSequenceNumber(podStateManager.messageSequenceNumber) //
|
||||
.setUniqueId(DEFAULT_UNIQUE_ID) //
|
||||
.build()
|
||||
|
||||
return Observable.concat(
|
||||
observePodReadyForActivationPart1,
|
||||
observeConnectToPod,
|
||||
Observable.defer {
|
||||
bleManager.sendCommand(command)
|
||||
Observable.just(PodEvent.CommandSent(command)) // TODO should be returned in BleManager
|
||||
}
|
||||
// ... Send more commands
|
||||
)
|
||||
}
|
||||
|
||||
override fun activatePodPart2(): Observable<PodEvent> {
|
||||
|
@ -66,7 +100,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()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm
|
||||
|
||||
import info.nightscout.androidaps.utils.extensions.toHex
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
data class Id(val address: ByteArray) {
|
||||
init {
|
||||
require(address.size == 4)
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to obtain podId from controllerId
|
||||
* The original PDM seems to rotate over 3 Ids:
|
||||
* controllerID+1, controllerID+2 and controllerID+3
|
||||
*/
|
||||
fun increment(): Id {
|
||||
val nodeId = address.copyOf()
|
||||
nodeId[3] = (nodeId[3].toInt() and -4).toByte()
|
||||
nodeId[3] = (nodeId[3].toInt() or PERIPHERAL_NODE_INDEX).toByte()
|
||||
return Id(nodeId)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val asInt = ByteBuffer.wrap(address).int
|
||||
return "${asInt}/${address.toHex()}"
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private val PERIPHERAL_NODE_INDEX = 1 // TODO: understand the meaning of this value. It comes from preferences
|
||||
|
||||
fun fromInt(v: Int): Id {
|
||||
return Id(ByteBuffer.allocate(4).putInt(v).array())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -13,4 +13,6 @@ interface OmnipodDashBleManager {
|
|||
fun connect()
|
||||
|
||||
fun disconnect()
|
||||
|
||||
fun getPodId(): Id
|
||||
}
|
|
@ -12,6 +12,9 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.callback
|
|||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command.BleCommandHello
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.*
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.BleIO
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.CharacteristicType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.ltk.LTKExchanger
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessageIO
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.scan.PodScanner
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.status.ConnectionStatus
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command
|
||||
|
@ -28,22 +31,13 @@ class OmnipodDashBleManagerImpl @Inject constructor(private val context: Context
|
|||
private val bluetoothManager: BluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
|
||||
private val bluetoothAdapter: BluetoothAdapter = bluetoothManager.adapter
|
||||
|
||||
@Throws(InterruptedException::class, ScanFailException::class, FailedToConnectException::class, CouldNotSendBleException::class, BleIOBusyException::class, TimeoutException::class, CouldNotConfirmWriteException::class, CouldNotEnableNotifications::class, DescriptorNotFoundException::class, CouldNotConfirmDescriptorWriteException::class)
|
||||
fun activateNewPod() {
|
||||
aapsLogger.info(LTag.PUMPBTCOMM, "starting new pod activation")
|
||||
val podScanner = PodScanner(aapsLogger, bluetoothAdapter)
|
||||
val podAddress = podScanner.scanForPod(PodScanner.SCAN_FOR_SERVICE_UUID, PodScanner.POD_ID_NOT_ACTIVATED).scanResult.device.address
|
||||
// For tests: this.podAddress = "B8:27:EB:1D:7E:BB";
|
||||
connect(podAddress)
|
||||
}
|
||||
|
||||
@Throws(FailedToConnectException::class, CouldNotSendBleException::class, InterruptedException::class, BleIOBusyException::class, TimeoutException::class, CouldNotConfirmWriteException::class, CouldNotEnableNotifications::class, DescriptorNotFoundException::class, CouldNotConfirmDescriptorWriteException::class)
|
||||
private fun connect(podAddress: String) {
|
||||
private fun connect(podAddress: String): BleIO {
|
||||
// TODO: locking?
|
||||
val podDevice = bluetoothAdapter.getRemoteDevice(podAddress)
|
||||
val incomingPackets: Map<CharacteristicType, BlockingQueue<ByteArray>> =
|
||||
mapOf(CharacteristicType.CMD to LinkedBlockingDeque(),
|
||||
CharacteristicType.DATA to LinkedBlockingDeque());
|
||||
CharacteristicType.DATA to LinkedBlockingDeque())
|
||||
val bleCommCallbacks = BleCommCallbacks(aapsLogger, incomingPackets)
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Connecting to $podAddress")
|
||||
var autoConnect = true
|
||||
|
@ -65,6 +59,7 @@ class OmnipodDashBleManagerImpl @Inject constructor(private val context: Context
|
|||
aapsLogger.debug(LTag.PUMPBTCOMM, "Saying hello to the pod")
|
||||
bleIO.sendAndConfirmPacket(CharacteristicType.CMD, BleCommandHello(CONTROLLER_ID).data)
|
||||
bleIO.readyToRead()
|
||||
return bleIO
|
||||
}
|
||||
|
||||
override fun sendCommand(cmd: Command): Response {
|
||||
|
@ -75,17 +70,35 @@ class OmnipodDashBleManagerImpl @Inject constructor(private val context: Context
|
|||
TODO("not implemented")
|
||||
}
|
||||
|
||||
@Throws(InterruptedException::class, ScanFailException::class, FailedToConnectException::class, CouldNotSendBleException::class, BleIOBusyException::class, TimeoutException::class, CouldNotConfirmWriteException::class, CouldNotEnableNotifications::class, DescriptorNotFoundException::class, CouldNotConfirmDescriptorWriteException::class)
|
||||
override fun connect() {
|
||||
TODO("not implemented")
|
||||
// TODO: this is wrong and I know it
|
||||
aapsLogger.info(LTag.PUMPBTCOMM, "starting new pod activation")
|
||||
val podScanner = PodScanner(aapsLogger, bluetoothAdapter)
|
||||
val podAddress = podScanner.scanForPod(PodScanner.SCAN_FOR_SERVICE_UUID, PodScanner.POD_ID_NOT_ACTIVATED).scanResult.device.address
|
||||
// For tests: this.podAddress = "B8:27:EB:1D:7E:BB";
|
||||
val bleIO = connect(podAddress)
|
||||
val msgIO = MessageIO(aapsLogger, bleIO)
|
||||
val ltkExchanger = LTKExchanger(aapsLogger, msgIO)
|
||||
val ltk = ltkExchanger.negociateLTKAndNonce()
|
||||
|
||||
aapsLogger.info(LTag.PUMPCOMM, "Got LTK and Nonce Prefix: ${ltk}")
|
||||
}
|
||||
|
||||
override fun disconnect() {
|
||||
TODO("not implemented")
|
||||
}
|
||||
|
||||
|
||||
override fun getPodId(): Id {
|
||||
// TODO: return something meaningful here
|
||||
return Id.fromInt(4243);
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val CONNECT_TIMEOUT_MS = 5000
|
||||
private const val CONTROLLER_ID = 4242 // TODO read from preferences or somewhere else.
|
||||
const val CONTROLLER_ID = 4242 // TODO read from preferences or somewhere else.
|
||||
}
|
||||
|
||||
}
|
|
@ -4,9 +4,11 @@ import android.bluetooth.BluetoothGatt
|
|||
import android.bluetooth.BluetoothGattCharacteristic
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.callbacks.BleCommCallbacks
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.CharacteristicNotFoundException
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.ServiceNotFoundException
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.CharacteristicType
|
||||
import java.math.BigInteger
|
||||
import java.util.*
|
||||
|
||||
|
@ -28,17 +30,17 @@ class ServiceDiscoverer(private val logger: AAPSLogger, private val gatt: Blueto
|
|||
val dataChar = service.getCharacteristic(CharacteristicType.DATA.uuid) // TODO: this is never used
|
||||
?: throw CharacteristicNotFoundException(CharacteristicType.DATA.value)
|
||||
var chars = mapOf(CharacteristicType.CMD to cmdChar,
|
||||
CharacteristicType.DATA to dataChar)
|
||||
CharacteristicType.DATA to dataChar)
|
||||
return chars
|
||||
}
|
||||
|
||||
|
||||
private fun String.toUuid(): UUID = UUID(
|
||||
BigInteger(replace("-", "").substring(0, 16), 16).toLong(),
|
||||
BigInteger(replace("-", "").substring(16), 16).toLong()
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
||||
private const val SERVICE_UUID = "1a7e-4024-e3ed-4464-8b7e-751e03d0dc5f"
|
||||
private const val DISCOVER_SERVICES_TIMEOUT_MS = 5000
|
||||
}
|
||||
|
|
|
@ -7,10 +7,11 @@ import android.bluetooth.BluetoothGattDescriptor
|
|||
import android.bluetooth.BluetoothProfile
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.CharacteristicType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.CharacteristicType.Companion.byValue
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.CouldNotConfirmDescriptorWriteException
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.CouldNotConfirmWriteException
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.CharacteristicType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.CharacteristicType.Companion.byValue
|
||||
import info.nightscout.androidaps.utils.extensions.toHex
|
||||
import java.util.concurrent.BlockingQueue
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.LinkedBlockingQueue
|
||||
|
@ -63,10 +64,10 @@ class BleCommCallbacks(private val aapsLogger: AAPSLogger, private val incomingP
|
|||
|
||||
private fun confirmWritePayload(expectedPayload: ByteArray, received: CharacteristicWriteConfirmationPayload) {
|
||||
if (!expectedPayload.contentEquals(received.payload)) {
|
||||
aapsLogger.warn(LTag.PUMPBTCOMM, "Could not confirm write. Got " + received.payload + ".Excepted: " + expectedPayload)
|
||||
aapsLogger.warn(LTag.PUMPBTCOMM, "Could not confirm write. Got " + received.payload.toHex() + ".Excepted: " + expectedPayload.toHex())
|
||||
throw CouldNotConfirmWriteException(expectedPayload, received.payload)
|
||||
}
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Confirmed write with value: " + received.payload)
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Confirmed write with value: " + received.payload.toHex())
|
||||
}
|
||||
|
||||
override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
|
||||
|
@ -77,7 +78,7 @@ class BleCommCallbacks(private val aapsLogger: AAPSLogger, private val incomingP
|
|||
CharacteristicWriteConfirmationError(status)
|
||||
}
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "OnCharacteristicWrite with status/char/value " +
|
||||
status + "/" + byValue(characteristic.uuid.toString()) + "/" + characteristic.value)
|
||||
status + "/" + byValue(characteristic.uuid.toString()) + "/" + characteristic.value.toHex())
|
||||
try {
|
||||
if (writeQueue.size > 0) {
|
||||
aapsLogger.warn(LTag.PUMPBTCOMM, "Write confirm queue should be empty. found: " + writeQueue.size)
|
||||
|
@ -98,7 +99,7 @@ class BleCommCallbacks(private val aapsLogger: AAPSLogger, private val incomingP
|
|||
val characteristicType = byValue(characteristic.uuid.toString())
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "OnCharacteristicChanged with char/value " +
|
||||
characteristicType + "/" +
|
||||
payload)
|
||||
payload.toHex())
|
||||
incomingPackets[characteristicType]!!.add(payload)
|
||||
}
|
||||
|
||||
|
@ -109,7 +110,7 @@ class BleCommCallbacks(private val aapsLogger: AAPSLogger, private val incomingP
|
|||
when (confirmed) {
|
||||
is DescriptorWriteConfirmationError -> throw CouldNotConfirmWriteException(confirmed.status)
|
||||
is DescriptorWriteConfirmationUUID -> if (confirmed.uuid != descriptorUUID) {
|
||||
aapsLogger.warn(LTag.PUMPBTCOMM, "Could not confirm descriptor write. Got ${confirmed.uuid}. Expected: ${descriptorUUID}")
|
||||
aapsLogger.warn(LTag.PUMPBTCOMM, "Could not confirm descriptor write. Got ${confirmed.uuid}. Expected: $descriptorUUID")
|
||||
throw CouldNotConfirmDescriptorWriteException(descriptorUUID, confirmed.uuid)
|
||||
} else {
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Confirmed descriptor write : " + confirmed.uuid)
|
||||
|
@ -120,14 +121,14 @@ class BleCommCallbacks(private val aapsLogger: AAPSLogger, private val incomingP
|
|||
override fun onDescriptorWrite(gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int) {
|
||||
super.onDescriptorWrite(gatt, descriptor, status)
|
||||
val writeConfirmation = if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "OnDescriptor value " + descriptor.value)
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "OnDescriptor value " + descriptor.value.toHex())
|
||||
DescriptorWriteConfirmationUUID(descriptor.uuid.toString())
|
||||
} else {
|
||||
DescriptorWriteConfirmationError(status)
|
||||
}
|
||||
try {
|
||||
if (descriptorWriteQueue.size > 0) {
|
||||
aapsLogger.warn(LTag.PUMPBTCOMM, "Descriptor write queue should be empty, found: " + descriptorWriteQueue.size)
|
||||
aapsLogger.warn(LTag.PUMPBTCOMM, "Descriptor write queue should be empty, found: ${descriptorWriteQueue.size}")
|
||||
descriptorWriteQueue.clear()
|
||||
}
|
||||
val offered = descriptorWriteQueue.offer(writeConfirmation, WRITE_CONFIRM_TIMEOUT_MS.toLong(), TimeUnit.MILLISECONDS)
|
||||
|
@ -140,6 +141,7 @@ class BleCommCallbacks(private val aapsLogger: AAPSLogger, private val incomingP
|
|||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val WRITE_CONFIRM_TIMEOUT_MS = 10 // the confirmation queue should be empty anyway
|
||||
}
|
||||
}
|
|
@ -2,6 +2,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.callbac
|
|||
|
||||
sealed class DescriptorWriteConfirmation
|
||||
|
||||
data class DescriptorWriteConfirmationUUID(val uuid: String): DescriptorWriteConfirmation()
|
||||
data class DescriptorWriteConfirmationUUID(val uuid: String) : DescriptorWriteConfirmation()
|
||||
|
||||
data class DescriptorWriteConfirmationError(val status: Int): DescriptorWriteConfirmation()
|
||||
data class DescriptorWriteConfirmationError(val status: Int) : DescriptorWriteConfirmation()
|
|
@ -1,17 +1,33 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command
|
||||
|
||||
abstract class BleCommand {
|
||||
open class BleCommand(val data: ByteArray) {
|
||||
|
||||
val data: ByteArray
|
||||
constructor(type: BleCommandType) : this(byteArrayOf(type.value))
|
||||
|
||||
constructor(type: BleCommandType) {
|
||||
data = byteArrayOf(type.value)
|
||||
constructor(type: BleCommandType, payload: ByteArray) : this(
|
||||
byteArrayOf(type.value) + payload
|
||||
)
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is BleCommand) return false
|
||||
|
||||
if (!data.contentEquals(other.data)) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
constructor(type: BleCommandType, payload: ByteArray) {
|
||||
val n = payload.size + 1
|
||||
data = ByteArray(n)
|
||||
data[0] = type.value
|
||||
System.arraycopy(payload, 0, data, 1, payload.size)
|
||||
override fun hashCode(): Int {
|
||||
return data.contentHashCode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BleCommandRTS : BleCommand(BleCommandType.RTS)
|
||||
|
||||
class BleCommandCTS : BleCommand(BleCommandType.CTS)
|
||||
|
||||
class BleCommandAbort : BleCommand(BleCommandType.ABORT)
|
||||
|
||||
class BleCommandSuccess : BleCommand(BleCommandType.SUCCESS)
|
||||
|
||||
class BleCommandFail : BleCommand(BleCommandType.FAIL)
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command
|
||||
|
||||
class BleCommandNack(idx: Byte) : BleCommand(BleCommandType.NACK, byteArrayOf(idx))
|
|
@ -1,6 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions
|
||||
|
||||
class CouldNotConfirmDescriptorWriteException(override val message: String?) : Exception(message) {
|
||||
constructor(sent: String, confirmed: String): this("Could not confirm write. Sent: {$sent} .Received: ${confirmed}")
|
||||
constructor(status: Int): this("Could not confirm write. Write status: ${status}")
|
||||
constructor(sent: String, confirmed: String) : this("Could not confirm write. Sent: {$sent} .Received: ${confirmed}")
|
||||
constructor(status: Int) : this("Could not confirm write. Write status: ${status}")
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions
|
||||
|
||||
class CouldNotConfirmWriteException(override val message: String?) : Exception(message) {
|
||||
constructor(sent: ByteArray, confirmed: ByteArray): this("Could not confirm write. Sent: {$sent} .Received: ${confirmed}")
|
||||
constructor(status: Int): this("Could not confirm write. Write status: ${status}")
|
||||
constructor(sent: ByteArray, confirmed: ByteArray) : this("Could not confirm write. Sent: {$sent} .Received: ${confirmed}")
|
||||
constructor(status: Int) : this("Could not confirm write. Write status: ${status}")
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.CharacteristicType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.CharacteristicType
|
||||
|
||||
class CouldNotEnableNotifications(cmd: CharacteristicType) : Exception(cmd.value)
|
|
@ -2,7 +2,7 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.excepti
|
|||
|
||||
import android.os.ParcelUuid
|
||||
|
||||
class DiscoveredInvalidPodException: Exception {
|
||||
constructor(message: String) : super(message) {}
|
||||
constructor(message: String, serviceUUIds: List<ParcelUuid?>) : super("$message service UUIDs: $serviceUUIds"){}
|
||||
class DiscoveredInvalidPodException : Exception {
|
||||
constructor(message: String) : super(message)
|
||||
constructor(message: String, serviceUUIds: List<ParcelUuid?>) : super("$message service UUIDs: $serviceUUIds")
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions
|
||||
|
||||
open class FailedToConnectException : Exception {
|
||||
constructor() : super() {}
|
||||
constructor(message: String?) : super(message) {}
|
||||
constructor() : super()
|
||||
constructor(message: String?) : super(message)
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions
|
||||
|
||||
open class ScanFailException : Exception {
|
||||
constructor() {}
|
||||
constructor(errorCode: Int) : super("errorCode$errorCode") {}
|
||||
constructor()
|
||||
constructor(errorCode: Int) : super("errorCode$errorCode")
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command.BleCommand
|
||||
|
||||
class UnexpectedCommandException(val cmd: BleCommand) : Exception("Unexpected command: ${cmd}")
|
|
@ -5,9 +5,9 @@ import android.bluetooth.BluetoothGattCharacteristic
|
|||
import android.bluetooth.BluetoothGattDescriptor
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.CharacteristicType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.callbacks.BleCommCallbacks
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.*
|
||||
import info.nightscout.androidaps.utils.extensions.toHex
|
||||
import java.util.concurrent.BlockingQueue
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.TimeoutException
|
||||
|
@ -49,7 +49,8 @@ class BleIO(private val aapsLogger: AAPSLogger, private val chars: Map<Character
|
|||
}
|
||||
state = IOState.WRITING
|
||||
}
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "BleIO: Sending data on" + characteristic.name + "/" + payload.toString())
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "BleIO: Sending data on " + characteristic.name + "/" + payload.toHex())
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "BleIO: Sending data on " + characteristic.name + "/" + payload.toHex())
|
||||
val ch = chars[characteristic]
|
||||
val set = ch!!.setValue(payload)
|
||||
if (!set) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm
|
||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io
|
||||
|
||||
import java.math.BigInteger
|
||||
import java.util.*
|
|
@ -0,0 +1,8 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.ltk
|
||||
|
||||
data class LTK(val ltk: ByteArray, val noncePrefix: ByteArray) {
|
||||
init {
|
||||
require(ltk.size == 16)
|
||||
require(noncePrefix.size == 16)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.ltk
|
||||
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.OmnipodDashBleManagerImpl
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessageIO
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.StringLengthPrefixEncoding
|
||||
import info.nightscout.androidaps.utils.extensions.hexStringToByteArray
|
||||
|
||||
internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgIO: MessageIO) {
|
||||
|
||||
fun negociateLTKAndNonce(): LTK? {
|
||||
// send SP1, SP2
|
||||
// TODO: get this from somewhere(preferences?)
|
||||
var seq: Byte = 1
|
||||
val controllerId = Id.fromInt(OmnipodDashBleManagerImpl.CONTROLLER_ID)
|
||||
val nodeId = controllerId.increment()
|
||||
|
||||
var sp1sp2 = sp1sp2(nodeId.address, sp2(), seq, controllerId, nodeId)
|
||||
msgIO.sendMesssage(sp1sp2.messagePacket)
|
||||
|
||||
/*
|
||||
var sps1 =
|
||||
msgIO.sendMesssage(sps1.messagePacket)
|
||||
// send SPS1
|
||||
// read SPS1
|
||||
val podSps1 = msgIO.receiveMessage()
|
||||
|
||||
// send SPS2
|
||||
var sps2 = PairMessage()
|
||||
msgIO.sendMesssage(sps2.messagePacket)
|
||||
// read SPS2
|
||||
val podSps2 = msgIO.receiveMessage()
|
||||
|
||||
// send SP0GP0
|
||||
msgIO.sendMesssage(sps2.messagePacket)
|
||||
// read P0
|
||||
val p0 = msgIO.receiveMessage()
|
||||
*/
|
||||
return null
|
||||
}
|
||||
|
||||
private fun sp2(): ByteArray {
|
||||
// This is GetPodStatus command, with page 0 parameter.
|
||||
// We could replace that in the future with the serialized GetPodStatus()
|
||||
return GET_POD_STATUS_HEX_COMMAND.hexStringToByteArray()
|
||||
}
|
||||
|
||||
fun sp1sp2(sp1: ByteArray, sp2: ByteArray, seq: Byte, controllerId: Id, nodeId: Id): PairMessage {
|
||||
val payload = StringLengthPrefixEncoding.formatKeys(
|
||||
arrayOf("SP1=", ",SP2="),
|
||||
arrayOf(sp1, sp2),
|
||||
)
|
||||
return PairMessage(
|
||||
sequenceNumber = seq,
|
||||
source = controllerId,
|
||||
destination = nodeId,
|
||||
payload = payload,
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private val GET_POD_STATUS_HEX_COMMAND = "ffc32dbd08030e0100008a" // TODO for now we are assuming this command is build out of constant parameters, use a proper command builder for that.
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.ltk
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessagePacket
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessageType
|
||||
|
||||
data class PairMessage(
|
||||
val sequenceNumber: Byte,
|
||||
val source: Id,
|
||||
val destination: Id,
|
||||
val payload: ByteArray,
|
||||
val messagePacket: MessagePacket = MessagePacket(
|
||||
type = MessageType.PAIRING,
|
||||
source = source,
|
||||
destination = destination,
|
||||
payload = payload,
|
||||
sequenceNumber = sequenceNumber,
|
||||
sas = true // TODO: understand why this is true for PairMessages
|
||||
),
|
||||
)
|
|
@ -0,0 +1,70 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message
|
||||
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command.*
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.UnexpectedCommandException
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.BleIO
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.CharacteristicType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.PayloadJoiner
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.PayloadJoinerActionAccept
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.PayloadJoinerActionReject
|
||||
import info.nightscout.androidaps.utils.extensions.toHex
|
||||
|
||||
class MessageIO(private val aapsLogger: AAPSLogger, private val bleIO: BleIO) {
|
||||
|
||||
fun sendMesssage(msg: MessagePacket) {
|
||||
bleIO.flushIncomingQueues()
|
||||
bleIO.sendAndConfirmPacket(CharacteristicType.CMD, BleCommandRTS().data)
|
||||
val expectCTS = bleIO.receivePacket(CharacteristicType.CMD)
|
||||
if (BleCommand(expectCTS) != BleCommandCTS()) {
|
||||
throw UnexpectedCommandException(BleCommand(expectCTS))
|
||||
}
|
||||
val payload = msg.asByteArray()
|
||||
val splitter = PayloadSplitter(payload)
|
||||
val packets = splitter.splitInPackets()
|
||||
for (packet in packets) {
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Sending DATA: ", packet.asByteArray().toHex())
|
||||
bleIO.sendAndConfirmPacket(CharacteristicType.DATA, packet.asByteArray())
|
||||
}
|
||||
// TODO: peek for NACKs
|
||||
val expectSuccess = bleIO.receivePacket(CharacteristicType.CMD)
|
||||
if (BleCommand(expectSuccess) != BleCommandSuccess()) {
|
||||
throw UnexpectedCommandException(BleCommand(expectSuccess))
|
||||
}
|
||||
// TODO: handle NACKS/FAILS/etc
|
||||
bleIO.flushIncomingQueues()
|
||||
}
|
||||
|
||||
fun receiveMessage(): MessagePacket {
|
||||
val expectRTS = bleIO.receivePacket(CharacteristicType.CMD)
|
||||
if (BleCommand(expectRTS) != BleCommandCTS()) {
|
||||
throw UnexpectedCommandException(BleCommand(expectRTS))
|
||||
}
|
||||
bleIO.sendAndConfirmPacket(CharacteristicType.CMD, BleCommandCTS().data)
|
||||
val joiner = PayloadJoiner()
|
||||
var data = bleIO.receivePacket(CharacteristicType.DATA)
|
||||
val fragments = joiner.start(data)
|
||||
for (i in 1 until fragments) {
|
||||
data = bleIO.receivePacket(CharacteristicType.DATA)
|
||||
val accumlateAction = joiner.accumulate(data)
|
||||
if (accumlateAction is PayloadJoinerActionReject) {
|
||||
bleIO.sendAndConfirmPacket(CharacteristicType.CMD, BleCommandNack(accumlateAction.idx).data)
|
||||
}
|
||||
}
|
||||
if (joiner.oneExtra) {
|
||||
var data = bleIO.receivePacket(CharacteristicType.DATA)
|
||||
val accumulateAction = joiner.accumulate(data)
|
||||
if (accumulateAction is PayloadJoinerActionReject) {
|
||||
bleIO.sendAndConfirmPacket(CharacteristicType.CMD, BleCommandNack(accumulateAction.idx).data)
|
||||
}
|
||||
}
|
||||
val finalCmd = when (joiner.finalize()) {
|
||||
is PayloadJoinerActionAccept -> BleCommandSuccess()
|
||||
is PayloadJoinerActionReject -> BleCommandFail()
|
||||
}
|
||||
bleIO.sendAndConfirmPacket(CharacteristicType.CMD, finalCmd.data)
|
||||
val fullPayload = joiner.bytes()
|
||||
return MessagePacket.parse(fullPayload)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
/***
|
||||
* MessagePacket contains header and raw payload for a message
|
||||
*/
|
||||
data class MessagePacket(
|
||||
val type: MessageType,
|
||||
val source: Id,
|
||||
val destination: Id,
|
||||
val payload: ByteArray,
|
||||
val sequenceNumber: Byte,
|
||||
val ack: Boolean = false,
|
||||
val ackNumber: Byte = 0.toByte(),
|
||||
val eqos: Short = 0.toShort(), // TODO: understand
|
||||
val priority: Boolean = false,
|
||||
val lastMessage: Boolean = false,
|
||||
val gateway: Boolean = false,
|
||||
val sas: Boolean = false, // TODO: understand
|
||||
val tfs: Boolean = false, // TODO: understand
|
||||
val version: Short = 0.toShort()) {
|
||||
|
||||
fun asByteArray(): ByteArray {
|
||||
val bb = ByteBuffer.allocate(16 + payload.size)
|
||||
bb.put(MAGIC_PATTERN.toByteArray())
|
||||
|
||||
val f1 = Flag()
|
||||
f1.set(0, this.version.toInt() and 4 != 0)
|
||||
f1.set(1, this.version.toInt() and 2 != 0)
|
||||
f1.set(2, this.version.toInt() and 1 != 0)
|
||||
f1.set(3, this.sas)
|
||||
f1.set(4, this.tfs)
|
||||
f1.set(5, this.eqos.toInt() and 4 != 0)
|
||||
f1.set(6, this.eqos.toInt() and 2 != 0)
|
||||
f1.set(7, this.eqos.toInt() and 1 != 0)
|
||||
|
||||
val f2 = Flag()
|
||||
f2.set(0, this.ack)
|
||||
f2.set(1, this.priority)
|
||||
f2.set(2, this.lastMessage)
|
||||
f2.set(3, this.gateway)
|
||||
f2.set(4, this.type.value.toInt() and 8 != 0)
|
||||
f2.set(5, this.type.value.toInt() and 4 != 0)
|
||||
f2.set(6, this.type.value.toInt() and 2 != 0)
|
||||
f2.set(7, this.type.value.toInt() and 1 != 0)
|
||||
|
||||
bb.put(f1.value.toByte())
|
||||
bb.put(f2.value.toByte())
|
||||
bb.put(this.sequenceNumber)
|
||||
bb.put(this.ackNumber)
|
||||
|
||||
bb.put((this.payload.size ushr 3).toByte())
|
||||
bb.put((this.payload.size shl 5).toByte())
|
||||
|
||||
bb.put(this.source.address)
|
||||
bb.put(this.destination.address)
|
||||
|
||||
bb.put(this.payload)
|
||||
|
||||
val ret = ByteArray(bb.position())
|
||||
bb.flip()
|
||||
bb.get(ret)
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private val MAGIC_PATTERN = "TW" // all messages start with this string
|
||||
|
||||
fun parse(payload: ByteArray): MessagePacket {
|
||||
TODO("implement message header parsing")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class Flag(var value: Int = 0) {
|
||||
|
||||
fun set(idx: Byte, set: Boolean) {
|
||||
val mask = 1 shl (7 - idx)
|
||||
if (!set)
|
||||
return
|
||||
value = value or mask
|
||||
}
|
||||
|
||||
fun get(idx: Byte): Boolean {
|
||||
val mask = 1 shl (7 - idx)
|
||||
return value and mask != 0
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message
|
||||
|
||||
enum class MessageType(val value: Byte) {
|
||||
CLEAR(0),
|
||||
ENCRYPTED(1),
|
||||
SESSION_ESTABLISHMENT(2),
|
||||
PAIRING(3);
|
||||
|
||||
companion object {
|
||||
|
||||
fun byValue(value: Byte): MessageType =
|
||||
MessageType.values().firstOrNull { it.value == value }
|
||||
?: throw IllegalArgumentException("Unknown MessageType: $value")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io
|
||||
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
sealed class PayloadJoinerAction
|
||||
|
||||
class PayloadJoinerActionAccept : PayloadJoinerAction()
|
||||
class PayloadJoinerActionReject(val idx: Byte) : PayloadJoinerAction()
|
||||
|
||||
class PayloadJoiner {
|
||||
|
||||
var oneExtra: Boolean = false
|
||||
|
||||
private val payload = ByteArrayOutputStream()
|
||||
|
||||
fun start(payload: ByteArray): Int {
|
||||
TODO("not implemented")
|
||||
}
|
||||
|
||||
fun accumulate(payload: ByteArray): PayloadJoinerAction {
|
||||
TODO("not implemented")
|
||||
}
|
||||
|
||||
fun finalize(): PayloadJoinerAction {
|
||||
TODO("not implemented")
|
||||
}
|
||||
|
||||
fun bytes(): ByteArray {
|
||||
TODO("not implemented")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet.BlePacket
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet.FirstBlePacket
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet.LastBlePacket
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet.LastOptionalPlusOneBlePacket
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet.MiddleBlePacket
|
||||
import java.lang.Integer.min
|
||||
import java.util.zip.CRC32
|
||||
|
||||
internal class PayloadSplitter(private val payload: ByteArray) {
|
||||
|
||||
fun splitInPackets(): List<BlePacket> {
|
||||
val ret = ArrayList<BlePacket>()
|
||||
val crc32 = payload.crc32()
|
||||
if (payload.size <= FirstBlePacket.CAPACITY_WITH_THE_OPTIONAL_PLUS_ONE_PACKET) {
|
||||
val end = min(FirstBlePacket.CAPACITY_WITHOUT_MIDDLE_PACKETS, payload.size)
|
||||
ret.add(FirstBlePacket(
|
||||
totalFragments = 0,
|
||||
payload = payload.copyOfRange(0, end),
|
||||
size = payload.size.toByte(),
|
||||
crc32 = crc32,
|
||||
))
|
||||
if (payload.size > FirstBlePacket.CAPACITY_WITHOUT_MIDDLE_PACKETS) {
|
||||
ret.add(LastOptionalPlusOneBlePacket(
|
||||
index = 1,
|
||||
payload = payload.copyOfRange(end, payload.size),
|
||||
))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
val middleFragments = (payload.size - FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS) / MiddleBlePacket.CAPACITY
|
||||
val rest = ((payload.size - middleFragments * MiddleBlePacket.CAPACITY) - FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS).toByte()
|
||||
ret.add(FirstBlePacket(
|
||||
totalFragments = (middleFragments + 1).toByte(),
|
||||
payload = payload.copyOfRange(0, FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS),
|
||||
))
|
||||
for (i in 1..middleFragments) {
|
||||
val p = if (i == 1) {
|
||||
payload.copyOfRange(FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS, FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + MiddleBlePacket.CAPACITY)
|
||||
} else {
|
||||
payload.copyOfRange(FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + (i - 1) * MiddleBlePacket.CAPACITY, FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + i * MiddleBlePacket.CAPACITY)
|
||||
}
|
||||
ret.add(MiddleBlePacket(
|
||||
index = i.toByte(),
|
||||
payload = p,
|
||||
))
|
||||
}
|
||||
val end = min(LastBlePacket.CAPACITY, rest.toInt())
|
||||
ret.add(LastBlePacket(
|
||||
index = (middleFragments + 1).toByte(),
|
||||
size = rest,
|
||||
payload = payload.copyOfRange(middleFragments * MiddleBlePacket.CAPACITY + FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS, middleFragments * MiddleBlePacket.CAPACITY + FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + end),
|
||||
crc32 = crc32,
|
||||
))
|
||||
if (rest > 14) {
|
||||
ret.add(LastOptionalPlusOneBlePacket(
|
||||
index = (middleFragments + 2).toByte(),
|
||||
payload = payload.copyOfRange(middleFragments * MiddleBlePacket.CAPACITY + FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + LastBlePacket.CAPACITY, payload.size),
|
||||
))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
private fun ByteArray.crc32(): Long {
|
||||
val crc = CRC32()
|
||||
crc.update(this)
|
||||
return crc.value
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message
|
||||
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
/***
|
||||
* String prefix and length encoding and decoding. Example message:
|
||||
*/
|
||||
class StringLengthPrefixEncoding {
|
||||
|
||||
companion object {
|
||||
|
||||
fun parseKeys(keys: List<String>): List<ByteArray> {
|
||||
TODO("not implemented")
|
||||
}
|
||||
|
||||
fun formatKeys(keys: Array<String>, payloads: Array<ByteArray>): ByteArray {
|
||||
val payloadTotalSize = payloads.fold(0) { acc, i -> acc + i.size }
|
||||
val keyTotalSize = keys.fold(0) { acc, i -> acc + i.length }
|
||||
|
||||
val bb = ByteBuffer.allocate(2 * keys.size + keyTotalSize + payloadTotalSize)
|
||||
for (idx in keys.indices) {
|
||||
val k = keys[idx]
|
||||
val payload = payloads[idx]
|
||||
bb.put(k.toByteArray())
|
||||
bb.putShort(payload.size.toShort())
|
||||
bb.put(payload)
|
||||
}
|
||||
|
||||
val ret = ByteArray(bb.position())
|
||||
bb.flip()
|
||||
bb.get(ret)
|
||||
|
||||
return ret
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,79 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet
|
||||
|
||||
class BlePacket
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
sealed class BlePacket {
|
||||
|
||||
abstract fun asByteArray(): ByteArray
|
||||
|
||||
companion object {
|
||||
const val MAX_BLE_PACKET_LEN = 20
|
||||
const val MAX_BLE_BUFFER_LEN = MAX_BLE_PACKET_LEN + 1 // we use this as the size allocated for the ByteBuffer
|
||||
}
|
||||
}
|
||||
|
||||
data class FirstBlePacket(val totalFragments: Byte, val payload: ByteArray, val size: Byte? = null, val crc32: Long? = null) : BlePacket() {
|
||||
|
||||
override fun asByteArray(): ByteArray {
|
||||
val bb = ByteBuffer
|
||||
.allocate(MAX_BLE_BUFFER_LEN)
|
||||
.put(0) // index
|
||||
.put(totalFragments) // # of fragments except FirstBlePacket and LastOptionalPlusOneBlePacket
|
||||
crc32?.let {
|
||||
bb.putInt(crc32.toInt())
|
||||
}
|
||||
size?.let {
|
||||
bb.put(size)
|
||||
}
|
||||
bb.put(payload)
|
||||
val ret = ByteArray(bb.position())
|
||||
bb.flip()
|
||||
bb.get(ret)
|
||||
return ret
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal const val CAPACITY_WITHOUT_MIDDLE_PACKETS = 13 // we are using all fields
|
||||
internal const val CAPACITY_WITH_MIDDLE_PACKETS = 18 // we are not using crc32 or size
|
||||
internal const val CAPACITY_WITH_THE_OPTIONAL_PLUS_ONE_PACKET = 18
|
||||
}
|
||||
}
|
||||
|
||||
data class MiddleBlePacket(val index: Byte, val payload: ByteArray) : BlePacket() {
|
||||
|
||||
override fun asByteArray(): ByteArray {
|
||||
return byteArrayOf(index) + payload
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal const val CAPACITY = 19
|
||||
}
|
||||
}
|
||||
|
||||
data class LastBlePacket(val index: Byte, val size: Byte, val payload: ByteArray, val crc32: Long) : BlePacket() {
|
||||
|
||||
override fun asByteArray(): ByteArray {
|
||||
val bb = ByteBuffer
|
||||
.allocate(MAX_BLE_BUFFER_LEN)
|
||||
.put(index)
|
||||
.put(size)
|
||||
.putInt(crc32.toInt())
|
||||
.put(payload)
|
||||
val ret = ByteArray(bb.position())
|
||||
bb.flip()
|
||||
bb.get(ret)
|
||||
return ret
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal const val CAPACITY = 14
|
||||
}
|
||||
}
|
||||
|
||||
data class LastOptionalPlusOneBlePacket(val index: Byte, val payload: ByteArray) : BlePacket() {
|
||||
|
||||
override fun asByteArray(): ByteArray {
|
||||
return byteArrayOf(index) + payload
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,33 +1,35 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.scan
|
||||
|
||||
import android.bluetooth.le.ScanRecord
|
||||
import android.bluetooth.le.ScanResult
|
||||
import android.os.ParcelUuid
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.DiscoveredInvalidPodException
|
||||
|
||||
class BleDiscoveredDevice(val scanResult: ScanResult, private val podId: Long) {
|
||||
class BleDiscoveredDevice(val scanResult: ScanResult, private val scanRecord: ScanRecord, private val podId: Long) {
|
||||
|
||||
private val sequenceNo: Int
|
||||
private val lotNo: Long
|
||||
|
||||
@Throws(DiscoveredInvalidPodException::class)
|
||||
private fun validateServiceUUIDs() {
|
||||
val scanRecord = scanResult.scanRecord
|
||||
?: throw DiscoveredInvalidPodException("Scan record is null");
|
||||
val serviceUuids = scanRecord.serviceUuids
|
||||
if (serviceUuids.size != 9) {
|
||||
throw DiscoveredInvalidPodException("Expected 9 service UUIDs, got" + serviceUuids.size, serviceUuids)
|
||||
|
||||
}
|
||||
if (extractUUID16(serviceUuids[0]) != MAIN_SERVICE_UUID) {
|
||||
// this is the service that we filtered for
|
||||
throw DiscoveredInvalidPodException("The first exposed service UUID should be 4024, got " + extractUUID16(serviceUuids[0]), serviceUuids)
|
||||
}
|
||||
// TODO understand what is serviceUUIDs[1]. 0x2470. Alarms?
|
||||
if (extractUUID16(serviceUuids[2]) != "000a") {
|
||||
if (extractUUID16(serviceUuids[2]) != UNKNOWN_THIRD_SERVICE_UUID) {
|
||||
// constant?
|
||||
throw DiscoveredInvalidPodException("The third exposed service UUID should be 000a, got " + serviceUuids[2], serviceUuids)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(DiscoveredInvalidPodException::class)
|
||||
|
||||
private fun validatePodId() {
|
||||
val scanRecord = scanResult.scanRecord
|
||||
val serviceUUIDs = scanRecord.serviceUuids
|
||||
|
@ -39,7 +41,6 @@ class BleDiscoveredDevice(val scanResult: ScanResult, private val podId: Long) {
|
|||
}
|
||||
|
||||
private fun parseLotNo(): Long {
|
||||
val scanRecord = scanResult.scanRecord
|
||||
val serviceUUIDs = scanRecord.serviceUuids
|
||||
val lotSeq = extractUUID16(serviceUUIDs[5]) +
|
||||
extractUUID16(serviceUUIDs[6]) +
|
||||
|
@ -48,7 +49,6 @@ class BleDiscoveredDevice(val scanResult: ScanResult, private val podId: Long) {
|
|||
}
|
||||
|
||||
private fun parseSeqNo(): Int {
|
||||
val scanRecord = scanResult.scanRecord
|
||||
val serviceUUIDs = scanRecord.serviceUuids
|
||||
val lotSeq = extractUUID16(serviceUUIDs[7]) +
|
||||
extractUUID16(serviceUUIDs[8])
|
||||
|
@ -57,15 +57,18 @@ class BleDiscoveredDevice(val scanResult: ScanResult, private val podId: Long) {
|
|||
|
||||
override fun toString(): String {
|
||||
return "BleDiscoveredDevice{" +
|
||||
"scanResult=" + scanResult +
|
||||
"scanRecord=" + scanRecord +
|
||||
", podID=" + podId +
|
||||
"scanResult=" + scanResult +
|
||||
", sequenceNo=" + sequenceNo +
|
||||
", lotNo=" + lotNo +
|
||||
'}'
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val MAIN_SERVICE_UUID = "4024";
|
||||
|
||||
const val MAIN_SERVICE_UUID = "4024"
|
||||
const val UNKNOWN_THIRD_SERVICE_UUID = "000a" // FIXME: why is this 000a?
|
||||
private fun extractUUID16(uuid: ParcelUuid): String {
|
||||
return uuid.toString().substring(4, 8)
|
||||
}
|
||||
|
|
|
@ -33,9 +33,11 @@ class ScanCollector(private val logger: AAPSLogger, private val podID: Long) : S
|
|||
logger.debug(LTag.PUMPBTCOMM, "ScanCollector looking for podID: $podID")
|
||||
for (result in found.values) {
|
||||
try {
|
||||
val device = BleDiscoveredDevice(result, podID)
|
||||
ret.add(device)
|
||||
logger.debug(LTag.PUMPBTCOMM, "ScanCollector found: " + result.toString() + "Pod ID: " + podID)
|
||||
result.scanRecord?.let {
|
||||
val device = BleDiscoveredDevice(result, result.scanRecord, podID)
|
||||
ret.add(device)
|
||||
logger.debug(LTag.PUMPBTCOMM, "ScanCollector found: " + result.toString() + "Pod ID: " + podID)
|
||||
}
|
||||
} catch (e: DiscoveredInvalidPodException) {
|
||||
logger.debug(LTag.PUMPBTCOMM, "ScanCollector: pod not matching$e")
|
||||
// this is not the POD we are looking for
|
||||
|
|
|
@ -1,6 +1,16 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.event
|
||||
|
||||
class PodEvent(
|
||||
val type: PodEventType,
|
||||
val data: Any?
|
||||
)
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.Response
|
||||
|
||||
sealed class PodEvent {
|
||||
|
||||
object Scanning : PodEvent()
|
||||
object Pairing : PodEvent()
|
||||
object Connecting : PodEvent()
|
||||
class Connected(val uniqueId: Int) : PodEvent()
|
||||
class CommandSending(val command: Command) : PodEvent()
|
||||
class CommandSent(val command: Command) : PodEvent()
|
||||
class ResponseReceived(val response: Response) : PodEvent()
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.event
|
||||
|
||||
enum class PodEventType {
|
||||
SCANNING,
|
||||
PAIRING,
|
||||
CONNECTING,
|
||||
CONNECTED,
|
||||
COMMAND_SENDING,
|
||||
COMMAND_SENT,
|
||||
RESPONSE_RECEIVED,
|
||||
// ...
|
||||
}
|
|
@ -5,7 +5,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.b
|
|||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.NonceEnabledCommandBuilder
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
class DeactivateCommand internal constructor(
|
||||
class DeactivateCommand private constructor(
|
||||
uniqueId: Int,
|
||||
sequenceNumber: Short,
|
||||
multiCommandFlag: Boolean,
|
||||
|
|
|
@ -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 private constructor(
|
||||
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
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.b
|
|||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.HeaderEnabledCommandBuilder
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
class GetVersionCommand internal constructor(
|
||||
class GetVersionCommand private constructor(
|
||||
uniqueId: Int,
|
||||
sequenceNumber: Short,
|
||||
multiCommandFlag: Boolean
|
||||
|
|
|
@ -7,11 +7,11 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definitio
|
|||
import java.nio.ByteBuffer
|
||||
import java.util.*
|
||||
|
||||
class ProgramAlertsCommand internal constructor(
|
||||
class ProgramAlertsCommand private constructor(
|
||||
uniqueId: Int,
|
||||
sequenceNumber: Short,
|
||||
multiCommandFlag: Boolean,
|
||||
alertConfigurations: List<AlertConfiguration>?,
|
||||
alertConfigurations: List<AlertConfiguration>,
|
||||
nonce: Int
|
||||
) : NonceEnabledCommand(CommandType.PROGRAM_ALERTS, uniqueId, sequenceNumber, multiCommandFlag, nonce) {
|
||||
|
||||
|
@ -52,6 +52,7 @@ class ProgramAlertsCommand internal constructor(
|
|||
class Builder : NonceEnabledCommandBuilder<Builder, ProgramAlertsCommand>() {
|
||||
|
||||
private var alertConfigurations: List<AlertConfiguration>? = null
|
||||
|
||||
fun setAlertConfigurations(alertConfigurations: List<AlertConfiguration>?): Builder {
|
||||
this.alertConfigurations = alertConfigurations
|
||||
return this
|
||||
|
@ -59,7 +60,7 @@ class ProgramAlertsCommand internal constructor(
|
|||
|
||||
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
|
||||
return ProgramAlertsCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, alertConfigurations!!, nonce!!) // TODO this might crash if not all are set
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import java.nio.ByteBuffer
|
|||
import java.util.*
|
||||
|
||||
// Always preceded by 0x1a ProgramInsulinCommand
|
||||
class ProgramBasalCommand internal constructor(
|
||||
class ProgramBasalCommand private constructor(
|
||||
private val interlockCommand: ProgramInsulinCommand,
|
||||
uniqueId: Int,
|
||||
sequenceNumber: Short,
|
||||
|
@ -76,6 +76,7 @@ class ProgramBasalCommand internal constructor(
|
|||
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
|
||||
|
|
|
@ -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 private 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
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.Mess
|
|||
import java.nio.ByteBuffer
|
||||
|
||||
// NOT SUPPORTED: extended bolus
|
||||
class ProgramBolusCommand internal constructor(
|
||||
class ProgramBolusCommand private constructor(
|
||||
private val interlockCommand: ProgramInsulinCommand,
|
||||
uniqueId: Int,
|
||||
sequenceNumber: Short,
|
||||
|
@ -57,6 +57,7 @@ class ProgramBolusCommand internal constructor(
|
|||
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" }
|
||||
|
@ -78,6 +79,7 @@ class ProgramBolusCommand internal constructor(
|
|||
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),
|
||||
|
|
|
@ -7,7 +7,7 @@ import java.nio.ByteBuffer
|
|||
import java.util.*
|
||||
|
||||
// Always followed by one of: 0x13, 0x16, 0x17
|
||||
class ProgramInsulinCommand(
|
||||
class ProgramInsulinCommand internal constructor(
|
||||
uniqueId: Int,
|
||||
sequenceNumber: Short,
|
||||
multiCommandFlag: Boolean,
|
||||
|
@ -34,14 +34,6 @@ class ProgramInsulinCommand(
|
|||
}
|
||||
}
|
||||
|
||||
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()) //
|
||||
|
|
|
@ -11,7 +11,7 @@ import java.nio.ByteBuffer
|
|||
import java.util.*
|
||||
|
||||
// NOT SUPPORTED: percentage temp basal
|
||||
class ProgramTempBasalCommand protected constructor(
|
||||
class ProgramTempBasalCommand private constructor(
|
||||
private val interlockCommand: ProgramInsulinCommand,
|
||||
uniqueId: Int,
|
||||
sequenceNumber: Short,
|
||||
|
@ -20,16 +20,18 @@ class ProgramTempBasalCommand protected constructor(
|
|||
insulinProgramElements: List<BasalInsulinProgramElement>
|
||||
) : HeaderEnabledCommand(CommandType.PROGRAM_TEMP_BASAL, uniqueId, sequenceNumber, multiCommandFlag) {
|
||||
|
||||
private val insulinProgramElements: List<BasalInsulinProgramElement>
|
||||
fun getBodyLength(): Byte = (insulinProgramElements.size * 6 + 8).toByte()
|
||||
private val insulinProgramElements: List<BasalInsulinProgramElement> = ArrayList(insulinProgramElements)
|
||||
|
||||
fun getLength(): Short = (getBodyLength() + 2).toShort()
|
||||
private fun getBodyLength(): Byte = (insulinProgramElements.size * 6 + 8).toByte()
|
||||
|
||||
private 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
|
||||
|
@ -42,6 +44,7 @@ class ProgramTempBasalCommand protected constructor(
|
|||
|
||||
fun setDurationInMinutes(durationInMinutes: Short): Builder {
|
||||
require(durationInMinutes % 30 == 0) { "durationInMinutes must be dividable by 30" }
|
||||
|
||||
this.durationInMinutes = durationInMinutes
|
||||
return this
|
||||
}
|
||||
|
@ -50,22 +53,19 @@ class ProgramTempBasalCommand protected constructor(
|
|||
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,
|
||||
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]
|
||||
|
@ -90,7 +90,7 @@ class ProgramTempBasalCommand protected constructor(
|
|||
}
|
||||
val tempBasalCommand = buffer.array()
|
||||
val interlockCommand = interlockCommand.encoded
|
||||
val header: ByteArray = encodeHeader(uniqueId, sequenceNumber, (tempBasalCommand.size + interlockCommand!!.size).toShort(), multiCommandFlag)
|
||||
val header: ByteArray = encodeHeader(uniqueId, sequenceNumber, (tempBasalCommand.size + interlockCommand.size).toShort(), multiCommandFlag)
|
||||
return appendCrc(ByteBuffer.allocate(header.size + interlockCommand.size + tempBasalCommand.size) //
|
||||
.put(header) //
|
||||
.put(interlockCommand) //
|
||||
|
|
|
@ -6,7 +6,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.b
|
|||
import java.nio.ByteBuffer
|
||||
import java.util.*
|
||||
|
||||
class SetUniqueIdCommand internal constructor(
|
||||
class SetUniqueIdCommand private constructor(
|
||||
uniqueId: Int,
|
||||
sequenceNumber: Short,
|
||||
multiCommandFlag: Boolean,
|
||||
|
@ -45,6 +45,7 @@ class SetUniqueIdCommand internal constructor(
|
|||
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
|
||||
|
|
|
@ -7,7 +7,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definitio
|
|||
import java.nio.ByteBuffer
|
||||
import java.util.*
|
||||
|
||||
class SilenceAlertsCommand internal constructor(
|
||||
class SilenceAlertsCommand private constructor(
|
||||
uniqueId: Int,
|
||||
sequenceNumber: Short,
|
||||
multiCommandFlag: Boolean,
|
||||
|
@ -63,6 +63,7 @@ class SilenceAlertsCommand internal constructor(
|
|||
private var silenceSuspendInProgressAlert = false
|
||||
private var silenceSuspendEndedAlert = false
|
||||
private var silencePodExpirationAlert = false
|
||||
|
||||
fun setSilenceAutoOffAlert(silenceAutoOffAlert: Boolean): Builder {
|
||||
this.silenceAutoOffAlert = silenceAutoOffAlert
|
||||
return this
|
||||
|
|
|
@ -8,7 +8,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definitio
|
|||
import java.nio.ByteBuffer
|
||||
import java.util.*
|
||||
|
||||
class StopDeliveryCommand internal constructor(
|
||||
class StopDeliveryCommand private constructor(
|
||||
uniqueId: Int,
|
||||
sequenceNumber: Short,
|
||||
multiCommandFlag: Boolean,
|
||||
|
@ -24,7 +24,7 @@ class StopDeliveryCommand internal constructor(
|
|||
.put(commandType.value) //
|
||||
.put(BODY_LENGTH) //
|
||||
.putInt(nonce) //
|
||||
.put((beepType.value.toInt() shl 4 or deliveryType.encoded[0].toInt()).toByte()) // TODO bitstuff
|
||||
.put((beepType.value.toInt() shl 4 or deliveryType.encoded[0].toInt()).toByte()) //
|
||||
.array())
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,7 @@ class StopDeliveryCommand internal constructor(
|
|||
|
||||
private var deliveryType: DeliveryType? = null
|
||||
private var beepType: BeepType? = BeepType.LONG_SINGLE_BEEP
|
||||
|
||||
fun setDeliveryType(deliveryType: DeliveryType?): Builder {
|
||||
this.deliveryType = deliveryType
|
||||
return this
|
||||
|
@ -70,6 +71,7 @@ class StopDeliveryCommand internal constructor(
|
|||
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!!)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base
|
||||
|
||||
enum class CommandType(
|
||||
val value: Byte
|
||||
) {
|
||||
enum class CommandType(val value: Byte) {
|
||||
|
||||
SET_UNIQUE_ID(0x03.toByte()),
|
||||
GET_VERSION(0x07.toByte()),
|
||||
|
|
|
@ -2,11 +2,13 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.
|
|||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
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" }
|
||||
|
|
|
@ -2,6 +2,7 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.
|
|||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
abstract class NonceEnabledCommandBuilder<T : NonceEnabledCommandBuilder<T, R>, R : Command> : HeaderEnabledCommandBuilder<T, R>() {
|
||||
|
||||
protected var nonce: Int? = null
|
||||
|
|
|
@ -17,10 +17,10 @@ object ProgramBasalUtil {
|
|||
private const val MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT: Byte = 16
|
||||
|
||||
fun mapTenthPulsesPerSlotToLongInsulinProgramElements(
|
||||
tenthPulsesPerSlot: ShortArray?,
|
||||
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" }
|
||||
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
|
||||
|
|
|
@ -9,7 +9,7 @@ import kotlin.math.roundToInt
|
|||
|
||||
object ProgramTempBasalUtil {
|
||||
|
||||
fun mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot: ShortArray?): List<BasalInsulinProgramElement> {
|
||||
fun mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot: ShortArray): List<BasalInsulinProgramElement> {
|
||||
return ProgramBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot) { startSlotIndex: Byte, numberOfSlots: Byte, totalTenthPulses: Short -> TempBasalInsulinProgramElement(startSlotIndex, numberOfSlots, totalTenthPulses) }
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||
|
||||
enum class AlarmType(
|
||||
private val value: Byte
|
||||
) {
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.HasValue
|
||||
|
||||
enum class AlarmType(override val value: Byte) : HasValue {
|
||||
|
||||
NONE(0x00.toByte()),
|
||||
ALARM_PW_FLASH_ERASE(0x01.toByte()),
|
||||
|
@ -160,15 +160,4 @@ enum class AlarmType(
|
|||
ALARM_BLE_QN_CRIT_VAR_FAIL(0xc2.toByte()),
|
||||
UNKNOWN(0xff.toByte());
|
||||
|
||||
companion object {
|
||||
|
||||
fun byValue(value: Byte): AlarmType {
|
||||
for (type in values()) {
|
||||
if (type.value == value) {
|
||||
return type
|
||||
}
|
||||
}
|
||||
return UNKNOWN
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,7 +26,7 @@ class AlertConfiguration(
|
|||
if (autoOff) {
|
||||
firstByte = firstByte or (1 shl 1)
|
||||
}
|
||||
firstByte = firstByte or ((durationInMinutes.toInt() shr 8 and 0x01).toByte()) //Todo bitstuff
|
||||
firstByte = firstByte or ((durationInMinutes.toInt() shr 8 and 0x01).toByte())
|
||||
return ByteBuffer.allocate(6) //
|
||||
.put(firstByte)
|
||||
.put(durationInMinutes.toByte()) //
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||
|
||||
enum class AlertSlot(
|
||||
val value: Byte
|
||||
) {
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.HasValue
|
||||
|
||||
enum class AlertSlot(override val value: Byte) : HasValue {
|
||||
|
||||
AUTO_OFF(0x00.toByte()),
|
||||
MULTI_COMMAND(0x01.toByte()),
|
||||
|
@ -13,16 +13,4 @@ enum class AlertSlot(
|
|||
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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ class BasalProgram(
|
|||
) {
|
||||
|
||||
val segments: MutableList<Segment> = segments.toMutableList()
|
||||
get() = Collections.unmodifiableList(field) // TODO Adrian: moved method here
|
||||
get() = Collections.unmodifiableList(field)
|
||||
|
||||
fun addSegment(segment: Segment) {
|
||||
segments.add(segment)
|
||||
|
@ -19,7 +19,11 @@ class BasalProgram(
|
|||
|
||||
fun rateAt(date: Date): Double = 0.0 // TODO
|
||||
|
||||
class Segment(val startSlotIndex: Short, val endSlotIndex: Short, val basalRateInHundredthUnitsPerHour: Int) {
|
||||
class Segment(
|
||||
val startSlotIndex: Short,
|
||||
val endSlotIndex: Short,
|
||||
val basalRateInHundredthUnitsPerHour: Int
|
||||
) {
|
||||
|
||||
fun getPulsesPerHour(): Short {
|
||||
return (basalRateInHundredthUnitsPerHour * PULSES_PER_UNIT / 100).toShort()
|
||||
|
@ -37,6 +41,26 @@ class BasalProgram(
|
|||
'}'
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as Segment
|
||||
|
||||
if (startSlotIndex != other.startSlotIndex) return false
|
||||
if (endSlotIndex != other.endSlotIndex) return false
|
||||
if (basalRateInHundredthUnitsPerHour != other.basalRateInHundredthUnitsPerHour) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result: Int = startSlotIndex.toInt()
|
||||
result = 31 * result + endSlotIndex
|
||||
result = 31 * result + basalRateInHundredthUnitsPerHour
|
||||
return result
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val PULSES_PER_UNIT: Byte = 20
|
||||
|
@ -48,4 +72,19 @@ class BasalProgram(
|
|||
"segments=" + segments +
|
||||
'}'
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as BasalProgram
|
||||
|
||||
if (segments != other.segments) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return segments.hashCode()
|
||||
}
|
||||
}
|
|
@ -1,10 +1,8 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||
|
||||
enum class BeepType( // Used in stop delivery command
|
||||
val value: Byte
|
||||
) {
|
||||
enum class BeepType(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());
|
||||
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()); // Used in stop delivery command
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||
|
||||
enum class DeliveryStatus(
|
||||
private val value: Byte
|
||||
) {
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.HasValue
|
||||
|
||||
enum class DeliveryStatus(override val value: Byte) : HasValue {
|
||||
|
||||
SUSPENDED(0x00.toByte()),
|
||||
BASAL_ACTIVE(0x01.toByte()),
|
||||
|
@ -11,16 +11,4 @@ enum class DeliveryStatus(
|
|||
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,8 +1,8 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||
|
||||
enum class NakErrorType(
|
||||
private val value: Byte
|
||||
) {
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.HasValue
|
||||
|
||||
enum class NakErrorType(override val value: Byte) : HasValue {
|
||||
|
||||
FLASH_WRITE(0x01.toByte()),
|
||||
FLASH_ERASE(0x02.toByte()),
|
||||
|
@ -34,16 +34,4 @@ enum class NakErrorType(
|
|||
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,8 +1,8 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||
|
||||
enum class PodStatus(
|
||||
private val value: Byte
|
||||
) {
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.HasValue
|
||||
|
||||
enum class PodStatus(override val value: Byte) : HasValue {
|
||||
|
||||
UNINITIALIZED(0x00.toByte()),
|
||||
MFG_TEST(0x01.toByte()),
|
||||
|
@ -22,17 +22,5 @@ enum class PodStatus(
|
|||
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
|
||||
}
|
||||
}
|
||||
|
||||
fun isRunning(): Boolean = this == RUNNING_ABOVE_MIN_VOLUME || this == RUNNING_BELOW_MIN_VOLUME
|
||||
}
|
|
@ -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)
|
|
@ -3,164 +3,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.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 info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.byValue
|
||||
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
|
||||
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
|
||||
val messageType: Byte = encoded[0]
|
||||
val messageLength: Short = (encoded[1].toInt() and 0xff).toShort()
|
||||
val additionalStatusResponseType: Byte = encoded[2]
|
||||
val podStatus: PodStatus = byValue((encoded[3] and 0x0f), PodStatus.UNKNOWN)
|
||||
val deliveryStatus: DeliveryStatus = byValue((encoded[4] and 0x0f), DeliveryStatus.UNKNOWN)
|
||||
val bolusPulsesRemaining: Short = (ByteBuffer.wrap(byteArrayOf(encoded[5], encoded[6])).short and 2047)
|
||||
val sequenceNumberOfLastProgrammingCommand: Short = (encoded[7] and 0x0f).toShort()
|
||||
val totalPulsesDelivered: Short = ByteBuffer.wrap(byteArrayOf(encoded[8], encoded[9])).short
|
||||
val alarmType: AlarmType = byValue(encoded[10], AlarmType.UNKNOWN)
|
||||
val alarmTime: Short = ByteBuffer.wrap(byteArrayOf(encoded[11], encoded[12])).short
|
||||
val reservoirPulsesRemaining: Short = ByteBuffer.wrap(byteArrayOf(encoded[13], encoded[14])).short
|
||||
val minutesSinceActivation: Short = ByteBuffer.wrap(byteArrayOf(encoded[15], encoded[16])).short
|
||||
val alert0Active: Boolean
|
||||
val alert1Active: Boolean
|
||||
val alert2Active: Boolean
|
||||
val alert3Active: Boolean
|
||||
val alert4Active: Boolean
|
||||
val alert5Active: Boolean
|
||||
val alert6Active: Boolean
|
||||
val alert7Active: Boolean
|
||||
val occlusionAlarm: Boolean
|
||||
val pulseInfoInvalid: Boolean
|
||||
val podStatusWhenAlarmOccurred: PodStatus
|
||||
val immediateBolusWhenAlarmOccurred: Boolean
|
||||
val occlusionType: Byte
|
||||
val occurredWhenFetchingImmediateBolusActiveInformation: Boolean
|
||||
val rssi: Short
|
||||
val receiverLowerGain: Short
|
||||
val podStatusWhenAlarmOccurred2: PodStatus
|
||||
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
|
||||
init {
|
||||
val activeAlerts = encoded[17].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 = byValue((byte19 and 0x0f), PodStatus.UNKNOWN)
|
||||
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 = byValue((encoded[21] and 0x0f), PodStatus.UNKNOWN)
|
||||
returnAddressOfPodAlarmHandlerCaller = ByteBuffer.wrap(byteArrayOf(encoded[22], encoded[23])).short
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
|
@ -197,52 +102,11 @@ class AlarmStatusResponse(
|
|||
", returnAddressOfPodAlarmHandlerCaller=" + returnAddressOfPodAlarmHandlerCaller +
|
||||
", statusResponseType=" + statusResponseType +
|
||||
", responseType=" + responseType +
|
||||
", encoded=" + Arrays.toString(encoded) +
|
||||
", encoded=" + encoded.contentToString() +
|
||||
'}'
|
||||
}
|
||||
|
||||
init {
|
||||
messageType = encoded[0]
|
||||
messageLength = (encoded[1].toInt() and 0xff).toShort()
|
||||
additionalStatusResponseType = encoded[2]
|
||||
podStatus = PodStatus.byValue((encoded[3] and 0x0f))
|
||||
deliveryStatus = DeliveryStatus.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.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
|
||||
infix fun Byte.shr(i: Int): Int = toInt() shr i
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -2,93 +2,30 @@ 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 info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.byValue
|
||||
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.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
|
||||
}
|
||||
val messageType: Byte = encoded[0]
|
||||
val deliveryStatus: DeliveryStatus = byValue((encoded[1].toInt() shr 4 and 0x0f).toByte(), DeliveryStatus.UNKNOWN)
|
||||
val podStatus: PodStatus = byValue((encoded[1] and 0x0f), PodStatus.UNKNOWN)
|
||||
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())
|
||||
val sequenceNumberOfLastProgrammingCommand: Short = (encoded[4] ushr 3 and 0x0f).toShort()
|
||||
val bolusPulsesRemaining: Short = ((encoded[4] and 0x07 shl 10 or (encoded[5].toInt() and 0xff) and 2047).toShort())
|
||||
val activeAlerts = (encoded[6].toInt() and 0xff shl 1 or (encoded[7] ushr 7)).toShort()
|
||||
val occlusionAlertActive: Boolean = (activeAlerts and 1).toInt() == 1
|
||||
val alert1Active: Boolean = activeAlerts shr 1 and 1 == 1
|
||||
val alert2Active: Boolean = activeAlerts shr 2 and 1 == 1
|
||||
val alert3Active: Boolean = activeAlerts shr 3 and 1 == 1
|
||||
val alert4Active: Boolean = activeAlerts shr 4 and 1 == 1
|
||||
val alert5Active: Boolean = activeAlerts shr 5 and 1 == 1
|
||||
val alert6Active: Boolean = activeAlerts shr 6 and 1 == 1
|
||||
val alert7Active: Boolean = activeAlerts shr 7 and 1 == 1
|
||||
val minutesSinceActivation: Short = (encoded[7] and 0x7f shl 6 or (encoded[8].toInt() and 0xff ushr 2 and 0x3f)).toShort()
|
||||
val reservoirPulsesRemaining: Short = (encoded[8] shl 8 or encoded[9].toInt() and 0x3ff).toShort()
|
||||
|
||||
override fun toString(): String {
|
||||
return "DefaultStatusResponse{" +
|
||||
|
@ -114,7 +51,6 @@ class DefaultStatusResponse(
|
|||
}
|
||||
}
|
||||
|
||||
//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
|
||||
infix fun Byte.ushr(i: Int) = toInt() ushr i
|
||||
infix fun Short.shr(i: Int): Int = toInt() shr i
|
||||
infix fun Byte.shl(i: Int): Int = toInt() shl i
|
||||
|
|
|
@ -3,39 +3,35 @@ 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 info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.byValue
|
||||
|
||||
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
|
||||
}
|
||||
val messageType: Byte = encoded[0]
|
||||
val messageLength: Short = encoded[1].toShort()
|
||||
val nakErrorType: NakErrorType = byValue(encoded[2], NakErrorType.UNKNOWN)
|
||||
var alarmType: AlarmType? = null
|
||||
private set
|
||||
var podStatus: PodStatus? = null
|
||||
private set
|
||||
|
||||
fun getMessageLength(): Short {
|
||||
return messageLength
|
||||
}
|
||||
var securityNakSyncCount: Short = 0
|
||||
private set
|
||||
|
||||
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
|
||||
init {
|
||||
val byte3 = encoded[3]
|
||||
val byte4 = encoded[4]
|
||||
if (nakErrorType == NakErrorType.ILLEGAL_SECURITY_CODE) {
|
||||
securityNakSyncCount = ((byte3.toInt() shl 8 or byte4.toInt()).toShort())
|
||||
alarmType = null
|
||||
podStatus = null
|
||||
} else {
|
||||
securityNakSyncCount = 0
|
||||
alarmType = byValue(byte3, AlarmType.UNKNOWN)
|
||||
podStatus = byValue(byte4, PodStatus.UNKNOWN)
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
|
@ -50,21 +46,4 @@ class NakResponse(
|
|||
", encoded=" + encoded.contentToString() +
|
||||
'}'
|
||||
}
|
||||
|
||||
init {
|
||||
messageType = encoded[0]
|
||||
messageLength = encoded[1].toShort()
|
||||
nakErrorType = NakErrorType.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,8 +1,8 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response
|
||||
|
||||
enum class ResponseType(
|
||||
private val value: Byte
|
||||
) {
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.HasValue
|
||||
|
||||
enum class ResponseType(override val value: Byte) : HasValue {
|
||||
|
||||
ACTIVATION_RESPONSE(0x01.toByte()),
|
||||
DEFAULT_STATUS_RESPONSE(0x1d.toByte()),
|
||||
|
@ -10,55 +10,24 @@ enum class ResponseType(
|
|||
NAK_RESPONSE(0x06.toByte()),
|
||||
UNKNOWN(0xff.toByte());
|
||||
|
||||
fun getValue(): Byte {
|
||||
return value
|
||||
enum class StatusResponseType(override val value: Byte) : HasValue {
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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());
|
||||
enum class ActivationResponseType(override val value: Byte) : HasValue {
|
||||
|
||||
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
|
||||
}
|
||||
GET_VERSION_RESPONSE(0x15.toByte()),
|
||||
SET_UNIQUE_ID_RESPONSE(0x1b.toByte()),
|
||||
UNKNOWN(0xff.toByte());
|
||||
}
|
||||
}
|
|
@ -2,107 +2,32 @@ 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 info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.byValue
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
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
|
||||
}
|
||||
val messageType: Byte = encoded[0]
|
||||
val messageLength: Short = (encoded[1].toInt() and 0xff).toShort()
|
||||
val pulseVolumeInTenThousandthMicroLiter: Short = ByteBuffer.wrap(byteArrayOf(encoded[2], encoded[3])).short
|
||||
val pumpRate: Short = (encoded[4].toInt() and 0xff).toShort()
|
||||
val primePumpRate: Short = (encoded[5].toInt() and 0xff).toShort()
|
||||
val numberOfEngagingClutchDrivePulses: Short = (encoded[6].toInt() and 0xff).toShort()
|
||||
val numberOfPrimePulses: Short = (encoded[7].toInt() and 0xff).toShort()
|
||||
val podExpirationTimeInHours: Short = (encoded[8].toInt() and 0xff).toShort()
|
||||
val firmwareVersionMajor: Short = (encoded[9].toInt() and 0xff).toShort()
|
||||
val firmwareVersionMinor: Short = (encoded[10].toInt() and 0xff).toShort()
|
||||
val firmwareVersionInterim: Short = (encoded[11].toInt() and 0xff).toShort()
|
||||
val bleVersionMajor: Short = (encoded[12].toInt() and 0xff).toShort()
|
||||
val bleVersionMinor: Short = (encoded[13].toInt() and 0xff).toShort()
|
||||
val bleVersionInterim: Short = (encoded[14].toInt() and 0xff).toShort()
|
||||
val productId: Short = (encoded[15].toInt() and 0xff).toShort()
|
||||
val podStatus: PodStatus = byValue(encoded[16], PodStatus.UNKNOWN)
|
||||
val lotNumber: Long = ByteBuffer.wrap(byteArrayOf(0, 0, 0, 0, encoded[17], encoded[18], encoded[19], encoded[20])).long
|
||||
val podSequenceNumber: Long = ByteBuffer.wrap(byteArrayOf(0, 0, 0, 0, encoded[21], encoded[22], encoded[23], encoded[24])).long
|
||||
val uniqueIdReceivedInCommand: Long = ByteBuffer.wrap(byteArrayOf(0, 0, 0, 0, encoded[25], encoded[26], encoded[27], encoded[28])).long
|
||||
|
||||
override fun toString(): String {
|
||||
return "SetUniqueIdResponse{" +
|
||||
|
@ -131,25 +56,4 @@ class SetUniqueIdResponse(
|
|||
'}'
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ 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 info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.byValue
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.*
|
||||
import kotlin.experimental.and
|
||||
|
@ -10,81 +11,21 @@ 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
|
||||
}
|
||||
val messageType: Byte = encoded[0]
|
||||
val messageLength: Short = (encoded[1].toInt() and 0xff).toShort()
|
||||
val firmwareVersionMajor: Short = (encoded[2].toInt() and 0xff).toShort()
|
||||
val firmwareVersionMinor: Short = (encoded[3].toInt() and 0xff).toShort()
|
||||
val firmwareVersionInterim: Short = (encoded[4].toInt() and 0xff).toShort()
|
||||
val bleVersionMajor: Short = (encoded[5].toInt() and 0xff).toShort()
|
||||
val bleVersionMinor: Short = (encoded[6].toInt() and 0xff).toShort()
|
||||
val bleVersionInterim: Short = (encoded[7].toInt() and 0xff).toShort()
|
||||
val productId: Short = (encoded[8].toInt() and 0xff).toShort()
|
||||
val podStatus: PodStatus = byValue((encoded[9] and 0xf), PodStatus.UNKNOWN)
|
||||
val lotNumber: Long = ByteBuffer.wrap(byteArrayOf(0, 0, 0, 0, encoded[10], encoded[11], encoded[12], encoded[13])).long
|
||||
val podSequenceNumber: Long = ByteBuffer.wrap(byteArrayOf(0, 0, 0, 0, encoded[14], encoded[15], encoded[16], encoded[17])).long
|
||||
val rssi: Byte = (encoded[18] and 0x3f)
|
||||
val receiverLowerGain: Byte = ((encoded[18].toInt() shr 6 and 0x03).toByte())
|
||||
val uniqueIdReceivedInCommand: Long = ByteBuffer.wrap(byteArrayOf(0, 0, 0, 0, encoded[19], encoded[20], encoded[21], encoded[22])).long
|
||||
|
||||
override fun toString(): String {
|
||||
return "VersionResponse{" +
|
||||
|
|
|
@ -34,14 +34,20 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
|||
store()
|
||||
}
|
||||
|
||||
override val isUniqueIdSet: Boolean = activationProgress.isAtLeast(ActivationProgress.SET_UNIQUE_ID)
|
||||
// TODO: dynamic get() fun instead of assignment
|
||||
|
||||
override val isActivationCompleted: Boolean = activationProgress == ActivationProgress.COMPLETED
|
||||
override val isUniqueIdSet: Boolean
|
||||
get() = activationProgress.isAtLeast(ActivationProgress.SET_UNIQUE_ID)
|
||||
|
||||
override val isSuspended: Boolean = podState.deliveryStatus?.equals(DeliveryStatus.SUSPENDED)
|
||||
?: true
|
||||
override val isActivationCompleted: Boolean
|
||||
get() = activationProgress == ActivationProgress.COMPLETED
|
||||
|
||||
override val isPodRunning: Boolean = podState.podStatus?.isRunning() ?: false
|
||||
override val isSuspended: Boolean
|
||||
get() = podState.deliveryStatus?.equals(DeliveryStatus.SUSPENDED)
|
||||
?: true
|
||||
|
||||
override val isPodRunning: Boolean
|
||||
get() = podState.podStatus?.isRunning() ?: false
|
||||
|
||||
override var lastConnection: Long
|
||||
get() = podState.lastConnection
|
||||
|
@ -50,54 +56,77 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
|||
store()
|
||||
}
|
||||
|
||||
override val lastUpdated: Long = podState.lastUpdated
|
||||
override val lastUpdated: Long
|
||||
get() = podState.lastUpdated
|
||||
|
||||
override val messageSequenceNumber: Short = podState.messageSequenceNumber
|
||||
override val messageSequenceNumber: Short
|
||||
get() = podState.messageSequenceNumber
|
||||
|
||||
override val sequenceNumberOfLastProgrammingCommand: Short? = podState.sequenceNumberOfLastProgrammingCommand
|
||||
override val sequenceNumberOfLastProgrammingCommand: Short?
|
||||
get() = podState.sequenceNumberOfLastProgrammingCommand
|
||||
|
||||
override val activationTime: Long? = podState.activationTime
|
||||
override val activationTime: Long?
|
||||
get() = podState.activationTime
|
||||
|
||||
override val uniqueId: Long? = podState.uniqueId
|
||||
override val uniqueId: Long?
|
||||
get() = podState.uniqueId
|
||||
|
||||
override val bluetoothAddress: String? = podState.bluetoothAddress
|
||||
override val bluetoothAddress: String?
|
||||
get() = podState.bluetoothAddress
|
||||
|
||||
override val bluetoothVersion: SoftwareVersion? = podState.bleVersion
|
||||
override val bluetoothVersion: SoftwareVersion?
|
||||
get() = podState.bleVersion
|
||||
|
||||
override val firmwareVersion: SoftwareVersion? = podState.firmwareVersion
|
||||
override val firmwareVersion: SoftwareVersion?
|
||||
get() = podState.firmwareVersion
|
||||
|
||||
override val lotNumber: Long? = podState.lotNumber
|
||||
override val lotNumber: Long?
|
||||
get() = podState.lotNumber
|
||||
|
||||
override val podSequenceNumber: Long? = podState.podSequenceNumber
|
||||
override val podSequenceNumber: Long?
|
||||
get() = podState.podSequenceNumber
|
||||
|
||||
override val pulseRate: Short? = podState.pulseRate
|
||||
override val pulseRate: Short?
|
||||
get() = podState.pulseRate
|
||||
|
||||
override val primePulseRate: Short? = podState.primePulseRate
|
||||
override val primePulseRate: Short?
|
||||
get() = podState.primePulseRate
|
||||
|
||||
override val podLifeInHours: Short? = podState.podLifeInHours
|
||||
override val podLifeInHours: Short?
|
||||
get() = podState.podLifeInHours
|
||||
|
||||
override val firstPrimeBolusVolume: Short? = podState.firstPrimeBolusVolume
|
||||
override val firstPrimeBolusVolume: Short?
|
||||
get() = podState.firstPrimeBolusVolume
|
||||
|
||||
override val secondPrimeBolusVolume: Short? = podState.secondPrimeBolusVolume
|
||||
override val secondPrimeBolusVolume: Short?
|
||||
get() = podState.secondPrimeBolusVolume
|
||||
|
||||
override val pulsesDelivered: Short? = podState.pulsesDelivered
|
||||
override val pulsesDelivered: Short?
|
||||
get() = podState.pulsesDelivered
|
||||
|
||||
override val pulsesRemaining: Short? = podState.pulsesRemaining
|
||||
override val pulsesRemaining: Short?
|
||||
get() = podState.pulsesRemaining
|
||||
|
||||
override val podStatus: PodStatus? = podState.podStatus
|
||||
override val podStatus: PodStatus?
|
||||
get() = podState.podStatus
|
||||
|
||||
override val deliveryStatus: DeliveryStatus? = podState.deliveryStatus
|
||||
override val deliveryStatus: DeliveryStatus?
|
||||
get() = podState.deliveryStatus
|
||||
|
||||
override val minutesSinceActivation: Short? = podState.minutesSinceActivation
|
||||
override val minutesSinceActivation: Short?
|
||||
get() = podState.minutesSinceActivation
|
||||
|
||||
override val activeAlerts: EnumSet<AlertSlot>? = podState.activeAlerts
|
||||
override val activeAlerts: EnumSet<AlertSlot>?
|
||||
get() = podState.activeAlerts
|
||||
|
||||
override val tempBasal: OmnipodDashPodStateManager.TempBasal? = podState.tempBasal
|
||||
override val tempBasal: OmnipodDashPodStateManager.TempBasal?
|
||||
get() = podState.tempBasal
|
||||
|
||||
override val tempBasalActive: Boolean
|
||||
get() = tempBasal != null && tempBasal.startTime + tempBasal.durationInMinutes * 60 * 1000 > System.currentTimeMillis()
|
||||
get() = tempBasal != null && tempBasal!!.startTime + tempBasal!!.durationInMinutes * 60 * 1000 > System.currentTimeMillis()
|
||||
|
||||
override val basalProgram: BasalProgram? = podState.basalProgram
|
||||
override val basalProgram: BasalProgram?
|
||||
get() = podState.basalProgram
|
||||
|
||||
override fun increaseMessageSequenceNumber() {
|
||||
podState.messageSequenceNumber = ((podState.messageSequenceNumber.toInt() + 1) and 0x0f).toShort()
|
||||
|
@ -105,42 +134,42 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
|||
}
|
||||
|
||||
override fun updateFromDefaultStatusResponse(response: DefaultStatusResponse) {
|
||||
podState.deliveryStatus = response.getDeliveryStatus()
|
||||
podState.podStatus = response.getPodStatus()
|
||||
podState.pulsesDelivered = response.getTotalPulsesDelivered()
|
||||
podState.pulsesRemaining = response.getReservoirPulsesRemaining()
|
||||
podState.sequenceNumberOfLastProgrammingCommand = response.getSequenceNumberOfLastProgrammingCommand()
|
||||
podState.minutesSinceActivation = response.getMinutesSinceActivation()
|
||||
podState.deliveryStatus = response.deliveryStatus
|
||||
podState.podStatus = response.podStatus
|
||||
podState.pulsesDelivered = response.totalPulsesDelivered
|
||||
podState.pulsesRemaining = response.reservoirPulsesRemaining
|
||||
podState.sequenceNumberOfLastProgrammingCommand = response.sequenceNumberOfLastProgrammingCommand
|
||||
podState.minutesSinceActivation = response.minutesSinceActivation
|
||||
|
||||
// TODO active alerts
|
||||
|
||||
podState.lastUpdated = System.currentTimeMillis()
|
||||
store();
|
||||
store()
|
||||
}
|
||||
|
||||
override fun updateFromVersionResponse(response: VersionResponse) {
|
||||
podState.bleVersion = SoftwareVersion(response.getBleVersionMajor(), response.getBleVersionMinor(), response.getBleVersionInterim())
|
||||
podState.firmwareVersion = SoftwareVersion(response.getFirmwareVersionMajor(), response.getFirmwareVersionMinor(), response.getFirmwareVersionInterim())
|
||||
podState.podStatus = response.getPodStatus()
|
||||
podState.lotNumber = response.getLotNumber()
|
||||
podState.podSequenceNumber = response.getPodSequenceNumber()
|
||||
podState.bleVersion = SoftwareVersion(response.bleVersionMajor, response.bleVersionMinor, response.bleVersionInterim)
|
||||
podState.firmwareVersion = SoftwareVersion(response.firmwareVersionMajor, response.firmwareVersionMinor, response.firmwareVersionInterim)
|
||||
podState.podStatus = response.podStatus
|
||||
podState.lotNumber = response.lotNumber
|
||||
podState.podSequenceNumber = response.podSequenceNumber
|
||||
|
||||
podState.lastUpdated = System.currentTimeMillis()
|
||||
store()
|
||||
}
|
||||
|
||||
override fun updateFromSetUniqueIdResponse(response: SetUniqueIdResponse) {
|
||||
podState.pulseRate = response.getDeliveryRate()
|
||||
podState.primePulseRate = response.getPrimeRate()
|
||||
podState.firstPrimeBolusVolume = response.getNumberOfPrimePulses()
|
||||
podState.secondPrimeBolusVolume = response.getNumberOfEngagingClutchDrivePulses()
|
||||
podState.podLifeInHours = response.getPodExpirationTimeInHours()
|
||||
podState.bleVersion = SoftwareVersion(response.getBleVersionMajor(), response.getBleVersionMinor(), response.getBleVersionInterim())
|
||||
podState.firmwareVersion = SoftwareVersion(response.getFirmwareVersionMajor(), response.getFirmwareVersionMinor(), response.getFirmwareVersionInterim())
|
||||
podState.podStatus = response.getPodStatus()
|
||||
podState.lotNumber = response.getLotNumber()
|
||||
podState.podSequenceNumber = response.getPodSequenceNumber()
|
||||
podState.uniqueId = response.getUniqueIdReceivedInCommand()
|
||||
podState.pulseRate = response.pumpRate
|
||||
podState.primePulseRate = response.primePumpRate
|
||||
podState.firstPrimeBolusVolume = response.numberOfPrimePulses
|
||||
podState.secondPrimeBolusVolume = response.numberOfEngagingClutchDrivePulses
|
||||
podState.podLifeInHours = response.podExpirationTimeInHours
|
||||
podState.bleVersion = SoftwareVersion(response.bleVersionMajor, response.bleVersionMinor, response.bleVersionInterim)
|
||||
podState.firmwareVersion = SoftwareVersion(response.firmwareVersionMajor, response.firmwareVersionMinor, response.firmwareVersionInterim)
|
||||
podState.podStatus = response.podStatus
|
||||
podState.lotNumber = response.lotNumber
|
||||
podState.podSequenceNumber = response.podSequenceNumber
|
||||
podState.uniqueId = response.uniqueIdReceivedInCommand
|
||||
|
||||
podState.lastUpdated = System.currentTimeMillis()
|
||||
store()
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util
|
||||
|
||||
interface HasValue {
|
||||
|
||||
val value: Byte
|
||||
}
|
||||
|
||||
inline fun <reified T> byValue(value: Byte, default: T): T where T : Enum<T>, T : HasValue {
|
||||
return enumValues<T>().firstOrNull { it.value == value } ?: default
|
||||
}
|
|
@ -14,7 +14,7 @@ object MessageUtil {
|
|||
val b = sArr[s.toInt()].toByte()
|
||||
var s2 = b.toShort()
|
||||
if (b < 0) {
|
||||
s2 = ((b and Byte.MAX_VALUE) as Byte + 128).toShort()
|
||||
s2 = ((b and Byte.MAX_VALUE) + 128).toShort()
|
||||
}
|
||||
i += s2.toInt()
|
||||
s = (s + 1).toShort()
|
||||
|
@ -28,7 +28,7 @@ object MessageUtil {
|
|||
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()
|
||||
s2 = ((b2 and Byte.MAX_VALUE) + 128).toShort()
|
||||
}
|
||||
s = (((s.toInt() shr 8).toShort() and 255) xor crc16table[s2.toInt()])
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.wizard.activation.viewmodel.action
|
||||
|
||||
import android.os.AsyncTask
|
||||
import androidx.annotation.StringRes
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.data.PumpEnactResult
|
||||
|
@ -8,12 +7,12 @@ import info.nightscout.androidaps.logging.AAPSLogger
|
|||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.ui.wizard.activation.viewmodel.action.InitializePodViewModel
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.R
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.OmnipodDashBleManager
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.OmnipodDashManager
|
||||
import javax.inject.Inject
|
||||
|
||||
class DashInitializePodViewModel @Inject constructor(private val aapsLogger: AAPSLogger,
|
||||
private val injector: HasAndroidInjector,
|
||||
private val bleManager: OmnipodDashBleManager) : InitializePodViewModel() {
|
||||
private val omnipodManager: OmnipodDashManager) : InitializePodViewModel() {
|
||||
|
||||
override fun isPodInAlarm(): Boolean = false // TODO
|
||||
|
||||
|
@ -23,13 +22,11 @@ class DashInitializePodViewModel @Inject constructor(private val aapsLogger: AAP
|
|||
|
||||
override fun doExecuteAction(): PumpEnactResult {
|
||||
// TODO FIRST STEP OF ACTIVATION
|
||||
AsyncTask.execute {
|
||||
try {
|
||||
bleManager.activateNewPod()
|
||||
} catch (e: Exception) {
|
||||
aapsLogger.error(LTag.PUMP, "TEST ACTIVATE Exception" + e.toString())
|
||||
}
|
||||
}
|
||||
val disposable = omnipodManager.activatePodPart1().subscribe(
|
||||
{ podEvent -> aapsLogger.debug(LTag.PUMP, "Received PodEvent in Pod activation part 1: $podEvent") },
|
||||
{ throwable -> aapsLogger.error(LTag.PUMP, "Error in Pod activation part 1: $throwable") },
|
||||
{ aapsLogger.debug("Pod activation part 1 completed") }
|
||||
)
|
||||
|
||||
return PumpEnactResult(injector).success(false).comment("not implemented")
|
||||
}
|
||||
|
@ -39,4 +36,4 @@ class DashInitializePodViewModel @Inject constructor(private val aapsLogger: AAP
|
|||
|
||||
@StringRes
|
||||
override fun getTextId() = R.string.omnipod_dash_pod_activation_wizard_initialize_pod_text
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.util
|
||||
|
||||
import info.nightscout.androidaps.data.Profile
|
||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BasalProgram
|
||||
import java.util.*
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
fun mapProfileToBasalProgram(profile: Profile): BasalProgram {
|
||||
val basalValues = profile.basalValues
|
||||
?: throw IllegalArgumentException("Basal values can not be null")
|
||||
if (basalValues.isEmpty()) {
|
||||
throw IllegalArgumentException("Basal values should contain values")
|
||||
}
|
||||
|
||||
val entries: MutableList<BasalProgram.Segment> = ArrayList()
|
||||
|
||||
var previousBasalValue: Profile.ProfileValue? = null
|
||||
|
||||
for (basalValue in basalValues) {
|
||||
if (basalValue.timeAsSeconds >= 86_400) {
|
||||
throw IllegalArgumentException("Basal segment start time can not be greater than 86400")
|
||||
}
|
||||
if (basalValue.timeAsSeconds < 0) {
|
||||
throw IllegalArgumentException("Basal segment start time can not be less than 0")
|
||||
}
|
||||
if (basalValue.timeAsSeconds % 1_800 != 0) {
|
||||
throw IllegalArgumentException("Basal segment time should be dividable by 30 minutes")
|
||||
}
|
||||
|
||||
val startSlotIndex = (basalValue.timeAsSeconds / 1800).toShort()
|
||||
|
||||
if (previousBasalValue != null) {
|
||||
entries.add(
|
||||
BasalProgram.Segment(
|
||||
(previousBasalValue!!.timeAsSeconds / 1800).toShort(),
|
||||
startSlotIndex,
|
||||
(PumpType.Omnipod_Dash.determineCorrectBasalSize(previousBasalValue.value) * 100).roundToInt()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if (entries.size == 0 && basalValue.timeAsSeconds != 0) {
|
||||
throw java.lang.IllegalArgumentException("First basal segment start time should be 0")
|
||||
}
|
||||
|
||||
if (entries.size > 0 && entries[entries.size - 1].endSlotIndex != startSlotIndex) {
|
||||
throw IllegalArgumentException("Illegal start time for basal segment: does not match previous previous segment's end time")
|
||||
}
|
||||
|
||||
previousBasalValue = basalValue
|
||||
}
|
||||
|
||||
entries.add(
|
||||
BasalProgram.Segment(
|
||||
(previousBasalValue!!.timeAsSeconds / 1800).toShort(),
|
||||
48,
|
||||
(PumpType.Omnipod_Dash.determineCorrectBasalSize(previousBasalValue.value) * 100).roundToInt()
|
||||
)
|
||||
)
|
||||
|
||||
return BasalProgram(entries)
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
|
||||
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
public class DeactivateCommandTest {
|
||||
@Test
|
||||
public void testEncoding() throws DecoderException {
|
||||
byte[] encoded = new DeactivateCommand.Builder() //
|
||||
.setUniqueId(37879809) //
|
||||
.setSequenceNumber((short) 5) //
|
||||
.setNonce(1229869870) //
|
||||
.build() //
|
||||
.getEncoded();
|
||||
|
||||
assertArrayEquals(Hex.decodeHex("0242000114061C04494E532E001C"), encoded);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
|
||||
|
||||
import org.apache.commons.codec.DecoderException
|
||||
import org.apache.commons.codec.binary.Hex
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
|
||||
class DeactivateCommandTest {
|
||||
|
||||
@Test @Throws(DecoderException::class) fun testEncoding() {
|
||||
val encoded = DeactivateCommand.Builder() //
|
||||
.setUniqueId(37879809) //
|
||||
.setSequenceNumber(5.toShort()) //
|
||||
.setNonce(1229869870) //
|
||||
.build() //
|
||||
.encoded
|
||||
|
||||
Assert.assertArrayEquals(Hex.decodeHex("0242000114061C04494E532E001C"), encoded)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
|
||||
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
public class GetVersionCommandTest {
|
||||
@Test
|
||||
public void testEncoding() throws DecoderException {
|
||||
byte[] encoded = new GetVersionCommand.Builder() //
|
||||
.setSequenceNumber((short) 0) //
|
||||
.setUniqueId(GetVersionCommand.DEFAULT_UNIQUE_ID) //
|
||||
.build() //
|
||||
.getEncoded();
|
||||
|
||||
assertArrayEquals(Hex.decodeHex("FFFFFFFF00060704FFFFFFFF82B2"), encoded);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
|
||||
|
||||
import org.apache.commons.codec.DecoderException
|
||||
import org.apache.commons.codec.binary.Hex
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
|
||||
class GetVersionCommandTest {
|
||||
|
||||
@Test @Throws(DecoderException::class) fun testEncoding() {
|
||||
val encoded = GetVersionCommand.Builder() //
|
||||
.setSequenceNumber(0.toShort()) //
|
||||
.setUniqueId(GetVersionCommand.DEFAULT_UNIQUE_ID) //
|
||||
.build() //
|
||||
.encoded
|
||||
|
||||
Assert.assertArrayEquals(Hex.decodeHex("FFFFFFFF00060704FFFFFFFF82B2"), encoded)
|
||||
}
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
|
||||
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertConfiguration;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertSlot;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertTriggerType;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepRepetitionType;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
public class ProgramAlertsCommandTest {
|
||||
@Test
|
||||
public void testExpirationAlerts() throws DecoderException {
|
||||
List<AlertConfiguration> configurations = new ArrayList<>();
|
||||
configurations.add(new AlertConfiguration(AlertSlot.EXPIRATION, true, (short) 420, false, AlertTriggerType.TIME_TRIGGER, (short) 4305, BeepType.FOUR_TIMES_BIP_BEEP, BeepRepetitionType.XXX3));
|
||||
configurations.add(new AlertConfiguration(AlertSlot.EXPIRATION_IMMINENT, true, (short) 0, false, AlertTriggerType.TIME_TRIGGER, (short) 4725, BeepType.FOUR_TIMES_BIP_BEEP, BeepRepetitionType.XXX4));
|
||||
|
||||
byte[] encoded = new ProgramAlertsCommand.Builder() //
|
||||
.setUniqueId(37879811) //
|
||||
.setSequenceNumber((short) 3) //
|
||||
.setMultiCommandFlag(true) //
|
||||
.setNonce(1229869870) //
|
||||
.setAlertConfigurations(configurations) //
|
||||
.build() //
|
||||
.getEncoded();
|
||||
|
||||
assertArrayEquals(Hex.decodeHex("024200038C121910494E532E79A410D1050228001275060280F5"), encoded);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLowReservoirAlert() throws DecoderException {
|
||||
List<AlertConfiguration> configurations = new ArrayList<>();
|
||||
configurations.add(new AlertConfiguration(AlertSlot.LOW_RESERVOIR, true, (short) 0, false, AlertTriggerType.RESERVOIR_VOLUME_TRIGGER, (short) 200, BeepType.FOUR_TIMES_BIP_BEEP, BeepRepetitionType.XXX));
|
||||
|
||||
byte[] encoded = new ProgramAlertsCommand.Builder() //
|
||||
.setUniqueId(37879811) //
|
||||
.setSequenceNumber((short) 8) //
|
||||
.setNonce(1229869870) //
|
||||
.setAlertConfigurations(configurations) //
|
||||
.build() //
|
||||
.getEncoded();
|
||||
|
||||
assertArrayEquals(Hex.decodeHex("02420003200C190A494E532E4C0000C801020149"), encoded);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserExpirationAlert() throws DecoderException {
|
||||
List<AlertConfiguration> configurations = new ArrayList<>();
|
||||
configurations.add(new AlertConfiguration(AlertSlot.USER_SET_EXPIRATION, true, (short) 0, false, AlertTriggerType.TIME_TRIGGER, (short) 4079, BeepType.FOUR_TIMES_BIP_BEEP, BeepRepetitionType.XXX2));
|
||||
|
||||
byte[] encoded = new ProgramAlertsCommand.Builder() //
|
||||
.setUniqueId(37879811) //
|
||||
.setSequenceNumber((short) 15) //
|
||||
.setNonce(1229869870) //
|
||||
.setAlertConfigurations(configurations) //
|
||||
.build() //
|
||||
.getEncoded();
|
||||
|
||||
assertArrayEquals(Hex.decodeHex("024200033C0C190A494E532E38000FEF030203E2"), encoded);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLumpOfCoalAlert() throws DecoderException {
|
||||
List<AlertConfiguration> configurations = new ArrayList<>();
|
||||
configurations.add(new AlertConfiguration(AlertSlot.EXPIRATION, true, (short) 55, false, AlertTriggerType.TIME_TRIGGER, (short) 5, BeepType.FOUR_TIMES_BIP_BEEP, BeepRepetitionType.XXX5));
|
||||
|
||||
byte[] encoded = new ProgramAlertsCommand.Builder() //
|
||||
.setUniqueId(37879811) //
|
||||
.setSequenceNumber((short) 10) //
|
||||
.setMultiCommandFlag(false) //
|
||||
.setNonce(1229869870) //
|
||||
.setAlertConfigurations(configurations) //
|
||||
.build() //
|
||||
.getEncoded();
|
||||
|
||||
assertArrayEquals(Hex.decodeHex("02420003280C190A494E532E7837000508020356"), encoded);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertConfiguration
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertSlot
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertTriggerType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepRepetitionType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType
|
||||
import org.apache.commons.codec.DecoderException
|
||||
import org.apache.commons.codec.binary.Hex
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import java.util.*
|
||||
|
||||
class ProgramAlertsCommandTest {
|
||||
|
||||
@Test @Throws(DecoderException::class) fun testExpirationAlerts() {
|
||||
val configurations: MutableList<AlertConfiguration> = ArrayList()
|
||||
configurations.add(AlertConfiguration(AlertSlot.EXPIRATION, true, 420.toShort(), false, AlertTriggerType.TIME_TRIGGER, 4305.toShort(), BeepType.FOUR_TIMES_BIP_BEEP, BeepRepetitionType.XXX3))
|
||||
configurations.add(AlertConfiguration(AlertSlot.EXPIRATION_IMMINENT, true, 0.toShort(), false, AlertTriggerType.TIME_TRIGGER, 4725.toShort(), BeepType.FOUR_TIMES_BIP_BEEP, BeepRepetitionType.XXX4))
|
||||
|
||||
val encoded = ProgramAlertsCommand.Builder() //
|
||||
.setUniqueId(37879811) //
|
||||
.setSequenceNumber(3.toShort()) //
|
||||
.setMultiCommandFlag(true) //
|
||||
.setNonce(1229869870) //
|
||||
.setAlertConfigurations(configurations) //
|
||||
.build() //
|
||||
.encoded
|
||||
|
||||
Assert.assertArrayEquals(Hex.decodeHex("024200038C121910494E532E79A410D1050228001275060280F5"), encoded)
|
||||
}
|
||||
|
||||
@Test @Throws(DecoderException::class) fun testLowReservoirAlert() {
|
||||
val configurations: MutableList<AlertConfiguration> = ArrayList()
|
||||
configurations.add(AlertConfiguration(AlertSlot.LOW_RESERVOIR, true, 0.toShort(), false, AlertTriggerType.RESERVOIR_VOLUME_TRIGGER, 200.toShort(), BeepType.FOUR_TIMES_BIP_BEEP, BeepRepetitionType.XXX))
|
||||
|
||||
val encoded = ProgramAlertsCommand.Builder() //
|
||||
.setUniqueId(37879811) //
|
||||
.setSequenceNumber(8.toShort()) //
|
||||
.setNonce(1229869870) //
|
||||
.setAlertConfigurations(configurations) //
|
||||
.build() //
|
||||
.encoded
|
||||
|
||||
Assert.assertArrayEquals(Hex.decodeHex("02420003200C190A494E532E4C0000C801020149"), encoded)
|
||||
}
|
||||
|
||||
@Test @Throws(DecoderException::class) fun testUserExpirationAlert() {
|
||||
val configurations: MutableList<AlertConfiguration> = ArrayList()
|
||||
configurations.add(AlertConfiguration(AlertSlot.USER_SET_EXPIRATION, true, 0.toShort(), false, AlertTriggerType.TIME_TRIGGER, 4079.toShort(), BeepType.FOUR_TIMES_BIP_BEEP, BeepRepetitionType.XXX2))
|
||||
|
||||
val encoded = ProgramAlertsCommand.Builder() //
|
||||
.setUniqueId(37879811) //
|
||||
.setSequenceNumber(15.toShort()) //
|
||||
.setNonce(1229869870) //
|
||||
.setAlertConfigurations(configurations) //
|
||||
.build() //
|
||||
.encoded
|
||||
|
||||
Assert.assertArrayEquals(Hex.decodeHex("024200033C0C190A494E532E38000FEF030203E2"), encoded)
|
||||
}
|
||||
|
||||
@Test @Throws(DecoderException::class) fun testLumpOfCoalAlert() {
|
||||
val configurations: MutableList<AlertConfiguration> = ArrayList()
|
||||
configurations.add(AlertConfiguration(AlertSlot.EXPIRATION, true, 55.toShort(), false, AlertTriggerType.TIME_TRIGGER, 5.toShort(), BeepType.FOUR_TIMES_BIP_BEEP, BeepRepetitionType.XXX5))
|
||||
|
||||
val encoded = ProgramAlertsCommand.Builder() //
|
||||
.setUniqueId(37879811) //
|
||||
.setSequenceNumber(10.toShort()) //
|
||||
.setMultiCommandFlag(false) //
|
||||
.setNonce(1229869870) //
|
||||
.setAlertConfigurations(configurations) //
|
||||
.build() //
|
||||
.encoded
|
||||
|
||||
Assert.assertArrayEquals(Hex.decodeHex("02420003280C190A494E532E7837000508020356"), encoded)
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
|
||||
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
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 static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
public class ProgramBasalCommandTest {
|
||||
@Test
|
||||
public void testProgramBasalCommand() throws DecoderException {
|
||||
List<BasalProgram.Segment> segments = Arrays.asList(
|
||||
new BasalProgram.Segment((short) 0, (short) 48, 300)
|
||||
);
|
||||
BasalProgram basalProgram = new BasalProgram(segments);
|
||||
Date date = new Date(2021, 1, 17, 14, 47, 43);
|
||||
|
||||
byte[] encoded = new ProgramBasalCommand.Builder() //
|
||||
.setUniqueId(37879809) //
|
||||
.setNonce(1229869870) //
|
||||
.setSequenceNumber((short) 10) //
|
||||
.setBasalProgram(basalProgram) //
|
||||
.setCurrentTime(date) //
|
||||
.setProgramReminder(new ProgramReminder(false, true, (byte) 0)) //
|
||||
.build() //
|
||||
.getEncoded();
|
||||
|
||||
assertArrayEquals(Hex.decodeHex("0242000128241A12494E532E0005E81D1708000CF01EF01EF01E130E40001593004C4B403840005B8D80827C"), encoded);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
|
||||
|
||||
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 org.apache.commons.codec.DecoderException
|
||||
import org.apache.commons.codec.binary.Hex
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import java.util.*
|
||||
|
||||
class ProgramBasalCommandTest {
|
||||
|
||||
@Test @Throws(DecoderException::class) fun testProgramBasalCommand() {
|
||||
val segments = listOf(
|
||||
BasalProgram.Segment(0.toShort(), 48.toShort(), 300)
|
||||
)
|
||||
val basalProgram = BasalProgram(segments)
|
||||
val date = Date(2021, 1, 17, 14, 47, 43)
|
||||
|
||||
val encoded = ProgramBasalCommand.Builder() //
|
||||
.setUniqueId(37879809) //
|
||||
.setNonce(1229869870) //
|
||||
.setSequenceNumber(10.toShort()) //
|
||||
.setBasalProgram(basalProgram) //
|
||||
.setCurrentTime(date) //
|
||||
.setProgramReminder(ProgramReminder(false, true, 0.toByte())) //
|
||||
.build() //
|
||||
.encoded
|
||||
|
||||
Assert.assertArrayEquals(Hex.decodeHex("0242000128241A12494E532E0005E81D1708000CF01EF01EF01E130E40001593004C4B403840005B8D80827C"), encoded)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
|
||||
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.junit.Test;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ProgramReminder;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
public class ProgramBolusCommandTest {
|
||||
@Test
|
||||
public void testProgramBolusCommand() throws DecoderException {
|
||||
byte[] encoded = new ProgramBolusCommand.Builder() //
|
||||
.setNumberOfUnits(5) //
|
||||
.setProgramReminder(new ProgramReminder(false, true, (byte) 0)) //
|
||||
.setDelayBetweenPulsesInEighthSeconds((byte) 16) //
|
||||
.setUniqueId(37879809) //
|
||||
.setSequenceNumber((short) 14) //
|
||||
.setNonce(1229869870) //
|
||||
.build() //
|
||||
.getEncoded();
|
||||
|
||||
assertArrayEquals(Hex.decodeHex("02420001381F1A0E494E532E02010F01064000640064170D4003E800030D4000000000000080F6"), encoded);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
|
||||
|
||||
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 ProgramBolusCommandTest {
|
||||
|
||||
@Test @Throws(DecoderException::class) fun testProgramBolusCommand() {
|
||||
val encoded = ProgramBolusCommand.Builder() //
|
||||
.setNumberOfUnits(5.0) //
|
||||
.setProgramReminder(ProgramReminder(false, true, 0.toByte())) //
|
||||
.setDelayBetweenPulsesInEighthSeconds(16.toByte()) //
|
||||
.setUniqueId(37879809) //
|
||||
.setSequenceNumber(14.toShort()) //
|
||||
.setNonce(1229869870) //
|
||||
.build() //
|
||||
.encoded
|
||||
|
||||
Assert.assertArrayEquals(Hex.decodeHex("02420001381F1A0E494E532E02010F01064000640064170D4003E800030D4000000000000080F6"), encoded)
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
|
||||
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.junit.Test;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ProgramReminder;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
public class ProgramTempBasalCommandTest {
|
||||
@Test
|
||||
public void testExtraAlternateSegmentPulseTempBasal() throws DecoderException {
|
||||
ProgramTempBasalCommand command = new ProgramTempBasalCommand.Builder() //
|
||||
.setUniqueId(37879809) //
|
||||
.setNonce(1229869870) //
|
||||
.setSequenceNumber((short) 15) //
|
||||
.setRateInUnitsPerHour(5.05d) //
|
||||
.setDurationInMinutes((short) 60) //
|
||||
.setProgramReminder(new ProgramReminder(false, true, (byte) 0)) //
|
||||
.build();
|
||||
|
||||
assertArrayEquals(Hex.decodeHex("024200013C201A0E494E532E01011102384000321832160E400003F20036634403F20036634482A6"), command.getEncoded());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testZeroTempBasal() throws DecoderException {
|
||||
ProgramTempBasalCommand command = new ProgramTempBasalCommand.Builder() //
|
||||
.setUniqueId(37879809) //
|
||||
.setNonce(1229869870) //
|
||||
.setSequenceNumber((short) 7) //
|
||||
.setRateInUnitsPerHour(0.0) //
|
||||
.setDurationInMinutes((short) 300) //
|
||||
.setProgramReminder(new ProgramReminder(true, true, (byte) 0)) //
|
||||
.build();
|
||||
|
||||
assertArrayEquals(Hex.decodeHex("024200011C201A0E494E532E0100820A384000009000160EC000000A6B49D200000AEB49D20001DE"), command.getEncoded());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
|
||||
|
||||
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 ProgramTempBasalCommandTest {
|
||||
|
||||
@Test @Throws(DecoderException::class) fun testExtraAlternateSegmentPulseTempBasal() {
|
||||
val command = ProgramTempBasalCommand.Builder() //
|
||||
.setUniqueId(37879809) //
|
||||
.setNonce(1229869870) //
|
||||
.setSequenceNumber(15.toShort()) //
|
||||
.setRateInUnitsPerHour(5.05) //
|
||||
.setDurationInMinutes(60.toShort()) //
|
||||
.setProgramReminder(ProgramReminder(false, true, 0.toByte())) //
|
||||
.build()
|
||||
|
||||
Assert.assertArrayEquals(Hex.decodeHex("024200013C201A0E494E532E01011102384000321832160E400003F20036634403F20036634482A6"), command.encoded)
|
||||
}
|
||||
|
||||
@Test @Throws(DecoderException::class) fun testZeroTempBasal() {
|
||||
val command = ProgramTempBasalCommand.Builder() //
|
||||
.setUniqueId(37879809) //
|
||||
.setNonce(1229869870) //
|
||||
.setSequenceNumber(7.toShort()) //
|
||||
.setRateInUnitsPerHour(0.0) //
|
||||
.setDurationInMinutes(300.toShort()) //
|
||||
.setProgramReminder(ProgramReminder(true, true, 0.toByte())) //
|
||||
.build()
|
||||
|
||||
Assert.assertArrayEquals(Hex.decodeHex("024200011C201A0E494E532E0100820A384000009000160EC000000A6B49D200000AEB49D20001DE"), command.encoded)
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
|
||||
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
public class SetUniqueIdCommandTest {
|
||||
@Test
|
||||
public void testEncoding() throws DecoderException {
|
||||
@SuppressWarnings("deprecation")
|
||||
byte[] encoded = new SetUniqueIdCommand.Builder() //
|
||||
.setUniqueId(37879811) //
|
||||
.setSequenceNumber((short) 6) //
|
||||
.setLotNumber(135556289) //
|
||||
.setPodSequenceNumber(681767) //
|
||||
.setInitializationTime(new Date(2021, 1, 10, 14, 41)) //
|
||||
.build() //
|
||||
.getEncoded();
|
||||
|
||||
assertArrayEquals(Hex.decodeHex("FFFFFFFF18150313024200031404020A150E2908146CC1000A67278344"), encoded);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
|
||||
|
||||
import org.apache.commons.codec.DecoderException
|
||||
import org.apache.commons.codec.binary.Hex
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import java.util.*
|
||||
|
||||
class SetUniqueIdCommandTest {
|
||||
|
||||
@Test @Throws(DecoderException::class) fun testEncoding() {
|
||||
val encoded = SetUniqueIdCommand.Builder() //
|
||||
.setUniqueId(37879811) //
|
||||
.setSequenceNumber(6.toShort()) //
|
||||
.setLotNumber(135556289) //
|
||||
.setPodSequenceNumber(681767) //
|
||||
.setInitializationTime(Date(2021, 1, 10, 14, 41)) //
|
||||
.build() //
|
||||
.encoded
|
||||
|
||||
Assert.assertArrayEquals(Hex.decodeHex("FFFFFFFF18150313024200031404020A150E2908146CC1000A67278344"), encoded)
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
|
||||
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
public class SilenceAlertsCommandTest {
|
||||
@Test
|
||||
public void testSilenceLowReservoirAlert() throws DecoderException {
|
||||
byte[] encoded = new SilenceAlertsCommand.Builder() //
|
||||
.setUniqueId(37879811) //
|
||||
.setSequenceNumber((short) 1) //
|
||||
.setNonce(1229869870) //
|
||||
.setSilenceLowReservoirAlert(true) //
|
||||
.build() //
|
||||
.getEncoded();
|
||||
|
||||
assertArrayEquals(Hex.decodeHex("0242000304071105494E532E1081CE"), encoded);
|
||||
}
|
||||
|
||||
// TODO capture more silence alerts commands
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
|
||||
|
||||
import org.apache.commons.codec.DecoderException
|
||||
import org.apache.commons.codec.binary.Hex
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
|
||||
class SilenceAlertsCommandTest {
|
||||
|
||||
@Test @Throws(DecoderException::class) fun testSilenceLowReservoirAlert() {
|
||||
val encoded = SilenceAlertsCommand.Builder() //
|
||||
.setUniqueId(37879811) //
|
||||
.setSequenceNumber(1.toShort()) //
|
||||
.setNonce(1229869870) //
|
||||
.setSilenceLowReservoirAlert(true) //
|
||||
.build() //
|
||||
.encoded
|
||||
|
||||
Assert.assertArrayEquals(Hex.decodeHex("0242000304071105494E532E1081CE"), encoded)
|
||||
}
|
||||
|
||||
// TODO capture more silence alerts commands
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
|
||||
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.junit.Test;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
public class StopDeliveryCommandTest {
|
||||
@Test
|
||||
public void testStopTempBasal() throws DecoderException {
|
||||
byte[] encoded = new StopDeliveryCommand.Builder() //
|
||||
.setUniqueId(37879811) //
|
||||
.setSequenceNumber((short) 0) //
|
||||
.setNonce(1229869870) //
|
||||
.setDeliveryType(StopDeliveryCommand.DeliveryType.TEMP_BASAL) //
|
||||
.setBeepType(BeepType.LONG_SINGLE_BEEP) //
|
||||
.build() //
|
||||
.getEncoded();
|
||||
|
||||
assertArrayEquals(Hex.decodeHex("0242000300071F05494E532E6201B1"), encoded);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuspendDelivery() throws DecoderException {
|
||||
byte[] encoded = new StopDeliveryCommand.Builder() //
|
||||
.setUniqueId(37879811) //
|
||||
.setSequenceNumber((short) 2) //
|
||||
.setNonce(1229869870) //
|
||||
.setDeliveryType(StopDeliveryCommand.DeliveryType.ALL) //
|
||||
.setBeepType(BeepType.SILENT) //
|
||||
.build() //
|
||||
.getEncoded();
|
||||
|
||||
assertArrayEquals(Hex.decodeHex("0242000308071F05494E532E078287"), encoded);
|
||||
}
|
||||
|
||||
// TODO test cancel bolus
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType
|
||||
import org.apache.commons.codec.DecoderException
|
||||
import org.apache.commons.codec.binary.Hex
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
|
||||
class StopDeliveryCommandTest {
|
||||
|
||||
@Test @Throws(DecoderException::class) fun testStopTempBasal() {
|
||||
val encoded = StopDeliveryCommand.Builder() //
|
||||
.setUniqueId(37879811) //
|
||||
.setSequenceNumber(0.toShort()) //
|
||||
.setNonce(1229869870) //
|
||||
.setDeliveryType(StopDeliveryCommand.DeliveryType.TEMP_BASAL) //
|
||||
.setBeepType(BeepType.LONG_SINGLE_BEEP) //
|
||||
.build() //
|
||||
.encoded
|
||||
|
||||
Assert.assertArrayEquals(Hex.decodeHex("0242000300071F05494E532E6201B1"), encoded)
|
||||
}
|
||||
|
||||
@Test @Throws(DecoderException::class) fun testSuspendDelivery() {
|
||||
val encoded = StopDeliveryCommand.Builder() //
|
||||
.setUniqueId(37879811) //
|
||||
.setSequenceNumber(2.toShort()) //
|
||||
.setNonce(1229869870) //
|
||||
.setDeliveryType(StopDeliveryCommand.DeliveryType.ALL) //
|
||||
.setBeepType(BeepType.SILENT) //
|
||||
.build() //
|
||||
.encoded
|
||||
|
||||
Assert.assertArrayEquals(Hex.decodeHex("0242000308071F05494E532E078287"), encoded)
|
||||
}
|
||||
|
||||
// TODO test cancel bolus
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response;
|
||||
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.junit.Test;
|
||||
|
||||
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 static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
|
||||
public class AlarmStatusResponseTest {
|
||||
@Test
|
||||
public void testValidResponse() throws DecoderException {
|
||||
byte[] encoded = Hex.decodeHex("021602080100000501BD00000003FF01950000000000670A");
|
||||
AlarmStatusResponse response = new AlarmStatusResponse(encoded);
|
||||
|
||||
assertArrayEquals(encoded, response.getEncoded());
|
||||
assertNotSame(encoded, response.getEncoded());
|
||||
assertEquals(ResponseType.ADDITIONAL_STATUS_RESPONSE, response.getResponseType());
|
||||
assertEquals(ResponseType.ADDITIONAL_STATUS_RESPONSE.getValue(), response.getMessageType());
|
||||
assertEquals(ResponseType.AdditionalStatusResponseType.ALARM_STATUS, response.getStatusResponseType());
|
||||
assertEquals(ResponseType.AdditionalStatusResponseType.ALARM_STATUS.getValue(), response.getAdditionalStatusResponseType());
|
||||
assertEquals(PodStatus.RUNNING_ABOVE_MIN_VOLUME, response.getPodStatus());
|
||||
assertEquals(DeliveryStatus.BASAL_ACTIVE, response.getDeliveryStatus());
|
||||
assertEquals((short) 0, response.getBolusPulsesRemaining());
|
||||
assertEquals((short) 5, response.getSequenceNumberOfLastProgrammingCommand());
|
||||
assertEquals((short) 445, response.getTotalPulsesDelivered());
|
||||
assertEquals(AlarmType.NONE, response.getAlarmType());
|
||||
assertEquals((short) 0, response.getAlarmTime());
|
||||
assertEquals((short) 1023, response.getReservoirPulsesRemaining());
|
||||
assertEquals((short) 405, response.getMinutesSinceActivation());
|
||||
assertFalse(response.isAlert0Active());
|
||||
assertFalse(response.isAlert1Active());
|
||||
assertFalse(response.isAlert2Active());
|
||||
assertFalse(response.isAlert3Active());
|
||||
assertFalse(response.isAlert4Active());
|
||||
assertFalse(response.isAlert5Active());
|
||||
assertFalse(response.isAlert6Active());
|
||||
assertFalse(response.isAlert7Active());
|
||||
assertFalse(response.isOcclusionAlarm());
|
||||
assertFalse(response.isPulseInfoInvalid());
|
||||
assertEquals(PodStatus.UNINITIALIZED, response.getPodStatusWhenAlarmOccurred());
|
||||
assertFalse(response.isImmediateBolusWhenAlarmOccurred());
|
||||
assertEquals((byte) 0x00, response.getOcclusionType());
|
||||
assertFalse(response.isOccurredWhenFetchingImmediateBolusActiveInformation());
|
||||
assertEquals(0, response.getRssi());
|
||||
assertEquals(0, response.getReceiverLowerGain());
|
||||
assertEquals(PodStatus.UNINITIALIZED, response.getPodStatusWhenAlarmOccurred2());
|
||||
assertEquals((short) 26378, response.getReturnAddressOfPodAlarmHandlerCaller());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
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 org.apache.commons.codec.DecoderException
|
||||
import org.apache.commons.codec.binary.Hex
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
|
||||
class AlarmStatusResponseTest {
|
||||
|
||||
@Test @Throws(DecoderException::class) fun testValidResponse() {
|
||||
val encoded = Hex.decodeHex("021602080100000501BD00000003FF01950000000000670A")
|
||||
val response = AlarmStatusResponse(encoded)
|
||||
|
||||
Assert.assertArrayEquals(encoded, response.encoded)
|
||||
Assert.assertNotSame(encoded, response.encoded)
|
||||
Assert.assertEquals(ResponseType.ADDITIONAL_STATUS_RESPONSE, response.responseType)
|
||||
Assert.assertEquals(ResponseType.ADDITIONAL_STATUS_RESPONSE.value, response.messageType)
|
||||
Assert.assertEquals(ResponseType.StatusResponseType.ALARM_STATUS, response.statusResponseType)
|
||||
Assert.assertEquals(ResponseType.StatusResponseType.ALARM_STATUS.value, response.additionalStatusResponseType)
|
||||
Assert.assertEquals(PodStatus.RUNNING_ABOVE_MIN_VOLUME, response.podStatus)
|
||||
Assert.assertEquals(DeliveryStatus.BASAL_ACTIVE, response.deliveryStatus)
|
||||
Assert.assertEquals(0.toShort(), response.bolusPulsesRemaining)
|
||||
Assert.assertEquals(5.toShort(), response.sequenceNumberOfLastProgrammingCommand)
|
||||
Assert.assertEquals(445.toShort(), response.totalPulsesDelivered)
|
||||
Assert.assertEquals(AlarmType.NONE, response.alarmType)
|
||||
Assert.assertEquals(0.toShort(), response.alarmTime)
|
||||
Assert.assertEquals(1023.toShort(), response.reservoirPulsesRemaining)
|
||||
Assert.assertEquals(405.toShort(), response.minutesSinceActivation)
|
||||
Assert.assertFalse(response.alert0Active)
|
||||
Assert.assertFalse(response.alert1Active)
|
||||
Assert.assertFalse(response.alert2Active)
|
||||
Assert.assertFalse(response.alert3Active)
|
||||
Assert.assertFalse(response.alert4Active)
|
||||
Assert.assertFalse(response.alert5Active)
|
||||
Assert.assertFalse(response.alert6Active)
|
||||
Assert.assertFalse(response.alert7Active)
|
||||
Assert.assertFalse(response.occlusionAlarm)
|
||||
Assert.assertFalse(response.pulseInfoInvalid)
|
||||
Assert.assertEquals(PodStatus.UNINITIALIZED, response.podStatusWhenAlarmOccurred)
|
||||
Assert.assertFalse(response.immediateBolusWhenAlarmOccurred)
|
||||
Assert.assertEquals(0x00.toByte(), response.occlusionType)
|
||||
Assert.assertFalse(response.occurredWhenFetchingImmediateBolusActiveInformation)
|
||||
Assert.assertEquals(0.toShort(), response.rssi)
|
||||
Assert.assertEquals(0.toShort(), response.receiverLowerGain)
|
||||
Assert.assertEquals(PodStatus.UNINITIALIZED, response.podStatusWhenAlarmOccurred2)
|
||||
Assert.assertEquals(26378.toShort(), response.returnAddressOfPodAlarmHandlerCaller)
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response;
|
||||
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.junit.Test;
|
||||
|
||||
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 static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
|
||||
public class DefaultStatusResponseTest {
|
||||
@Test
|
||||
public void testValidResponse() throws DecoderException {
|
||||
byte[] encoded = Hex.decodeHex("1D1800A02800000463FF");
|
||||
DefaultStatusResponse response = new DefaultStatusResponse(encoded);
|
||||
|
||||
assertArrayEquals(encoded, response.getEncoded());
|
||||
assertNotSame(encoded, response.getEncoded());
|
||||
assertEquals(ResponseType.DEFAULT_STATUS_RESPONSE, response.getResponseType());
|
||||
assertEquals(ResponseType.DEFAULT_STATUS_RESPONSE.getValue(), response.getMessageType());
|
||||
assertEquals(DeliveryStatus.BASAL_ACTIVE, response.getDeliveryStatus());
|
||||
assertEquals(PodStatus.RUNNING_ABOVE_MIN_VOLUME, response.getPodStatus());
|
||||
assertEquals((short) 320, response.getTotalPulsesDelivered());
|
||||
assertEquals((short) 5, response.getSequenceNumberOfLastProgrammingCommand());
|
||||
assertEquals((short) 0, response.getBolusPulsesRemaining());
|
||||
assertFalse(response.isOcclusionAlertActive());
|
||||
assertFalse(response.isAlert1Active());
|
||||
assertFalse(response.isAlert2Active());
|
||||
assertFalse(response.isAlert3Active());
|
||||
assertFalse(response.isAlert4Active());
|
||||
assertFalse(response.isAlert5Active());
|
||||
assertFalse(response.isAlert6Active());
|
||||
assertFalse(response.isAlert7Active());
|
||||
assertEquals((short) 280, response.getMinutesSinceActivation());
|
||||
assertEquals((short) 1023, response.getReservoirPulsesRemaining());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
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 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 DefaultStatusResponseTest {
|
||||
|
||||
@Test @Throws(DecoderException::class) fun testValidResponse() {
|
||||
val encoded = Hex.decodeHex("1D1800A02800000463FF")
|
||||
val response = DefaultStatusResponse(encoded)
|
||||
Assert.assertArrayEquals(encoded, response.encoded)
|
||||
Assert.assertNotSame(encoded, response.encoded)
|
||||
Assert.assertEquals(ResponseType.DEFAULT_STATUS_RESPONSE, response.responseType)
|
||||
Assert.assertEquals(ResponseType.DEFAULT_STATUS_RESPONSE.value, response.messageType)
|
||||
Assert.assertEquals(DeliveryStatus.BASAL_ACTIVE, response.deliveryStatus)
|
||||
Assert.assertEquals(PodStatus.RUNNING_ABOVE_MIN_VOLUME, response.podStatus)
|
||||
Assert.assertEquals(320.toShort(), response.totalPulsesDelivered)
|
||||
Assert.assertEquals(5.toShort(), response.sequenceNumberOfLastProgrammingCommand)
|
||||
Assert.assertEquals(0.toShort(), response.bolusPulsesRemaining)
|
||||
Assert.assertFalse(response.occlusionAlertActive)
|
||||
Assert.assertFalse(response.alert1Active)
|
||||
Assert.assertFalse(response.alert2Active)
|
||||
Assert.assertFalse(response.alert3Active)
|
||||
Assert.assertFalse(response.alert4Active)
|
||||
Assert.assertFalse(response.alert5Active)
|
||||
Assert.assertFalse(response.alert6Active)
|
||||
Assert.assertFalse(response.alert7Active)
|
||||
Assert.assertEquals(280.toShort(), response.minutesSinceActivation)
|
||||
Assert.assertEquals(1023.toShort(), response.reservoirPulsesRemaining)
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response;
|
||||
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.junit.Test;
|
||||
|
||||
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 static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
|
||||
public class NakResponseTest {
|
||||
@Test
|
||||
public void testValidResponse() throws DecoderException {
|
||||
byte[] encoded = Hex.decodeHex("0603070009");
|
||||
NakResponse response = new NakResponse(encoded);
|
||||
|
||||
assertArrayEquals(encoded, response.getEncoded());
|
||||
assertNotSame(encoded, response.getEncoded());
|
||||
assertEquals(ResponseType.NAK_RESPONSE, response.getResponseType());
|
||||
assertEquals(ResponseType.NAK_RESPONSE.getValue(), response.getMessageType());
|
||||
assertEquals(NakErrorType.ILLEGAL_PARAM, response.getNakErrorType());
|
||||
assertEquals(AlarmType.NONE, response.getAlarmType());
|
||||
assertEquals(PodStatus.RUNNING_BELOW_MIN_VOLUME, response.getPodStatus());
|
||||
assertEquals((byte) 0x00, response.getSecurityNakSyncCount());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
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 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 NakResponseTest {
|
||||
|
||||
@Test @Throws(DecoderException::class) fun testValidResponse() {
|
||||
val encoded = Hex.decodeHex("0603070009")
|
||||
val response = NakResponse(encoded)
|
||||
|
||||
Assert.assertArrayEquals(encoded, response.encoded)
|
||||
Assert.assertNotSame(encoded, response.encoded)
|
||||
Assert.assertEquals(ResponseType.NAK_RESPONSE, response.responseType)
|
||||
Assert.assertEquals(ResponseType.NAK_RESPONSE.value, response.messageType)
|
||||
Assert.assertEquals(NakErrorType.ILLEGAL_PARAM, response.nakErrorType)
|
||||
Assert.assertEquals(AlarmType.NONE, response.alarmType)
|
||||
Assert.assertEquals(PodStatus.RUNNING_BELOW_MIN_VOLUME, response.podStatus)
|
||||
Assert.assertEquals(0x00.toShort(), response.securityNakSyncCount)
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response;
|
||||
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.junit.Test;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
|
||||
public class SetUniqueIdResponseTest {
|
||||
@Test
|
||||
public void testValidResponse() throws DecoderException {
|
||||
byte[] encoded = Hex.decodeHex("011B13881008340A50040A00010300040308146CC1000954D402420001");
|
||||
SetUniqueIdResponse response = new SetUniqueIdResponse(encoded);
|
||||
|
||||
assertArrayEquals(encoded, response.getEncoded());
|
||||
assertNotSame(encoded, response.getEncoded());
|
||||
assertEquals(ResponseType.ACTIVATION_RESPONSE, response.getResponseType());
|
||||
assertEquals(ResponseType.ActivationResponseType.SET_UNIQUE_ID_RESPONSE, response.getActivationResponseType());
|
||||
|
||||
assertEquals(ResponseType.ACTIVATION_RESPONSE.getValue(), response.getMessageType());
|
||||
assertEquals(27, response.getMessageLength());
|
||||
assertEquals(5000, response.getPulseVolumeInTenThousandthMicroLiter());
|
||||
assertEquals(16, response.getDeliveryRate());
|
||||
assertEquals(8, response.getPrimeRate());
|
||||
assertEquals(52, response.getNumberOfEngagingClutchDrivePulses());
|
||||
assertEquals(10, response.getNumberOfPrimePulses());
|
||||
assertEquals(80, response.getPodExpirationTimeInHours());
|
||||
assertEquals(4, response.getFirmwareVersionMajor());
|
||||
assertEquals(10, response.getFirmwareVersionMinor());
|
||||
assertEquals(0, response.getFirmwareVersionInterim());
|
||||
assertEquals(1, response.getBleVersionMajor());
|
||||
assertEquals(3, response.getBleVersionMinor());
|
||||
assertEquals(0, response.getBleVersionInterim());
|
||||
assertEquals(4, response.getProductId());
|
||||
assertEquals(PodStatus.UID_SET, response.getPodStatus());
|
||||
assertEquals(135556289L, response.getLotNumber());
|
||||
assertEquals(611540L, response.getPodSequenceNumber());
|
||||
assertEquals(37879809L, response.getUniqueIdReceivedInCommand());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus
|
||||
import org.apache.commons.codec.DecoderException
|
||||
import org.apache.commons.codec.binary.Hex
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
|
||||
class SetUniqueIdResponseTest {
|
||||
|
||||
@Test @Throws(DecoderException::class) fun testValidResponse() {
|
||||
val encoded = Hex.decodeHex("011B13881008340A50040A00010300040308146CC1000954D402420001")
|
||||
val response = SetUniqueIdResponse(encoded)
|
||||
|
||||
Assert.assertArrayEquals(encoded, response.encoded)
|
||||
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.value, response.messageType)
|
||||
Assert.assertEquals(27.toShort(), response.messageLength)
|
||||
Assert.assertEquals(5000.toShort(), response.pulseVolumeInTenThousandthMicroLiter)
|
||||
Assert.assertEquals(16.toShort(), response.pumpRate)
|
||||
Assert.assertEquals(8.toShort(), response.primePumpRate)
|
||||
Assert.assertEquals(52.toShort(), response.numberOfEngagingClutchDrivePulses)
|
||||
Assert.assertEquals(10.toShort(), response.numberOfPrimePulses)
|
||||
Assert.assertEquals(80.toShort(), response.podExpirationTimeInHours)
|
||||
Assert.assertEquals(4.toShort(), response.firmwareVersionMajor)
|
||||
Assert.assertEquals(10.toShort(), response.firmwareVersionMinor)
|
||||
Assert.assertEquals(0.toShort(), response.firmwareVersionInterim)
|
||||
Assert.assertEquals(1.toShort(), response.bleVersionMajor)
|
||||
Assert.assertEquals(3.toShort(), response.bleVersionMinor)
|
||||
Assert.assertEquals(0.toShort(), response.bleVersionInterim)
|
||||
Assert.assertEquals(4.toShort(), response.productId)
|
||||
Assert.assertEquals(PodStatus.UID_SET, response.podStatus)
|
||||
Assert.assertEquals(135556289L, response.lotNumber)
|
||||
Assert.assertEquals(611540L, response.podSequenceNumber)
|
||||
Assert.assertEquals(37879809L, response.uniqueIdReceivedInCommand)
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response;
|
||||
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.junit.Test;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
|
||||
public class VersionResponseTest {
|
||||
|
||||
@Test
|
||||
public void testValidResponse() throws DecoderException {
|
||||
byte[] encoded = Hex.decodeHex("0115040A00010300040208146CC1000954D400FFFFFFFF");
|
||||
VersionResponse response = new VersionResponse(encoded);
|
||||
|
||||
assertArrayEquals(encoded, response.getEncoded());
|
||||
assertNotSame(encoded, response.getEncoded());
|
||||
assertEquals(ResponseType.ACTIVATION_RESPONSE, response.getResponseType());
|
||||
assertEquals(ResponseType.ActivationResponseType.GET_VERSION_RESPONSE, response.getActivationResponseType());
|
||||
|
||||
assertEquals(ResponseType.ACTIVATION_RESPONSE.getValue(), response.getMessageType());
|
||||
assertEquals(21, response.getMessageLength());
|
||||
assertEquals(4, response.getFirmwareVersionMajor());
|
||||
assertEquals(10, response.getFirmwareVersionMinor());
|
||||
assertEquals(0, response.getFirmwareVersionInterim());
|
||||
assertEquals(1, response.getBleVersionMajor());
|
||||
assertEquals(3, response.getBleVersionMinor());
|
||||
assertEquals(0, response.getBleVersionInterim());
|
||||
assertEquals(4, response.getProductId());
|
||||
assertEquals(PodStatus.FILLED, response.getPodStatus());
|
||||
assertEquals(135556289, response.getLotNumber());
|
||||
assertEquals(611540, response.getPodSequenceNumber());
|
||||
assertEquals(0L, response.getRssi());
|
||||
assertEquals(0L, response.getReceiverLowerGain());
|
||||
assertEquals(4294967295L, response.getUniqueIdReceivedInCommand());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus
|
||||
import org.apache.commons.codec.DecoderException
|
||||
import org.apache.commons.codec.binary.Hex
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
|
||||
class VersionResponseTest {
|
||||
|
||||
@Test @Throws(DecoderException::class) fun testValidResponse() {
|
||||
val encoded = Hex.decodeHex("0115040A00010300040208146CC1000954D400FFFFFFFF")
|
||||
val response = VersionResponse(encoded)
|
||||
|
||||
Assert.assertArrayEquals(encoded, response.encoded)
|
||||
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.value, response.messageType)
|
||||
Assert.assertEquals(21.toShort(), response.messageLength)
|
||||
Assert.assertEquals(4.toShort(), response.firmwareVersionMajor)
|
||||
Assert.assertEquals(10.toShort(), response.firmwareVersionMinor)
|
||||
Assert.assertEquals(0.toShort(), response.firmwareVersionInterim)
|
||||
Assert.assertEquals(1.toShort(), response.bleVersionMajor)
|
||||
Assert.assertEquals(3.toShort(), response.bleVersionMinor)
|
||||
Assert.assertEquals(0.toShort(), response.bleVersionInterim)
|
||||
Assert.assertEquals(4.toShort(), response.productId)
|
||||
Assert.assertEquals(PodStatus.FILLED, response.podStatus)
|
||||
Assert.assertEquals(135556289L, response.lotNumber)
|
||||
Assert.assertEquals(611540L, response.podSequenceNumber)
|
||||
Assert.assertEquals(0.toByte(), response.rssi)
|
||||
Assert.assertEquals(0.toByte(), response.receiverLowerGain)
|
||||
Assert.assertEquals(4294967295L, response.uniqueIdReceivedInCommand)
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue