a bit more formatting
This commit is contained in:
parent
5ef07dd0be
commit
89ff502518
43 changed files with 927 additions and 153 deletions
|
@ -22,6 +22,7 @@
|
|||
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="6" />
|
||||
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="6" />
|
||||
<option name="BLANK_LINES_AROUND_BLOCK_WHEN_BRANCHES" value="1" />
|
||||
<option name="WRAP_EXPRESSION_BODY_FUNCTIONS" value="1" />
|
||||
</JetCodeStyleSettings>
|
||||
<codeStyleSettings language="JAVA">
|
||||
<option name="METHOD_ANNOTATION_WRAP" value="0" />
|
||||
|
@ -140,14 +141,28 @@
|
|||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="kotlin">
|
||||
<option name="RIGHT_MARGIN" value="120" />
|
||||
<option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
|
||||
<option name="LINE_COMMENT_ADD_SPACE" value="true" />
|
||||
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
|
||||
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
||||
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="1" />
|
||||
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
|
||||
<option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" />
|
||||
<option name="CALL_PARAMETERS_WRAP" value="5" />
|
||||
<option name="CALL_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
|
||||
<option name="CALL_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
|
||||
<option name="METHOD_PARAMETERS_WRAP" value="5" />
|
||||
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
|
||||
<option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
|
||||
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
|
||||
<option name="ASSIGNMENT_WRAP" value="5" />
|
||||
<option name="METHOD_ANNOTATION_WRAP" value="5" />
|
||||
<option name="FIELD_ANNOTATION_WRAP" value="0" />
|
||||
<option name="CLASS_ANNOTATION_WRAP" value="1" />
|
||||
<option name="FIELD_ANNOTATION_WRAP" value="1" />
|
||||
<option name="PARAMETER_ANNOTATION_WRAP" value="1" />
|
||||
<option name="VARIABLE_ANNOTATION_WRAP" value="1" />
|
||||
<option name="ENUM_CONSTANTS_WRAP" value="5" />
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
|
|
|
@ -268,7 +268,7 @@ formatting:
|
|||
continuationIndentSize: 4
|
||||
MaximumLineLength:
|
||||
active: true
|
||||
maxLineLength: 120
|
||||
maxLineLength: 150
|
||||
ModifierOrdering:
|
||||
active: true
|
||||
autoCorrect: true
|
||||
|
|
|
@ -129,19 +129,31 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
|||
// TODO
|
||||
}
|
||||
|
||||
override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult {
|
||||
override fun setTempBasalAbsolute(
|
||||
absoluteRate: Double,
|
||||
durationInMinutes: Int,
|
||||
profile: Profile,
|
||||
enforceNew: Boolean
|
||||
): PumpEnactResult {
|
||||
// TODO
|
||||
return PumpEnactResult(injector).success(false).enacted(false).comment("TODO")
|
||||
}
|
||||
|
||||
override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult {
|
||||
override fun setTempBasalPercent(
|
||||
percent: Int,
|
||||
durationInMinutes: Int,
|
||||
profile: Profile,
|
||||
enforceNew: Boolean
|
||||
): PumpEnactResult {
|
||||
// TODO i18n
|
||||
return PumpEnactResult(injector).success(false).enacted(false).comment("Omnipod Dash driver does not support percentage temp basals")
|
||||
return PumpEnactResult(injector).success(false).enacted(false)
|
||||
.comment("Omnipod Dash driver does not support percentage temp basals")
|
||||
}
|
||||
|
||||
override fun setExtendedBolus(insulin: Double, durationInMinutes: Int): PumpEnactResult {
|
||||
// TODO i18n
|
||||
return PumpEnactResult(injector).success(false).enacted(false).comment("Omnipod Dash driver does not support extended boluses")
|
||||
return PumpEnactResult(injector).success(false).enacted(false)
|
||||
.comment("Omnipod Dash driver does not support extended boluses")
|
||||
}
|
||||
|
||||
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
|
||||
|
@ -151,7 +163,8 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
|||
|
||||
override fun cancelExtendedBolus(): PumpEnactResult {
|
||||
// TODO i18n
|
||||
return PumpEnactResult(injector).success(false).enacted(false).comment("Omnipod Dash driver does not support extended boluses")
|
||||
return PumpEnactResult(injector).success(false).enacted(false)
|
||||
.comment("Omnipod Dash driver does not support extended boluses")
|
||||
}
|
||||
|
||||
override fun getJSONStatus(profile: Profile, profileName: String, version: String): JSONObject {
|
||||
|
@ -184,7 +197,8 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
|||
|
||||
override fun loadTDDs(): PumpEnactResult {
|
||||
// TODO i18n
|
||||
return PumpEnactResult(injector).success(false).enacted(false).comment("Omnipod Dash driver does not support TDD")
|
||||
return PumpEnactResult(injector).success(false).enacted(false)
|
||||
.comment("Omnipod Dash driver does not support TDD")
|
||||
}
|
||||
|
||||
override fun canHandleDST(): Boolean {
|
||||
|
|
|
@ -19,7 +19,8 @@ class OmnipodDashHistoryModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
internal fun provideHistoryRecordDao(dashHistoryDatabase: DashHistoryDatabase): HistoryRecordDao = dashHistoryDatabase.historyRecordDao()
|
||||
internal fun provideHistoryRecordDao(dashHistoryDatabase: DashHistoryDatabase): HistoryRecordDao =
|
||||
dashHistoryDatabase.historyRecordDao()
|
||||
|
||||
@Provides
|
||||
@Reusable // no state, let system decide when to reuse or create new.
|
||||
|
|
|
@ -38,7 +38,9 @@ class OmnipodDashManagerImpl @Inject constructor(
|
|||
|
||||
private val observePodReadyForActivationPart2: Observable<PodEvent>
|
||||
get() = Observable.defer {
|
||||
if (podStateManager.activationProgress.isAtLeast(ActivationProgress.PHASE_1_COMPLETED) && podStateManager.activationProgress.isBefore(ActivationProgress.COMPLETED)) {
|
||||
if (podStateManager.activationProgress.isAtLeast(ActivationProgress.PHASE_1_COMPLETED) && podStateManager.activationProgress.isBefore(
|
||||
ActivationProgress.COMPLETED
|
||||
)) {
|
||||
Observable.empty()
|
||||
} else {
|
||||
Observable.error(IllegalStateException("Pod is in an incorrect state"))
|
||||
|
@ -46,9 +48,16 @@ class OmnipodDashManagerImpl @Inject constructor(
|
|||
}
|
||||
|
||||
private val observeConnectToPod: Observable<PodEvent>
|
||||
get() = Observable.defer { bleManager.connect().retryWithBackoff(retries = 2, delay = 3, timeUnit = TimeUnit.SECONDS) } // TODO are these reasonable values?
|
||||
get() = Observable.defer {
|
||||
bleManager.connect().retryWithBackoff(retries = 2, delay = 3, timeUnit = TimeUnit.SECONDS)
|
||||
} // TODO are these reasonable values?
|
||||
|
||||
private fun observeSendProgramBolusCommand(units: Double, rateInEighthPulsesPerSeconds: Byte, confirmationBeeps: Boolean, completionBeeps: Boolean): Observable<PodEvent> {
|
||||
private fun observeSendProgramBolusCommand(
|
||||
units: Double,
|
||||
rateInEighthPulsesPerSeconds: Byte,
|
||||
confirmationBeeps: Boolean,
|
||||
completionBeeps: Boolean
|
||||
): Observable<PodEvent> {
|
||||
return Observable.defer {
|
||||
bleManager.sendCommand(
|
||||
ProgramBolusCommand.Builder()
|
||||
|
@ -90,7 +99,10 @@ class OmnipodDashManagerImpl @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun observeSendProgramAlertsCommand(alertConfigurations: List<AlertConfiguration>, multiCommandFlag: Boolean = false): Observable<PodEvent> {
|
||||
private fun observeSendProgramAlertsCommand(
|
||||
alertConfigurations: List<AlertConfiguration>,
|
||||
multiCommandFlag: Boolean = false
|
||||
): Observable<PodEvent> {
|
||||
return Observable.defer {
|
||||
bleManager.sendCommand(
|
||||
ProgramAlertsCommand.Builder()
|
||||
|
@ -295,7 +307,9 @@ class OmnipodDashManagerImpl @Inject constructor(
|
|||
enabled = true,
|
||||
durationInMinutes = TimeUnit.HOURS.toMinutes(7).toShort(),
|
||||
autoOff = false,
|
||||
AlertTrigger.TimerTrigger(TimeUnit.HOURS.toMinutes(73).toShort()), // FIXME use activation time
|
||||
AlertTrigger.TimerTrigger(
|
||||
TimeUnit.HOURS.toMinutes(73).toShort()
|
||||
), // FIXME use activation time
|
||||
BeepType.FOUR_TIMES_BIP_BEEP,
|
||||
BeepRepetitionType.XXX3
|
||||
),
|
||||
|
@ -304,7 +318,9 @@ class OmnipodDashManagerImpl @Inject constructor(
|
|||
enabled = true,
|
||||
durationInMinutes = TimeUnit.HOURS.toMinutes(1).toShort(),
|
||||
autoOff = false,
|
||||
AlertTrigger.TimerTrigger(TimeUnit.HOURS.toMinutes(79).toShort()), // FIXME use activation time
|
||||
AlertTrigger.TimerTrigger(
|
||||
TimeUnit.HOURS.toMinutes(79).toShort()
|
||||
), // FIXME use activation time
|
||||
BeepType.FOUR_TIMES_BIP_BEEP,
|
||||
BeepRepetitionType.XXX4
|
||||
)
|
||||
|
@ -410,7 +426,7 @@ class OmnipodDashManagerImpl @Inject constructor(
|
|||
handleResponse(event.response)
|
||||
}
|
||||
|
||||
else -> {
|
||||
else -> {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,12 +29,26 @@ import javax.inject.Inject
|
|||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class OmnipodDashBleManagerImpl @Inject constructor(private val context: Context, private val aapsLogger: AAPSLogger) : OmnipodDashBleManager {
|
||||
class OmnipodDashBleManagerImpl @Inject constructor(
|
||||
private val context: Context,
|
||||
private val aapsLogger: AAPSLogger
|
||||
) : OmnipodDashBleManager {
|
||||
|
||||
private val bluetoothManager: BluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
|
||||
private val bluetoothManager: BluetoothManager =
|
||||
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
|
||||
private val bluetoothAdapter: BluetoothAdapter = bluetoothManager.adapter
|
||||
|
||||
@Throws(FailedToConnectException::class, CouldNotSendBleException::class, InterruptedException::class, BleIOBusyException::class, TimeoutException::class, CouldNotConfirmWriteException::class, CouldNotEnableNotifications::class, DescriptorNotFoundException::class, CouldNotConfirmDescriptorWriteException::class)
|
||||
@Throws(
|
||||
FailedToConnectException::class,
|
||||
CouldNotSendBleException::class,
|
||||
InterruptedException::class,
|
||||
BleIOBusyException::class,
|
||||
TimeoutException::class,
|
||||
CouldNotConfirmWriteException::class,
|
||||
CouldNotEnableNotifications::class,
|
||||
DescriptorNotFoundException::class,
|
||||
CouldNotConfirmDescriptorWriteException::class
|
||||
)
|
||||
private fun connect(podAddress: String): BleIO {
|
||||
// TODO: locking?
|
||||
val podDevice = bluetoothAdapter.getRemoteDevice(podAddress)
|
||||
|
@ -76,7 +90,18 @@ 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)
|
||||
@Throws(
|
||||
InterruptedException::class,
|
||||
ScanFailException::class,
|
||||
FailedToConnectException::class,
|
||||
CouldNotSendBleException::class,
|
||||
BleIOBusyException::class,
|
||||
TimeoutException::class,
|
||||
CouldNotConfirmWriteException::class,
|
||||
CouldNotEnableNotifications::class,
|
||||
DescriptorNotFoundException::class,
|
||||
CouldNotConfirmDescriptorWriteException::class
|
||||
)
|
||||
override fun connect(): Observable<PodEvent> = Observable.create { emitter ->
|
||||
// TODO: when we are already connected,
|
||||
// emit PodEvent.AlreadyConnected, complete the observable and return from this method
|
||||
|
@ -88,7 +113,10 @@ class OmnipodDashBleManagerImpl @Inject constructor(private val context: Context
|
|||
val podScanner = PodScanner(aapsLogger, bluetoothAdapter)
|
||||
emitter.onNext(PodEvent.Scanning)
|
||||
|
||||
val podAddress = podScanner.scanForPod(PodScanner.SCAN_FOR_SERVICE_UUID, PodScanner.POD_ID_NOT_ACTIVATED).scanResult.device.address
|
||||
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";
|
||||
emitter.onNext(PodEvent.BluetoothConnecting)
|
||||
|
||||
|
|
|
@ -11,7 +11,11 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.Chara
|
|||
import java.math.BigInteger
|
||||
import java.util.*
|
||||
|
||||
class ServiceDiscoverer(private val logger: AAPSLogger, private val gatt: BluetoothGatt, private val bleCallbacks: BleCommCallbacks) {
|
||||
class ServiceDiscoverer(
|
||||
private val logger: AAPSLogger,
|
||||
private val gatt: BluetoothGatt,
|
||||
private val bleCallbacks: BleCommCallbacks
|
||||
) {
|
||||
|
||||
/***
|
||||
* This is first step after connection establishment
|
||||
|
|
|
@ -18,7 +18,10 @@ import java.util.concurrent.LinkedBlockingQueue
|
|||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.TimeoutException
|
||||
|
||||
class BleCommCallbacks(private val aapsLogger: AAPSLogger, private val incomingPackets: Map<CharacteristicType, BlockingQueue<ByteArray>>) : BluetoothGattCallback() {
|
||||
class BleCommCallbacks(
|
||||
private val aapsLogger: AAPSLogger,
|
||||
private val incomingPackets: Map<CharacteristicType, BlockingQueue<ByteArray>>
|
||||
) : BluetoothGattCallback() {
|
||||
|
||||
private val serviceDiscoveryComplete: CountDownLatch = CountDownLatch(1)
|
||||
private val connected: CountDownLatch = CountDownLatch(1)
|
||||
|
@ -64,7 +67,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.toHex() + ".Excepted: " + expectedPayload.toHex())
|
||||
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.toHex())
|
||||
|
@ -111,13 +117,19 @@ class BleCommCallbacks(private val aapsLogger: AAPSLogger, private val incomingP
|
|||
|
||||
@Throws(InterruptedException::class, CouldNotConfirmDescriptorWriteException::class)
|
||||
fun confirmWriteDescriptor(descriptorUUID: String, timeout_ms: Int) {
|
||||
val confirmed: DescriptorWriteConfirmation = descriptorWriteQueue.poll(timeout_ms.toLong(), TimeUnit.MILLISECONDS)
|
||||
val confirmed: DescriptorWriteConfirmation = descriptorWriteQueue.poll(
|
||||
timeout_ms.toLong(),
|
||||
TimeUnit.MILLISECONDS
|
||||
)
|
||||
?: throw TimeoutException()
|
||||
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)
|
||||
|
@ -135,10 +147,17 @@ class BleCommCallbacks(private val aapsLogger: AAPSLogger, private val incomingP
|
|||
}
|
||||
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)
|
||||
val offered = descriptorWriteQueue.offer(
|
||||
writeConfirmation,
|
||||
WRITE_CONFIRM_TIMEOUT_MS.toLong(),
|
||||
TimeUnit.MILLISECONDS
|
||||
)
|
||||
if (!offered) {
|
||||
aapsLogger.warn(LTag.PUMPBTCOMM, "Received delayed descriptor write confirmation")
|
||||
}
|
||||
|
|
|
@ -1,7 +1,15 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command
|
||||
|
||||
enum class BleCommandType(val value: Byte) {
|
||||
RTS(0x00.toByte()), CTS(0x01.toByte()), NACK(0x02.toByte()), ABORT(0x03.toByte()), SUCCESS(0x04.toByte()), FAIL(0x05.toByte()), HELLO(0x06.toByte());
|
||||
RTS(0x00.toByte()),
|
||||
CTS(0x01.toByte()),
|
||||
NACK(0x02.toByte()),
|
||||
ABORT(0x03.toByte()),
|
||||
SUCCESS(0x04.toByte()),
|
||||
FAIL(0x05.toByte()),
|
||||
HELLO(
|
||||
0x06.toByte()
|
||||
);
|
||||
|
||||
companion object {
|
||||
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
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(
|
||||
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,4 +1,5 @@
|
|||
@file:Suppress("WildcardImport")
|
||||
|
||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io
|
||||
|
||||
import android.bluetooth.BluetoothGatt
|
||||
|
@ -13,7 +14,13 @@ import java.util.concurrent.BlockingQueue
|
|||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.TimeoutException
|
||||
|
||||
class BleIO(private val aapsLogger: AAPSLogger, private val chars: Map<CharacteristicType, BluetoothGattCharacteristic>, private val incomingPackets: Map<CharacteristicType, BlockingQueue<ByteArray>>, private val gatt: BluetoothGatt, private val bleCommCallbacks: BleCommCallbacks) {
|
||||
class BleIO(
|
||||
private val aapsLogger: AAPSLogger,
|
||||
private val chars: Map<CharacteristicType, BluetoothGattCharacteristic>,
|
||||
private val incomingPackets: Map<CharacteristicType, BlockingQueue<ByteArray>>,
|
||||
private val gatt: BluetoothGatt,
|
||||
private val bleCommCallbacks: BleCommCallbacks
|
||||
) {
|
||||
|
||||
private var state: IOState = IOState.IDLE
|
||||
|
||||
|
@ -42,7 +49,13 @@ class BleIO(private val aapsLogger: AAPSLogger, private val chars: Map<Character
|
|||
* @param payload the data to send
|
||||
* @throws CouldNotSendBleException
|
||||
*/
|
||||
@Throws(CouldNotSendBleException::class, BleIOBusyException::class, InterruptedException::class, CouldNotConfirmWriteException::class, TimeoutException::class)
|
||||
@Throws(
|
||||
CouldNotSendBleException::class,
|
||||
BleIOBusyException::class,
|
||||
InterruptedException::class,
|
||||
CouldNotConfirmWriteException::class,
|
||||
TimeoutException::class
|
||||
)
|
||||
fun sendAndConfirmPacket(characteristic: CharacteristicType, payload: ByteArray) {
|
||||
synchronized(state) {
|
||||
if (state != IOState.IDLE) {
|
||||
|
@ -75,7 +88,13 @@ class BleIO(private val aapsLogger: AAPSLogger, private val chars: Map<Character
|
|||
* This will signal the pod it can start sending back data
|
||||
* @return
|
||||
*/
|
||||
@Throws(CouldNotSendBleException::class, CouldNotEnableNotifications::class, DescriptorNotFoundException::class, InterruptedException::class, CouldNotConfirmDescriptorWriteException::class)
|
||||
@Throws(
|
||||
CouldNotSendBleException::class,
|
||||
CouldNotEnableNotifications::class,
|
||||
DescriptorNotFoundException::class,
|
||||
InterruptedException::class,
|
||||
CouldNotConfirmDescriptorWriteException::class
|
||||
)
|
||||
fun readyToRead() {
|
||||
for (type in CharacteristicType.values()) {
|
||||
val ch = chars[type]
|
||||
|
|
|
@ -2,4 +2,7 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message
|
|||
|
||||
import info.nightscout.androidaps.utils.extensions.toHex
|
||||
|
||||
class IncorrectPacketException(val expectedIndex: Byte, val payload: ByteArray) : Exception("Invalid payload: ${payload.toHex()}. Expected index: $expectedIndex")
|
||||
class IncorrectPacketException(
|
||||
val expectedIndex: Byte,
|
||||
val payload: ByteArray
|
||||
) : Exception("Invalid payload: ${payload.toHex()}. Expected index: $expectedIndex")
|
||||
|
|
|
@ -91,7 +91,8 @@ data class MessagePacket(
|
|||
val priority = f2.get(1) != 0
|
||||
val lastMessage = f2.get(2) != 0
|
||||
val gateway = f2.get(3) != 0
|
||||
val type = MessageType.byValue((f1.get(7) or (f1.get(6) shl 1) or (f1.get(5) shl 2) or (f1.get(4) shl 3)).toByte())
|
||||
val type =
|
||||
MessageType.byValue((f1.get(7) or (f1.get(6) shl 1) or (f1.get(5) shl 2) or (f1.get(4) shl 3)).toByte())
|
||||
if (version.toInt() != 0) {
|
||||
throw CouldNotParseMessageException(payload)
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ class PayloadJoiner(private val firstPacket: ByteArray) {
|
|||
firstPacket.size < FirstBlePacket.HEADER_SIZE_WITHOUT_MIDDLE_PACKETS ->
|
||||
throw IncorrectPacketException(0, firstPacket)
|
||||
|
||||
fullFragments == 0 -> {
|
||||
fullFragments == 0 -> {
|
||||
crc = ByteBuffer.wrap(firstPacket.copyOfRange(2, 6)).int.toUnsignedLong()
|
||||
val rest = firstPacket[6]
|
||||
val end = min(rest + FirstBlePacket.HEADER_SIZE_WITHOUT_MIDDLE_PACKETS, BlePacket.MAX_SIZE)
|
||||
|
@ -41,11 +41,16 @@ class PayloadJoiner(private val firstPacket: ByteArray) {
|
|||
}
|
||||
|
||||
// With middle packets
|
||||
firstPacket.size < BlePacket.MAX_SIZE ->
|
||||
firstPacket.size < BlePacket.MAX_SIZE ->
|
||||
throw IncorrectPacketException(0, firstPacket)
|
||||
|
||||
else -> {
|
||||
fragments.add(firstPacket.copyOfRange(FirstBlePacket.HEADER_SIZE_WITH_MIDDLE_PACKETS, BlePacket.MAX_SIZE))
|
||||
else -> {
|
||||
fragments.add(
|
||||
firstPacket.copyOfRange(
|
||||
FirstBlePacket.HEADER_SIZE_WITH_MIDDLE_PACKETS,
|
||||
BlePacket.MAX_SIZE
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +65,7 @@ class PayloadJoiner(private val firstPacket: ByteArray) {
|
|||
}
|
||||
expectedIndex++
|
||||
when {
|
||||
idx < fullFragments -> { // this is a middle fragment
|
||||
idx < fullFragments -> { // this is a middle fragment
|
||||
if (packet.size < BlePacket.MAX_SIZE) {
|
||||
throw IncorrectPacketException(idx.toByte(), packet)
|
||||
}
|
||||
|
@ -81,13 +86,18 @@ class PayloadJoiner(private val firstPacket: ByteArray) {
|
|||
fragments.add(packet.copyOfRange(LastBlePacket.HEADER_SIZE, packet.size))
|
||||
}
|
||||
|
||||
idx > fullFragments -> { // this is the extra fragment
|
||||
idx > fullFragments -> { // this is the extra fragment
|
||||
val size = packet[1].toInt()
|
||||
if (packet.size < LastOptionalPlusOneBlePacket.HEADER_SIZE + size) {
|
||||
throw IncorrectPacketException(idx.toByte(), packet)
|
||||
}
|
||||
|
||||
fragments.add(packet.copyOfRange(LastOptionalPlusOneBlePacket.HEADER_SIZE, LastOptionalPlusOneBlePacket.HEADER_SIZE + size))
|
||||
fragments.add(
|
||||
packet.copyOfRange(
|
||||
LastOptionalPlusOneBlePacket.HEADER_SIZE,
|
||||
LastOptionalPlusOneBlePacket.HEADER_SIZE + size
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,8 @@ internal class PayloadSplitter(private val payload: ByteArray) {
|
|||
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()
|
||||
val rest =
|
||||
((payload.size - middleFragments * MiddleBlePacket.CAPACITY) - FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS).toByte()
|
||||
ret.add(
|
||||
FirstBlePacket(
|
||||
totalFragments = (middleFragments + 1).toByte(),
|
||||
|
@ -44,9 +45,15 @@ internal class PayloadSplitter(private val payload: ByteArray) {
|
|||
)
|
||||
for (i in 1..middleFragments) {
|
||||
val p = if (i == 1) {
|
||||
payload.copyOfRange(FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS, FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + MiddleBlePacket.CAPACITY)
|
||||
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)
|
||||
payload.copyOfRange(
|
||||
FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + (i - 1) * MiddleBlePacket.CAPACITY,
|
||||
FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + i * MiddleBlePacket.CAPACITY
|
||||
)
|
||||
}
|
||||
ret.add(
|
||||
MiddleBlePacket(
|
||||
|
@ -60,7 +67,10 @@ internal class PayloadSplitter(private val payload: ByteArray) {
|
|||
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),
|
||||
payload = payload.copyOfRange(
|
||||
middleFragments * MiddleBlePacket.CAPACITY + FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS,
|
||||
middleFragments * MiddleBlePacket.CAPACITY + FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + end
|
||||
),
|
||||
crc32 = crc32,
|
||||
)
|
||||
)
|
||||
|
@ -69,7 +79,10 @@ internal class PayloadSplitter(private val payload: ByteArray) {
|
|||
LastOptionalPlusOneBlePacket(
|
||||
index = (middleFragments + 2).toByte(),
|
||||
size = (rest - LastBlePacket.CAPACITY).toByte(),
|
||||
payload = payload.copyOfRange(middleFragments * MiddleBlePacket.CAPACITY + FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + LastBlePacket.CAPACITY, payload.size),
|
||||
payload = payload.copyOfRange(
|
||||
middleFragments * MiddleBlePacket.CAPACITY + FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + LastBlePacket.CAPACITY,
|
||||
payload.size
|
||||
),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -18,15 +18,15 @@ class StringLengthPrefixEncoding {
|
|||
var remaining = payload
|
||||
for ((index, key) in keys.withIndex()) {
|
||||
when {
|
||||
remaining.size < key.length ->
|
||||
remaining.size < key.length ->
|
||||
throw MessageIOException("Payload too short: ${payload.toHex()} for key: $key")
|
||||
!(remaining.copyOfRange(0, key.length).decodeToString() == key) ->
|
||||
throw MessageIOException("Key not found: $key in ${payload.toHex()}")
|
||||
// last key can be empty, no length
|
||||
index == keys.size - 1 && remaining.size == key.length ->
|
||||
index == keys.size - 1 && remaining.size == key.length ->
|
||||
return ret
|
||||
|
||||
remaining.size < key.length + LENGTH_BYTES ->
|
||||
remaining.size < key.length + LENGTH_BYTES ->
|
||||
throw MessageIOException("Length not found: for $key in ${payload.toHex()}")
|
||||
}
|
||||
remaining = remaining.copyOfRange(key.length, remaining.size)
|
||||
|
|
|
@ -12,7 +12,12 @@ sealed class BlePacket {
|
|||
}
|
||||
}
|
||||
|
||||
data class FirstBlePacket(val totalFragments: Byte, val payload: ByteArray, val size: Byte? = null, val crc32: Long? = null) : BlePacket() {
|
||||
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
|
||||
|
@ -40,8 +45,10 @@ data class FirstBlePacket(val totalFragments: Byte, val payload: ByteArray, val
|
|||
internal const val HEADER_SIZE_WITHOUT_MIDDLE_PACKETS = 7 // we are using all fields
|
||||
internal const val HEADER_SIZE_WITH_MIDDLE_PACKETS = 2
|
||||
|
||||
internal const val CAPACITY_WITHOUT_MIDDLE_PACKETS = MAX_SIZE - HEADER_SIZE_WITHOUT_MIDDLE_PACKETS // we are using all fields
|
||||
internal const val CAPACITY_WITH_MIDDLE_PACKETS = MAX_SIZE - HEADER_SIZE_WITH_MIDDLE_PACKETS // we are not using crc32 or size
|
||||
internal const val CAPACITY_WITHOUT_MIDDLE_PACKETS =
|
||||
MAX_SIZE - HEADER_SIZE_WITHOUT_MIDDLE_PACKETS // we are using all fields
|
||||
internal const val CAPACITY_WITH_MIDDLE_PACKETS =
|
||||
MAX_SIZE - HEADER_SIZE_WITH_MIDDLE_PACKETS // we are not using crc32 or size
|
||||
internal const val CAPACITY_WITH_THE_OPTIONAL_PLUS_ONE_PACKET = 18
|
||||
}
|
||||
}
|
||||
|
|
|
@ -139,7 +139,10 @@ internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgI
|
|||
throw MessageIOException("Invalid payload size")
|
||||
}
|
||||
if (!podConf.contentEquals(payload)) {
|
||||
aapsLogger.warn(LTag.PUMPBTCOMM, "Received invalid podConf. Expected: ${podConf.toHex()}. Got: ${payload.toHex()}")
|
||||
aapsLogger.warn(
|
||||
LTag.PUMPBTCOMM,
|
||||
"Received invalid podConf. Expected: ${podConf.toHex()}. Got: ${payload.toHex()}"
|
||||
)
|
||||
throw MessageIOException("Invalid podConf value received")
|
||||
}
|
||||
}
|
||||
|
@ -235,7 +238,8 @@ internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgI
|
|||
private val PDM_CONF_MAGIC_PREFIX = "KC_2_U".toByteArray()
|
||||
private val POD_CONF_MAGIC_PREFIX = "KC_2_V".toByteArray()
|
||||
|
||||
private const 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.
|
||||
private const 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.
|
||||
|
||||
private const val SP1 = "SP1="
|
||||
private const val SP2 = ",SP2="
|
||||
|
|
|
@ -18,12 +18,19 @@ class BleDiscoveredDevice(val scanResult: ScanResult, private val scanRecord: Sc
|
|||
}
|
||||
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)
|
||||
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]) != UNKNOWN_THIRD_SERVICE_UUID) {
|
||||
// constant?
|
||||
throw DiscoveredInvalidPodException("The third exposed service UUID should be 000a, got " + serviceUuids[2], serviceUuids)
|
||||
throw DiscoveredInvalidPodException(
|
||||
"The third exposed service UUID should be 000a, got " + serviceUuids[2],
|
||||
serviceUuids
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,7 +41,10 @@ class BleDiscoveredDevice(val scanResult: ScanResult, private val scanRecord: Sc
|
|||
val hexPodId = extractUUID16(serviceUUIDs[3]) + extractUUID16(serviceUUIDs[4])
|
||||
val podId = hexPodId.toLong(16)
|
||||
if (this.podId != podId) {
|
||||
throw DiscoveredInvalidPodException("This is not the POD we are looking for. " + this.podId + " found: " + this.podId, serviceUUIDs)
|
||||
throw DiscoveredInvalidPodException(
|
||||
"This is not the POD we are looking for. " + this.podId + " found: " + this.podId,
|
||||
serviceUUIDs
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,12 @@ class DeactivateCommand private constructor(
|
|||
class Builder : NonceEnabledCommandBuilder<Builder, DeactivateCommand>() {
|
||||
|
||||
override fun buildCommand(): DeactivateCommand =
|
||||
DeactivateCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, nonce!!) // TODO this might crash if not all are set
|
||||
DeactivateCommand(
|
||||
uniqueId!!,
|
||||
sequenceNumber!!,
|
||||
multiCommandFlag,
|
||||
nonce!!
|
||||
) // TODO this might crash if not all are set
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -48,7 +48,12 @@ class ProgramBasalCommand private constructor(
|
|||
}
|
||||
val basalCommand = buffer.array()
|
||||
val interlockCommand = interlockCommand.encoded
|
||||
val header: ByteArray = encodeHeader(uniqueId, sequenceNumber, (basalCommand.size + interlockCommand.size).toShort(), multiCommandFlag)
|
||||
val header: ByteArray = encodeHeader(
|
||||
uniqueId,
|
||||
sequenceNumber,
|
||||
(basalCommand.size + interlockCommand.size).toShort(),
|
||||
multiCommandFlag
|
||||
)
|
||||
return appendCrc(
|
||||
ByteBuffer.allocate(basalCommand.size + interlockCommand.size + header.size) //
|
||||
.put(header) //
|
||||
|
@ -101,18 +106,32 @@ class ProgramBasalCommand private constructor(
|
|||
val pulsesPerSlot = ProgramBasalUtil.mapBasalProgramToPulsesPerSlot(basalProgram!!)
|
||||
val currentSlot = ProgramBasalUtil.calculateCurrentSlot(pulsesPerSlot, currentTime)
|
||||
val checksum = ProgramBasalUtil.calculateChecksum(pulsesPerSlot, currentSlot)
|
||||
val longInsulinProgramElements: List<BasalInsulinProgramElement> = mapTenthPulsesPerSlotToLongInsulinProgramElements(ProgramBasalUtil.mapBasalProgramToTenthPulsesPerSlot(basalProgram!!))
|
||||
val shortInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot)
|
||||
val currentBasalInsulinProgramElement = ProgramBasalUtil.calculateCurrentLongInsulinProgramElement(longInsulinProgramElements, currentTime)
|
||||
val longInsulinProgramElements: List<BasalInsulinProgramElement> =
|
||||
mapTenthPulsesPerSlotToLongInsulinProgramElements(
|
||||
ProgramBasalUtil.mapBasalProgramToTenthPulsesPerSlot(basalProgram!!)
|
||||
)
|
||||
val shortInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(
|
||||
pulsesPerSlot
|
||||
)
|
||||
val currentBasalInsulinProgramElement = ProgramBasalUtil.calculateCurrentLongInsulinProgramElement(
|
||||
longInsulinProgramElements,
|
||||
currentTime
|
||||
)
|
||||
val interlockCommand = ProgramInsulinCommand(
|
||||
uniqueId!!, sequenceNumber!!, multiCommandFlag, nonce!!,
|
||||
shortInsulinProgramElements, checksum, currentSlot.index, currentSlot.eighthSecondsRemaining,
|
||||
currentSlot.pulsesRemaining, ProgramInsulinCommand.DeliveryType.BASAL
|
||||
)
|
||||
return ProgramBasalCommand(
|
||||
interlockCommand, uniqueId!!, sequenceNumber!!, multiCommandFlag,
|
||||
longInsulinProgramElements, programReminder!!, currentBasalInsulinProgramElement.index,
|
||||
currentBasalInsulinProgramElement.remainingTenthPulses, currentBasalInsulinProgramElement.delayUntilNextTenthPulseInUsec
|
||||
interlockCommand,
|
||||
uniqueId!!,
|
||||
sequenceNumber!!,
|
||||
multiCommandFlag,
|
||||
longInsulinProgramElements,
|
||||
programReminder!!,
|
||||
currentBasalInsulinProgramElement.index,
|
||||
currentBasalInsulinProgramElement.remainingTenthPulses,
|
||||
currentBasalInsulinProgramElement.delayUntilNextTenthPulseInUsec
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,7 +63,15 @@ class ProgramBeepsCommand private constructor(
|
|||
requireNotNull(tempBasalReminder) { "tempBasalReminder can not be null" }
|
||||
requireNotNull(bolusReminder) { "bolusReminder can not be null" }
|
||||
|
||||
return ProgramBeepsCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, immediateBeepType!!, basalReminder!!, tempBasalReminder!!, bolusReminder!!)
|
||||
return ProgramBeepsCommand(
|
||||
uniqueId!!,
|
||||
sequenceNumber!!,
|
||||
multiCommandFlag,
|
||||
immediateBeepType!!,
|
||||
basalReminder!!,
|
||||
tempBasalReminder!!,
|
||||
bolusReminder!!
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,12 @@ class ProgramBolusCommand private constructor(
|
|||
.putInt(0) // Delay between tenth extended pulses in usec
|
||||
.array()
|
||||
val interlockCommand = interlockCommand.encoded
|
||||
val header: ByteArray = encodeHeader(uniqueId, sequenceNumber, (bolusCommand.size + interlockCommand.size).toShort(), multiCommandFlag)
|
||||
val header: ByteArray = encodeHeader(
|
||||
uniqueId,
|
||||
sequenceNumber,
|
||||
(bolusCommand.size + interlockCommand.size).toShort(),
|
||||
multiCommandFlag
|
||||
)
|
||||
return appendCrc(
|
||||
ByteBuffer.allocate(header.size + interlockCommand.size + bolusCommand.size) //
|
||||
.put(header) //
|
||||
|
@ -85,11 +90,27 @@ class ProgramBolusCommand private constructor(
|
|||
val numberOfPulses = Math.round(numberOfUnits!! * 20).toShort()
|
||||
val byte10And11 = (numberOfPulses * delayBetweenPulsesInEighthSeconds!!).toShort()
|
||||
val interlockCommand = ProgramInsulinCommand(
|
||||
uniqueId!!, sequenceNumber!!, multiCommandFlag, nonce!!, listOf(BolusShortInsulinProgramElement(numberOfPulses)), calculateChecksum(0x01.toByte(), byte10And11, numberOfPulses),
|
||||
0x01.toByte(), byte10And11, numberOfPulses, ProgramInsulinCommand.DeliveryType.BOLUS
|
||||
uniqueId!!,
|
||||
sequenceNumber!!,
|
||||
multiCommandFlag,
|
||||
nonce!!,
|
||||
listOf(BolusShortInsulinProgramElement(numberOfPulses)),
|
||||
calculateChecksum(0x01.toByte(), byte10And11, numberOfPulses),
|
||||
0x01.toByte(),
|
||||
byte10And11,
|
||||
numberOfPulses,
|
||||
ProgramInsulinCommand.DeliveryType.BOLUS
|
||||
)
|
||||
val delayUntilFirstTenthPulseInUsec = delayBetweenPulsesInEighthSeconds!! / 8 * 100000
|
||||
return ProgramBolusCommand(interlockCommand, uniqueId!!, sequenceNumber!!, multiCommandFlag, programReminder!!, (numberOfPulses * 10).toShort(), delayUntilFirstTenthPulseInUsec)
|
||||
return ProgramBolusCommand(
|
||||
interlockCommand,
|
||||
uniqueId!!,
|
||||
sequenceNumber!!,
|
||||
multiCommandFlag,
|
||||
programReminder!!,
|
||||
(numberOfPulses * 10).toShort(),
|
||||
delayUntilFirstTenthPulseInUsec
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ class ProgramInsulinCommand internal constructor(
|
|||
multiCommandFlag: Boolean,
|
||||
nonce: Int,
|
||||
insulinProgramElements:
|
||||
List<ShortInsulinProgramElement>,
|
||||
List<ShortInsulinProgramElement>,
|
||||
private val checksum: Short,
|
||||
private val byte9: Byte,
|
||||
private val byte10And11: Short,
|
||||
|
|
|
@ -56,15 +56,36 @@ class ProgramTempBasalCommand private constructor(
|
|||
|
||||
val durationInSlots = (durationInMinutes!! / 30).toByte()
|
||||
val pulsesPerSlot = ProgramTempBasalUtil.mapTempBasalToPulsesPerSlot(durationInSlots, rateInUnitsPerHour!!)
|
||||
val tenthPulsesPerSlot = ProgramTempBasalUtil.mapTempBasalToTenthPulsesPerSlot(durationInSlots.toInt(), rateInUnitsPerHour!!)
|
||||
val shortInsulinProgramElements = ProgramTempBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot)
|
||||
val insulinProgramElements = ProgramTempBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot)
|
||||
val interlockCommand = ProgramInsulinCommand(
|
||||
uniqueId!!, sequenceNumber!!, multiCommandFlag, nonce!!, shortInsulinProgramElements,
|
||||
ProgramTempBasalUtil.calculateChecksum(durationInSlots, pulsesPerSlot[0], pulsesPerSlot), durationInSlots,
|
||||
0x3840.toShort(), pulsesPerSlot[0], ProgramInsulinCommand.DeliveryType.TEMP_BASAL
|
||||
val tenthPulsesPerSlot = ProgramTempBasalUtil.mapTempBasalToTenthPulsesPerSlot(
|
||||
durationInSlots.toInt(),
|
||||
rateInUnitsPerHour!!
|
||||
)
|
||||
val shortInsulinProgramElements = ProgramTempBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(
|
||||
pulsesPerSlot
|
||||
)
|
||||
val insulinProgramElements = ProgramTempBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements(
|
||||
tenthPulsesPerSlot
|
||||
)
|
||||
val interlockCommand = ProgramInsulinCommand(
|
||||
uniqueId!!,
|
||||
sequenceNumber!!,
|
||||
multiCommandFlag,
|
||||
nonce!!,
|
||||
shortInsulinProgramElements,
|
||||
ProgramTempBasalUtil.calculateChecksum(durationInSlots, pulsesPerSlot[0], pulsesPerSlot),
|
||||
durationInSlots,
|
||||
0x3840.toShort(),
|
||||
pulsesPerSlot[0],
|
||||
ProgramInsulinCommand.DeliveryType.TEMP_BASAL
|
||||
)
|
||||
return ProgramTempBasalCommand(
|
||||
interlockCommand,
|
||||
uniqueId!!,
|
||||
sequenceNumber!!,
|
||||
multiCommandFlag,
|
||||
programReminder!!,
|
||||
insulinProgramElements
|
||||
)
|
||||
return ProgramTempBasalCommand(interlockCommand, uniqueId!!, sequenceNumber!!, multiCommandFlag, programReminder!!, insulinProgramElements)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,10 +96,12 @@ class ProgramTempBasalCommand private constructor(
|
|||
val delayUntilNextTenthPulseInUsec: Int
|
||||
if (firstProgramElement.totalTenthPulses.toInt() == 0) {
|
||||
remainingTenthPulsesInFirstElement = firstProgramElement.numberOfSlots.toShort()
|
||||
delayUntilNextTenthPulseInUsec = ProgramBasalUtil.MAX_DELAY_BETWEEN_TENTH_PULSES_IN_USEC_AND_USECS_IN_BASAL_SLOT
|
||||
delayUntilNextTenthPulseInUsec =
|
||||
ProgramBasalUtil.MAX_DELAY_BETWEEN_TENTH_PULSES_IN_USEC_AND_USECS_IN_BASAL_SLOT
|
||||
} else {
|
||||
remainingTenthPulsesInFirstElement = firstProgramElement.totalTenthPulses
|
||||
delayUntilNextTenthPulseInUsec = (firstProgramElement.numberOfSlots.toLong() * 1800.0 / remainingTenthPulsesInFirstElement * 1000000).toInt()
|
||||
delayUntilNextTenthPulseInUsec =
|
||||
(firstProgramElement.numberOfSlots.toLong() * 1800.0 / remainingTenthPulsesInFirstElement * 1000000).toInt()
|
||||
}
|
||||
val buffer = ByteBuffer.allocate(getLength().toInt()) //
|
||||
.put(commandType.value) //
|
||||
|
@ -92,7 +115,12 @@ class ProgramTempBasalCommand private 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) //
|
||||
|
|
|
@ -67,7 +67,14 @@ class SetUniqueIdCommand private constructor(
|
|||
requireNotNull(lotNumber) { "lotNumber can not be null" }
|
||||
requireNotNull(podSequenceNumber) { "podSequenceNumber can not be null" }
|
||||
requireNotNull(initializationTime) { "initializationTime can not be null" }
|
||||
return SetUniqueIdCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, lotNumber!!, podSequenceNumber!!, initializationTime!!)
|
||||
return SetUniqueIdCommand(
|
||||
uniqueId!!,
|
||||
sequenceNumber!!,
|
||||
multiCommandFlag,
|
||||
lotNumber!!,
|
||||
podSequenceNumber!!,
|
||||
initializationTime!!
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,12 @@ class StopDeliveryCommand private constructor(
|
|||
'}'
|
||||
}
|
||||
|
||||
enum class DeliveryType(private val basal: Boolean, private val tempBasal: Boolean, private val bolus: Boolean) : Encodable {
|
||||
enum class DeliveryType(
|
||||
private val basal: Boolean,
|
||||
private val tempBasal: Boolean,
|
||||
private val bolus: Boolean
|
||||
) : Encodable {
|
||||
|
||||
BASAL(true, false, false), TEMP_BASAL(false, true, false), BOLUS(false, false, true), ALL(true, true, true);
|
||||
|
||||
override val encoded: ByteArray
|
||||
|
@ -74,7 +79,14 @@ class StopDeliveryCommand private constructor(
|
|||
requireNotNull(deliveryType) { "deliveryType can not be null" }
|
||||
requireNotNull(beepType) { "beepType can not be null" }
|
||||
|
||||
return StopDeliveryCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, deliveryType!!, beepType!!, nonce!!)
|
||||
return StopDeliveryCommand(
|
||||
uniqueId!!,
|
||||
sequenceNumber!!,
|
||||
multiCommandFlag,
|
||||
deliveryType!!,
|
||||
beepType!!,
|
||||
nonce!!
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,12 @@ abstract class HeaderEnabledCommand protected constructor(
|
|||
.putShort(MessageUtil.createCrc(command)) //
|
||||
.array()
|
||||
|
||||
internal fun encodeHeader(uniqueId: Int, sequenceNumber: Short, length: Short, multiCommandFlag: Boolean): ByteArray =
|
||||
internal fun encodeHeader(
|
||||
uniqueId: Int,
|
||||
sequenceNumber: Short,
|
||||
length: Short,
|
||||
multiCommandFlag: Boolean
|
||||
): ByteArray =
|
||||
ByteBuffer.allocate(6) //
|
||||
.putInt(uniqueId) //
|
||||
.putShort((sequenceNumber.toInt() and 0x0f shl 10 or length.toInt() or ((if (multiCommandFlag) 1 else 0) shl 15)).toShort()) //
|
||||
|
|
|
@ -30,7 +30,13 @@ object ProgramBasalUtil {
|
|||
previousTenthPulsesPerSlot = tenthPulsesPerSlot[i]
|
||||
numberOfSlotsInCurrentElement = 1
|
||||
} else if (previousTenthPulsesPerSlot != tenthPulsesPerSlot[i] || (numberOfSlotsInCurrentElement + 1) * previousTenthPulsesPerSlot > 65534) {
|
||||
elements.add(insulinProgramElementFactory(startSlotIndex, numberOfSlotsInCurrentElement, (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement).toShort()))
|
||||
elements.add(
|
||||
insulinProgramElementFactory(
|
||||
startSlotIndex,
|
||||
numberOfSlotsInCurrentElement,
|
||||
(previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement).toShort()
|
||||
)
|
||||
)
|
||||
previousTenthPulsesPerSlot = tenthPulsesPerSlot[i]
|
||||
numberOfSlotsInCurrentElement = 1
|
||||
startSlotIndex = (numberOfSlotsInCurrentElement + startSlotIndex).toByte()
|
||||
|
@ -38,7 +44,13 @@ object ProgramBasalUtil {
|
|||
numberOfSlotsInCurrentElement++
|
||||
}
|
||||
}
|
||||
elements.add(insulinProgramElementFactory(startSlotIndex, numberOfSlotsInCurrentElement, (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement).toShort()))
|
||||
elements.add(
|
||||
insulinProgramElementFactory(
|
||||
startSlotIndex,
|
||||
numberOfSlotsInCurrentElement,
|
||||
(previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement).toShort()
|
||||
)
|
||||
)
|
||||
return elements
|
||||
}
|
||||
|
||||
|
@ -60,7 +72,13 @@ object ProgramBasalUtil {
|
|||
if (numberOfSlotsInCurrentElement < MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT) {
|
||||
numberOfSlotsInCurrentElement++
|
||||
} else {
|
||||
elements.add(BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse))
|
||||
elements.add(
|
||||
BasalShortInsulinProgramElement(
|
||||
numberOfSlotsInCurrentElement,
|
||||
previousPulsesPerSlot,
|
||||
extraAlternatePulse
|
||||
)
|
||||
)
|
||||
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots.toInt()]
|
||||
numberOfSlotsInCurrentElement = 1
|
||||
extraAlternatePulse = false
|
||||
|
@ -82,7 +100,13 @@ object ProgramBasalUtil {
|
|||
numberOfSlotsInCurrentElement++
|
||||
} else {
|
||||
// End of alternate pulse segment (no slots left in element)
|
||||
elements.add(BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse))
|
||||
elements.add(
|
||||
BasalShortInsulinProgramElement(
|
||||
numberOfSlotsInCurrentElement,
|
||||
previousPulsesPerSlot,
|
||||
extraAlternatePulse
|
||||
)
|
||||
)
|
||||
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots.toInt()]
|
||||
numberOfSlotsInCurrentElement = 1
|
||||
extraAlternatePulse = false
|
||||
|
@ -90,7 +114,13 @@ object ProgramBasalUtil {
|
|||
}
|
||||
} else {
|
||||
// End of alternate pulse segment (new number of pulses per slot)
|
||||
elements.add(BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse))
|
||||
elements.add(
|
||||
BasalShortInsulinProgramElement(
|
||||
numberOfSlotsInCurrentElement,
|
||||
previousPulsesPerSlot,
|
||||
extraAlternatePulse
|
||||
)
|
||||
)
|
||||
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots.toInt()]
|
||||
numberOfSlotsInCurrentElement = 1
|
||||
extraAlternatePulse = false
|
||||
|
@ -100,7 +130,13 @@ object ProgramBasalUtil {
|
|||
}
|
||||
} else if (previousPulsesPerSlot != pulsesPerSlot[currentTotalNumberOfSlots.toInt()]) {
|
||||
// End of segment (new number of pulses per slot)
|
||||
elements.add(BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse))
|
||||
elements.add(
|
||||
BasalShortInsulinProgramElement(
|
||||
numberOfSlotsInCurrentElement,
|
||||
previousPulsesPerSlot,
|
||||
extraAlternatePulse
|
||||
)
|
||||
)
|
||||
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots.toInt()]
|
||||
currentTotalNumberOfSlots++
|
||||
extraAlternatePulse = false
|
||||
|
@ -109,7 +145,13 @@ object ProgramBasalUtil {
|
|||
throw IllegalStateException("Reached illegal point in mapBasalProgramToShortInsulinProgramElements")
|
||||
}
|
||||
}
|
||||
elements.add(BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse))
|
||||
elements.add(
|
||||
BasalShortInsulinProgramElement(
|
||||
numberOfSlotsInCurrentElement,
|
||||
previousPulsesPerSlot,
|
||||
extraAlternatePulse
|
||||
)
|
||||
)
|
||||
return elements
|
||||
}
|
||||
|
||||
|
@ -117,7 +159,8 @@ object ProgramBasalUtil {
|
|||
val tenthPulsesPerSlot = ShortArray(NUMBER_OF_BASAL_SLOTS.toInt())
|
||||
for (segment in basalProgram.segments) {
|
||||
for (i in segment.startSlotIndex until segment.endSlotIndex) {
|
||||
tenthPulsesPerSlot[i] = (roundToHalf(segment.getPulsesPerHour() / 2.0) * 10).toInt().toShort() // TODO Adrian: int conversion ok?
|
||||
tenthPulsesPerSlot[i] = (roundToHalf(segment.getPulsesPerHour() / 2.0) * 10).toInt()
|
||||
.toShort() // TODO Adrian: int conversion ok?
|
||||
}
|
||||
}
|
||||
return tenthPulsesPerSlot
|
||||
|
@ -157,7 +200,10 @@ object ProgramBasalUtil {
|
|||
return CurrentSlot(index, (secondsRemaining * 8).toShort(), pulsesRemaining)
|
||||
}
|
||||
|
||||
fun calculateCurrentLongInsulinProgramElement(elements: List<BasalInsulinProgramElement>, currentTime: Date?): CurrentBasalInsulinProgramElement {
|
||||
fun calculateCurrentLongInsulinProgramElement(
|
||||
elements: List<BasalInsulinProgramElement>,
|
||||
currentTime: Date?
|
||||
): CurrentBasalInsulinProgramElement {
|
||||
val instance = Calendar.getInstance()
|
||||
instance.time = currentTime
|
||||
val hourOfDay = instance[Calendar.HOUR_OF_DAY]
|
||||
|
@ -176,8 +222,10 @@ object ProgramBasalUtil {
|
|||
}
|
||||
val durationInSeconds = endTimeInSeconds - startTimeInSeconds
|
||||
val secondsPassedInCurrentSlot = secondOfDay - startTimeInSeconds
|
||||
val remainingTenThousandthPulses = ((durationInSeconds - secondsPassedInCurrentSlot) / durationInSeconds.toDouble() * totalNumberOfTenThousandthPulsesInSlot).toLong()
|
||||
val delayBetweenTenthPulsesInUsec = (durationInSeconds * 1000000L * 1000 / totalNumberOfTenThousandthPulsesInSlot).toInt()
|
||||
val remainingTenThousandthPulses =
|
||||
((durationInSeconds - secondsPassedInCurrentSlot) / durationInSeconds.toDouble() * totalNumberOfTenThousandthPulsesInSlot).toLong()
|
||||
val delayBetweenTenthPulsesInUsec =
|
||||
(durationInSeconds * 1000000L * 1000 / totalNumberOfTenThousandthPulsesInSlot).toInt()
|
||||
val secondsRemaining = secondsPassedInCurrentSlot % 1800
|
||||
var delayUntilNextTenthPulseInUsec = delayBetweenTenthPulsesInUsec
|
||||
for (i in 0 until secondsRemaining) {
|
||||
|
@ -186,7 +234,8 @@ object ProgramBasalUtil {
|
|||
delayUntilNextTenthPulseInUsec += delayBetweenTenthPulsesInUsec
|
||||
}
|
||||
}
|
||||
val remainingTenthPulses = ((if (remainingTenThousandthPulses % 1000 != 0L) 1 else 0) + remainingTenThousandthPulses / 1000).toShort()
|
||||
val remainingTenthPulses =
|
||||
((if (remainingTenThousandthPulses % 1000 != 0L) 1 else 0) + remainingTenThousandthPulses / 1000).toShort()
|
||||
return CurrentBasalInsulinProgramElement(index, delayUntilNextTenthPulseInUsec, remainingTenthPulses)
|
||||
}
|
||||
index++
|
||||
|
|
|
@ -10,7 +10,13 @@ import kotlin.math.roundToInt
|
|||
object ProgramTempBasalUtil {
|
||||
|
||||
fun mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot: ShortArray): List<BasalInsulinProgramElement> {
|
||||
return ProgramBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot) { startSlotIndex: Byte, numberOfSlots: Byte, totalTenthPulses: Short -> TempBasalInsulinProgramElement(startSlotIndex, numberOfSlots, totalTenthPulses) }
|
||||
return ProgramBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot) { startSlotIndex: Byte, numberOfSlots: Byte, totalTenthPulses: Short ->
|
||||
TempBasalInsulinProgramElement(
|
||||
startSlotIndex,
|
||||
numberOfSlots,
|
||||
totalTenthPulses
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun mapTempBasalToTenthPulsesPerSlot(durationInSlots: Int, rateInUnitsPerHour: Double): ShortArray {
|
||||
|
|
|
@ -35,7 +35,7 @@ class AlertConfiguration(
|
|||
trigger.thresholdInMicroLiters
|
||||
}
|
||||
|
||||
is AlertTrigger.TimerTrigger -> {
|
||||
is AlertTrigger.TimerTrigger -> {
|
||||
trigger.offsetInMinutes
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,11 +15,14 @@ class DefaultStatusResponse(
|
|||
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 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: EnumSet<AlertType> = AlertUtil.decodeAlertSet((encoded[6].toInt() and 0xff shl 1 or (encoded[7] ushr 7)).toByte())
|
||||
val minutesSinceActivation: Short = (encoded[7] and 0x7f shl 6 or (encoded[8].toInt() and 0xff ushr 2 and 0x3f)).toShort()
|
||||
val activeAlerts: EnumSet<AlertType> =
|
||||
AlertUtil.decodeAlertSet((encoded[6].toInt() and 0xff shl 1 or (encoded[7] ushr 7)).toByte())
|
||||
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 {
|
||||
|
|
|
@ -25,9 +25,42 @@ class SetUniqueIdResponse(
|
|||
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
|
||||
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{" +
|
||||
|
|
|
@ -21,11 +21,44 @@ class VersionResponse(
|
|||
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 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
|
||||
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{" +
|
||||
|
|
|
@ -165,8 +165,16 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
|||
}
|
||||
|
||||
override fun updateFromVersionResponse(response: VersionResponse) {
|
||||
podState.bleVersion = SoftwareVersion(response.bleVersionMajor, response.bleVersionMinor, response.bleVersionInterim)
|
||||
podState.firmwareVersion = SoftwareVersion(response.firmwareVersionMajor, response.firmwareVersionMinor, response.firmwareVersionInterim)
|
||||
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
|
||||
|
@ -182,8 +190,16 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
|||
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.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
|
||||
|
@ -196,7 +212,10 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
|||
|
||||
override fun updateFromAlarmStatusResponse(response: AlarmStatusResponse) {
|
||||
// TODO
|
||||
logger.error(LTag.PUMP, "Not implemented: OmnipodDashPodStateManagerImpl.updateFromAlarmStatusResponse(AlarmStatusResponse)")
|
||||
logger.error(
|
||||
LTag.PUMP,
|
||||
"Not implemented: OmnipodDashPodStateManagerImpl.updateFromAlarmStatusResponse(AlarmStatusResponse)"
|
||||
)
|
||||
|
||||
store()
|
||||
rxBus.send(EventOmnipodDashPumpValuesChanged())
|
||||
|
@ -220,7 +239,10 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
|||
private fun load(): PodState {
|
||||
if (sharedPreferences.contains(R.string.key_omnipod_dash_pod_state)) {
|
||||
try {
|
||||
return Gson().fromJson(sharedPreferences.getString(R.string.key_omnipod_dash_pod_state, ""), PodState::class.java)
|
||||
return Gson().fromJson(
|
||||
sharedPreferences.getString(R.string.key_omnipod_dash_pod_state, ""),
|
||||
PodState::class.java
|
||||
)
|
||||
} catch (ex: Exception) {
|
||||
logger.error(LTag.PUMP, "Failed to deserialize Pod state", ex)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,264 @@ import kotlin.experimental.xor
|
|||
|
||||
object MessageUtil {
|
||||
|
||||
private val crc16table = shortArrayOf(0, -32763, -32753, 10, -32741, 30, 20, -32751, -32717, 54, 60, -32711, 40, -32723, -32729, 34, -32669, 102, 108, -32663, 120, -32643, -32649, 114, 80, -32683, -32673, 90, -32693, 78, 68, -32703, -32573, 198, 204, -32567, 216, -32547, -32553, 210, 240, -32523, -32513, 250, -32533, 238, 228, -32543, 160, -32603, -32593, 170, -32581, 190, 180, -32591, -32621, 150, 156, -32615, 136, -32627, -32633, 130, -32381, 390, 396, -32375, 408, -32355, -32361, 402, 432, -32331, -32321, 442, -32341, 430, 420, -32351, 480, -32283, -32273, 490, -32261, 510, 500, -32271, -32301, 470, 476, -32295, 456, -32307, -32313, 450, 320, -32443, -32433, 330, -32421, 350, 340, -32431, -32397, 374, 380, -32391, 360, -32403, -32409, 354, -32477, 294, 300, -32471, 312, -32451, -32457, 306, 272, -32491, -32481, 282, -32501, 270, 260, -32511, -31997, 774, 780, -31991, 792, -31971, -31977, 786, 816, -31947, -31937, 826, -31957, 814, 804, -31967, 864, -31899, -31889, 874, -31877, 894, 884, -31887, -31917, 854, 860, -31911, 840, -31923, -31929, 834, 960, -31803, -31793, 970, -31781, 990, 980, -31791, -31757, 1014, 1020, -31751, 1000, -31763, -31769, 994, -31837, 934, 940, -31831, 952, -31811, -31817, 946, 912, -31851, -31841, 922, -31861, 910, 900, -31871, 640, -32123, -32113, 650, -32101, 670, 660, -32111, -32077, 694, 700, -32071, 680, -32083, -32089, 674, -32029, 742, 748, -32023, 760, -32003, -32009, 754, 720, -32043, -32033, 730, -32053, 718, 708, -32063, -32189, 582, 588, -32183, 600, -32163, -32169, 594, 624, -32139, -32129, 634, -32149, 622, 612, -32159, 544, -32219, -32209, 554, -32197, 574, 564, -32207, -32237, 534, 540, -32231, 520, -32243, -32249, 514)
|
||||
private val crc16table = shortArrayOf(
|
||||
0,
|
||||
-32763,
|
||||
-32753,
|
||||
10,
|
||||
-32741,
|
||||
30,
|
||||
20,
|
||||
-32751,
|
||||
-32717,
|
||||
54,
|
||||
60,
|
||||
-32711,
|
||||
40,
|
||||
-32723,
|
||||
-32729,
|
||||
34,
|
||||
-32669,
|
||||
102,
|
||||
108,
|
||||
-32663,
|
||||
120,
|
||||
-32643,
|
||||
-32649,
|
||||
114,
|
||||
80,
|
||||
-32683,
|
||||
-32673,
|
||||
90,
|
||||
-32693,
|
||||
78,
|
||||
68,
|
||||
-32703,
|
||||
-32573,
|
||||
198,
|
||||
204,
|
||||
-32567,
|
||||
216,
|
||||
-32547,
|
||||
-32553,
|
||||
210,
|
||||
240,
|
||||
-32523,
|
||||
-32513,
|
||||
250,
|
||||
-32533,
|
||||
238,
|
||||
228,
|
||||
-32543,
|
||||
160,
|
||||
-32603,
|
||||
-32593,
|
||||
170,
|
||||
-32581,
|
||||
190,
|
||||
180,
|
||||
-32591,
|
||||
-32621,
|
||||
150,
|
||||
156,
|
||||
-32615,
|
||||
136,
|
||||
-32627,
|
||||
-32633,
|
||||
130,
|
||||
-32381,
|
||||
390,
|
||||
396,
|
||||
-32375,
|
||||
408,
|
||||
-32355,
|
||||
-32361,
|
||||
402,
|
||||
432,
|
||||
-32331,
|
||||
-32321,
|
||||
442,
|
||||
-32341,
|
||||
430,
|
||||
420,
|
||||
-32351,
|
||||
480,
|
||||
-32283,
|
||||
-32273,
|
||||
490,
|
||||
-32261,
|
||||
510,
|
||||
500,
|
||||
-32271,
|
||||
-32301,
|
||||
470,
|
||||
476,
|
||||
-32295,
|
||||
456,
|
||||
-32307,
|
||||
-32313,
|
||||
450,
|
||||
320,
|
||||
-32443,
|
||||
-32433,
|
||||
330,
|
||||
-32421,
|
||||
350,
|
||||
340,
|
||||
-32431,
|
||||
-32397,
|
||||
374,
|
||||
380,
|
||||
-32391,
|
||||
360,
|
||||
-32403,
|
||||
-32409,
|
||||
354,
|
||||
-32477,
|
||||
294,
|
||||
300,
|
||||
-32471,
|
||||
312,
|
||||
-32451,
|
||||
-32457,
|
||||
306,
|
||||
272,
|
||||
-32491,
|
||||
-32481,
|
||||
282,
|
||||
-32501,
|
||||
270,
|
||||
260,
|
||||
-32511,
|
||||
-31997,
|
||||
774,
|
||||
780,
|
||||
-31991,
|
||||
792,
|
||||
-31971,
|
||||
-31977,
|
||||
786,
|
||||
816,
|
||||
-31947,
|
||||
-31937,
|
||||
826,
|
||||
-31957,
|
||||
814,
|
||||
804,
|
||||
-31967,
|
||||
864,
|
||||
-31899,
|
||||
-31889,
|
||||
874,
|
||||
-31877,
|
||||
894,
|
||||
884,
|
||||
-31887,
|
||||
-31917,
|
||||
854,
|
||||
860,
|
||||
-31911,
|
||||
840,
|
||||
-31923,
|
||||
-31929,
|
||||
834,
|
||||
960,
|
||||
-31803,
|
||||
-31793,
|
||||
970,
|
||||
-31781,
|
||||
990,
|
||||
980,
|
||||
-31791,
|
||||
-31757,
|
||||
1014,
|
||||
1020,
|
||||
-31751,
|
||||
1000,
|
||||
-31763,
|
||||
-31769,
|
||||
994,
|
||||
-31837,
|
||||
934,
|
||||
940,
|
||||
-31831,
|
||||
952,
|
||||
-31811,
|
||||
-31817,
|
||||
946,
|
||||
912,
|
||||
-31851,
|
||||
-31841,
|
||||
922,
|
||||
-31861,
|
||||
910,
|
||||
900,
|
||||
-31871,
|
||||
640,
|
||||
-32123,
|
||||
-32113,
|
||||
650,
|
||||
-32101,
|
||||
670,
|
||||
660,
|
||||
-32111,
|
||||
-32077,
|
||||
694,
|
||||
700,
|
||||
-32071,
|
||||
680,
|
||||
-32083,
|
||||
-32089,
|
||||
674,
|
||||
-32029,
|
||||
742,
|
||||
748,
|
||||
-32023,
|
||||
760,
|
||||
-32003,
|
||||
-32009,
|
||||
754,
|
||||
720,
|
||||
-32043,
|
||||
-32033,
|
||||
730,
|
||||
-32053,
|
||||
718,
|
||||
708,
|
||||
-32063,
|
||||
-32189,
|
||||
582,
|
||||
588,
|
||||
-32183,
|
||||
600,
|
||||
-32163,
|
||||
-32169,
|
||||
594,
|
||||
624,
|
||||
-32139,
|
||||
-32129,
|
||||
634,
|
||||
-32149,
|
||||
622,
|
||||
612,
|
||||
-32159,
|
||||
544,
|
||||
-32219,
|
||||
-32209,
|
||||
554,
|
||||
-32197,
|
||||
574,
|
||||
564,
|
||||
-32207,
|
||||
-32237,
|
||||
534,
|
||||
540,
|
||||
-32231,
|
||||
520,
|
||||
-32243,
|
||||
-32249,
|
||||
514
|
||||
)
|
||||
|
||||
fun createCrc(sArr: ShortArray): Int {
|
||||
var i = 0
|
||||
|
|
|
@ -22,9 +22,17 @@ class DashHistory @Inject constructor(
|
|||
private val historyMapper: HistoryMapper
|
||||
) {
|
||||
|
||||
fun markSuccess(id: String, date: Long): Completable = dao.markResolved(id, ResolvedResult.SUCCESS, currentTimeMillis())
|
||||
fun markSuccess(id: String, date: Long): Completable = dao.markResolved(
|
||||
id,
|
||||
ResolvedResult.SUCCESS,
|
||||
currentTimeMillis()
|
||||
)
|
||||
|
||||
fun markFailure(id: String, date: Long): Completable = dao.markResolved(id, ResolvedResult.FAILURE, currentTimeMillis())
|
||||
fun markFailure(id: String, date: Long): Completable = dao.markResolved(
|
||||
id,
|
||||
ResolvedResult.FAILURE,
|
||||
currentTimeMillis()
|
||||
)
|
||||
|
||||
@Suppress("ReturnCount")
|
||||
fun createRecord(
|
||||
|
@ -39,7 +47,7 @@ class DashHistory @Inject constructor(
|
|||
val id = ULID.random()
|
||||
|
||||
when {
|
||||
commandType == SET_BOLUS && bolusRecord == null ->
|
||||
commandType == SET_BOLUS && bolusRecord == null ->
|
||||
return Single.error(IllegalArgumentException("bolusRecord missing on SET_BOLUS"))
|
||||
commandType == SET_TEMPORARY_BASAL && tempBasalRecord == null ->
|
||||
return Single.error(IllegalArgumentException("tempBasalRecord missing on SET_TEMPORARY_BASAL"))
|
||||
|
|
|
@ -21,7 +21,11 @@ abstract class DashHistoryDatabase : RoomDatabase() {
|
|||
const val VERSION = 1
|
||||
|
||||
fun build(context: Context) =
|
||||
Room.databaseBuilder(context.applicationContext, DashHistoryDatabase::class.java, "omnipod_dash_history_database.db")
|
||||
Room.databaseBuilder(
|
||||
context.applicationContext,
|
||||
DashHistoryDatabase::class.java,
|
||||
"omnipod_dash_history_database.db"
|
||||
)
|
||||
.fallbackToDestructiveMigration()
|
||||
.build()
|
||||
}
|
||||
|
|
|
@ -85,7 +85,15 @@ class DashPodManagementActivity : NoSplashAppCompatActivity() {
|
|||
object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
displayErrorDialog(resourceHelper.gs(R.string.omnipod_common_warning), resourceHelper.gs(R.string.omnipod_common_two_strings_concatenated_by_colon, resourceHelper.gs(R.string.omnipod_common_error_failed_to_play_test_beep), result.comment), false)
|
||||
displayErrorDialog(
|
||||
resourceHelper.gs(R.string.omnipod_common_warning),
|
||||
resourceHelper.gs(
|
||||
R.string.omnipod_common_two_strings_concatenated_by_colon,
|
||||
resourceHelper.gs(R.string.omnipod_common_error_failed_to_play_test_beep),
|
||||
result.comment
|
||||
),
|
||||
false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,7 +109,10 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
|||
disablePodActionButtons()
|
||||
commandQueue.customCommand(
|
||||
CommandResumeDelivery(),
|
||||
DisplayResultDialogCallback(resourceHelper.gs(R.string.omnipod_common_error_failed_to_resume_delivery), true).messageOnSuccess(resourceHelper.gs(R.string.omnipod_common_confirmation_delivery_resumed))
|
||||
DisplayResultDialogCallback(
|
||||
resourceHelper.gs(R.string.omnipod_common_error_failed_to_resume_delivery),
|
||||
true
|
||||
).messageOnSuccess(resourceHelper.gs(R.string.omnipod_common_confirmation_delivery_resumed))
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -117,7 +120,10 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
|||
disablePodActionButtons()
|
||||
commandQueue.readStatus(
|
||||
"REQUESTED BY USER",
|
||||
DisplayResultDialogCallback(resourceHelper.gs(R.string.omnipod_common_error_failed_to_refresh_status), false)
|
||||
DisplayResultDialogCallback(
|
||||
resourceHelper.gs(R.string.omnipod_common_error_failed_to_refresh_status),
|
||||
false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -125,7 +131,10 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
|||
disablePodActionButtons()
|
||||
commandQueue.customCommand(
|
||||
CommandAcknowledgeAlerts(),
|
||||
DisplayResultDialogCallback(resourceHelper.gs(R.string.omnipod_common_error_failed_to_silence_alerts), false)
|
||||
DisplayResultDialogCallback(
|
||||
resourceHelper.gs(R.string.omnipod_common_error_failed_to_silence_alerts),
|
||||
false
|
||||
)
|
||||
.messageOnSuccess(resourceHelper.gs(R.string.omnipod_common_confirmation_silenced_alerts))
|
||||
.actionOnSuccess { rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_ALERTS)) }
|
||||
)
|
||||
|
@ -135,7 +144,10 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
|||
disablePodActionButtons()
|
||||
commandQueue.customCommand(
|
||||
CommandSuspendDelivery(),
|
||||
DisplayResultDialogCallback(resourceHelper.gs(R.string.omnipod_common_error_failed_to_suspend_delivery), true)
|
||||
DisplayResultDialogCallback(
|
||||
resourceHelper.gs(R.string.omnipod_common_error_failed_to_suspend_delivery),
|
||||
true
|
||||
)
|
||||
.messageOnSuccess(resourceHelper.gs(R.string.omnipod_common_confirmation_suspended_delivery))
|
||||
)
|
||||
}
|
||||
|
@ -229,7 +241,11 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
|||
podInfoBinding.uniqueId.text = podStateManager.uniqueId.toString()
|
||||
podInfoBinding.podLot.text = podStateManager.lotNumber.toString()
|
||||
podInfoBinding.podSequenceNumber.text = podStateManager.podSequenceNumber.toString()
|
||||
podInfoBinding.firmwareVersion.text = resourceHelper.gs(R.string.omnipod_dash_overview_firmware_version_value, podStateManager.firmwareVersion.toString(), podStateManager.bluetoothVersion.toString())
|
||||
podInfoBinding.firmwareVersion.text = resourceHelper.gs(
|
||||
R.string.omnipod_dash_overview_firmware_version_value,
|
||||
podStateManager.firmwareVersion.toString(),
|
||||
podStateManager.bluetoothVersion.toString()
|
||||
)
|
||||
|
||||
// TODO
|
||||
/*
|
||||
|
@ -267,21 +283,27 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
|||
|
||||
// base basal rate
|
||||
podInfoBinding.baseBasalRate.text = if (podStateManager.basalProgram != null) {
|
||||
resourceHelper.gs(R.string.pump_basebasalrate, omnipodDashPumpPlugin.model().determineCorrectBasalSize(podStateManager.basalProgram!!.rateAt(Date())))
|
||||
resourceHelper.gs(
|
||||
R.string.pump_basebasalrate,
|
||||
omnipodDashPumpPlugin.model()
|
||||
.determineCorrectBasalSize(podStateManager.basalProgram!!.rateAt(Date()))
|
||||
)
|
||||
} else {
|
||||
PLACEHOLDER
|
||||
}
|
||||
|
||||
// total delivered
|
||||
podInfoBinding.totalDelivered.text = if (podStateManager.isActivationCompleted && podStateManager.pulsesDelivered != null) {
|
||||
resourceHelper.gs(R.string.omnipod_common_overview_total_delivered_value, podStateManager.pulseRate)
|
||||
} else {
|
||||
PLACEHOLDER
|
||||
}
|
||||
podInfoBinding.totalDelivered.text =
|
||||
if (podStateManager.isActivationCompleted && podStateManager.pulsesDelivered != null) {
|
||||
resourceHelper.gs(R.string.omnipod_common_overview_total_delivered_value, podStateManager.pulseRate)
|
||||
} else {
|
||||
PLACEHOLDER
|
||||
}
|
||||
|
||||
// reservoir
|
||||
if (podStateManager.pulsesRemaining == null) {
|
||||
podInfoBinding.reservoir.text = resourceHelper.gs(R.string.omnipod_common_overview_reservoir_value_over50)
|
||||
podInfoBinding.reservoir.text =
|
||||
resourceHelper.gs(R.string.omnipod_common_overview_reservoir_value_over50)
|
||||
podInfoBinding.reservoir.setTextColor(Color.WHITE)
|
||||
} else {
|
||||
// TODO
|
||||
|
@ -289,7 +311,10 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
|||
// ?: OmnipodConstants.DEFAULT_MAX_RESERVOIR_ALERT_THRESHOLD).toDouble()
|
||||
val lowReservoirThreshold: Short = 20
|
||||
|
||||
podInfoBinding.reservoir.text = resourceHelper.gs(R.string.omnipod_common_overview_reservoir_value, podStateManager.pulsesRemaining)
|
||||
podInfoBinding.reservoir.text = resourceHelper.gs(
|
||||
R.string.omnipod_common_overview_reservoir_value,
|
||||
podStateManager.pulsesRemaining
|
||||
)
|
||||
podInfoBinding.reservoir.setTextColor(
|
||||
if (podStateManager.pulsesRemaining!! < lowReservoirThreshold) {
|
||||
Color.RED
|
||||
|
@ -365,11 +390,12 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
val podStatusColor = if (!podStateManager.isActivationCompleted || /* TODO podStateManager.isPodDead || */ podStateManager.isSuspended) {
|
||||
Color.RED
|
||||
} else {
|
||||
Color.WHITE
|
||||
}
|
||||
val podStatusColor =
|
||||
if (!podStateManager.isActivationCompleted || /* TODO podStateManager.isPodDead || */ podStateManager.isSuspended) {
|
||||
Color.RED
|
||||
} else {
|
||||
Color.WHITE
|
||||
}
|
||||
podInfoBinding.podStatus.setTextColor(podStatusColor)
|
||||
}
|
||||
|
||||
|
@ -405,7 +431,13 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
|||
|
||||
val minutesRunning = 0 // TODO
|
||||
|
||||
podInfoBinding.tempBasal.text = resourceHelper.gs(R.string.omnipod_common_overview_temp_basal_value, rate, dateUtil.timeString(startTime), minutesRunning, duration)
|
||||
podInfoBinding.tempBasal.text = resourceHelper.gs(
|
||||
R.string.omnipod_common_overview_temp_basal_value,
|
||||
rate,
|
||||
dateUtil.timeString(startTime),
|
||||
minutesRunning,
|
||||
duration
|
||||
)
|
||||
} else {
|
||||
podInfoBinding.tempBasal.text = PLACEHOLDER
|
||||
}
|
||||
|
@ -437,12 +469,17 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
|||
}
|
||||
|
||||
private fun updateRefreshStatusButton() {
|
||||
buttonBinding.buttonRefreshStatus.isEnabled = podStateManager.isUniqueIdSet && podStateManager.activationProgress.isAtLeast(ActivationProgress.PHASE_1_COMPLETED) &&
|
||||
isQueueEmpty()
|
||||
buttonBinding.buttonRefreshStatus.isEnabled =
|
||||
podStateManager.isUniqueIdSet && podStateManager.activationProgress.isAtLeast(
|
||||
ActivationProgress.PHASE_1_COMPLETED
|
||||
) &&
|
||||
isQueueEmpty()
|
||||
}
|
||||
|
||||
private fun updateResumeDeliveryButton() {
|
||||
if (podStateManager.isPodRunning && (podStateManager.isSuspended || commandQueue.isCustomCommandInQueue(CommandResumeDelivery::class.java))) {
|
||||
if (podStateManager.isPodRunning && (podStateManager.isSuspended || commandQueue.isCustomCommandInQueue(
|
||||
CommandResumeDelivery::class.java
|
||||
))) {
|
||||
buttonBinding.buttonResumeDelivery.visibility = View.VISIBLE
|
||||
buttonBinding.buttonResumeDelivery.isEnabled = isQueueEmpty()
|
||||
} else {
|
||||
|
@ -451,7 +488,9 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
|||
}
|
||||
|
||||
private fun updateSilenceAlertsButton() {
|
||||
if (isAutomaticallySilenceAlertsEnabled() && podStateManager.isPodRunning && (podStateManager.activeAlerts!!.size > 0 || commandQueue.isCustomCommandInQueue(CommandAcknowledgeAlerts::class.java))) {
|
||||
if (isAutomaticallySilenceAlertsEnabled() && podStateManager.isPodRunning && (podStateManager.activeAlerts!!.size > 0 || commandQueue.isCustomCommandInQueue(
|
||||
CommandAcknowledgeAlerts::class.java
|
||||
))) {
|
||||
buttonBinding.buttonSilenceAlerts.visibility = View.VISIBLE
|
||||
buttonBinding.buttonSilenceAlerts.isEnabled = isQueueEmpty()
|
||||
} else {
|
||||
|
@ -461,9 +500,12 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
|||
|
||||
private fun updateSuspendDeliveryButton() {
|
||||
// If the Pod is currently suspended, we show the Resume delivery button instead.
|
||||
if (isSuspendDeliveryButtonEnabled() && podStateManager.isPodRunning && (!podStateManager.isSuspended || commandQueue.isCustomCommandInQueue(CommandSuspendDelivery::class.java))) {
|
||||
if (isSuspendDeliveryButtonEnabled() && podStateManager.isPodRunning && (!podStateManager.isSuspended || commandQueue.isCustomCommandInQueue(
|
||||
CommandSuspendDelivery::class.java
|
||||
))) {
|
||||
buttonBinding.buttonSuspendDelivery.visibility = View.VISIBLE
|
||||
buttonBinding.buttonSuspendDelivery.isEnabled = podStateManager.isPodRunning && !podStateManager.isSuspended && isQueueEmpty()
|
||||
buttonBinding.buttonSuspendDelivery.isEnabled =
|
||||
podStateManager.isPodRunning && !podStateManager.isSuspended && isQueueEmpty()
|
||||
} else {
|
||||
buttonBinding.buttonSuspendDelivery.visibility = View.GONE
|
||||
}
|
||||
|
@ -566,10 +608,18 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
|||
|
||||
// FIXME ideally we should just have access to LocalAlertUtils here
|
||||
private fun getPumpUnreachableTimeout(): Duration {
|
||||
return Duration.standardMinutes(sp.getInt(R.string.key_pump_unreachable_threshold_minutes, Constants.DEFAULT_PUMP_UNREACHABLE_THRESHOLD_MINUTES).toLong())
|
||||
return Duration.standardMinutes(
|
||||
sp.getInt(
|
||||
R.string.key_pump_unreachable_threshold_minutes,
|
||||
Constants.DEFAULT_PUMP_UNREACHABLE_THRESHOLD_MINUTES
|
||||
).toLong()
|
||||
)
|
||||
}
|
||||
|
||||
inner class DisplayResultDialogCallback(private val errorMessagePrefix: String, private val withSoundOnError: Boolean) : Callback() {
|
||||
inner class DisplayResultDialogCallback(
|
||||
private val errorMessagePrefix: String,
|
||||
private val withSoundOnError: Boolean
|
||||
) : Callback() {
|
||||
|
||||
private var messageOnSuccess: String? = null
|
||||
private var actionOnSuccess: Runnable? = null
|
||||
|
@ -582,7 +632,15 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
|||
}
|
||||
actionOnSuccess?.run()
|
||||
} else {
|
||||
displayErrorDialog(resourceHelper.gs(R.string.omnipod_common_warning), resourceHelper.gs(R.string.omnipod_common_two_strings_concatenated_by_colon, errorMessagePrefix, result.comment), withSoundOnError)
|
||||
displayErrorDialog(
|
||||
resourceHelper.gs(R.string.omnipod_common_warning),
|
||||
resourceHelper.gs(
|
||||
R.string.omnipod_common_two_strings_concatenated_by_colon,
|
||||
errorMessagePrefix,
|
||||
result.comment
|
||||
),
|
||||
withSoundOnError
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,12 @@ class DashInitializePodViewModel @Inject constructor(
|
|||
Single.create { source ->
|
||||
// TODO use configured value for low reservoir trigger
|
||||
val disposable = omnipodManager.activatePodPart1(AlertTrigger.ReservoirVolumeTrigger(200)).subscribeBy(
|
||||
onNext = { podEvent -> logger.debug(LTag.PUMP, "Received PodEvent in Pod activation part 1: $podEvent") },
|
||||
onNext = { podEvent ->
|
||||
logger.debug(
|
||||
LTag.PUMP,
|
||||
"Received PodEvent in Pod activation part 1: $podEvent"
|
||||
)
|
||||
},
|
||||
onError = { throwable ->
|
||||
logger.error(LTag.PUMP, "Error in Pod activation part 1", throwable)
|
||||
source.onSuccess(PumpEnactResult(injector).success(false).comment(throwable.message))
|
||||
|
|
|
@ -33,7 +33,12 @@ class DashInsertCannulaViewModel @Inject constructor(
|
|||
source.onError(IllegalStateException("No profile set"))
|
||||
} else {
|
||||
val disposable = omnipodManager.activatePodPart2(mapProfileToBasalProgram(profile)).subscribeBy(
|
||||
onNext = { podEvent -> logger.debug(LTag.PUMP, "Received PodEvent in Pod activation part 2: $podEvent") },
|
||||
onNext = { podEvent ->
|
||||
logger.debug(
|
||||
LTag.PUMP,
|
||||
"Received PodEvent in Pod activation part 2: $podEvent"
|
||||
)
|
||||
},
|
||||
onError = { throwable ->
|
||||
logger.error(LTag.PUMP, "Error in Pod activation part 2", throwable)
|
||||
source.onSuccess(PumpEnactResult(injector).success(false).comment(throwable.message))
|
||||
|
|
|
@ -14,7 +14,9 @@ class DashDeactivatePodViewModel @Inject constructor(
|
|||
logger: AAPSLogger
|
||||
) : DeactivatePodViewModel(injector, logger) {
|
||||
|
||||
override fun doExecuteAction(): Single<PumpEnactResult> = Single.just(PumpEnactResult(injector).success(false).comment("TODO")) // TODO
|
||||
override fun doExecuteAction(): Single<PumpEnactResult> = Single.just(
|
||||
PumpEnactResult(injector).success(false).comment("TODO")
|
||||
) // TODO
|
||||
|
||||
override fun discardPod() {
|
||||
// TODO
|
||||
|
|
Loading…
Reference in a new issue