Merge pull request #6 from 0pen-dash/adrian/kotlinify-driver-pod
Kotlinify Omnipod Dash driver
This commit is contained in:
commit
5db17e735c
122 changed files with 3919 additions and 3348 deletions
|
@ -32,7 +32,7 @@
|
|||
tools:ignore="HardcodedText" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pod_address"
|
||||
android:id="@+id/unique_id"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
|
@ -110,7 +110,7 @@
|
|||
tools:ignore="HardcodedText" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pod_tid"
|
||||
android:id="@+id/pod_sequence_number"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
|
||||
class EventOmnipodDashPumpValuesChanged : Event()
|
|
@ -1,213 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.data.DetailedBolusInfo;
|
||||
import info.nightscout.androidaps.data.Profile;
|
||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider;
|
||||
import info.nightscout.androidaps.interfaces.PluginDescription;
|
||||
import info.nightscout.androidaps.interfaces.PluginType;
|
||||
import info.nightscout.androidaps.interfaces.PumpDescription;
|
||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||
import info.nightscout.androidaps.interfaces.PumpPluginBase;
|
||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||
import info.nightscout.androidaps.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.common.ManufacturerType;
|
||||
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction;
|
||||
import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType;
|
||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.OmnipodDashOverviewFragment;
|
||||
import info.nightscout.androidaps.queue.commands.CustomCommand;
|
||||
import info.nightscout.androidaps.utils.TimeChangeType;
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||
|
||||
@Singleton
|
||||
public class OmnipodDashPumpPlugin extends PumpPluginBase implements PumpInterface {
|
||||
private static final PumpDescription PUMP_DESCRIPTION = new PumpDescription(PumpType.Omnipod_Dash);
|
||||
|
||||
private final AAPSLogger aapsLogger;
|
||||
private final ResourceHelper resourceHelper;
|
||||
private final CommandQueueProvider commandQueue;
|
||||
|
||||
@Inject
|
||||
public OmnipodDashPumpPlugin(HasAndroidInjector injector, AAPSLogger aapsLogger, ResourceHelper resourceHelper, CommandQueueProvider commandQueue) {
|
||||
super(new PluginDescription() //
|
||||
.mainType(PluginType.PUMP) //
|
||||
.fragmentClass(OmnipodDashOverviewFragment.class.getName()) //
|
||||
.pluginIcon(R.drawable.ic_pod_128)
|
||||
.pluginName(R.string.omnipod_dash_name) //
|
||||
.shortName(R.string.omnipod_dash_name_short) //
|
||||
.preferencesId(R.xml.omnipod_dash_preferences) //
|
||||
.description(R.string.omnipod_dash_pump_description), injector, aapsLogger, resourceHelper, commandQueue);
|
||||
this.aapsLogger = aapsLogger;
|
||||
this.resourceHelper = resourceHelper;
|
||||
this.commandQueue = commandQueue;
|
||||
}
|
||||
|
||||
@Override public boolean isInitialized() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean isSuspended() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public boolean isBusy() {
|
||||
// prevents the queue from executing
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean isConnected() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public boolean isConnecting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public boolean isHandshakeInProgress() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public void finishHandshaking() {
|
||||
|
||||
}
|
||||
|
||||
@Override public void connect(@NotNull String reason) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void disconnect(@NotNull String reason) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void stopConnecting() {
|
||||
|
||||
}
|
||||
|
||||
@Override public void getPumpStatus(@NotNull String reason) {
|
||||
|
||||
}
|
||||
|
||||
@NotNull @Override public PumpEnactResult setNewBasalProfile(@NotNull Profile profile) {
|
||||
// TODO
|
||||
return new PumpEnactResult(getInjector()).success(true).enacted(true);
|
||||
}
|
||||
|
||||
@Override public boolean isThisProfileSet(@NotNull Profile profile) {
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public long lastDataTime() {
|
||||
// TODO
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@Override public double getBaseBasalRate() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override public double getReservoirLevel() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override public int getBatteryLevel() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@NotNull @Override public PumpEnactResult deliverTreatment(@NotNull DetailedBolusInfo detailedBolusInfo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public void stopBolusDelivering() {
|
||||
|
||||
}
|
||||
|
||||
@NotNull @Override public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NotNull Profile profile, boolean enforceNew) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull @Override public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NotNull Profile profile, boolean enforceNew) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull @Override public PumpEnactResult setExtendedBolus(double insulin, int durationInMinutes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull @Override public PumpEnactResult cancelTempBasal(boolean enforceNew) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull @Override public PumpEnactResult cancelExtendedBolus() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull @Override public JSONObject getJSONStatus(@NotNull Profile profile, @NotNull String profileName, @NotNull String version) {
|
||||
return new JSONObject();
|
||||
}
|
||||
|
||||
@NotNull @Override public ManufacturerType manufacturer() {
|
||||
return getPumpDescription().pumpType.getManufacturer();
|
||||
}
|
||||
|
||||
@NotNull @Override public PumpType model() {
|
||||
return getPumpDescription().pumpType;
|
||||
}
|
||||
|
||||
@NotNull @Override public String serialNumber() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull @Override public PumpDescription getPumpDescription() {
|
||||
return PUMP_DESCRIPTION;
|
||||
}
|
||||
|
||||
@NotNull @Override public String shortStatus(boolean veryShort) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public boolean isFakingTempsByExtendedBoluses() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull @Override public PumpEnactResult loadTDDs() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public boolean canHandleDST() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CustomAction> getCustomActions() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeCustomAction(@NotNull CustomActionType customActionType) {
|
||||
aapsLogger.warn(LTag.PUMP, "Unsupported custom action: " + customActionType);
|
||||
}
|
||||
|
||||
@Nullable @Override public PumpEnactResult executeCustomCommand(@NotNull CustomCommand customCommand) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public void timezoneOrDSTChanged(@NotNull TimeChangeType timeChangeType) {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,210 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||
import info.nightscout.androidaps.data.Profile
|
||||
import info.nightscout.androidaps.data.PumpEnactResult
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.common.ManufacturerType
|
||||
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction
|
||||
import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType
|
||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.OmnipodDashManager
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.OmnipodDashOverviewFragment
|
||||
import info.nightscout.androidaps.queue.commands.CustomCommand
|
||||
import info.nightscout.androidaps.utils.TimeChangeType
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import org.json.JSONObject
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class OmnipodDashPumpPlugin @Inject constructor(
|
||||
private val omnipodManager: OmnipodDashManager,
|
||||
private val podStateManager: OmnipodDashPodStateManager,
|
||||
injector: HasAndroidInjector,
|
||||
aapsLogger: AAPSLogger,
|
||||
resourceHelper: ResourceHelper,
|
||||
commandQueue: CommandQueueProvider
|
||||
) : PumpPluginBase(pluginDescription, injector, aapsLogger, resourceHelper, commandQueue), PumpInterface {
|
||||
|
||||
companion object {
|
||||
|
||||
private val pluginDescription = PluginDescription() //
|
||||
.mainType(PluginType.PUMP) //
|
||||
.fragmentClass(OmnipodDashOverviewFragment::class.java.name) //
|
||||
.pluginIcon(R.drawable.ic_pod_128)
|
||||
.pluginName(R.string.omnipod_dash_name) //
|
||||
.shortName(R.string.omnipod_dash_name_short) //
|
||||
.preferencesId(R.xml.omnipod_dash_preferences) //
|
||||
.description(R.string.omnipod_dash_pump_description)
|
||||
|
||||
private val pumpDescription = PumpDescription(PumpType.Omnipod_Dash)
|
||||
}
|
||||
|
||||
override fun isInitialized(): Boolean {
|
||||
// TODO
|
||||
return true
|
||||
}
|
||||
|
||||
override fun isSuspended(): Boolean {
|
||||
// TODO
|
||||
return false
|
||||
}
|
||||
|
||||
override fun isBusy(): Boolean {
|
||||
// prevents the queue from executing commands
|
||||
// TODO
|
||||
return true
|
||||
}
|
||||
|
||||
override fun isConnected(): Boolean {
|
||||
// TODO
|
||||
return false
|
||||
}
|
||||
|
||||
override fun isConnecting(): Boolean {
|
||||
// TODO
|
||||
return false
|
||||
}
|
||||
|
||||
override fun isHandshakeInProgress(): Boolean {
|
||||
// TODO
|
||||
return false
|
||||
}
|
||||
|
||||
override fun finishHandshaking() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
override fun connect(reason: String) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
override fun disconnect(reason: String) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
override fun stopConnecting() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
override fun getPumpStatus(reason: String) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
|
||||
// TODO
|
||||
return PumpEnactResult(injector).success(true).enacted(true)
|
||||
}
|
||||
|
||||
override fun isThisProfileSet(profile: Profile): Boolean {
|
||||
// TODO
|
||||
return true
|
||||
}
|
||||
|
||||
override fun lastDataTime(): Long {
|
||||
// TODO
|
||||
return System.currentTimeMillis()
|
||||
}
|
||||
|
||||
override val baseBasalRate: Double
|
||||
get() = 0.0 // TODO
|
||||
|
||||
override val reservoirLevel: Double
|
||||
get() = 0.0 // TODO
|
||||
|
||||
override val batteryLevel: Int
|
||||
get() = 0
|
||||
|
||||
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
|
||||
// TODO
|
||||
return PumpEnactResult(injector).success(false).enacted(false).comment("TODO")
|
||||
}
|
||||
|
||||
override fun stopBolusDelivering() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
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 {
|
||||
// TODO i18n
|
||||
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")
|
||||
}
|
||||
|
||||
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
|
||||
// TODO
|
||||
return PumpEnactResult(injector).success(false).enacted(false).comment("TODO")
|
||||
}
|
||||
|
||||
override fun cancelExtendedBolus(): PumpEnactResult {
|
||||
// TODO i18n
|
||||
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 {
|
||||
// TODO
|
||||
return JSONObject()
|
||||
}
|
||||
|
||||
override val pumpDescription: PumpDescription = Companion.pumpDescription
|
||||
|
||||
override fun manufacturer(): ManufacturerType {
|
||||
return pumpDescription.pumpType.manufacturer
|
||||
}
|
||||
|
||||
override fun model(): PumpType {
|
||||
return pumpDescription.pumpType
|
||||
}
|
||||
|
||||
override fun serialNumber(): String {
|
||||
// TODO
|
||||
return "TODO"
|
||||
}
|
||||
|
||||
override fun shortStatus(veryShort: Boolean): String {
|
||||
// TODO
|
||||
return "TODO"
|
||||
}
|
||||
|
||||
override val isFakingTempsByExtendedBoluses: Boolean
|
||||
get() = false
|
||||
|
||||
override fun loadTDDs(): PumpEnactResult {
|
||||
// TODO i18n
|
||||
return PumpEnactResult(injector).success(false).enacted(false).comment("Omnipod Dash driver does not support TDD")
|
||||
}
|
||||
|
||||
override fun canHandleDST(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun getCustomActions(): List<CustomAction> {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override fun executeCustomAction(customActionType: CustomActionType) {
|
||||
aapsLogger.warn(LTag.PUMP, "Unsupported custom action: $customActionType")
|
||||
}
|
||||
|
||||
override fun executeCustomCommand(customCommand: CustomCommand): PumpEnactResult? {
|
||||
// TODO
|
||||
return null
|
||||
}
|
||||
|
||||
override fun timezoneOrDSTChanged(timeChangeType: TimeChangeType) {
|
||||
// TODO
|
||||
}
|
||||
}
|
|
@ -1,10 +1,16 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.dagger
|
||||
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.dagger.ActivityScope
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.dagger.OmnipodWizardModule
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.BleManager
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.OmnipodDashManager
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.OmnipodDashManagerImpl
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.OmnipodDashBleManager
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.OmnipodDashBleManagerImpl
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManagerImpl
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.DashPodManagementActivity
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.OmnipodDashOverviewFragment
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.wizard.activation.DashPodActivationWizardActivity
|
||||
|
@ -31,6 +37,14 @@ abstract class OmnipodDashModule {
|
|||
@ContributesAndroidInjector
|
||||
abstract fun contributesOmnipodDashOverviewFragment(): OmnipodDashOverviewFragment
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesBleManager(): BleManager
|
||||
}
|
||||
// MANAGERS
|
||||
|
||||
@Binds
|
||||
abstract fun bindsOmnipodDashBleManagerImpl(bleManager: OmnipodDashBleManagerImpl): OmnipodDashBleManager
|
||||
|
||||
@Binds
|
||||
abstract fun bindsOmnipodDashPodStateManagerImpl(podStateManager: OmnipodDashPodStateManagerImpl): OmnipodDashPodStateManager
|
||||
|
||||
@Binds
|
||||
abstract fun bindsOmnipodDashManagerImpl(omnipodManager: OmnipodDashManagerImpl): OmnipodDashManager
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver;
|
||||
|
||||
public interface OmnipodDashManager {
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
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 io.reactivex.Observable
|
||||
|
||||
interface OmnipodDashManager {
|
||||
|
||||
fun activatePodPart1(): Observable<PodEvent>
|
||||
|
||||
fun activatePodPart2(): Observable<PodEvent>
|
||||
|
||||
fun getStatus(): Observable<PodEvent>
|
||||
|
||||
fun setBasalProgram(program: BasalProgram): Observable<PodEvent>
|
||||
|
||||
fun suspendDelivery(): Observable<PodEvent>
|
||||
|
||||
fun setTime(): Observable<PodEvent>
|
||||
|
||||
fun setTempBasal(rate: Double, durationInMinutes: Short): Observable<PodEvent>
|
||||
|
||||
fun cancelTempBasal(): Observable<PodEvent>
|
||||
|
||||
fun bolus(amount: Double): Observable<PodEvent>
|
||||
|
||||
fun cancelBolus(): Observable<PodEvent>
|
||||
|
||||
fun silenceAlerts(): Observable<PodEvent>
|
||||
|
||||
fun deactivatePod(): Observable<PodEvent>
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
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.state.OmnipodDashPodStateManager
|
||||
import io.reactivex.Observable
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class OmnipodDashManagerImpl @Inject constructor(
|
||||
private val aapsLogger: AAPSLogger,
|
||||
private val podStateManager: OmnipodDashPodStateManager,
|
||||
private val bleManager: OmnipodDashBleManager
|
||||
) : OmnipodDashManager {
|
||||
|
||||
override fun activatePodPart1(): Observable<PodEvent> {
|
||||
// TODO
|
||||
return Observable.empty()
|
||||
}
|
||||
|
||||
override fun activatePodPart2(): Observable<PodEvent> {
|
||||
// TODO
|
||||
return Observable.empty()
|
||||
}
|
||||
|
||||
override fun getStatus(): Observable<PodEvent> {
|
||||
// TODO
|
||||
return Observable.empty()
|
||||
}
|
||||
|
||||
override fun setBasalProgram(program: BasalProgram): Observable<PodEvent> {
|
||||
// TODO
|
||||
return Observable.empty()
|
||||
}
|
||||
|
||||
override fun suspendDelivery(): Observable<PodEvent> {
|
||||
// TODO
|
||||
return Observable.empty()
|
||||
}
|
||||
|
||||
override fun setTime(): Observable<PodEvent> {
|
||||
// TODO
|
||||
return Observable.empty()
|
||||
}
|
||||
|
||||
override fun setTempBasal(rate: Double, durationInMinutes: Short): Observable<PodEvent> {
|
||||
// TODO
|
||||
return Observable.empty()
|
||||
}
|
||||
|
||||
override fun cancelTempBasal(): Observable<PodEvent> {
|
||||
// TODO
|
||||
return Observable.empty()
|
||||
}
|
||||
|
||||
override fun bolus(amount: Double): Observable<PodEvent> {
|
||||
// TODO
|
||||
return Observable.empty()
|
||||
}
|
||||
|
||||
override fun cancelBolus(): Observable<PodEvent> {
|
||||
// TODO
|
||||
return Observable.empty()
|
||||
}
|
||||
|
||||
override fun silenceAlerts(): Observable<PodEvent> {
|
||||
// TODO
|
||||
return Observable.empty()
|
||||
}
|
||||
|
||||
override fun deactivatePod(): Observable<PodEvent> {
|
||||
// TODO
|
||||
return Observable.empty()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm
|
||||
|
||||
interface OmnipodDashBleManager {
|
||||
|
||||
// TODO should we keep this method?
|
||||
fun activateNewPod()
|
||||
}
|
|
@ -20,13 +20,13 @@ import javax.inject.Inject
|
|||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class BleManager @Inject constructor(private val context: Context, private val aapsLogger: AAPSLogger) : OmnipodDashCommunicationManager {
|
||||
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 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() {
|
||||
override 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
|
|
@ -1,3 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm
|
||||
|
||||
interface OmnipodDashCommunicationManager
|
|
@ -7,7 +7,7 @@ enum class BleCommandType(val value: Byte) {
|
|||
|
||||
@JvmStatic
|
||||
fun byValue(value: Byte): BleCommandType =
|
||||
BleCommandType.values().firstOrNull { it.value == value }
|
||||
values().firstOrNull { it.value == value }
|
||||
?: throw IllegalArgumentException("Unknown BleCommandType: $value")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.event
|
||||
|
||||
class PodEvent(
|
||||
val type: PodEventType,
|
||||
val data: Any?
|
||||
)
|
|
@ -0,0 +1,12 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.event
|
||||
|
||||
enum class PodEventType {
|
||||
SCANNING,
|
||||
PAIRING,
|
||||
CONNECTING,
|
||||
CONNECTED,
|
||||
COMMAND_SENDING,
|
||||
COMMAND_SENT,
|
||||
RESPONSE_RECEIVED,
|
||||
// ...
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.NonceEnabledCommand;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.NonceEnabledCommandBuilder;
|
||||
|
||||
public final class DeactivateCommand extends NonceEnabledCommand {
|
||||
private static final short LENGTH = 6;
|
||||
private static final byte BODY_LENGTH = 4;
|
||||
|
||||
DeactivateCommand(int uniqueId, short sequenceNumber, boolean multiCommandFlag, int nonce) {
|
||||
super(CommandType.DEACTIVATE, uniqueId, sequenceNumber, multiCommandFlag, nonce);
|
||||
}
|
||||
|
||||
@Override public byte[] getEncoded() {
|
||||
return appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) //
|
||||
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
|
||||
.put(commandType.getValue()) //
|
||||
.put(BODY_LENGTH) //
|
||||
.putInt(nonce) //
|
||||
.array());
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "DeactivateCommand{" +
|
||||
"nonce=" + nonce +
|
||||
", commandType=" + commandType +
|
||||
", uniqueId=" + uniqueId +
|
||||
", sequenceNumber=" + sequenceNumber +
|
||||
", multiCommandFlag=" + multiCommandFlag +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static final class Builder extends NonceEnabledCommandBuilder<Builder, DeactivateCommand> {
|
||||
@Override protected final DeactivateCommand buildCommand() {
|
||||
return new DeactivateCommand(uniqueId, sequenceNumber, multiCommandFlag, nonce);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.NonceEnabledCommand
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.NonceEnabledCommandBuilder
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
class DeactivateCommand internal constructor(
|
||||
uniqueId: Int,
|
||||
sequenceNumber: Short,
|
||||
multiCommandFlag: Boolean,
|
||||
nonce: Int
|
||||
) : NonceEnabledCommand(CommandType.DEACTIVATE, uniqueId, sequenceNumber, multiCommandFlag, nonce) {
|
||||
|
||||
override val encoded: ByteArray
|
||||
get() = appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) //
|
||||
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
|
||||
.put(commandType.value) //
|
||||
.put(BODY_LENGTH) //
|
||||
.putInt(nonce) //
|
||||
.array())
|
||||
|
||||
override fun toString(): String = "DeactivateCommand{" +
|
||||
"nonce=" + nonce +
|
||||
", commandType=" + commandType +
|
||||
", uniqueId=" + uniqueId +
|
||||
", sequenceNumber=" + sequenceNumber +
|
||||
", multiCommandFlag=" + multiCommandFlag +
|
||||
'}'
|
||||
|
||||
class Builder : NonceEnabledCommandBuilder<Builder, DeactivateCommand>() {
|
||||
|
||||
override fun buildCommand(): DeactivateCommand =
|
||||
DeactivateCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, nonce!!) // TODO this might crash if not all are set
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val LENGTH: Short = 6
|
||||
private const val BODY_LENGTH: Byte = 4
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.HeaderEnabledCommand;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.HeaderEnabledCommandBuilder;
|
||||
|
||||
public final class GetVersionCommand extends HeaderEnabledCommand {
|
||||
public static final int DEFAULT_UNIQUE_ID = -1; // FIXME move
|
||||
|
||||
private static final short LENGTH = 6;
|
||||
private static final byte BODY_LENGTH = 4;
|
||||
|
||||
GetVersionCommand(int uniqueId, short sequenceNumber, boolean multiCommandFlag) {
|
||||
super(CommandType.GET_VERSION, uniqueId, sequenceNumber, multiCommandFlag);
|
||||
}
|
||||
|
||||
@Override public byte[] getEncoded() {
|
||||
return appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) //
|
||||
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
|
||||
.put(commandType.getValue()) //
|
||||
.put(BODY_LENGTH) //
|
||||
.putInt(uniqueId) //
|
||||
.array());
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "GetVersionCommand{" +
|
||||
"commandType=" + commandType +
|
||||
", uniqueId=" + uniqueId +
|
||||
", sequenceNumber=" + sequenceNumber +
|
||||
", multiCommandFlag=" + multiCommandFlag +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static final class Builder extends HeaderEnabledCommandBuilder<Builder, GetVersionCommand> {
|
||||
@Override protected final GetVersionCommand buildCommand() {
|
||||
return new GetVersionCommand(uniqueId, sequenceNumber, multiCommandFlag);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.HeaderEnabledCommand
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.HeaderEnabledCommandBuilder
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
class GetVersionCommand internal constructor(
|
||||
uniqueId: Int,
|
||||
sequenceNumber: Short,
|
||||
multiCommandFlag: Boolean
|
||||
) : HeaderEnabledCommand(CommandType.GET_VERSION, uniqueId, sequenceNumber, multiCommandFlag) {
|
||||
|
||||
override val encoded: ByteArray
|
||||
get() = appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) //
|
||||
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
|
||||
.put(commandType.value) //
|
||||
.put(BODY_LENGTH) //
|
||||
.putInt(uniqueId) //
|
||||
.array())
|
||||
|
||||
override fun toString(): String {
|
||||
return "GetVersionCommand{" +
|
||||
"commandType=" + commandType +
|
||||
", uniqueId=" + uniqueId +
|
||||
", sequenceNumber=" + sequenceNumber +
|
||||
", multiCommandFlag=" + multiCommandFlag +
|
||||
'}'
|
||||
}
|
||||
|
||||
class Builder : HeaderEnabledCommandBuilder<Builder, GetVersionCommand>() {
|
||||
|
||||
override fun buildCommand(): GetVersionCommand {
|
||||
return GetVersionCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val DEFAULT_UNIQUE_ID = -1 // FIXME move
|
||||
private const val LENGTH: Short = 6
|
||||
private const val BODY_LENGTH: Byte = 4
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.NonceEnabledCommand;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.NonceEnabledCommandBuilder;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertConfiguration;
|
||||
|
||||
public final class ProgramAlertsCommand extends NonceEnabledCommand {
|
||||
private final List<AlertConfiguration> alertConfigurations;
|
||||
|
||||
ProgramAlertsCommand(int uniqueId, short sequenceNumber, boolean multiCommandFlag, List<AlertConfiguration> alertConfigurations, int nonce) {
|
||||
super(CommandType.PROGRAM_ALERTS, uniqueId, sequenceNumber, multiCommandFlag, nonce);
|
||||
this.alertConfigurations = new ArrayList<>(alertConfigurations);
|
||||
}
|
||||
|
||||
@Override public byte[] getEncoded() {
|
||||
ByteBuffer byteBuffer = ByteBuffer.allocate(getLength() + HEADER_LENGTH) //
|
||||
.put(encodeHeader(uniqueId, sequenceNumber, getLength(), multiCommandFlag)) //
|
||||
.put(commandType.getValue()) //
|
||||
.put(getBodyLength()) //
|
||||
.putInt(nonce);
|
||||
for (AlertConfiguration configuration : alertConfigurations) {
|
||||
byteBuffer.put(configuration.getEncoded());
|
||||
}
|
||||
return appendCrc(byteBuffer.array());
|
||||
}
|
||||
|
||||
private short getLength() {
|
||||
return (short) (alertConfigurations.size() * 6 + 6);
|
||||
}
|
||||
|
||||
private byte getBodyLength() {
|
||||
return (byte) (alertConfigurations.size() * 6 + 4);
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "ProgramAlertsCommand{" +
|
||||
"alertConfigurations=" + alertConfigurations +
|
||||
", nonce=" + nonce +
|
||||
", commandType=" + commandType +
|
||||
", uniqueId=" + uniqueId +
|
||||
", sequenceNumber=" + sequenceNumber +
|
||||
", multiCommandFlag=" + multiCommandFlag +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static final class Builder extends NonceEnabledCommandBuilder<Builder, ProgramAlertsCommand> {
|
||||
private List<AlertConfiguration> alertConfigurations;
|
||||
|
||||
public Builder setAlertConfigurations(List<AlertConfiguration> alertConfigurations) {
|
||||
this.alertConfigurations = alertConfigurations;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override protected final ProgramAlertsCommand buildCommand() {
|
||||
if (this.alertConfigurations == null) {
|
||||
throw new IllegalArgumentException("alertConfigurations can not be null");
|
||||
}
|
||||
return new ProgramAlertsCommand(uniqueId, sequenceNumber, multiCommandFlag, alertConfigurations, nonce);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.NonceEnabledCommand
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.NonceEnabledCommandBuilder
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertConfiguration
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.*
|
||||
|
||||
class ProgramAlertsCommand internal constructor(
|
||||
uniqueId: Int,
|
||||
sequenceNumber: Short,
|
||||
multiCommandFlag: Boolean,
|
||||
alertConfigurations: List<AlertConfiguration>?,
|
||||
nonce: Int
|
||||
) : NonceEnabledCommand(CommandType.PROGRAM_ALERTS, uniqueId, sequenceNumber, multiCommandFlag, nonce) {
|
||||
|
||||
private val alertConfigurations: List<AlertConfiguration>
|
||||
|
||||
private fun getLength(): Short {
|
||||
return (alertConfigurations.size * 6 + 6).toShort()
|
||||
}
|
||||
|
||||
private fun getBodyLength(): Byte {
|
||||
return (alertConfigurations.size * 6 + 4).toByte()
|
||||
}
|
||||
|
||||
override val encoded: ByteArray
|
||||
get() {
|
||||
val byteBuffer: ByteBuffer = ByteBuffer.allocate(getLength() + HEADER_LENGTH) //
|
||||
.put(encodeHeader(uniqueId, sequenceNumber, getLength(), multiCommandFlag)) //
|
||||
.put(commandType.value) //
|
||||
.put(getBodyLength()) //
|
||||
.putInt(nonce)
|
||||
for (configuration in alertConfigurations) {
|
||||
byteBuffer.put(configuration.encoded)
|
||||
}
|
||||
return appendCrc(byteBuffer.array())
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "ProgramAlertsCommand{" +
|
||||
"alertConfigurations=" + alertConfigurations +
|
||||
", nonce=" + nonce +
|
||||
", commandType=" + commandType +
|
||||
", uniqueId=" + uniqueId +
|
||||
", sequenceNumber=" + sequenceNumber +
|
||||
", multiCommandFlag=" + multiCommandFlag +
|
||||
'}'
|
||||
}
|
||||
|
||||
class Builder : NonceEnabledCommandBuilder<Builder, ProgramAlertsCommand>() {
|
||||
|
||||
private var alertConfigurations: List<AlertConfiguration>? = null
|
||||
fun setAlertConfigurations(alertConfigurations: List<AlertConfiguration>?): Builder {
|
||||
this.alertConfigurations = alertConfigurations
|
||||
return this
|
||||
}
|
||||
|
||||
override fun buildCommand(): ProgramAlertsCommand {
|
||||
requireNotNull(alertConfigurations) { "alertConfigurations can not be null" } // !!?
|
||||
return ProgramAlertsCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, alertConfigurations, nonce!!) // TODO this might crash if not all are set
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
this.alertConfigurations = ArrayList(alertConfigurations)
|
||||
}
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.HeaderEnabledCommand;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.NonceEnabledCommandBuilder;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.BasalInsulinProgramElement;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.CurrentBasalInsulinProgramElement;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.CurrentSlot;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.ShortInsulinProgramElement;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.util.ProgramBasalUtil;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BasalProgram;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ProgramReminder;
|
||||
|
||||
// Always preceded by 0x1a ProgramInsulinCommand
|
||||
public final class ProgramBasalCommand extends HeaderEnabledCommand {
|
||||
private final ProgramInsulinCommand interlockCommand;
|
||||
private final List<BasalInsulinProgramElement> insulinProgramElements;
|
||||
private final ProgramReminder programReminder;
|
||||
private final byte currentInsulinProgramElementIndex;
|
||||
private final short remainingTenthPulsesInCurrentInsulinProgramElement;
|
||||
private final int delayUntilNextTenthPulseInUsec;
|
||||
|
||||
ProgramBasalCommand(ProgramInsulinCommand interlockCommand, int uniqueId, short sequenceNumber, boolean multiCommandFlag, List<BasalInsulinProgramElement> insulinProgramElements, ProgramReminder programReminder, byte currentInsulinProgramElementIndex, short remainingTenthPulsesInCurrentInsulinProgramElement, int delayUntilNextTenthPulseInUsec) {
|
||||
super(CommandType.PROGRAM_BASAL, uniqueId, sequenceNumber, multiCommandFlag);
|
||||
|
||||
this.interlockCommand = interlockCommand;
|
||||
this.insulinProgramElements = new ArrayList<>(insulinProgramElements);
|
||||
this.programReminder = programReminder;
|
||||
this.currentInsulinProgramElementIndex = currentInsulinProgramElementIndex;
|
||||
this.remainingTenthPulsesInCurrentInsulinProgramElement = remainingTenthPulsesInCurrentInsulinProgramElement;
|
||||
this.delayUntilNextTenthPulseInUsec = delayUntilNextTenthPulseInUsec;
|
||||
}
|
||||
|
||||
short getLength() {
|
||||
return (short) (insulinProgramElements.size() * 6 + 10);
|
||||
}
|
||||
|
||||
byte getBodyLength() {
|
||||
return (byte) (insulinProgramElements.size() * 6 + 8);
|
||||
}
|
||||
|
||||
@Override public byte[] getEncoded() {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(getLength()) //
|
||||
.put(getCommandType().getValue()) //
|
||||
.put(getBodyLength()) //
|
||||
.put(programReminder.getEncoded()) //
|
||||
.put(currentInsulinProgramElementIndex) //
|
||||
.putShort(remainingTenthPulsesInCurrentInsulinProgramElement) //
|
||||
.putInt(delayUntilNextTenthPulseInUsec);
|
||||
for (BasalInsulinProgramElement insulinProgramElement : insulinProgramElements) {
|
||||
buffer.put(insulinProgramElement.getEncoded());
|
||||
}
|
||||
|
||||
byte[] basalCommand = buffer.array();
|
||||
byte[] interlockCommand = this.interlockCommand.getEncoded();
|
||||
byte[] header = encodeHeader(uniqueId, sequenceNumber, (short) (basalCommand.length + interlockCommand.length), multiCommandFlag);
|
||||
|
||||
return appendCrc(ByteBuffer.allocate(basalCommand.length + interlockCommand.length + header.length) //
|
||||
.put(header) //
|
||||
.put(interlockCommand) //
|
||||
.put(basalCommand) //
|
||||
.array());
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "ProgramBasalCommand{" +
|
||||
"interlockCommand=" + interlockCommand +
|
||||
", insulinProgramElements=" + insulinProgramElements +
|
||||
", programReminder=" + programReminder +
|
||||
", currentInsulinProgramElementIndex=" + currentInsulinProgramElementIndex +
|
||||
", remainingTenthPulsesInCurrentInsulinProgramElement=" + remainingTenthPulsesInCurrentInsulinProgramElement +
|
||||
", delayUntilNextTenthPulseInUsec=" + delayUntilNextTenthPulseInUsec +
|
||||
", commandType=" + commandType +
|
||||
", uniqueId=" + uniqueId +
|
||||
", sequenceNumber=" + sequenceNumber +
|
||||
", multiCommandFlag=" + multiCommandFlag +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static final class Builder extends NonceEnabledCommandBuilder<Builder, ProgramBasalCommand> {
|
||||
private BasalProgram basalProgram;
|
||||
private ProgramReminder programReminder;
|
||||
private Date currentTime;
|
||||
|
||||
public Builder setBasalProgram(BasalProgram basalProgram) {
|
||||
this.basalProgram = basalProgram;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setProgramReminder(ProgramReminder programReminder) {
|
||||
this.programReminder = programReminder;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setCurrentTime(Date currentTime) {
|
||||
this.currentTime = currentTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override protected ProgramBasalCommand buildCommand() {
|
||||
if (basalProgram == null) {
|
||||
throw new IllegalArgumentException("basalProgram can not be null");
|
||||
}
|
||||
if (programReminder == null) {
|
||||
throw new IllegalArgumentException("programReminder can not be null");
|
||||
}
|
||||
if (currentTime == null) {
|
||||
throw new IllegalArgumentException("currentTime can not be null");
|
||||
}
|
||||
|
||||
short[] pulsesPerSlot = ProgramBasalUtil.mapBasalProgramToPulsesPerSlot(basalProgram);
|
||||
CurrentSlot currentSlot = ProgramBasalUtil.calculateCurrentSlot(pulsesPerSlot, currentTime);
|
||||
short checksum = ProgramBasalUtil.calculateChecksum(pulsesPerSlot, currentSlot);
|
||||
List<BasalInsulinProgramElement> longInsulinProgramElements = ProgramBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements(ProgramBasalUtil.mapBasalProgramToTenthPulsesPerSlot(basalProgram));
|
||||
List<ShortInsulinProgramElement> shortInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot);
|
||||
CurrentBasalInsulinProgramElement currentBasalInsulinProgramElement = ProgramBasalUtil.calculateCurrentLongInsulinProgramElement(longInsulinProgramElements, currentTime);
|
||||
|
||||
ProgramInsulinCommand interlockCommand = new ProgramInsulinCommand(uniqueId, sequenceNumber, multiCommandFlag, nonce,
|
||||
shortInsulinProgramElements, checksum, currentSlot.getIndex(), currentSlot.getEighthSecondsRemaining(),
|
||||
currentSlot.getPulsesRemaining(), ProgramInsulinCommand.DeliveryType.BASAL);
|
||||
|
||||
return new ProgramBasalCommand(interlockCommand, uniqueId, sequenceNumber, multiCommandFlag,
|
||||
longInsulinProgramElements, programReminder, currentBasalInsulinProgramElement.getIndex(),
|
||||
currentBasalInsulinProgramElement.getRemainingTenthPulses(), currentBasalInsulinProgramElement.getDelayUntilNextTenthPulseInUsec());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.HeaderEnabledCommand
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.NonceEnabledCommandBuilder
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.BasalInsulinProgramElement
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.util.ProgramBasalUtil
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.util.ProgramTempBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BasalProgram
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ProgramReminder
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.*
|
||||
|
||||
// Always preceded by 0x1a ProgramInsulinCommand
|
||||
class ProgramBasalCommand internal constructor(
|
||||
private val interlockCommand: ProgramInsulinCommand,
|
||||
uniqueId: Int,
|
||||
sequenceNumber: Short,
|
||||
multiCommandFlag: Boolean,
|
||||
insulinProgramElements: List<BasalInsulinProgramElement>,
|
||||
programReminder: ProgramReminder,
|
||||
currentInsulinProgramElementIndex: Byte,
|
||||
remainingTenthPulsesInCurrentInsulinProgramElement: Short,
|
||||
delayUntilNextTenthPulseInUsec: Int
|
||||
) : HeaderEnabledCommand(CommandType.PROGRAM_BASAL, uniqueId, sequenceNumber, multiCommandFlag) {
|
||||
|
||||
private val insulinProgramElements: List<BasalInsulinProgramElement>
|
||||
private val programReminder: ProgramReminder
|
||||
private val currentInsulinProgramElementIndex: Byte
|
||||
private val remainingTenthPulsesInCurrentInsulinProgramElement: Short
|
||||
private val delayUntilNextTenthPulseInUsec: Int
|
||||
val length: Short
|
||||
get() = (insulinProgramElements.size * 6 + 10).toShort()
|
||||
val bodyLength: Byte
|
||||
get() = (insulinProgramElements.size * 6 + 8).toByte()
|
||||
|
||||
override val encoded: ByteArray
|
||||
get() {
|
||||
val buffer = ByteBuffer.allocate(length.toInt()) //
|
||||
.put(commandType.value) //
|
||||
.put(bodyLength) //
|
||||
.put(programReminder.encoded) //
|
||||
.put(currentInsulinProgramElementIndex) //
|
||||
.putShort(remainingTenthPulsesInCurrentInsulinProgramElement) //
|
||||
.putInt(delayUntilNextTenthPulseInUsec)
|
||||
for (insulinProgramElement in insulinProgramElements) {
|
||||
buffer.put(insulinProgramElement.encoded)
|
||||
}
|
||||
val basalCommand = buffer.array()
|
||||
val interlockCommand = interlockCommand.encoded
|
||||
val header: ByteArray = encodeHeader(uniqueId, sequenceNumber, (basalCommand.size + interlockCommand.size).toShort(), multiCommandFlag)
|
||||
return appendCrc(ByteBuffer.allocate(basalCommand.size + interlockCommand.size + header.size) //
|
||||
.put(header) //
|
||||
.put(interlockCommand) //
|
||||
.put(basalCommand) //
|
||||
.array())
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "ProgramBasalCommand{" +
|
||||
"interlockCommand=" + interlockCommand +
|
||||
", insulinProgramElements=" + insulinProgramElements +
|
||||
", programReminder=" + programReminder +
|
||||
", currentInsulinProgramElementIndex=" + currentInsulinProgramElementIndex +
|
||||
", remainingTenthPulsesInCurrentInsulinProgramElement=" + remainingTenthPulsesInCurrentInsulinProgramElement +
|
||||
", delayUntilNextTenthPulseInUsec=" + delayUntilNextTenthPulseInUsec +
|
||||
", commandType=" + commandType +
|
||||
", uniqueId=" + uniqueId +
|
||||
", sequenceNumber=" + sequenceNumber +
|
||||
", multiCommandFlag=" + multiCommandFlag +
|
||||
'}'
|
||||
}
|
||||
|
||||
class Builder : NonceEnabledCommandBuilder<Builder, ProgramBasalCommand>() {
|
||||
|
||||
private var basalProgram: BasalProgram? = null
|
||||
private var programReminder: ProgramReminder? = null
|
||||
private var currentTime: Date? = null
|
||||
fun setBasalProgram(basalProgram: BasalProgram?): Builder {
|
||||
this.basalProgram = basalProgram
|
||||
return this
|
||||
}
|
||||
|
||||
fun setProgramReminder(programReminder: ProgramReminder?): Builder {
|
||||
this.programReminder = programReminder
|
||||
return this
|
||||
}
|
||||
|
||||
fun setCurrentTime(currentTime: Date?): Builder {
|
||||
this.currentTime = currentTime
|
||||
return this
|
||||
}
|
||||
|
||||
override fun buildCommand(): ProgramBasalCommand {
|
||||
requireNotNull(basalProgram) { "basalProgram can not be null" }
|
||||
requireNotNull(programReminder) { "programReminder can not be null" }
|
||||
requireNotNull(currentTime) { "currentTime can not be null" }
|
||||
val pulsesPerSlot = ProgramBasalUtil.mapBasalProgramToPulsesPerSlot(basalProgram!!)
|
||||
val currentSlot = ProgramBasalUtil.calculateCurrentSlot(pulsesPerSlot, currentTime)
|
||||
val checksum = ProgramBasalUtil.calculateChecksum(pulsesPerSlot, currentSlot)
|
||||
val longInsulinProgramElements: List<BasalInsulinProgramElement> = mapTenthPulsesPerSlotToLongInsulinProgramElements(ProgramBasalUtil.mapBasalProgramToTenthPulsesPerSlot(basalProgram!!))
|
||||
val shortInsulinProgramElements = ProgramBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot)
|
||||
val currentBasalInsulinProgramElement = ProgramBasalUtil.calculateCurrentLongInsulinProgramElement(longInsulinProgramElements, currentTime)
|
||||
val interlockCommand = ProgramInsulinCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, nonce!!,
|
||||
shortInsulinProgramElements, checksum, currentSlot.index, currentSlot.eighthSecondsRemaining,
|
||||
currentSlot.pulsesRemaining, ProgramInsulinCommand.DeliveryType.BASAL)
|
||||
return ProgramBasalCommand(interlockCommand, uniqueId!!, sequenceNumber!!, multiCommandFlag,
|
||||
longInsulinProgramElements, programReminder!!, currentBasalInsulinProgramElement.index,
|
||||
currentBasalInsulinProgramElement.remainingTenthPulses, currentBasalInsulinProgramElement.delayUntilNextTenthPulseInUsec)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
this.insulinProgramElements = ArrayList(insulinProgramElements)
|
||||
this.programReminder = programReminder
|
||||
this.currentInsulinProgramElementIndex = currentInsulinProgramElementIndex
|
||||
this.remainingTenthPulsesInCurrentInsulinProgramElement = remainingTenthPulsesInCurrentInsulinProgramElement
|
||||
this.delayUntilNextTenthPulseInUsec = delayUntilNextTenthPulseInUsec
|
||||
}
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collections;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.HeaderEnabledCommand;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.NonceEnabledCommandBuilder;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.BolusShortInsulinProgramElement;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ProgramReminder;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.MessageUtil;
|
||||
|
||||
// NOT SUPPORTED: extended bolus
|
||||
public final class ProgramBolusCommand extends HeaderEnabledCommand {
|
||||
private static final short LENGTH = 15;
|
||||
private static final byte BODY_LENGTH = 13;
|
||||
|
||||
private final ProgramInsulinCommand interlockCommand;
|
||||
private final ProgramReminder programReminder;
|
||||
private final short numberOfTenthPulses;
|
||||
private final int delayUntilFirstTenthPulseInUsec;
|
||||
|
||||
ProgramBolusCommand(ProgramInsulinCommand interlockCommand, int uniqueId, short sequenceNumber, boolean multiCommandFlag, ProgramReminder programReminder, short numberOfTenthPulses, int delayUntilFirstTenthPulseInUsec) {
|
||||
super(CommandType.PROGRAM_BOLUS, uniqueId, sequenceNumber, multiCommandFlag);
|
||||
this.interlockCommand = interlockCommand;
|
||||
this.programReminder = programReminder;
|
||||
this.numberOfTenthPulses = numberOfTenthPulses;
|
||||
this.delayUntilFirstTenthPulseInUsec = delayUntilFirstTenthPulseInUsec;
|
||||
}
|
||||
|
||||
@Override public byte[] getEncoded() {
|
||||
byte[] bolusCommand = ByteBuffer.allocate(LENGTH) //
|
||||
.put(commandType.getValue()) //
|
||||
.put(BODY_LENGTH) //
|
||||
.put(programReminder.getEncoded()) //
|
||||
.putShort(numberOfTenthPulses) //
|
||||
.putInt(delayUntilFirstTenthPulseInUsec) //
|
||||
.putShort((short) 0) // Extended bolus pulses
|
||||
.putInt(0) // Delay between tenth extended pulses in usec
|
||||
.array();
|
||||
|
||||
byte[] interlockCommand = this.interlockCommand.getEncoded();
|
||||
byte[] header = encodeHeader(uniqueId, sequenceNumber, (short) (bolusCommand.length + interlockCommand.length), multiCommandFlag);
|
||||
|
||||
return appendCrc(ByteBuffer.allocate(header.length + interlockCommand.length + bolusCommand.length) //
|
||||
.put(header) //
|
||||
.put(interlockCommand) //
|
||||
.put(bolusCommand) //
|
||||
.array());
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "ProgramBolusCommand{" +
|
||||
"interlockCommand=" + interlockCommand +
|
||||
", programReminder=" + programReminder +
|
||||
", numberOfTenthPulses=" + numberOfTenthPulses +
|
||||
", delayUntilFirstTenthPulseInUsec=" + delayUntilFirstTenthPulseInUsec +
|
||||
", commandType=" + commandType +
|
||||
", uniqueId=" + uniqueId +
|
||||
", sequenceNumber=" + sequenceNumber +
|
||||
", multiCommandFlag=" + multiCommandFlag +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static final class Builder extends NonceEnabledCommandBuilder<Builder, ProgramBolusCommand> {
|
||||
private Double numberOfUnits;
|
||||
private Byte delayBetweenPulsesInEighthSeconds;
|
||||
private ProgramReminder programReminder;
|
||||
|
||||
public Builder setNumberOfUnits(double numberOfUnits) {
|
||||
if (numberOfUnits <= 0.0D) {
|
||||
throw new IllegalArgumentException("Number of units should be greater than zero");
|
||||
}
|
||||
if ((int) (numberOfUnits * 1000) % 50 != 0) {
|
||||
throw new IllegalArgumentException("Number of units must be dividable by 0.05");
|
||||
}
|
||||
this.numberOfUnits = ((int) (numberOfUnits * 100)) / 100.0d;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setDelayBetweenPulsesInEighthSeconds(byte delayBetweenPulsesInEighthSeconds) {
|
||||
this.delayBetweenPulsesInEighthSeconds = delayBetweenPulsesInEighthSeconds;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setProgramReminder(ProgramReminder programReminder) {
|
||||
this.programReminder = programReminder;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override protected ProgramBolusCommand buildCommand() {
|
||||
if (numberOfUnits == null) {
|
||||
throw new IllegalArgumentException("numberOfUnits can not be null");
|
||||
}
|
||||
if (delayBetweenPulsesInEighthSeconds == null) {
|
||||
throw new IllegalArgumentException("delayBetweenPulsesInEighthSeconds can not be null");
|
||||
}
|
||||
if (programReminder == null) {
|
||||
throw new IllegalArgumentException("programReminder can not be null");
|
||||
}
|
||||
|
||||
short numberOfPulses = (short) Math.round(numberOfUnits * 20);
|
||||
short byte10And11 = (short) (numberOfPulses * delayBetweenPulsesInEighthSeconds);
|
||||
|
||||
ProgramInsulinCommand interlockCommand = new ProgramInsulinCommand(uniqueId, sequenceNumber, multiCommandFlag, nonce,
|
||||
Collections.singletonList(new BolusShortInsulinProgramElement(numberOfPulses)), calculateChecksum((byte) 0x01, byte10And11, numberOfPulses),
|
||||
(byte) 0x01, byte10And11, (short) numberOfPulses, ProgramInsulinCommand.DeliveryType.BOLUS);
|
||||
|
||||
int delayUntilFirstTenthPulseInUsec = delayBetweenPulsesInEighthSeconds / 8 * 100_000;
|
||||
|
||||
return new ProgramBolusCommand(interlockCommand, uniqueId, sequenceNumber, multiCommandFlag, programReminder, (short) (numberOfPulses * 10), delayUntilFirstTenthPulseInUsec);
|
||||
}
|
||||
}
|
||||
|
||||
private static short calculateChecksum(byte numberOfSlots, short byte10And11, short numberOfPulses) {
|
||||
return MessageUtil.calculateChecksum(ByteBuffer.allocate(7) //
|
||||
.put(numberOfSlots) //
|
||||
.putShort(byte10And11) //
|
||||
.putShort(numberOfPulses) //
|
||||
.putShort(numberOfPulses) //
|
||||
.array());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.HeaderEnabledCommand
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.NonceEnabledCommandBuilder
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.BolusShortInsulinProgramElement
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ProgramReminder
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.MessageUtil
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
// NOT SUPPORTED: extended bolus
|
||||
class ProgramBolusCommand internal constructor(
|
||||
private val interlockCommand: ProgramInsulinCommand,
|
||||
uniqueId: Int,
|
||||
sequenceNumber: Short,
|
||||
multiCommandFlag: Boolean,
|
||||
private val programReminder: ProgramReminder,
|
||||
private val numberOfTenthPulses: Short,
|
||||
private val delayUntilFirstTenthPulseInUsec: Int
|
||||
) : HeaderEnabledCommand(CommandType.PROGRAM_BOLUS, uniqueId, sequenceNumber, multiCommandFlag) {
|
||||
|
||||
override val encoded: ByteArray
|
||||
get() {
|
||||
val bolusCommand = ByteBuffer.allocate(LENGTH.toInt()) //
|
||||
.put(commandType.value) //
|
||||
.put(BODY_LENGTH) //
|
||||
.put(programReminder.encoded) //
|
||||
.putShort(numberOfTenthPulses) //
|
||||
.putInt(delayUntilFirstTenthPulseInUsec) //
|
||||
.putShort(0.toShort()) // Extended bolus pulses
|
||||
.putInt(0) // Delay between tenth extended pulses in usec
|
||||
.array()
|
||||
val interlockCommand = interlockCommand.encoded
|
||||
val header: ByteArray = encodeHeader(uniqueId, sequenceNumber, (bolusCommand.size + interlockCommand.size).toShort(), multiCommandFlag)
|
||||
return appendCrc(ByteBuffer.allocate(header.size + interlockCommand.size + bolusCommand.size) //
|
||||
.put(header) //
|
||||
.put(interlockCommand) //
|
||||
.put(bolusCommand) //
|
||||
.array())
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "ProgramBolusCommand{" +
|
||||
"interlockCommand=" + interlockCommand +
|
||||
", programReminder=" + programReminder +
|
||||
", numberOfTenthPulses=" + numberOfTenthPulses +
|
||||
", delayUntilFirstTenthPulseInUsec=" + delayUntilFirstTenthPulseInUsec +
|
||||
", commandType=" + commandType +
|
||||
", uniqueId=" + uniqueId +
|
||||
", sequenceNumber=" + sequenceNumber +
|
||||
", multiCommandFlag=" + multiCommandFlag +
|
||||
'}'
|
||||
}
|
||||
|
||||
class Builder : NonceEnabledCommandBuilder<Builder, ProgramBolusCommand>() {
|
||||
|
||||
private var numberOfUnits: Double? = null
|
||||
private var delayBetweenPulsesInEighthSeconds: Byte? = null
|
||||
private var programReminder: ProgramReminder? = null
|
||||
fun setNumberOfUnits(numberOfUnits: Double): Builder {
|
||||
require(numberOfUnits > 0.0) { "Number of units should be greater than zero" }
|
||||
require((numberOfUnits * 1000).toInt() % 50 == 0) { "Number of units must be dividable by 0.05" }
|
||||
this.numberOfUnits = (numberOfUnits * 100).toInt() / 100.0
|
||||
return this
|
||||
}
|
||||
|
||||
fun setDelayBetweenPulsesInEighthSeconds(delayBetweenPulsesInEighthSeconds: Byte): Builder {
|
||||
this.delayBetweenPulsesInEighthSeconds = delayBetweenPulsesInEighthSeconds
|
||||
return this
|
||||
}
|
||||
|
||||
fun setProgramReminder(programReminder: ProgramReminder?): Builder {
|
||||
this.programReminder = programReminder
|
||||
return this
|
||||
}
|
||||
|
||||
override fun buildCommand(): ProgramBolusCommand {
|
||||
requireNotNull(numberOfUnits) { "numberOfUnits can not be null" }
|
||||
requireNotNull(delayBetweenPulsesInEighthSeconds) { "delayBetweenPulsesInEighthSeconds can not be null" }
|
||||
requireNotNull(programReminder) { "programReminder can not be null" }
|
||||
val numberOfPulses = Math.round(numberOfUnits!! * 20).toShort()
|
||||
val byte10And11 = (numberOfPulses * delayBetweenPulsesInEighthSeconds!!).toShort()
|
||||
val interlockCommand = ProgramInsulinCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, nonce!!, listOf(BolusShortInsulinProgramElement(numberOfPulses)), calculateChecksum(0x01.toByte(), byte10And11, numberOfPulses),
|
||||
0x01.toByte(), byte10And11, numberOfPulses, ProgramInsulinCommand.DeliveryType.BOLUS)
|
||||
val delayUntilFirstTenthPulseInUsec = delayBetweenPulsesInEighthSeconds!! / 8 * 100000
|
||||
return ProgramBolusCommand(interlockCommand, uniqueId!!, sequenceNumber!!, multiCommandFlag, programReminder!!, (numberOfPulses * 10).toShort(), delayUntilFirstTenthPulseInUsec)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val LENGTH: Short = 15
|
||||
private const val BODY_LENGTH: Byte = 13
|
||||
private fun calculateChecksum(numberOfSlots: Byte, byte10And11: Short, numberOfPulses: Short): Short {
|
||||
return MessageUtil.calculateChecksum(ByteBuffer.allocate(7) //
|
||||
.put(numberOfSlots) //
|
||||
.putShort(byte10And11) //
|
||||
.putShort(numberOfPulses) //
|
||||
.putShort(numberOfPulses) //
|
||||
.array())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.NonceEnabledCommand;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.ShortInsulinProgramElement;
|
||||
|
||||
// Always followed by one of: 0x13, 0x16, 0x17
|
||||
final class ProgramInsulinCommand extends NonceEnabledCommand {
|
||||
private final List<ShortInsulinProgramElement> insulinProgramElements;
|
||||
private final short checksum;
|
||||
private final byte byte9;
|
||||
private final short byte10And11;
|
||||
private final short byte12And13;
|
||||
private final DeliveryType deliveryType;
|
||||
|
||||
ProgramInsulinCommand(int uniqueId, short sequenceNumber, boolean multiCommandFlag, int nonce, List<ShortInsulinProgramElement> insulinProgramElements, short checksum, byte byte9, short byte10And11, short byte12And13, DeliveryType deliveryType) {
|
||||
super(CommandType.PROGRAM_INSULIN, uniqueId, sequenceNumber, multiCommandFlag, nonce);
|
||||
this.insulinProgramElements = new ArrayList<>(insulinProgramElements);
|
||||
this.checksum = checksum;
|
||||
this.byte9 = byte9;
|
||||
this.byte10And11 = byte10And11;
|
||||
this.byte12And13 = byte12And13;
|
||||
this.deliveryType = deliveryType;
|
||||
}
|
||||
|
||||
public short getLength() {
|
||||
return (short) (insulinProgramElements.size() * 2 + 14);
|
||||
}
|
||||
|
||||
public byte getBodyLength() {
|
||||
return (byte) (insulinProgramElements.size() * 2 + 12);
|
||||
}
|
||||
|
||||
@Override public byte[] getEncoded() {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(this.getLength()) //
|
||||
.put(commandType.getValue()) //
|
||||
.put(getBodyLength()) //
|
||||
.putInt(nonce) //
|
||||
.put(deliveryType.getValue()) //
|
||||
.putShort(checksum) //
|
||||
.put(byte9) // BASAL: currentSlot // BOLUS: number of ShortInsulinProgramElements
|
||||
.putShort(byte10And11) // BASAL: remainingEighthSecondsInCurrentSlot // BOLUS: immediate pulses multiplied by delay between pulses in eighth seconds
|
||||
.putShort(byte12And13); // BASAL: remainingPulsesInCurrentSlot // BOLUS: immediate pulses
|
||||
|
||||
for (ShortInsulinProgramElement element : insulinProgramElements) {
|
||||
buffer.put(element.getEncoded());
|
||||
}
|
||||
|
||||
return buffer.array();
|
||||
}
|
||||
|
||||
enum DeliveryType {
|
||||
BASAL((byte) 0x00),
|
||||
TEMP_BASAL((byte) 0x01),
|
||||
BOLUS((byte) 0x02);
|
||||
|
||||
private final byte value;
|
||||
|
||||
DeliveryType(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public byte getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public short calculateChecksum(byte[] bytes) {
|
||||
short sum = 0;
|
||||
for (byte b : bytes) {
|
||||
sum += (short) (b & 0xff);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "ProgramInsulinCommand{" +
|
||||
"insulinProgramElements=" + insulinProgramElements +
|
||||
", checksum=" + checksum +
|
||||
", byte9=" + byte9 +
|
||||
", byte10And11=" + byte10And11 +
|
||||
", byte12And13=" + byte12And13 +
|
||||
", deliveryType=" + deliveryType +
|
||||
", nonce=" + nonce +
|
||||
", commandType=" + commandType +
|
||||
", uniqueId=" + uniqueId +
|
||||
", sequenceNumber=" + sequenceNumber +
|
||||
", multiCommandFlag=" + multiCommandFlag +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.NonceEnabledCommand
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.ShortInsulinProgramElement
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.*
|
||||
|
||||
// Always followed by one of: 0x13, 0x16, 0x17
|
||||
class ProgramInsulinCommand(
|
||||
uniqueId: Int,
|
||||
sequenceNumber: Short,
|
||||
multiCommandFlag: Boolean,
|
||||
nonce: Int, insulinProgramElements:
|
||||
List<ShortInsulinProgramElement>,
|
||||
private val checksum: Short,
|
||||
private val byte9: Byte,
|
||||
private val byte10And11: Short,
|
||||
private val byte12And13: Short,
|
||||
private val deliveryType: DeliveryType
|
||||
) : NonceEnabledCommand(CommandType.PROGRAM_INSULIN, uniqueId, sequenceNumber, multiCommandFlag, nonce) {
|
||||
|
||||
private val insulinProgramElements: List<ShortInsulinProgramElement> = ArrayList(insulinProgramElements)
|
||||
|
||||
fun getLength(): Short = (insulinProgramElements.size * 2 + 14).toShort()
|
||||
|
||||
fun getBodyLength(): Byte = (insulinProgramElements.size * 2 + 12).toByte()
|
||||
|
||||
enum class DeliveryType(private val value: Byte) {
|
||||
BASAL(0x00.toByte()), TEMP_BASAL(0x01.toByte()), BOLUS(0x02.toByte());
|
||||
|
||||
fun getValue(): Byte {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
fun calculateChecksum(bytes: ByteArray): Short {
|
||||
var sum: Short = 0
|
||||
for (b in bytes) {
|
||||
sum = ((b.toInt() and 0xff) + sum).toShort() // TODO Adrian: int conversion ok?
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
override val encoded: ByteArray
|
||||
get() {
|
||||
val buffer = ByteBuffer.allocate(getLength().toInt()) //
|
||||
.put(commandType.value) //
|
||||
.put(getBodyLength()) //
|
||||
.putInt(nonce) //
|
||||
.put(deliveryType.getValue()) //
|
||||
.putShort(checksum) //
|
||||
.put(byte9) // BASAL: currentSlot // BOLUS: number of ShortInsulinProgramElements
|
||||
.putShort(byte10And11) // BASAL: remainingEighthSecondsInCurrentSlot // BOLUS: immediate pulses multiplied by delay between pulses in eighth seconds
|
||||
.putShort(byte12And13) // BASAL: remainingPulsesInCurrentSlot // BOLUS: immediate pulses
|
||||
for (element in insulinProgramElements) {
|
||||
buffer.put(element.encoded)
|
||||
}
|
||||
return buffer.array()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "ProgramInsulinCommand{" +
|
||||
"insulinProgramElements=" + insulinProgramElements +
|
||||
", checksum=" + checksum +
|
||||
", byte9=" + byte9 +
|
||||
", byte10And11=" + byte10And11 +
|
||||
", byte12And13=" + byte12And13 +
|
||||
", deliveryType=" + deliveryType +
|
||||
", nonce=" + nonce +
|
||||
", commandType=" + commandType +
|
||||
", uniqueId=" + uniqueId +
|
||||
", sequenceNumber=" + sequenceNumber +
|
||||
", multiCommandFlag=" + multiCommandFlag +
|
||||
'}'
|
||||
}
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.HeaderEnabledCommand;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.NonceEnabledCommandBuilder;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.BasalInsulinProgramElement;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.ShortInsulinProgramElement;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.util.ProgramBasalUtil;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.util.ProgramTempBasalUtil;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ProgramReminder;
|
||||
|
||||
// NOT SUPPORTED: percentage temp basal
|
||||
public final class ProgramTempBasalCommand extends HeaderEnabledCommand {
|
||||
private final ProgramInsulinCommand interlockCommand;
|
||||
private final ProgramReminder programReminder;
|
||||
private final List<BasalInsulinProgramElement> insulinProgramElements;
|
||||
|
||||
protected ProgramTempBasalCommand(ProgramInsulinCommand interlockCommand, int uniqueId, short sequenceNumber, boolean multiCommandFlag,
|
||||
ProgramReminder programReminder, List<BasalInsulinProgramElement> insulinProgramElements) {
|
||||
super(CommandType.PROGRAM_TEMP_BASAL, uniqueId, sequenceNumber, multiCommandFlag);
|
||||
this.interlockCommand = interlockCommand;
|
||||
this.programReminder = programReminder;
|
||||
this.insulinProgramElements = new ArrayList<>(insulinProgramElements);
|
||||
}
|
||||
|
||||
public byte getBodyLength() {
|
||||
return (byte) (insulinProgramElements.size() * 6 + 8);
|
||||
}
|
||||
|
||||
public short getLength() {
|
||||
return (short) (getBodyLength() + 2);
|
||||
}
|
||||
|
||||
@Override public byte[] getEncoded() {
|
||||
BasalInsulinProgramElement firstProgramElement = insulinProgramElements.get(0);
|
||||
|
||||
short remainingTenthPulsesInFirstElement;
|
||||
int delayUntilNextTenthPulseInUsec;
|
||||
|
||||
if (firstProgramElement.getTotalTenthPulses() == 0) {
|
||||
remainingTenthPulsesInFirstElement = firstProgramElement.getNumberOfSlots();
|
||||
delayUntilNextTenthPulseInUsec = ProgramBasalUtil.MAX_DELAY_BETWEEN_TENTH_PULSES_IN_USEC_AND_USECS_IN_BASAL_SLOT;
|
||||
} else {
|
||||
remainingTenthPulsesInFirstElement = firstProgramElement.getTotalTenthPulses();
|
||||
delayUntilNextTenthPulseInUsec = (int) ((long) firstProgramElement.getNumberOfSlots() * 1_800.0d / remainingTenthPulsesInFirstElement * 1_000_000);
|
||||
}
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocate(getLength()) //
|
||||
.put(commandType.getValue()) //
|
||||
.put(getBodyLength()) //
|
||||
.put(programReminder.getEncoded()) //
|
||||
.put((byte) 0x00) // Current slot index
|
||||
.putShort(remainingTenthPulsesInFirstElement) //
|
||||
.putInt(delayUntilNextTenthPulseInUsec);
|
||||
|
||||
for (BasalInsulinProgramElement element : insulinProgramElements) {
|
||||
buffer.put(element.getEncoded());
|
||||
}
|
||||
|
||||
byte[] tempBasalCommand = buffer.array();
|
||||
byte[] interlockCommand = this.interlockCommand.getEncoded();
|
||||
byte[] header = encodeHeader(uniqueId, sequenceNumber, (short) (tempBasalCommand.length + interlockCommand.length), multiCommandFlag);
|
||||
|
||||
return appendCrc(ByteBuffer.allocate(header.length + interlockCommand.length + tempBasalCommand.length) //
|
||||
.put(header) //
|
||||
.put(interlockCommand) //
|
||||
.put(tempBasalCommand) //
|
||||
.array());
|
||||
}
|
||||
|
||||
public static class Builder extends NonceEnabledCommandBuilder<Builder, ProgramTempBasalCommand> {
|
||||
private ProgramReminder programReminder;
|
||||
private Double rateInUnitsPerHour;
|
||||
private Short durationInMinutes;
|
||||
|
||||
public Builder setProgramReminder(ProgramReminder programReminder) {
|
||||
this.programReminder = programReminder;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setRateInUnitsPerHour(double rateInUnitsPerHour) {
|
||||
this.rateInUnitsPerHour = rateInUnitsPerHour;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setDurationInMinutes(short durationInMinutes) {
|
||||
if (durationInMinutes % 30 != 0) {
|
||||
throw new IllegalArgumentException("durationInMinutes must be dividable by 30");
|
||||
}
|
||||
this.durationInMinutes = durationInMinutes;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override protected ProgramTempBasalCommand buildCommand() {
|
||||
if (programReminder == null) {
|
||||
throw new IllegalArgumentException("programReminder can not be null");
|
||||
}
|
||||
if (rateInUnitsPerHour == null) {
|
||||
throw new IllegalArgumentException("rateInUnitsPerHour can not be null");
|
||||
}
|
||||
if (durationInMinutes == null) {
|
||||
throw new IllegalArgumentException("durationInMinutes can not be null");
|
||||
}
|
||||
|
||||
byte durationInSlots = (byte) (durationInMinutes / 30);
|
||||
short[] pulsesPerSlot = ProgramTempBasalUtil.mapTempBasalToPulsesPerSlot(durationInSlots, rateInUnitsPerHour);
|
||||
short[] tenthPulsesPerSlot = ProgramTempBasalUtil.mapTempBasalToTenthPulsesPerSlot(durationInSlots, rateInUnitsPerHour);
|
||||
|
||||
List<ShortInsulinProgramElement> shortInsulinProgramElements = ProgramTempBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot);
|
||||
List<BasalInsulinProgramElement> insulinProgramElements = ProgramTempBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot);
|
||||
|
||||
ProgramInsulinCommand interlockCommand = new ProgramInsulinCommand(uniqueId, sequenceNumber, multiCommandFlag, nonce, shortInsulinProgramElements,
|
||||
ProgramTempBasalUtil.calculateChecksum(durationInSlots, pulsesPerSlot[0], pulsesPerSlot), durationInSlots,
|
||||
(short) 0x3840, pulsesPerSlot[0], ProgramInsulinCommand.DeliveryType.TEMP_BASAL);
|
||||
|
||||
return new ProgramTempBasalCommand(interlockCommand, uniqueId, sequenceNumber, multiCommandFlag, programReminder, insulinProgramElements);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.HeaderEnabledCommand
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.NonceEnabledCommandBuilder
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.BasalInsulinProgramElement
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.util.ProgramBasalUtil
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.util.ProgramTempBasalUtil
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ProgramReminder
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.*
|
||||
|
||||
// NOT SUPPORTED: percentage temp basal
|
||||
class ProgramTempBasalCommand protected constructor(
|
||||
private val interlockCommand: ProgramInsulinCommand,
|
||||
uniqueId: Int,
|
||||
sequenceNumber: Short,
|
||||
multiCommandFlag: Boolean,
|
||||
private val programReminder: ProgramReminder,
|
||||
insulinProgramElements: List<BasalInsulinProgramElement>
|
||||
) : HeaderEnabledCommand(CommandType.PROGRAM_TEMP_BASAL, uniqueId, sequenceNumber, multiCommandFlag) {
|
||||
|
||||
private val insulinProgramElements: List<BasalInsulinProgramElement>
|
||||
fun getBodyLength(): Byte = (insulinProgramElements.size * 6 + 8).toByte()
|
||||
|
||||
fun getLength(): Short = (getBodyLength() + 2).toShort()
|
||||
|
||||
class Builder : NonceEnabledCommandBuilder<Builder, ProgramTempBasalCommand>() {
|
||||
|
||||
private var programReminder: ProgramReminder? = null
|
||||
private var rateInUnitsPerHour: Double? = null
|
||||
private var durationInMinutes: Short? = null
|
||||
fun setProgramReminder(programReminder: ProgramReminder?): Builder {
|
||||
this.programReminder = programReminder
|
||||
return this
|
||||
}
|
||||
|
||||
fun setRateInUnitsPerHour(rateInUnitsPerHour: Double): Builder {
|
||||
this.rateInUnitsPerHour = rateInUnitsPerHour
|
||||
return this
|
||||
}
|
||||
|
||||
fun setDurationInMinutes(durationInMinutes: Short): Builder {
|
||||
require(durationInMinutes % 30 == 0) { "durationInMinutes must be dividable by 30" }
|
||||
this.durationInMinutes = durationInMinutes
|
||||
return this
|
||||
}
|
||||
|
||||
override fun buildCommand(): ProgramTempBasalCommand {
|
||||
requireNotNull(programReminder) { "programReminder can not be null" }
|
||||
requireNotNull(rateInUnitsPerHour) { "rateInUnitsPerHour can not be null" }
|
||||
requireNotNull(durationInMinutes) { "durationInMinutes can not be null" }
|
||||
val durationInSlots = (durationInMinutes!! / 30).toByte()
|
||||
val pulsesPerSlot = ProgramTempBasalUtil.mapTempBasalToPulsesPerSlot(durationInSlots, rateInUnitsPerHour!!)
|
||||
val tenthPulsesPerSlot = ProgramTempBasalUtil.mapTempBasalToTenthPulsesPerSlot(durationInSlots.toInt(), rateInUnitsPerHour!!)
|
||||
val shortInsulinProgramElements = ProgramTempBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot)
|
||||
val insulinProgramElements = ProgramTempBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot)
|
||||
val interlockCommand = ProgramInsulinCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, nonce!!, shortInsulinProgramElements,
|
||||
ProgramTempBasalUtil.calculateChecksum(durationInSlots, pulsesPerSlot!![0], pulsesPerSlot), durationInSlots,
|
||||
0x3840.toShort(), pulsesPerSlot[0], ProgramInsulinCommand.DeliveryType.TEMP_BASAL)
|
||||
return ProgramTempBasalCommand(interlockCommand, uniqueId!!, sequenceNumber!!, multiCommandFlag, programReminder!!, insulinProgramElements)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
this.insulinProgramElements = ArrayList(insulinProgramElements)
|
||||
}
|
||||
|
||||
override val encoded: ByteArray
|
||||
get() {
|
||||
val firstProgramElement = insulinProgramElements[0]
|
||||
val remainingTenthPulsesInFirstElement: Short
|
||||
val delayUntilNextTenthPulseInUsec: Int
|
||||
if (firstProgramElement.totalTenthPulses.toInt() == 0) {
|
||||
remainingTenthPulsesInFirstElement = firstProgramElement.numberOfSlots.toShort()
|
||||
delayUntilNextTenthPulseInUsec = ProgramBasalUtil.MAX_DELAY_BETWEEN_TENTH_PULSES_IN_USEC_AND_USECS_IN_BASAL_SLOT
|
||||
} else {
|
||||
remainingTenthPulsesInFirstElement = firstProgramElement.totalTenthPulses
|
||||
delayUntilNextTenthPulseInUsec = (firstProgramElement.numberOfSlots.toLong() * 1800.0 / remainingTenthPulsesInFirstElement * 1000000).toInt()
|
||||
}
|
||||
val buffer = ByteBuffer.allocate(getLength().toInt()) //
|
||||
.put(commandType.value) //
|
||||
.put(getBodyLength()) //
|
||||
.put(programReminder.encoded) //
|
||||
.put(0x00.toByte()) // Current slot index
|
||||
.putShort(remainingTenthPulsesInFirstElement) //
|
||||
.putInt(delayUntilNextTenthPulseInUsec)
|
||||
for (element in insulinProgramElements) {
|
||||
buffer.put(element.encoded)
|
||||
}
|
||||
val tempBasalCommand = buffer.array()
|
||||
val interlockCommand = interlockCommand.encoded
|
||||
val header: ByteArray = encodeHeader(uniqueId, sequenceNumber, (tempBasalCommand.size + interlockCommand!!.size).toShort(), multiCommandFlag)
|
||||
return appendCrc(ByteBuffer.allocate(header.size + interlockCommand.size + tempBasalCommand.size) //
|
||||
.put(header) //
|
||||
.put(interlockCommand) //
|
||||
.put(tempBasalCommand) //
|
||||
.array())
|
||||
}
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.HeaderEnabledCommand;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.HeaderEnabledCommandBuilder;
|
||||
|
||||
public final class SetUniqueIdCommand extends HeaderEnabledCommand {
|
||||
private static final int DEFAULT_UNIQUE_ID = -1;
|
||||
private static final short LENGTH = 21;
|
||||
private static final byte BODY_LENGTH = 19;
|
||||
|
||||
private final int lotNumber;
|
||||
private final int podSequenceNumber;
|
||||
private final Date initializationTime;
|
||||
|
||||
SetUniqueIdCommand(int uniqueId, short sequenceNumber, boolean multiCommandFlag, int lotNumber, int podSequenceNumber, Date initializationTime) {
|
||||
super(CommandType.SET_UNIQUE_ID, uniqueId, sequenceNumber, multiCommandFlag);
|
||||
this.lotNumber = lotNumber;
|
||||
this.podSequenceNumber = podSequenceNumber;
|
||||
this.initializationTime = initializationTime;
|
||||
}
|
||||
|
||||
@Override public byte[] getEncoded() {
|
||||
return appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) //
|
||||
.put(encodeHeader(DEFAULT_UNIQUE_ID, sequenceNumber, LENGTH, multiCommandFlag)) //
|
||||
.put(commandType.getValue()) //
|
||||
.put(BODY_LENGTH) //
|
||||
.putInt(uniqueId) //
|
||||
.put((byte) 0x14) // FIXME ??
|
||||
.put((byte) 0x04) // FIXME ??
|
||||
.put(encodeInitializationTime(initializationTime)) //
|
||||
.putInt(lotNumber) //
|
||||
.putInt(podSequenceNumber) //
|
||||
.array());
|
||||
}
|
||||
|
||||
private static byte[] encodeInitializationTime(Date date) {
|
||||
Calendar instance = Calendar.getInstance();
|
||||
instance.setTime(date);
|
||||
|
||||
return new byte[]{ //
|
||||
(byte) (instance.get(Calendar.MONTH) + 1), //
|
||||
(byte) instance.get(Calendar.DATE), //
|
||||
(byte) (instance.get(Calendar.YEAR) % 100), //
|
||||
(byte) instance.get(Calendar.HOUR_OF_DAY), //
|
||||
(byte) instance.get(Calendar.MINUTE) //
|
||||
};
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "SetUniqueIdCommand{" +
|
||||
"lotNumber=" + lotNumber +
|
||||
", podSequenceNumber=" + podSequenceNumber +
|
||||
", initializationTime=" + initializationTime +
|
||||
", commandType=" + commandType +
|
||||
", uniqueId=" + uniqueId +
|
||||
", sequenceNumber=" + sequenceNumber +
|
||||
", multiCommandFlag=" + multiCommandFlag +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static final class Builder extends HeaderEnabledCommandBuilder<Builder, SetUniqueIdCommand> {
|
||||
private Integer lotNumber;
|
||||
private Integer podSequenceNumber;
|
||||
private Date initializationTime;
|
||||
|
||||
public Builder setLotNumber(int lotNumber) {
|
||||
this.lotNumber = lotNumber;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setPodSequenceNumber(int podSequenceNumber) {
|
||||
this.podSequenceNumber = podSequenceNumber;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setInitializationTime(Date initializationTime) {
|
||||
this.initializationTime = initializationTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override protected final SetUniqueIdCommand buildCommand() {
|
||||
if (lotNumber == null) {
|
||||
throw new IllegalArgumentException("lotNumber can not be null");
|
||||
}
|
||||
if (podSequenceNumber == null) {
|
||||
throw new IllegalArgumentException("podSequenceNumber can not be null");
|
||||
}
|
||||
if (initializationTime == null) {
|
||||
throw new IllegalArgumentException("initializationTime can not be null");
|
||||
}
|
||||
return new SetUniqueIdCommand(uniqueId, sequenceNumber, multiCommandFlag, lotNumber, podSequenceNumber, initializationTime);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.HeaderEnabledCommand
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.HeaderEnabledCommandBuilder
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.*
|
||||
|
||||
class SetUniqueIdCommand internal constructor(
|
||||
uniqueId: Int,
|
||||
sequenceNumber: Short,
|
||||
multiCommandFlag: Boolean,
|
||||
private val lotNumber: Int,
|
||||
private val podSequenceNumber: Int,
|
||||
private val initializationTime: Date
|
||||
) : HeaderEnabledCommand(CommandType.SET_UNIQUE_ID, uniqueId, sequenceNumber, multiCommandFlag) {
|
||||
|
||||
override val encoded: ByteArray
|
||||
get() = appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) //
|
||||
.put(encodeHeader(DEFAULT_UNIQUE_ID, sequenceNumber, LENGTH, multiCommandFlag)) //
|
||||
.put(commandType.value) //
|
||||
.put(BODY_LENGTH) //
|
||||
.putInt(uniqueId) //
|
||||
.put(0x14.toByte()) // FIXME ??
|
||||
.put(0x04.toByte()) // FIXME ??
|
||||
.put(encodeInitializationTime(initializationTime)) //
|
||||
.putInt(lotNumber) //
|
||||
.putInt(podSequenceNumber) //
|
||||
.array())
|
||||
|
||||
override fun toString(): String {
|
||||
return "SetUniqueIdCommand{" +
|
||||
"lotNumber=" + lotNumber +
|
||||
", podSequenceNumber=" + podSequenceNumber +
|
||||
", initializationTime=" + initializationTime +
|
||||
", commandType=" + commandType +
|
||||
", uniqueId=" + uniqueId +
|
||||
", sequenceNumber=" + sequenceNumber +
|
||||
", multiCommandFlag=" + multiCommandFlag +
|
||||
'}'
|
||||
}
|
||||
|
||||
class Builder : HeaderEnabledCommandBuilder<Builder, SetUniqueIdCommand>() {
|
||||
|
||||
private var lotNumber: Int? = null
|
||||
private var podSequenceNumber: Int? = null
|
||||
private var initializationTime: Date? = null
|
||||
fun setLotNumber(lotNumber: Int): Builder {
|
||||
this.lotNumber = lotNumber
|
||||
return this
|
||||
}
|
||||
|
||||
fun setPodSequenceNumber(podSequenceNumber: Int): Builder {
|
||||
this.podSequenceNumber = podSequenceNumber
|
||||
return this
|
||||
}
|
||||
|
||||
fun setInitializationTime(initializationTime: Date?): Builder {
|
||||
this.initializationTime = initializationTime
|
||||
return this
|
||||
}
|
||||
|
||||
override fun buildCommand(): SetUniqueIdCommand {
|
||||
requireNotNull(lotNumber) { "lotNumber can not be null" }
|
||||
requireNotNull(podSequenceNumber) { "podSequenceNumber can not be null" }
|
||||
requireNotNull(initializationTime) { "initializationTime can not be null" }
|
||||
return SetUniqueIdCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, lotNumber!!, podSequenceNumber!!, initializationTime!!)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val DEFAULT_UNIQUE_ID = -1
|
||||
private const val LENGTH: Short = 21
|
||||
private const val BODY_LENGTH: Byte = 19
|
||||
private fun encodeInitializationTime(date: Date): ByteArray {
|
||||
val instance = Calendar.getInstance()
|
||||
instance.time = date
|
||||
return byteArrayOf( //
|
||||
(instance[Calendar.MONTH] + 1).toByte(), //
|
||||
instance[Calendar.DATE].toByte(), //
|
||||
(instance[Calendar.YEAR] % 100).toByte(), //
|
||||
instance[Calendar.HOUR_OF_DAY].toByte(), //
|
||||
instance[Calendar.MINUTE].toByte() //
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,133 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.BitSet;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.NonceEnabledCommand;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.NonceEnabledCommandBuilder;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable;
|
||||
|
||||
public final class SilenceAlertsCommand extends NonceEnabledCommand {
|
||||
private static final short LENGTH = (short) 7;
|
||||
private static final byte BODY_LENGTH = (byte) 5;
|
||||
|
||||
private final SilenceAlertCommandParameters parameters;
|
||||
|
||||
SilenceAlertsCommand(int uniqueId, short sequenceNumber, boolean multiCommandFlag, SilenceAlertCommandParameters parameters, int nonce) {
|
||||
super(CommandType.SILENCE_ALERTS, uniqueId, sequenceNumber, multiCommandFlag, nonce);
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
@Override public byte[] getEncoded() {
|
||||
return appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) //
|
||||
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
|
||||
.put(commandType.getValue()) //
|
||||
.put(BODY_LENGTH) //
|
||||
.putInt(nonce) //
|
||||
.put(parameters.getEncoded()) //
|
||||
.array());
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "SilenceAlertsCommand{" +
|
||||
"parameters=" + parameters +
|
||||
", nonce=" + nonce +
|
||||
", commandType=" + commandType +
|
||||
", uniqueId=" + uniqueId +
|
||||
", sequenceNumber=" + sequenceNumber +
|
||||
", multiCommandFlag=" + multiCommandFlag +
|
||||
'}';
|
||||
}
|
||||
|
||||
private static final class SilenceAlertCommandParameters implements Encodable {
|
||||
private final boolean silenceAutoOffAlert;
|
||||
private final boolean silenceMultiCommandAlert;
|
||||
private final boolean silenceExpirationImminentAlert;
|
||||
private final boolean silenceUserSetExpirationAlert;
|
||||
private final boolean silenceLowReservoirAlert;
|
||||
private final boolean silenceSuspendInProgressAlert;
|
||||
private final boolean silenceSuspendEndedAlert;
|
||||
private final boolean silencePodExpirationAlert;
|
||||
|
||||
private SilenceAlertCommandParameters(boolean silenceAutoOffAlert, boolean silenceMultiCommandAlert, boolean silenceExpirationImminentAlert, boolean silenceUserSetExpirationAlert, boolean silenceLowReservoirAlert, boolean silenceSuspendInProgressAlert, boolean silenceSuspendEndedAlert, boolean silencePodExpirationAlert) {
|
||||
this.silenceAutoOffAlert = silenceAutoOffAlert;
|
||||
this.silenceMultiCommandAlert = silenceMultiCommandAlert;
|
||||
this.silenceExpirationImminentAlert = silenceExpirationImminentAlert;
|
||||
this.silenceUserSetExpirationAlert = silenceUserSetExpirationAlert;
|
||||
this.silenceLowReservoirAlert = silenceLowReservoirAlert;
|
||||
this.silenceSuspendInProgressAlert = silenceSuspendInProgressAlert;
|
||||
this.silenceSuspendEndedAlert = silenceSuspendEndedAlert;
|
||||
this.silencePodExpirationAlert = silencePodExpirationAlert;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
BitSet bitSet = new BitSet(8);
|
||||
bitSet.set(0, this.silenceAutoOffAlert);
|
||||
bitSet.set(1, this.silenceMultiCommandAlert);
|
||||
bitSet.set(2, this.silenceExpirationImminentAlert);
|
||||
bitSet.set(3, this.silenceUserSetExpirationAlert);
|
||||
bitSet.set(4, this.silenceLowReservoirAlert);
|
||||
bitSet.set(5, this.silenceSuspendInProgressAlert);
|
||||
bitSet.set(6, this.silenceSuspendEndedAlert);
|
||||
bitSet.set(7, this.silencePodExpirationAlert);
|
||||
return bitSet.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Builder extends NonceEnabledCommandBuilder<Builder, SilenceAlertsCommand> {
|
||||
private boolean silenceAutoOffAlert;
|
||||
private boolean silenceMultiCommandAlert;
|
||||
private boolean silenceExpirationImminentAlert;
|
||||
private boolean silenceUserSetExpirationAlert;
|
||||
private boolean silenceLowReservoirAlert;
|
||||
private boolean silenceSuspendInProgressAlert;
|
||||
private boolean silenceSuspendEndedAlert;
|
||||
private boolean silencePodExpirationAlert;
|
||||
|
||||
public Builder setSilenceAutoOffAlert(boolean silenceAutoOffAlert) {
|
||||
this.silenceAutoOffAlert = silenceAutoOffAlert;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setSilenceMultiCommandAlert(boolean silenceMultiCommandAlert) {
|
||||
this.silenceMultiCommandAlert = silenceMultiCommandAlert;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setSilenceExpirationImminentAlert(boolean silenceExpirationImminentAlert) {
|
||||
this.silenceExpirationImminentAlert = silenceExpirationImminentAlert;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setSilenceUserSetExpirationAlert(boolean silenceUserSetExpirationAlert) {
|
||||
this.silenceUserSetExpirationAlert = silenceUserSetExpirationAlert;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setSilenceLowReservoirAlert(boolean silenceLowReservoirAlert) {
|
||||
this.silenceLowReservoirAlert = silenceLowReservoirAlert;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setSilenceSuspendInProgressAlert(boolean silenceSuspendInProgressAlert) {
|
||||
this.silenceSuspendInProgressAlert = silenceSuspendInProgressAlert;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setSilenceSuspendEndedAlert(boolean silenceSuspendEndedAlert) {
|
||||
this.silenceSuspendEndedAlert = silenceSuspendEndedAlert;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setSilencePodExpirationAlert(boolean silencePodExpirationAlert) {
|
||||
this.silencePodExpirationAlert = silencePodExpirationAlert;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override protected final SilenceAlertsCommand buildCommand() {
|
||||
return new SilenceAlertsCommand(uniqueId, sequenceNumber, multiCommandFlag, new SilenceAlertCommandParameters(silenceAutoOffAlert, silenceMultiCommandAlert, silenceExpirationImminentAlert, silenceUserSetExpirationAlert, silenceLowReservoirAlert, silenceSuspendInProgressAlert, silenceSuspendEndedAlert, silencePodExpirationAlert), nonce);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.NonceEnabledCommand
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.NonceEnabledCommandBuilder
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.*
|
||||
|
||||
class SilenceAlertsCommand internal constructor(
|
||||
uniqueId: Int,
|
||||
sequenceNumber: Short,
|
||||
multiCommandFlag: Boolean,
|
||||
private val parameters: SilenceAlertCommandParameters,
|
||||
nonce: Int
|
||||
) : NonceEnabledCommand(CommandType.SILENCE_ALERTS, uniqueId, sequenceNumber, multiCommandFlag, nonce) {
|
||||
|
||||
override val encoded: ByteArray
|
||||
get() =
|
||||
appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) //
|
||||
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
|
||||
.put(commandType.value) //
|
||||
.put(BODY_LENGTH) //
|
||||
.putInt(nonce) //
|
||||
.put(parameters.encoded) //
|
||||
.array())
|
||||
|
||||
override fun toString(): String {
|
||||
return "SilenceAlertsCommand{" +
|
||||
"parameters=" + parameters +
|
||||
", nonce=" + nonce +
|
||||
", commandType=" + commandType +
|
||||
", uniqueId=" + uniqueId +
|
||||
", sequenceNumber=" + sequenceNumber +
|
||||
", multiCommandFlag=" + multiCommandFlag +
|
||||
'}'
|
||||
}
|
||||
|
||||
class SilenceAlertCommandParameters(private val silenceAutoOffAlert: Boolean, private val silenceMultiCommandAlert: Boolean, private val silenceExpirationImminentAlert: Boolean, private val silenceUserSetExpirationAlert: Boolean, private val silenceLowReservoirAlert: Boolean, private val silenceSuspendInProgressAlert: Boolean, private val silenceSuspendEndedAlert: Boolean, private val silencePodExpirationAlert: Boolean) : Encodable {
|
||||
|
||||
override val encoded: ByteArray
|
||||
get() {
|
||||
val bitSet = BitSet(8)
|
||||
bitSet[0] = silenceAutoOffAlert
|
||||
bitSet[1] = silenceMultiCommandAlert
|
||||
bitSet[2] = silenceExpirationImminentAlert
|
||||
bitSet[3] = silenceUserSetExpirationAlert
|
||||
bitSet[4] = silenceLowReservoirAlert
|
||||
bitSet[5] = silenceSuspendInProgressAlert
|
||||
bitSet[6] = silenceSuspendEndedAlert
|
||||
bitSet[7] = silencePodExpirationAlert
|
||||
return bitSet.toByteArray()
|
||||
}
|
||||
}
|
||||
|
||||
class Builder : NonceEnabledCommandBuilder<Builder, SilenceAlertsCommand>() {
|
||||
|
||||
private var silenceAutoOffAlert = false
|
||||
private var silenceMultiCommandAlert = false
|
||||
private var silenceExpirationImminentAlert = false
|
||||
private var silenceUserSetExpirationAlert = false
|
||||
private var silenceLowReservoirAlert = false
|
||||
private var silenceSuspendInProgressAlert = false
|
||||
private var silenceSuspendEndedAlert = false
|
||||
private var silencePodExpirationAlert = false
|
||||
fun setSilenceAutoOffAlert(silenceAutoOffAlert: Boolean): Builder {
|
||||
this.silenceAutoOffAlert = silenceAutoOffAlert
|
||||
return this
|
||||
}
|
||||
|
||||
fun setSilenceMultiCommandAlert(silenceMultiCommandAlert: Boolean): Builder {
|
||||
this.silenceMultiCommandAlert = silenceMultiCommandAlert
|
||||
return this
|
||||
}
|
||||
|
||||
fun setSilenceExpirationImminentAlert(silenceExpirationImminentAlert: Boolean): Builder {
|
||||
this.silenceExpirationImminentAlert = silenceExpirationImminentAlert
|
||||
return this
|
||||
}
|
||||
|
||||
fun setSilenceUserSetExpirationAlert(silenceUserSetExpirationAlert: Boolean): Builder {
|
||||
this.silenceUserSetExpirationAlert = silenceUserSetExpirationAlert
|
||||
return this
|
||||
}
|
||||
|
||||
fun setSilenceLowReservoirAlert(silenceLowReservoirAlert: Boolean): Builder {
|
||||
this.silenceLowReservoirAlert = silenceLowReservoirAlert
|
||||
return this
|
||||
}
|
||||
|
||||
fun setSilenceSuspendInProgressAlert(silenceSuspendInProgressAlert: Boolean): Builder {
|
||||
this.silenceSuspendInProgressAlert = silenceSuspendInProgressAlert
|
||||
return this
|
||||
}
|
||||
|
||||
fun setSilenceSuspendEndedAlert(silenceSuspendEndedAlert: Boolean): Builder {
|
||||
this.silenceSuspendEndedAlert = silenceSuspendEndedAlert
|
||||
return this
|
||||
}
|
||||
|
||||
fun setSilencePodExpirationAlert(silencePodExpirationAlert: Boolean): Builder {
|
||||
this.silencePodExpirationAlert = silencePodExpirationAlert
|
||||
return this
|
||||
}
|
||||
|
||||
override fun buildCommand(): SilenceAlertsCommand {
|
||||
return SilenceAlertsCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, SilenceAlertCommandParameters(silenceAutoOffAlert, silenceMultiCommandAlert, silenceExpirationImminentAlert, silenceUserSetExpirationAlert, silenceLowReservoirAlert, silenceSuspendInProgressAlert, silenceSuspendEndedAlert, silencePodExpirationAlert), nonce!!)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val LENGTH = 7.toShort()
|
||||
private const val BODY_LENGTH = 5.toByte()
|
||||
}
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.BitSet;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.NonceEnabledCommand;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.NonceEnabledCommandBuilder;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable;
|
||||
|
||||
public final class StopDeliveryCommand extends NonceEnabledCommand {
|
||||
private static final short LENGTH = 7;
|
||||
private static final byte BODY_LENGTH = 5;
|
||||
|
||||
private final DeliveryType deliveryType;
|
||||
private final BeepType beepType;
|
||||
|
||||
StopDeliveryCommand(int uniqueId, short sequenceNumber, boolean multiCommandFlag, DeliveryType deliveryType, BeepType beepType, int nonce) {
|
||||
super(CommandType.STOP_DELIVERY, uniqueId, sequenceNumber, multiCommandFlag, nonce);
|
||||
this.deliveryType = deliveryType;
|
||||
this.beepType = beepType;
|
||||
}
|
||||
|
||||
@Override public byte[] getEncoded() {
|
||||
return appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) //
|
||||
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
|
||||
.put(commandType.getValue()) //
|
||||
.put(BODY_LENGTH) //
|
||||
.putInt(nonce) //
|
||||
.put((byte) ((beepType.getValue() << 4) | deliveryType.getEncoded()[0])) //
|
||||
.array());
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "StopDeliveryCommand{" +
|
||||
"deliveryType=" + deliveryType +
|
||||
", beepType=" + beepType +
|
||||
", nonce=" + nonce +
|
||||
", commandType=" + commandType +
|
||||
", uniqueId=" + uniqueId +
|
||||
", sequenceNumber=" + sequenceNumber +
|
||||
", multiCommandFlag=" + multiCommandFlag +
|
||||
'}';
|
||||
}
|
||||
|
||||
public enum DeliveryType implements Encodable {
|
||||
BASAL(true, false, false),
|
||||
TEMP_BASAL(false, true, false),
|
||||
BOLUS(false, false, true),
|
||||
ALL(true, true, true);
|
||||
|
||||
private final boolean basal;
|
||||
private final boolean tempBasal;
|
||||
private final boolean bolus;
|
||||
|
||||
DeliveryType(boolean basal, boolean tempBasal, boolean bolus) {
|
||||
this.basal = basal;
|
||||
this.tempBasal = tempBasal;
|
||||
this.bolus = bolus;
|
||||
}
|
||||
|
||||
@Override public byte[] getEncoded() {
|
||||
BitSet bitSet = new BitSet(8);
|
||||
bitSet.set(0, this.basal);
|
||||
bitSet.set(1, this.tempBasal);
|
||||
bitSet.set(2, this.bolus);
|
||||
return bitSet.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Builder extends NonceEnabledCommandBuilder<Builder, StopDeliveryCommand> {
|
||||
private DeliveryType deliveryType;
|
||||
private BeepType beepType = BeepType.LONG_SINGLE_BEEP;
|
||||
|
||||
public Builder setDeliveryType(DeliveryType deliveryType) {
|
||||
this.deliveryType = deliveryType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setBeepType(BeepType beepType) {
|
||||
this.beepType = beepType;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override protected final StopDeliveryCommand buildCommand() {
|
||||
if (deliveryType == null) {
|
||||
throw new IllegalArgumentException("deliveryType can not be null");
|
||||
}
|
||||
if (beepType == null) {
|
||||
throw new IllegalArgumentException("beepType can not be null");
|
||||
}
|
||||
return new StopDeliveryCommand(uniqueId, sequenceNumber, multiCommandFlag, deliveryType, beepType, nonce);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.NonceEnabledCommand
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.NonceEnabledCommandBuilder
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.*
|
||||
|
||||
class StopDeliveryCommand internal constructor(
|
||||
uniqueId: Int,
|
||||
sequenceNumber: Short,
|
||||
multiCommandFlag: Boolean,
|
||||
private val deliveryType: DeliveryType,
|
||||
private val beepType: BeepType,
|
||||
nonce: Int
|
||||
) : NonceEnabledCommand(CommandType.STOP_DELIVERY, uniqueId, sequenceNumber, multiCommandFlag, nonce) {
|
||||
|
||||
override val encoded: ByteArray
|
||||
get() {
|
||||
return appendCrc(ByteBuffer.allocate(LENGTH + HEADER_LENGTH) //
|
||||
.put(encodeHeader(uniqueId, sequenceNumber, LENGTH, multiCommandFlag)) //
|
||||
.put(commandType.value) //
|
||||
.put(BODY_LENGTH) //
|
||||
.putInt(nonce) //
|
||||
.put((beepType.value.toInt() shl 4 or deliveryType.encoded[0].toInt()).toByte()) // TODO bitstuff
|
||||
.array())
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "StopDeliveryCommand{" +
|
||||
"deliveryType=" + deliveryType +
|
||||
", beepType=" + beepType +
|
||||
", nonce=" + nonce +
|
||||
", commandType=" + commandType +
|
||||
", uniqueId=" + uniqueId +
|
||||
", sequenceNumber=" + sequenceNumber +
|
||||
", multiCommandFlag=" + multiCommandFlag +
|
||||
'}'
|
||||
}
|
||||
|
||||
enum class DeliveryType(private val basal: Boolean, private val tempBasal: Boolean, private val bolus: Boolean) : Encodable {
|
||||
BASAL(true, false, false), TEMP_BASAL(false, true, false), BOLUS(false, false, true), ALL(true, true, true);
|
||||
|
||||
override val encoded: ByteArray
|
||||
get() {
|
||||
val bitSet = BitSet(8)
|
||||
bitSet[0] = basal
|
||||
bitSet[1] = tempBasal
|
||||
bitSet[2] = bolus
|
||||
return bitSet.toByteArray()
|
||||
}
|
||||
}
|
||||
|
||||
class Builder : NonceEnabledCommandBuilder<Builder, StopDeliveryCommand>() {
|
||||
|
||||
private var deliveryType: DeliveryType? = null
|
||||
private var beepType: BeepType? = BeepType.LONG_SINGLE_BEEP
|
||||
fun setDeliveryType(deliveryType: DeliveryType?): Builder {
|
||||
this.deliveryType = deliveryType
|
||||
return this
|
||||
}
|
||||
|
||||
fun setBeepType(beepType: BeepType?): Builder {
|
||||
this.beepType = beepType
|
||||
return this
|
||||
}
|
||||
|
||||
override fun buildCommand(): StopDeliveryCommand {
|
||||
requireNotNull(deliveryType) { "deliveryType can not be null" }
|
||||
requireNotNull(beepType) { "beepType can not be null" }
|
||||
return StopDeliveryCommand(uniqueId!!, sequenceNumber!!, multiCommandFlag, deliveryType!!, beepType!!, nonce!!)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val LENGTH: Short = 7
|
||||
private const val BODY_LENGTH: Byte = 5
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable;
|
||||
|
||||
public interface Command extends Encodable {
|
||||
CommandType getCommandType();
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable
|
||||
import java.io.Serializable
|
||||
|
||||
interface Command : Encodable, Serializable {
|
||||
|
||||
val commandType: CommandType
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base;
|
||||
|
||||
public enum CommandType {
|
||||
SET_UNIQUE_ID((byte) 0x03),
|
||||
GET_VERSION((byte) 0x07),
|
||||
GET_STATUS((byte) 0x0e),
|
||||
SILENCE_ALERTS((byte) 0x11),
|
||||
PROGRAM_BASAL((byte) 0x13), // Always preceded by 0x1a
|
||||
PROGRAM_TEMP_BASAL((byte) 0x16), // Always preceded by 0x1a
|
||||
PROGRAM_BOLUS((byte) 0x17), // Always preceded by 0x1a
|
||||
PROGRAM_ALERTS((byte) 0x19),
|
||||
PROGRAM_INSULIN((byte) 0x1a), // Always followed by one of: 0x13, 0x16, 0x17
|
||||
DEACTIVATE((byte) 0x1c),
|
||||
PROGRAM_BEEPS((byte) 0x1e),
|
||||
STOP_DELIVERY((byte) 0x1f);
|
||||
|
||||
byte value;
|
||||
|
||||
CommandType(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public byte getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base
|
||||
|
||||
enum class CommandType(
|
||||
val value: Byte
|
||||
) {
|
||||
|
||||
SET_UNIQUE_ID(0x03.toByte()),
|
||||
GET_VERSION(0x07.toByte()),
|
||||
GET_STATUS(0x0e.toByte()),
|
||||
SILENCE_ALERTS(0x11.toByte()),
|
||||
PROGRAM_BASAL(0x13.toByte()), // Always preceded by 0x1a
|
||||
PROGRAM_TEMP_BASAL(0x16.toByte()), // Always preceded by 0x1a
|
||||
PROGRAM_BOLUS(0x17.toByte()), // Always preceded by 0x1a
|
||||
PROGRAM_ALERTS(0x19.toByte()),
|
||||
PROGRAM_INSULIN(0x1a.toByte()), // Always followed by one of: 0x13, 0x16, 0x17
|
||||
DEACTIVATE(0x1c.toByte()),
|
||||
PROGRAM_BEEPS(0x1e.toByte()),
|
||||
STOP_DELIVERY(0x1f.toByte());
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.MessageUtil;
|
||||
|
||||
public abstract class HeaderEnabledCommand implements Command {
|
||||
protected static final short HEADER_LENGTH = 6;
|
||||
|
||||
protected final CommandType commandType;
|
||||
protected final int uniqueId;
|
||||
protected final short sequenceNumber;
|
||||
protected final boolean multiCommandFlag;
|
||||
|
||||
protected HeaderEnabledCommand(CommandType commandType, int uniqueId, short sequenceNumber, boolean multiCommandFlag) {
|
||||
this.commandType = commandType;
|
||||
this.uniqueId = uniqueId;
|
||||
this.sequenceNumber = sequenceNumber;
|
||||
this.multiCommandFlag = multiCommandFlag;
|
||||
}
|
||||
|
||||
@Override public CommandType getCommandType() {
|
||||
return commandType;
|
||||
}
|
||||
|
||||
protected static byte[] appendCrc(byte[] command) {
|
||||
return ByteBuffer.allocate(command.length + 2) //
|
||||
.put(command) //
|
||||
.putShort(MessageUtil.createCrc(command)) //
|
||||
.array();
|
||||
}
|
||||
|
||||
protected static byte[] encodeHeader(int uniqueId, short sequenceNumber, short length, boolean multiCommandFlag) {
|
||||
return ByteBuffer.allocate(6) //
|
||||
.putInt(uniqueId) //
|
||||
.putShort((short) (((sequenceNumber & 0x0f) << 10) | length | ((multiCommandFlag ? 1 : 0) << 15))) //
|
||||
.array();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.MessageUtil
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
abstract class HeaderEnabledCommand protected constructor(
|
||||
override val commandType: CommandType,
|
||||
protected val uniqueId: Int,
|
||||
protected val sequenceNumber: Short,
|
||||
protected val multiCommandFlag: Boolean
|
||||
) : Command {
|
||||
|
||||
companion object {
|
||||
|
||||
internal fun appendCrc(command: ByteArray): ByteArray =
|
||||
ByteBuffer.allocate(command.size + 2) //
|
||||
.put(command) //
|
||||
.putShort(MessageUtil.createCrc(command)) //
|
||||
.array()
|
||||
|
||||
internal fun encodeHeader(uniqueId: Int, sequenceNumber: Short, length: Short, multiCommandFlag: Boolean): ByteArray =
|
||||
ByteBuffer.allocate(6) //
|
||||
.putInt(uniqueId) //
|
||||
.putShort((sequenceNumber.toInt() and 0x0f shl 10 or length.toInt() or ((if (multiCommandFlag) 1 else 0) shl 15)).toShort()) //
|
||||
.array()
|
||||
|
||||
internal const val HEADER_LENGTH: Short = 6
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base;
|
||||
|
||||
public abstract class NonceEnabledCommand extends HeaderEnabledCommand {
|
||||
protected final int nonce;
|
||||
|
||||
protected NonceEnabledCommand(CommandType commandType, int uniqueId, short sequenceNumber, boolean multiCommandFlag, int nonce) {
|
||||
super(commandType, uniqueId, sequenceNumber, multiCommandFlag);
|
||||
this.nonce = nonce;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base
|
||||
|
||||
abstract class NonceEnabledCommand protected constructor(
|
||||
commandType: CommandType,
|
||||
uniqueId: Int,
|
||||
sequenceNumber: Short,
|
||||
multiCommandFlag: Boolean,
|
||||
protected val nonce: Int
|
||||
) : HeaderEnabledCommand(commandType, uniqueId, sequenceNumber, multiCommandFlag)
|
|
@ -1,7 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command;
|
||||
|
||||
public interface CommandBuilder<R extends Command> {
|
||||
R build();
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program;
|
||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command
|
||||
|
||||
public interface ShortInsulinProgramElement extends Encodable {
|
||||
}
|
||||
interface CommandBuilder<R : Command> {
|
||||
|
||||
fun build(): R
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command;
|
||||
|
||||
public abstract class HeaderEnabledCommandBuilder<T extends HeaderEnabledCommandBuilder<T, R>, R extends Command> implements CommandBuilder<R> {
|
||||
protected Integer uniqueId;
|
||||
protected Short sequenceNumber;
|
||||
protected boolean multiCommandFlag = false;
|
||||
|
||||
public R build() {
|
||||
if (uniqueId == null) {
|
||||
throw new IllegalArgumentException("uniqueId can not be null");
|
||||
}
|
||||
if (sequenceNumber == null) {
|
||||
throw new IllegalArgumentException("sequenceNumber can not be null");
|
||||
}
|
||||
return buildCommand();
|
||||
}
|
||||
|
||||
public final T setUniqueId(int uniqueId) {
|
||||
this.uniqueId = uniqueId;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public final T setSequenceNumber(short sequenceNumber) {
|
||||
this.sequenceNumber = sequenceNumber;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public final T setMultiCommandFlag(boolean multiCommandFlag) {
|
||||
this.multiCommandFlag = multiCommandFlag;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
protected abstract R buildCommand();
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command
|
||||
|
||||
abstract class HeaderEnabledCommandBuilder<T : HeaderEnabledCommandBuilder<T, R>, R : Command> : CommandBuilder<R> {
|
||||
|
||||
protected var uniqueId: Int? = null
|
||||
protected var sequenceNumber: Short? = null
|
||||
protected var multiCommandFlag = false
|
||||
override fun build(): R {
|
||||
requireNotNull(uniqueId) { "uniqueId can not be null" }
|
||||
requireNotNull(sequenceNumber) { "sequenceNumber can not be null" }
|
||||
return buildCommand()
|
||||
}
|
||||
|
||||
fun setUniqueId(uniqueId: Int): T {
|
||||
this.uniqueId = uniqueId
|
||||
return this as T
|
||||
}
|
||||
|
||||
fun setSequenceNumber(sequenceNumber: Short): T {
|
||||
this.sequenceNumber = sequenceNumber
|
||||
return this as T
|
||||
}
|
||||
|
||||
fun setMultiCommandFlag(multiCommandFlag: Boolean): T {
|
||||
this.multiCommandFlag = multiCommandFlag
|
||||
return this as T
|
||||
}
|
||||
|
||||
protected abstract fun buildCommand(): R
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command;
|
||||
|
||||
public abstract class NonceEnabledCommandBuilder<T extends NonceEnabledCommandBuilder<T, R>, R extends Command> extends HeaderEnabledCommandBuilder<T, R> {
|
||||
protected Integer nonce;
|
||||
|
||||
public final R build() {
|
||||
if (nonce == null) {
|
||||
throw new IllegalArgumentException("nonce can not be null");
|
||||
}
|
||||
return super.build();
|
||||
}
|
||||
|
||||
public final T setNonce(int nonce) {
|
||||
this.nonce = nonce;
|
||||
return (T) this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command
|
||||
|
||||
abstract class NonceEnabledCommandBuilder<T : NonceEnabledCommandBuilder<T, R>, R : Command> : HeaderEnabledCommandBuilder<T, R>() {
|
||||
|
||||
protected var nonce: Int? = null
|
||||
override fun build(): R {
|
||||
requireNotNull(nonce) { "nonce can not be null" }
|
||||
return super.build()
|
||||
}
|
||||
|
||||
fun setNonce(nonce: Int): T {
|
||||
this.nonce = nonce
|
||||
return this as T
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable;
|
||||
|
||||
import static info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.util.ProgramBasalUtil.MAX_DELAY_BETWEEN_TENTH_PULSES_IN_USEC_AND_USECS_IN_BASAL_SLOT;
|
||||
|
||||
public class BasalInsulinProgramElement implements Encodable {
|
||||
private final byte startSlotIndex;
|
||||
private final byte numberOfSlots;
|
||||
private final short totalTenthPulses;
|
||||
|
||||
public BasalInsulinProgramElement(byte startSlotIndex, byte numberOfSlots, short totalTenthPulses) {
|
||||
this.startSlotIndex = startSlotIndex;
|
||||
this.numberOfSlots = numberOfSlots;
|
||||
this.totalTenthPulses = totalTenthPulses;
|
||||
}
|
||||
|
||||
@Override public byte[] getEncoded() {
|
||||
return ByteBuffer.allocate(6) //
|
||||
.putShort(totalTenthPulses) //
|
||||
.putInt(totalTenthPulses == 0 ? Integer.MIN_VALUE | getDelayBetweenTenthPulsesInUsec() : getDelayBetweenTenthPulsesInUsec()) //
|
||||
.array();
|
||||
}
|
||||
|
||||
public byte getStartSlotIndex() {
|
||||
return startSlotIndex;
|
||||
}
|
||||
|
||||
public byte getNumberOfSlots() {
|
||||
return numberOfSlots;
|
||||
}
|
||||
|
||||
public short getDurationInSeconds() {
|
||||
return (short) (numberOfSlots * 1_800);
|
||||
}
|
||||
|
||||
public short getTotalTenthPulses() {
|
||||
return totalTenthPulses;
|
||||
}
|
||||
|
||||
public int getDelayBetweenTenthPulsesInUsec() {
|
||||
if (totalTenthPulses == 0) {
|
||||
return MAX_DELAY_BETWEEN_TENTH_PULSES_IN_USEC_AND_USECS_IN_BASAL_SLOT;
|
||||
}
|
||||
return (int) (((long) MAX_DELAY_BETWEEN_TENTH_PULSES_IN_USEC_AND_USECS_IN_BASAL_SLOT * numberOfSlots) / (double) totalTenthPulses);
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "LongInsulinProgramElement{" +
|
||||
"startSlotIndex=" + startSlotIndex +
|
||||
", numberOfSlots=" + numberOfSlots +
|
||||
", totalTenthPulses=" + totalTenthPulses +
|
||||
", delayBetweenTenthPulsesInUsec=" + getDelayBetweenTenthPulsesInUsec() +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.util.ProgramBasalUtil
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable
|
||||
import java.io.Serializable
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
open class BasalInsulinProgramElement(
|
||||
val startSlotIndex: Byte,
|
||||
val numberOfSlots: Byte,
|
||||
val totalTenthPulses: Short
|
||||
) : Encodable, Serializable {
|
||||
|
||||
override val encoded: ByteArray
|
||||
get() = ByteBuffer.allocate(6) //
|
||||
.putShort(totalTenthPulses) //
|
||||
.putInt(if (totalTenthPulses.toInt() == 0) Int.MIN_VALUE or delayBetweenTenthPulsesInUsec else delayBetweenTenthPulsesInUsec) //
|
||||
.array()
|
||||
val durationInSeconds: Short
|
||||
get() = (numberOfSlots * 1800).toShort()
|
||||
val delayBetweenTenthPulsesInUsec: Int
|
||||
get() = if (totalTenthPulses.toInt() == 0) {
|
||||
ProgramBasalUtil.MAX_DELAY_BETWEEN_TENTH_PULSES_IN_USEC_AND_USECS_IN_BASAL_SLOT
|
||||
} else (ProgramBasalUtil.MAX_DELAY_BETWEEN_TENTH_PULSES_IN_USEC_AND_USECS_IN_BASAL_SLOT.toLong() * numberOfSlots / totalTenthPulses.toDouble()).toInt()
|
||||
|
||||
override fun toString(): String {
|
||||
return "LongInsulinProgramElement{" +
|
||||
"startSlotIndex=" + startSlotIndex +
|
||||
", numberOfSlots=" + numberOfSlots +
|
||||
", totalTenthPulses=" + totalTenthPulses +
|
||||
", delayBetweenTenthPulsesInUsec=" + delayBetweenTenthPulsesInUsec +
|
||||
'}'
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class BasalShortInsulinProgramElement implements ShortInsulinProgramElement {
|
||||
private final byte numberOfSlots; // 4 bits
|
||||
private final short pulsesPerSlot; // 10 bits
|
||||
private final boolean extraAlternatePulse;
|
||||
|
||||
public BasalShortInsulinProgramElement(byte numberOfSlots, short pulsesPerSlot, boolean extraAlternatePulse) {
|
||||
this.numberOfSlots = numberOfSlots;
|
||||
this.pulsesPerSlot = pulsesPerSlot;
|
||||
this.extraAlternatePulse = extraAlternatePulse;
|
||||
}
|
||||
|
||||
@Override public byte[] getEncoded() {
|
||||
byte firstByte = (byte) ((((numberOfSlots - 1) & 0x0f) << 4) //
|
||||
| ((extraAlternatePulse ? 1 : 0) << 3) //
|
||||
| ((pulsesPerSlot >>> 8) & 0x03));
|
||||
|
||||
return ByteBuffer.allocate(2) //
|
||||
.put(firstByte) //
|
||||
.put((byte) (pulsesPerSlot & 0xff)) //
|
||||
.array();
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "ShortInsulinProgramElement{" +
|
||||
"numberOfSlotsMinusOne=" + numberOfSlots +
|
||||
", pulsesPerSlot=" + pulsesPerSlot +
|
||||
", extraAlternatePulse=" + extraAlternatePulse +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program
|
||||
|
||||
import java.nio.ByteBuffer
|
||||
import kotlin.experimental.and
|
||||
|
||||
class BasalShortInsulinProgramElement(
|
||||
private val numberOfSlots: Byte, // 4 bits
|
||||
private val pulsesPerSlot: Short, //10 bits
|
||||
private val extraAlternatePulse: Boolean
|
||||
) : ShortInsulinProgramElement {
|
||||
|
||||
override val encoded: ByteArray
|
||||
get() {
|
||||
val firstByte = (numberOfSlots - 1 and 0x0f shl 4 //
|
||||
or ((if (extraAlternatePulse) 1 else 0) shl 3) //
|
||||
or (pulsesPerSlot.toInt() ushr 8 and 0x03)).toByte()
|
||||
return ByteBuffer.allocate(2) //
|
||||
.put(firstByte) //
|
||||
.put((pulsesPerSlot and 0xff).toByte()) //
|
||||
.array()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "ShortInsulinProgramElement{" +
|
||||
"numberOfSlotsMinusOne=" + numberOfSlots +
|
||||
", pulsesPerSlot=" + pulsesPerSlot +
|
||||
", extraAlternatePulse=" + extraAlternatePulse +
|
||||
'}'
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class BolusShortInsulinProgramElement implements ShortInsulinProgramElement {
|
||||
private short numberOfPulses;
|
||||
|
||||
public BolusShortInsulinProgramElement(short numberOfPulses) {
|
||||
this.numberOfPulses = numberOfPulses;
|
||||
}
|
||||
|
||||
public short getNumberOfPulses() {
|
||||
return numberOfPulses;
|
||||
}
|
||||
|
||||
@Override public byte[] getEncoded() {
|
||||
return ByteBuffer.allocate(2).putShort(numberOfPulses).array();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program
|
||||
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
class BolusShortInsulinProgramElement(
|
||||
private val numberOfPulses: Short
|
||||
) : ShortInsulinProgramElement {
|
||||
|
||||
override val encoded: ByteArray
|
||||
get() = ByteBuffer.allocate(2).putShort(numberOfPulses).array()
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program;
|
||||
|
||||
public class CurrentBasalInsulinProgramElement {
|
||||
private final byte index;
|
||||
private final int delayUntilNextTenthPulseInUsec;
|
||||
private final short remainingTenthPulses;
|
||||
|
||||
public CurrentBasalInsulinProgramElement(byte index, int delayUntilNextTenthPulseInUsec, short remainingTenthPulses) {
|
||||
this.index = index;
|
||||
this.delayUntilNextTenthPulseInUsec = delayUntilNextTenthPulseInUsec;
|
||||
this.remainingTenthPulses = remainingTenthPulses;
|
||||
}
|
||||
|
||||
public byte getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public int getDelayUntilNextTenthPulseInUsec() {
|
||||
return delayUntilNextTenthPulseInUsec;
|
||||
}
|
||||
|
||||
public short getRemainingTenthPulses() {
|
||||
return remainingTenthPulses;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "CurrentLongInsulinProgramElement{" +
|
||||
"index=" + index +
|
||||
", delayUntilNextTenthPulseInUsec=" + delayUntilNextTenthPulseInUsec +
|
||||
", remainingTenthPulses=" + remainingTenthPulses +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
class CurrentBasalInsulinProgramElement(
|
||||
val index: Byte,
|
||||
val delayUntilNextTenthPulseInUsec: Int,
|
||||
val remainingTenthPulses: Short
|
||||
) : Serializable {
|
||||
|
||||
override fun toString(): String = "CurrentLongInsulinProgramElement{" +
|
||||
"index=" + index +
|
||||
", delayUntilNextTenthPulseInUsec=" + delayUntilNextTenthPulseInUsec +
|
||||
", remainingTenthPulses=" + remainingTenthPulses +
|
||||
'}'
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program;
|
||||
|
||||
public class CurrentSlot {
|
||||
private final byte index;
|
||||
private final short eighthSecondsRemaining;
|
||||
private final short pulsesRemaining;
|
||||
|
||||
public CurrentSlot(byte index, short eighthSecondsRemaining, short pulsesRemaining) {
|
||||
this.index = index;
|
||||
this.eighthSecondsRemaining = eighthSecondsRemaining;
|
||||
this.pulsesRemaining = pulsesRemaining;
|
||||
}
|
||||
|
||||
public byte getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public short getEighthSecondsRemaining() {
|
||||
return eighthSecondsRemaining;
|
||||
}
|
||||
|
||||
public short getPulsesRemaining() {
|
||||
return pulsesRemaining;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "CurrentSlot{" +
|
||||
"index=" + index +
|
||||
", eighthSecondsRemaining=" + eighthSecondsRemaining +
|
||||
", pulsesRemaining=" + pulsesRemaining +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
class CurrentSlot(
|
||||
val index: Byte,
|
||||
val eighthSecondsRemaining: Short,
|
||||
val pulsesRemaining: Short
|
||||
) : Serializable {
|
||||
|
||||
override fun toString(): String = "CurrentSlot{" +
|
||||
"index=" + index +
|
||||
", eighthSecondsRemaining=" + eighthSecondsRemaining +
|
||||
", pulsesRemaining=" + pulsesRemaining +
|
||||
'}'
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.Encodable
|
||||
import java.io.Serializable
|
||||
|
||||
interface ShortInsulinProgramElement : Encodable, Serializable
|
|
@ -1,23 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class TempBasalInsulinProgramElement extends BasalInsulinProgramElement {
|
||||
public TempBasalInsulinProgramElement(byte startSlotIndex, byte numberOfSlots, short totalTenthPulses) {
|
||||
super(startSlotIndex, numberOfSlots, totalTenthPulses);
|
||||
}
|
||||
|
||||
@Override public byte[] getEncoded() {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(6);
|
||||
if (getTotalTenthPulses() == 0) {
|
||||
int i = ((int) ((((double) getDurationInSeconds()) * 1_000_000.0d) / ((double) getNumberOfSlots()))) | Integer.MIN_VALUE;
|
||||
buffer.putShort(getNumberOfSlots()) //
|
||||
.putInt(i);
|
||||
} else {
|
||||
buffer.putShort(getTotalTenthPulses()) //
|
||||
.putInt(getDelayBetweenTenthPulsesInUsec());
|
||||
}
|
||||
return buffer.array();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program
|
||||
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
class TempBasalInsulinProgramElement(
|
||||
startSlotIndex: Byte,
|
||||
numberOfSlots: Byte,
|
||||
totalTenthPulses: Short
|
||||
) : BasalInsulinProgramElement(startSlotIndex, numberOfSlots, totalTenthPulses) {
|
||||
|
||||
override val encoded: ByteArray
|
||||
get() {
|
||||
val buffer = ByteBuffer.allocate(6)
|
||||
if (totalTenthPulses.toInt() == 0) {
|
||||
val i = (durationInSeconds.toDouble() * 1000000.0 / numberOfSlots.toDouble()).toInt() or Int.MIN_VALUE
|
||||
buffer.putShort(numberOfSlots.toShort()) //
|
||||
.putInt(i)
|
||||
} else {
|
||||
buffer.putShort(totalTenthPulses) //
|
||||
.putInt(delayBetweenTenthPulsesInUsec)
|
||||
}
|
||||
return buffer.array()
|
||||
}
|
||||
}
|
|
@ -1,257 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.util;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.BasalInsulinProgramElement;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.BasalShortInsulinProgramElement;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.CurrentBasalInsulinProgramElement;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.CurrentSlot;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.ShortInsulinProgramElement;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BasalProgram;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.MessageUtil;
|
||||
|
||||
public final class ProgramBasalUtil {
|
||||
public static final int MAX_DELAY_BETWEEN_TENTH_PULSES_IN_USEC_AND_USECS_IN_BASAL_SLOT = 1_800_000_000;
|
||||
|
||||
public static final byte NUMBER_OF_BASAL_SLOTS = 48;
|
||||
public static final byte MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT = 16;
|
||||
|
||||
private ProgramBasalUtil() {
|
||||
}
|
||||
|
||||
public interface BasalInsulinProgramElementFactory<T extends BasalInsulinProgramElement> {
|
||||
T create(byte startSlotIndex, byte numberOfSlots, short totalTenthPulses);
|
||||
}
|
||||
|
||||
public static List<BasalInsulinProgramElement> mapTenthPulsesPerSlotToLongInsulinProgramElements(short[] tenthPulsesPerSlot) {
|
||||
return mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot, BasalInsulinProgramElement::new);
|
||||
}
|
||||
|
||||
public static <T extends BasalInsulinProgramElement> List<BasalInsulinProgramElement> mapTenthPulsesPerSlotToLongInsulinProgramElements(short[] tenthPulsesPerSlot, BasalInsulinProgramElementFactory<T> insulinProgramElementFactory) {
|
||||
if (tenthPulsesPerSlot.length > NUMBER_OF_BASAL_SLOTS) {
|
||||
throw new IllegalArgumentException("Basal program must contain at most 48 slots");
|
||||
}
|
||||
|
||||
List<BasalInsulinProgramElement> elements = new ArrayList<>();
|
||||
long previousTenthPulsesPerSlot = 0;
|
||||
byte numberOfSlotsInCurrentElement = 0;
|
||||
byte startSlotIndex = 0;
|
||||
|
||||
for (int i = 0; i < tenthPulsesPerSlot.length; i++) {
|
||||
if (i == 0) {
|
||||
previousTenthPulsesPerSlot = tenthPulsesPerSlot[i];
|
||||
numberOfSlotsInCurrentElement = 1;
|
||||
} else if (previousTenthPulsesPerSlot != tenthPulsesPerSlot[i] || (numberOfSlotsInCurrentElement + 1) * previousTenthPulsesPerSlot > 65_534) {
|
||||
elements.add(insulinProgramElementFactory.create(startSlotIndex, numberOfSlotsInCurrentElement, (short) (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement)));
|
||||
|
||||
previousTenthPulsesPerSlot = tenthPulsesPerSlot[i];
|
||||
numberOfSlotsInCurrentElement = 1;
|
||||
startSlotIndex += numberOfSlotsInCurrentElement;
|
||||
} else {
|
||||
numberOfSlotsInCurrentElement++;
|
||||
}
|
||||
}
|
||||
elements.add(insulinProgramElementFactory.create(startSlotIndex, numberOfSlotsInCurrentElement, (short) (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement)));
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
public static List<ShortInsulinProgramElement> mapPulsesPerSlotToShortInsulinProgramElements(short[] pulsesPerSlot) {
|
||||
if (pulsesPerSlot.length > NUMBER_OF_BASAL_SLOTS) {
|
||||
throw new IllegalArgumentException("Basal program must contain at most 48 slots");
|
||||
}
|
||||
|
||||
List<ShortInsulinProgramElement> elements = new ArrayList<>();
|
||||
boolean extraAlternatePulse = false;
|
||||
short previousPulsesPerSlot = 0;
|
||||
byte numberOfSlotsInCurrentElement = 0;
|
||||
byte currentTotalNumberOfSlots = 0;
|
||||
|
||||
while (currentTotalNumberOfSlots < pulsesPerSlot.length) {
|
||||
if (currentTotalNumberOfSlots == 0) {
|
||||
// First slot
|
||||
|
||||
previousPulsesPerSlot = pulsesPerSlot[0];
|
||||
currentTotalNumberOfSlots++;
|
||||
numberOfSlotsInCurrentElement = 1;
|
||||
} else if (pulsesPerSlot[currentTotalNumberOfSlots] == previousPulsesPerSlot) {
|
||||
// Subsequent slot in element (same pulses per slot as previous slot)
|
||||
|
||||
if (numberOfSlotsInCurrentElement < MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT) {
|
||||
numberOfSlotsInCurrentElement++;
|
||||
} else {
|
||||
elements.add(new BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse));
|
||||
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots];
|
||||
numberOfSlotsInCurrentElement = 1;
|
||||
extraAlternatePulse = false;
|
||||
}
|
||||
|
||||
currentTotalNumberOfSlots++;
|
||||
} else if (numberOfSlotsInCurrentElement == 1 && pulsesPerSlot[currentTotalNumberOfSlots] == previousPulsesPerSlot + 1) {
|
||||
// Second slot of segment with extra alternate pulse
|
||||
|
||||
boolean expectAlternatePulseForNextSegment = false;
|
||||
currentTotalNumberOfSlots++;
|
||||
numberOfSlotsInCurrentElement++;
|
||||
extraAlternatePulse = true;
|
||||
while (currentTotalNumberOfSlots < pulsesPerSlot.length) {
|
||||
// Loop rest alternate pulse segment
|
||||
|
||||
if (pulsesPerSlot[currentTotalNumberOfSlots] == previousPulsesPerSlot + (expectAlternatePulseForNextSegment ? 1 : 0)) {
|
||||
// Still in alternate pulse segment
|
||||
|
||||
currentTotalNumberOfSlots++;
|
||||
expectAlternatePulseForNextSegment = !expectAlternatePulseForNextSegment;
|
||||
|
||||
if (numberOfSlotsInCurrentElement < MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT) {
|
||||
numberOfSlotsInCurrentElement++;
|
||||
} else {
|
||||
// End of alternate pulse segment (no slots left in element)
|
||||
|
||||
elements.add(new BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse));
|
||||
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots];
|
||||
numberOfSlotsInCurrentElement = 1;
|
||||
extraAlternatePulse = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// End of alternate pulse segment (new number of pulses per slot)
|
||||
|
||||
elements.add(new BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse));
|
||||
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots];
|
||||
numberOfSlotsInCurrentElement = 1;
|
||||
extraAlternatePulse = false;
|
||||
currentTotalNumberOfSlots++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (previousPulsesPerSlot != pulsesPerSlot[currentTotalNumberOfSlots]) {
|
||||
// End of segment (new number of pulses per slot)
|
||||
elements.add(new BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse));
|
||||
|
||||
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots];
|
||||
currentTotalNumberOfSlots++;
|
||||
extraAlternatePulse = false;
|
||||
numberOfSlotsInCurrentElement = 1;
|
||||
} else {
|
||||
throw new IllegalStateException("Reached illegal point in mapBasalProgramToShortInsulinProgramElements");
|
||||
}
|
||||
}
|
||||
|
||||
elements.add(new BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse));
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
public static short[] mapBasalProgramToTenthPulsesPerSlot(BasalProgram basalProgram) {
|
||||
short[] tenthPulsesPerSlot = new short[NUMBER_OF_BASAL_SLOTS];
|
||||
for (BasalProgram.Segment segment : basalProgram.getSegments()) {
|
||||
for (int i = segment.getStartSlotIndex(); i < segment.getEndSlotIndex(); i++) {
|
||||
tenthPulsesPerSlot[i] = (short) (roundToHalf(segment.getPulsesPerHour() / 2.0d) * 10);
|
||||
}
|
||||
}
|
||||
|
||||
return tenthPulsesPerSlot;
|
||||
}
|
||||
|
||||
private static double roundToHalf(double d) {
|
||||
return (double) (short) ((short) (int) (d * 10.0d) / 5 * 5) / 10.0d;
|
||||
}
|
||||
|
||||
public static short[] mapBasalProgramToPulsesPerSlot(BasalProgram basalProgram) {
|
||||
short[] pulsesPerSlot = new short[NUMBER_OF_BASAL_SLOTS];
|
||||
for (BasalProgram.Segment segment : basalProgram.getSegments()) {
|
||||
boolean remainingPulse = false;
|
||||
for (int i = segment.getStartSlotIndex(); i < segment.getEndSlotIndex(); i++) {
|
||||
pulsesPerSlot[i] = (short) (segment.getPulsesPerHour() / 2);
|
||||
if (segment.getPulsesPerHour() % 2 == 1) { // Do extra alternate pulse
|
||||
if (remainingPulse) {
|
||||
pulsesPerSlot[i] += 1;
|
||||
}
|
||||
remainingPulse = !remainingPulse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pulsesPerSlot;
|
||||
}
|
||||
|
||||
public static CurrentSlot calculateCurrentSlot(short[] pulsesPerSlot, Date currentTime) {
|
||||
Calendar instance = Calendar.getInstance();
|
||||
instance.setTime(currentTime);
|
||||
|
||||
int hourOfDay = instance.get(Calendar.HOUR_OF_DAY);
|
||||
int minuteOfHour = instance.get(Calendar.MINUTE);
|
||||
int secondOfMinute = instance.get(Calendar.SECOND);
|
||||
|
||||
byte index = (byte) ((hourOfDay * 60 + minuteOfHour) / 30);
|
||||
int secondOfDay = secondOfMinute + hourOfDay * 3_600 + minuteOfHour * 60;
|
||||
|
||||
short secondsRemaining = (short) ((index + 1) * 1_800 - secondOfDay);
|
||||
short pulsesRemaining = (short) ((double) pulsesPerSlot[index] * secondsRemaining / 1_800);
|
||||
|
||||
return new CurrentSlot(index, (short) (secondsRemaining * 8), pulsesRemaining);
|
||||
}
|
||||
|
||||
public static CurrentBasalInsulinProgramElement calculateCurrentLongInsulinProgramElement(List<BasalInsulinProgramElement> elements, Date currentTime) {
|
||||
Calendar instance = Calendar.getInstance();
|
||||
instance.setTime(currentTime);
|
||||
|
||||
int hourOfDay = instance.get(Calendar.HOUR_OF_DAY);
|
||||
int minuteOfHour = instance.get(Calendar.MINUTE);
|
||||
int secondOfMinute = instance.get(Calendar.SECOND);
|
||||
|
||||
int secondOfDay = secondOfMinute + hourOfDay * 3_600 + minuteOfHour * 60;
|
||||
int startSlotIndex = 0;
|
||||
|
||||
byte index = 0;
|
||||
for (BasalInsulinProgramElement element : elements) {
|
||||
int startTimeInSeconds = startSlotIndex * 1_800;
|
||||
int endTimeInSeconds = startTimeInSeconds + element.getNumberOfSlots() * 1_800;
|
||||
|
||||
if (secondOfDay >= startTimeInSeconds && secondOfDay < endTimeInSeconds) {
|
||||
long totalNumberOfTenThousandthPulsesInSlot = element.getTotalTenthPulses() * 1_000;
|
||||
if (totalNumberOfTenThousandthPulsesInSlot == 0) {
|
||||
totalNumberOfTenThousandthPulsesInSlot = element.getNumberOfSlots() * 1_000;
|
||||
}
|
||||
|
||||
int durationInSeconds = endTimeInSeconds - startTimeInSeconds;
|
||||
int secondsPassedInCurrentSlot = secondOfDay - startTimeInSeconds;
|
||||
long remainingTenThousandthPulses = (long) ((durationInSeconds - secondsPassedInCurrentSlot) / (double) durationInSeconds * totalNumberOfTenThousandthPulsesInSlot);
|
||||
int delayBetweenTenthPulsesInUsec = (int) (durationInSeconds * 1_000_000L * 1_000 / totalNumberOfTenThousandthPulsesInSlot);
|
||||
int secondsRemaining = secondsPassedInCurrentSlot % 1_800;
|
||||
int delayUntilNextTenthPulseInUsec = delayBetweenTenthPulsesInUsec;
|
||||
for (int i = 0; i < secondsRemaining; i++) {
|
||||
delayUntilNextTenthPulseInUsec = delayUntilNextTenthPulseInUsec - 1_000_000;
|
||||
while (delayUntilNextTenthPulseInUsec <= 0) {
|
||||
delayUntilNextTenthPulseInUsec += delayBetweenTenthPulsesInUsec;
|
||||
}
|
||||
}
|
||||
short remainingTenthPulses = (short) ((remainingTenThousandthPulses % 1_000 != 0 ? 1 : 0) + remainingTenThousandthPulses / 1_000);
|
||||
|
||||
return new CurrentBasalInsulinProgramElement(index, delayUntilNextTenthPulseInUsec, remainingTenthPulses);
|
||||
}
|
||||
|
||||
index++;
|
||||
startSlotIndex += element.getNumberOfSlots();
|
||||
}
|
||||
throw new IllegalStateException("Could not determine current long insulin program element");
|
||||
}
|
||||
|
||||
public static short calculateChecksum(short[] pulsesPerSlot, CurrentSlot currentSlot) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(1 + 2 + 2 + NUMBER_OF_BASAL_SLOTS * 2) //
|
||||
.put(currentSlot.getIndex()) //
|
||||
.putShort(currentSlot.getPulsesRemaining()) //
|
||||
.putShort(currentSlot.getEighthSecondsRemaining());
|
||||
|
||||
for (short pulses : pulsesPerSlot) {
|
||||
buffer.putShort(pulses);
|
||||
}
|
||||
|
||||
return MessageUtil.calculateChecksum(buffer.array());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.util
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.BasalInsulinProgramElement
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.BasalShortInsulinProgramElement
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.CurrentBasalInsulinProgramElement
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.CurrentSlot
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.ShortInsulinProgramElement
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BasalProgram
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.MessageUtil
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.*
|
||||
|
||||
object ProgramBasalUtil {
|
||||
|
||||
const val MAX_DELAY_BETWEEN_TENTH_PULSES_IN_USEC_AND_USECS_IN_BASAL_SLOT = 1800000000
|
||||
private const val NUMBER_OF_BASAL_SLOTS: Byte = 48
|
||||
private const val MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT: Byte = 16
|
||||
|
||||
fun mapTenthPulsesPerSlotToLongInsulinProgramElements(
|
||||
tenthPulsesPerSlot: ShortArray?,
|
||||
insulinProgramElementFactory: (Byte, Byte, Short) -> BasalInsulinProgramElement = ::BasalInsulinProgramElement
|
||||
): List<BasalInsulinProgramElement> {
|
||||
require(tenthPulsesPerSlot!!.size <= NUMBER_OF_BASAL_SLOTS) { "Basal program must contain at most 48 slots" }
|
||||
val elements: MutableList<BasalInsulinProgramElement> = ArrayList()
|
||||
var previousTenthPulsesPerSlot: Short = 0
|
||||
var numberOfSlotsInCurrentElement: Byte = 0
|
||||
var startSlotIndex: Byte = 0
|
||||
for (i in tenthPulsesPerSlot.indices) {
|
||||
if (i == 0) {
|
||||
previousTenthPulsesPerSlot = tenthPulsesPerSlot[i]
|
||||
numberOfSlotsInCurrentElement = 1
|
||||
} else if (previousTenthPulsesPerSlot != tenthPulsesPerSlot[i] || (numberOfSlotsInCurrentElement + 1) * previousTenthPulsesPerSlot > 65534) {
|
||||
elements.add(insulinProgramElementFactory(startSlotIndex, numberOfSlotsInCurrentElement, (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement).toShort()))
|
||||
previousTenthPulsesPerSlot = tenthPulsesPerSlot[i]
|
||||
numberOfSlotsInCurrentElement = 1
|
||||
startSlotIndex = (numberOfSlotsInCurrentElement + startSlotIndex).toByte()
|
||||
} else {
|
||||
numberOfSlotsInCurrentElement++
|
||||
}
|
||||
}
|
||||
elements.add(insulinProgramElementFactory(startSlotIndex, numberOfSlotsInCurrentElement, (previousTenthPulsesPerSlot * numberOfSlotsInCurrentElement).toShort()))
|
||||
return elements
|
||||
}
|
||||
|
||||
fun mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot: ShortArray?): List<ShortInsulinProgramElement> {
|
||||
require(pulsesPerSlot!!.size <= NUMBER_OF_BASAL_SLOTS) { "Basal program must contain at most 48 slots" }
|
||||
val elements: MutableList<ShortInsulinProgramElement> = ArrayList()
|
||||
var extraAlternatePulse = false
|
||||
var previousPulsesPerSlot: Short = 0
|
||||
var numberOfSlotsInCurrentElement: Byte = 0
|
||||
var currentTotalNumberOfSlots: Byte = 0
|
||||
while (currentTotalNumberOfSlots < pulsesPerSlot.size) {
|
||||
if (currentTotalNumberOfSlots.toInt() == 0) {
|
||||
// First slot
|
||||
previousPulsesPerSlot = pulsesPerSlot[0]
|
||||
currentTotalNumberOfSlots++
|
||||
numberOfSlotsInCurrentElement = 1
|
||||
} else if (pulsesPerSlot[currentTotalNumberOfSlots.toInt()] == previousPulsesPerSlot) {
|
||||
// Subsequent slot in element (same pulses per slot as previous slot)
|
||||
if (numberOfSlotsInCurrentElement < MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT) {
|
||||
numberOfSlotsInCurrentElement++
|
||||
} else {
|
||||
elements.add(BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse))
|
||||
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots.toInt()]
|
||||
numberOfSlotsInCurrentElement = 1
|
||||
extraAlternatePulse = false
|
||||
}
|
||||
currentTotalNumberOfSlots++
|
||||
} else if (numberOfSlotsInCurrentElement.toInt() == 1 && pulsesPerSlot[currentTotalNumberOfSlots.toInt()].toInt() == previousPulsesPerSlot + 1) {
|
||||
// Second slot of segment with extra alternate pulse
|
||||
var expectAlternatePulseForNextSegment = false
|
||||
currentTotalNumberOfSlots++
|
||||
numberOfSlotsInCurrentElement++
|
||||
extraAlternatePulse = true
|
||||
while (currentTotalNumberOfSlots < pulsesPerSlot.size) {
|
||||
// Loop rest alternate pulse segment
|
||||
if (pulsesPerSlot[currentTotalNumberOfSlots.toInt()].toInt() == previousPulsesPerSlot + (if (expectAlternatePulseForNextSegment) 1 else 0)) {
|
||||
// Still in alternate pulse segment
|
||||
currentTotalNumberOfSlots++
|
||||
expectAlternatePulseForNextSegment = !expectAlternatePulseForNextSegment
|
||||
if (numberOfSlotsInCurrentElement < MAX_NUMBER_OF_SLOTS_IN_INSULIN_PROGRAM_ELEMENT) {
|
||||
numberOfSlotsInCurrentElement++
|
||||
} else {
|
||||
// End of alternate pulse segment (no slots left in element)
|
||||
elements.add(BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse))
|
||||
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots.toInt()]
|
||||
numberOfSlotsInCurrentElement = 1
|
||||
extraAlternatePulse = false
|
||||
break
|
||||
}
|
||||
} else {
|
||||
// End of alternate pulse segment (new number of pulses per slot)
|
||||
elements.add(BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse))
|
||||
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots.toInt()]
|
||||
numberOfSlotsInCurrentElement = 1
|
||||
extraAlternatePulse = false
|
||||
currentTotalNumberOfSlots++
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if (previousPulsesPerSlot != pulsesPerSlot[currentTotalNumberOfSlots.toInt()]) {
|
||||
// End of segment (new number of pulses per slot)
|
||||
elements.add(BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse))
|
||||
previousPulsesPerSlot = pulsesPerSlot[currentTotalNumberOfSlots.toInt()]
|
||||
currentTotalNumberOfSlots++
|
||||
extraAlternatePulse = false
|
||||
numberOfSlotsInCurrentElement = 1
|
||||
} else {
|
||||
throw IllegalStateException("Reached illegal point in mapBasalProgramToShortInsulinProgramElements")
|
||||
}
|
||||
}
|
||||
elements.add(BasalShortInsulinProgramElement(numberOfSlotsInCurrentElement, previousPulsesPerSlot, extraAlternatePulse))
|
||||
return elements
|
||||
}
|
||||
|
||||
fun mapBasalProgramToTenthPulsesPerSlot(basalProgram: BasalProgram): ShortArray {
|
||||
val tenthPulsesPerSlot = ShortArray(NUMBER_OF_BASAL_SLOTS.toInt())
|
||||
for (segment in basalProgram.segments) {
|
||||
for (i in segment.startSlotIndex until segment.endSlotIndex) {
|
||||
tenthPulsesPerSlot[i] = (roundToHalf(segment.getPulsesPerHour() / 2.0) * 10).toInt().toShort() // TODO Adrian: int conversion ok?
|
||||
}
|
||||
}
|
||||
return tenthPulsesPerSlot
|
||||
}
|
||||
|
||||
private fun roundToHalf(d: Double): Double {
|
||||
return ((d * 10.0).toInt().toShort() / 5 * 5).toShort().toDouble() / 10.0
|
||||
}
|
||||
|
||||
fun mapBasalProgramToPulsesPerSlot(basalProgram: BasalProgram): ShortArray {
|
||||
val pulsesPerSlot = ShortArray(NUMBER_OF_BASAL_SLOTS.toInt())
|
||||
for (segment in basalProgram.segments) {
|
||||
var remainingPulse = false
|
||||
for (i in segment.startSlotIndex until segment.endSlotIndex) {
|
||||
pulsesPerSlot[i] = (segment.getPulsesPerHour() / 2).toShort()
|
||||
if (segment.getPulsesPerHour() % 2 == 1) { // Do extra alternate pulse
|
||||
if (remainingPulse) {
|
||||
pulsesPerSlot[i] = (pulsesPerSlot[i] + 1).toShort()
|
||||
}
|
||||
remainingPulse = !remainingPulse
|
||||
}
|
||||
}
|
||||
}
|
||||
return pulsesPerSlot
|
||||
}
|
||||
|
||||
fun calculateCurrentSlot(pulsesPerSlot: ShortArray?, currentTime: Date?): CurrentSlot {
|
||||
val instance = Calendar.getInstance()
|
||||
instance.time = currentTime
|
||||
val hourOfDay = instance[Calendar.HOUR_OF_DAY]
|
||||
val minuteOfHour = instance[Calendar.MINUTE]
|
||||
val secondOfMinute = instance[Calendar.SECOND]
|
||||
val index = ((hourOfDay * 60 + minuteOfHour) / 30).toByte()
|
||||
val secondOfDay = secondOfMinute + hourOfDay * 3600 + minuteOfHour * 60
|
||||
val secondsRemaining = ((index + 1) * 1800 - secondOfDay).toShort()
|
||||
val pulsesRemaining = (pulsesPerSlot!![index.toInt()].toDouble() * secondsRemaining / 1800).toShort()
|
||||
return CurrentSlot(index, (secondsRemaining * 8).toShort(), pulsesRemaining)
|
||||
}
|
||||
|
||||
fun calculateCurrentLongInsulinProgramElement(elements: List<BasalInsulinProgramElement>, currentTime: Date?): CurrentBasalInsulinProgramElement {
|
||||
val instance = Calendar.getInstance()
|
||||
instance.time = currentTime
|
||||
val hourOfDay = instance[Calendar.HOUR_OF_DAY]
|
||||
val minuteOfHour = instance[Calendar.MINUTE]
|
||||
val secondOfMinute = instance[Calendar.SECOND]
|
||||
val secondOfDay = secondOfMinute + hourOfDay * 3600 + minuteOfHour * 60
|
||||
var startSlotIndex = 0
|
||||
var index: Byte = 0
|
||||
for (element in elements) {
|
||||
val startTimeInSeconds = startSlotIndex * 1800
|
||||
val endTimeInSeconds = startTimeInSeconds + element.numberOfSlots * 1800
|
||||
if (secondOfDay in startTimeInSeconds until endTimeInSeconds) { // TODO Adrian Range check ok
|
||||
var totalNumberOfTenThousandthPulsesInSlot = (element.totalTenthPulses * 1000).toLong()
|
||||
if (totalNumberOfTenThousandthPulsesInSlot == 0L) {
|
||||
totalNumberOfTenThousandthPulsesInSlot = (element.numberOfSlots * 1000).toLong()
|
||||
}
|
||||
val durationInSeconds = endTimeInSeconds - startTimeInSeconds
|
||||
val secondsPassedInCurrentSlot = secondOfDay - startTimeInSeconds
|
||||
val remainingTenThousandthPulses = ((durationInSeconds - secondsPassedInCurrentSlot) / durationInSeconds.toDouble() * totalNumberOfTenThousandthPulsesInSlot).toLong()
|
||||
val delayBetweenTenthPulsesInUsec = (durationInSeconds * 1000000L * 1000 / totalNumberOfTenThousandthPulsesInSlot).toInt()
|
||||
val secondsRemaining = secondsPassedInCurrentSlot % 1800
|
||||
var delayUntilNextTenthPulseInUsec = delayBetweenTenthPulsesInUsec
|
||||
for (i in 0 until secondsRemaining) {
|
||||
delayUntilNextTenthPulseInUsec -= 1000000
|
||||
while (delayUntilNextTenthPulseInUsec <= 0) {
|
||||
delayUntilNextTenthPulseInUsec += delayBetweenTenthPulsesInUsec
|
||||
}
|
||||
}
|
||||
val remainingTenthPulses = ((if (remainingTenThousandthPulses % 1000 != 0L) 1 else 0) + remainingTenThousandthPulses / 1000).toShort()
|
||||
return CurrentBasalInsulinProgramElement(index, delayUntilNextTenthPulseInUsec, remainingTenthPulses)
|
||||
}
|
||||
index++
|
||||
startSlotIndex += element.numberOfSlots.toInt()
|
||||
}
|
||||
throw IllegalStateException("Could not determine current long insulin program element")
|
||||
}
|
||||
|
||||
fun calculateChecksum(pulsesPerSlot: ShortArray?, currentSlot: CurrentSlot): Short {
|
||||
val buffer = ByteBuffer.allocate(1 + 2 + 2 + NUMBER_OF_BASAL_SLOTS * 2) //
|
||||
.put(currentSlot.index) //
|
||||
.putShort(currentSlot.pulsesRemaining) //
|
||||
.putShort(currentSlot.eighthSecondsRemaining)
|
||||
for (pulses in pulsesPerSlot!!) {
|
||||
buffer.putShort(pulses)
|
||||
}
|
||||
return MessageUtil.calculateChecksum(buffer.array())
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.util;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.BasalInsulinProgramElement;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.ShortInsulinProgramElement;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.TempBasalInsulinProgramElement;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.MessageUtil;
|
||||
|
||||
public final class ProgramTempBasalUtil {
|
||||
private ProgramTempBasalUtil() {
|
||||
}
|
||||
|
||||
public static List<BasalInsulinProgramElement> mapTenthPulsesPerSlotToLongInsulinProgramElements(short[] tenthPulsesPerSlot) {
|
||||
return ProgramBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot, TempBasalInsulinProgramElement::new);
|
||||
}
|
||||
|
||||
public static short[] mapTempBasalToTenthPulsesPerSlot(int durationInSlots, double rateInUnitsPerHour) {
|
||||
short pulsesPerHour = (short) Math.round(rateInUnitsPerHour * 20);
|
||||
|
||||
short[] tenthPulsesPerSlot = new short[durationInSlots];
|
||||
for (int i = 0; durationInSlots > i; i++) {
|
||||
tenthPulsesPerSlot[i] = (short) (roundToHalf(pulsesPerHour / 2.0d) * 10);
|
||||
}
|
||||
|
||||
return tenthPulsesPerSlot;
|
||||
}
|
||||
|
||||
private static double roundToHalf(double d) {
|
||||
return (double) (short) ((short) (int) (d * 10.0d) / 5 * 5) / 10.0d;
|
||||
}
|
||||
|
||||
public static short[] mapTempBasalToPulsesPerSlot(byte durationInSlots, double rateInUnitsPerHour) {
|
||||
short pulsesPerHour = (short) Math.round(rateInUnitsPerHour * 20);
|
||||
short[] pulsesPerSlot = new short[durationInSlots];
|
||||
|
||||
boolean remainingPulse = false;
|
||||
|
||||
for (int i = 0; durationInSlots > i; i++) {
|
||||
pulsesPerSlot[i] = (short) (pulsesPerHour / 2);
|
||||
if (pulsesPerHour % 2 == 1) { // Do extra alternate pulse
|
||||
if (remainingPulse) {
|
||||
pulsesPerSlot[i] += 1;
|
||||
}
|
||||
remainingPulse = !remainingPulse;
|
||||
}
|
||||
}
|
||||
|
||||
return pulsesPerSlot;
|
||||
}
|
||||
|
||||
public static short calculateChecksum(byte totalNumberOfSlots, short pulsesInFirstSlot, short[] pulsesPerSlot) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(1 + 2 + 2 + 2 * pulsesPerSlot.length) //
|
||||
.put(totalNumberOfSlots) //
|
||||
.putShort((short) 0x3840) //
|
||||
.putShort(pulsesInFirstSlot);
|
||||
for (short pulses : pulsesPerSlot) {
|
||||
buffer.putShort(pulses);
|
||||
}
|
||||
|
||||
return MessageUtil.calculateChecksum(buffer.array());
|
||||
}
|
||||
|
||||
public static List<ShortInsulinProgramElement> mapPulsesPerSlotToShortInsulinProgramElements(short[] pulsesPerSlot) {
|
||||
return ProgramBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.util
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.BasalInsulinProgramElement
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.ShortInsulinProgramElement
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.insulin.program.TempBasalInsulinProgramElement
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.MessageUtil
|
||||
import java.nio.ByteBuffer
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
object ProgramTempBasalUtil {
|
||||
|
||||
fun mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot: ShortArray?): List<BasalInsulinProgramElement> {
|
||||
return ProgramBasalUtil.mapTenthPulsesPerSlotToLongInsulinProgramElements(tenthPulsesPerSlot) { startSlotIndex: Byte, numberOfSlots: Byte, totalTenthPulses: Short -> TempBasalInsulinProgramElement(startSlotIndex, numberOfSlots, totalTenthPulses) }
|
||||
}
|
||||
|
||||
fun mapTempBasalToTenthPulsesPerSlot(durationInSlots: Int, rateInUnitsPerHour: Double): ShortArray {
|
||||
val pulsesPerHour = (rateInUnitsPerHour * 20).roundToInt().toShort()
|
||||
val tenthPulsesPerSlot = ShortArray(durationInSlots)
|
||||
var i = 0
|
||||
while (durationInSlots > i) {
|
||||
tenthPulsesPerSlot[i] = (roundToHalf(pulsesPerHour / 2.0) * 10).toShort()
|
||||
i++
|
||||
}
|
||||
return tenthPulsesPerSlot
|
||||
}
|
||||
|
||||
private fun roundToHalf(d: Double): Double {
|
||||
return ((d * 10.0).toInt().toShort() / 5 * 5).toShort().toDouble() / 10.0
|
||||
}
|
||||
|
||||
fun mapTempBasalToPulsesPerSlot(durationInSlots: Byte, rateInUnitsPerHour: Double): ShortArray {
|
||||
val pulsesPerHour = (rateInUnitsPerHour * 20).roundToInt().toShort()
|
||||
val pulsesPerSlot = ShortArray(durationInSlots.toInt())
|
||||
var remainingPulse = false
|
||||
var i = 0
|
||||
while (durationInSlots > i) {
|
||||
pulsesPerSlot[i] = (pulsesPerHour / 2).toShort()
|
||||
if (pulsesPerHour % 2 == 1) { // Do extra alternate pulse
|
||||
if (remainingPulse) {
|
||||
pulsesPerSlot[i] = (pulsesPerSlot[i] + 1).toShort()
|
||||
}
|
||||
remainingPulse = !remainingPulse
|
||||
}
|
||||
i++
|
||||
}
|
||||
return pulsesPerSlot
|
||||
}
|
||||
|
||||
fun calculateChecksum(totalNumberOfSlots: Byte, pulsesInFirstSlot: Short, pulsesPerSlot: ShortArray?): Short {
|
||||
val buffer = ByteBuffer.allocate(1 + 2 + 2 + 2 * pulsesPerSlot!!.size) //
|
||||
.put(totalNumberOfSlots) //
|
||||
.putShort(0x3840.toShort()) //
|
||||
.putShort(pulsesInFirstSlot)
|
||||
for (pulses in pulsesPerSlot) {
|
||||
buffer.putShort(pulses)
|
||||
}
|
||||
return MessageUtil.calculateChecksum(buffer.array())
|
||||
}
|
||||
|
||||
fun mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot: ShortArray?): List<ShortInsulinProgramElement> =
|
||||
ProgramBasalUtil.mapPulsesPerSlotToShortInsulinProgramElements(pulsesPerSlot)
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||
|
||||
enum class ActivationProgress {
|
||||
NOT_STARTED,
|
||||
GOT_POD_VERSION,
|
||||
SET_UNIQUE_ID,
|
||||
PROGRAMMED_LOW_RESERVOIR_ALERTS,
|
||||
REPROGRAMMED_LUMP_OF_COAL_ALERT,
|
||||
PRIMING,
|
||||
PRIME_COMPLETED,
|
||||
PROGRAMMED_USER_SET_EXPIRATION_ALERT,
|
||||
PHASE_1_COMPLETED,
|
||||
PROGRAMMED_BASAL,
|
||||
PROGRAMMED_CANCEL_LOC_ETC_ALERT,
|
||||
INSERTING_CANNULA,
|
||||
CANNULA_INSERTED,
|
||||
COMPLETED;
|
||||
|
||||
fun isBefore(other: ActivationProgress): Boolean = ordinal < other.ordinal
|
||||
|
||||
fun isAtLeast(other: ActivationProgress): Boolean = ordinal >= other.ordinal
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
||||
|
||||
public enum AlarmType {
|
||||
NONE((byte) 0x00),
|
||||
ALARM_PW_FLASH_ERASE((byte) 0x01),
|
||||
ALARM_PW_FLASH_WRITE((byte) 0x02),
|
||||
ALARM_BASAL_CKSUM((byte) 0x03),
|
||||
ALARM_BASAL_PPULSE((byte) 0x04),
|
||||
ALARM_BASAL_STEP((byte) 0x05),
|
||||
ALARM_AUTO_WAKEUP_TIMEOUT((byte) 0x06),
|
||||
ALARM_WIRE_OVERDRIVEN((byte) 0x07),
|
||||
ALARM_BEEP_REP_INVALID_INDEX((byte) 0x08),
|
||||
ALARM_INVALID_REP_PATTERN((byte) 0x09),
|
||||
ALARM_TEMP_BASAL_STEP((byte) 0x0a),
|
||||
ALARM_TEMP_BASAL_CKSUM((byte) 0x0b),
|
||||
ALARM_BOLUS_OVERFLOW((byte) 0x0c),
|
||||
ALARM_COP_RESET((byte) 0x0d),
|
||||
ALARM_ILOP_RESET((byte) 0x0e),
|
||||
ALARM_ILAD_RESET((byte) 0x0f),
|
||||
ALARM_SAWCOP_RESET((byte) 0x10),
|
||||
ALARM_BOLUS_STEP((byte) 0x11),
|
||||
ALARM_LVD_RESET((byte) 0x12),
|
||||
ALARM_INVALID_RF_MSG_LENGTH((byte) 0x13),
|
||||
ALARM_OCCLUDED((byte) 0x14),
|
||||
ALARM_BOLUSPROG_CHKSUM((byte) 0x15),
|
||||
ALARM_BOLUS_LOG((byte) 0x16),
|
||||
ALARM_CRITICAL_VAR((byte) 0x17),
|
||||
ALARM_EMPTY_RESERVOIR((byte) 0x18),
|
||||
ALARM_LOADERR((byte) 0x19),
|
||||
ALARM_PSA_FAILURE((byte) 0x1a),
|
||||
ALARM_TICKCNT_NOT_CLEARED((byte) 0x1b),
|
||||
ALARM_PUMP_EXPIRED((byte) 0x1c),
|
||||
ALARM_COMD_BIT_NOT_SET((byte) 0x1d),
|
||||
ALARM_INVALID_COMD_SET((byte) 0x1e),
|
||||
ALARM_ALERTS_ARRAY_CKSM((byte) 0x1f),
|
||||
ALARM_UNIT_TEST((byte) 0x20),
|
||||
ALARM_TICK_TIME_ERROR((byte) 0x21),
|
||||
ALARM_CRITICAL_HAZARD((byte) 0x22),
|
||||
ALARM_PIEZO_FREQ((byte) 0x23),
|
||||
ALARM_TICKCNT_ERROR_RTC((byte) 0x24),
|
||||
ALARM_TICK_FAILURE((byte) 0x25),
|
||||
ALARM_INVALID((byte) 0x26),
|
||||
ALARM_LUMP_ALERT_PROGRAM((byte) 0x27),
|
||||
ALARM_INVALID_PASS_CODE((byte) 0x28),
|
||||
ALARM_ALERT0((byte) 0x29),
|
||||
ALARM_ALERT1((byte) 0x2a),
|
||||
ALARM_ALERT2((byte) 0x2b),
|
||||
ALARM_ALERT3((byte) 0x2c),
|
||||
ALARM_ALERT4((byte) 0x2d),
|
||||
ALARM_ALERT5((byte) 0x2e),
|
||||
ALARM_ALERT6((byte) 0x2f),
|
||||
ALARM_ALERT7((byte) 0x30),
|
||||
ALARM_ILLEGAL_PUMP_STATE((byte) 0x31),
|
||||
ALARM_COP_TEST_FAILURE((byte) 0x32),
|
||||
ALARM_MCTF((byte) 0x33),
|
||||
ALARM_ILLEGAL_RESET((byte) 0x34),
|
||||
ALARM_VETO_NOT_SET((byte) 0x35),
|
||||
ALARM_ILLEGAL_PIN_RESET((byte) 0x36),
|
||||
ALARM_INVALID_BEEP_PATTERN((byte) 0x37),
|
||||
ALARM_WIRE_STATE_MACHINE((byte) 0x38),
|
||||
ALARM_VETO_TEST_DEFAULT((byte) 0x39),
|
||||
ALARM_ALERT_INVALID_INDEX((byte) 0x3a),
|
||||
ALARM_SAWCOP_TEST_FAIL((byte) 0x3b),
|
||||
ALARM_MCUCOP_TEST_FAIL((byte) 0x3c),
|
||||
ALARM_STEP_SENSOR_SHORTED((byte) 0x3d),
|
||||
ALARM_FLASH_FAILURE((byte) 0x3e),
|
||||
ALARM_SPARE63((byte) 0x3f),
|
||||
ALARM_SS_OPEN_CNT_EXCEEDED((byte) 0x40),
|
||||
ALARM_SS_EXCESSIVE_SUMMED((byte) 0x41),
|
||||
ALARM_SS_MIN_PULSE_TRANSITION((byte) 0x42),
|
||||
ALARM_SS_DEFAULT((byte) 0x43),
|
||||
ALARM_OPEN_WIRE1((byte) 0x44),
|
||||
ALARM_OPEN_WIRE2((byte) 0x45),
|
||||
ALARM_LOADERR_FAILURE((byte) 0x46),
|
||||
ALARM_SAW_VETO_FAILURE((byte) 0x47),
|
||||
ALARM_BAD_RFM_CLOCK((byte) 0x48),
|
||||
ALARM_BAD_TICK_HIGH((byte) 0x49),
|
||||
ALARM_BAD_TICK_PERIOD((byte) 0x4a),
|
||||
ALARM_BAD_TRIM_VALUE((byte) 0x4b),
|
||||
ALARM_BAD_BUS_CLOCK((byte) 0x4c),
|
||||
ALARM_BAD_CAL_MODE((byte) 0x4d),
|
||||
ALARM_SAW_TRIM_ERROR((byte) 0x4e),
|
||||
ALARM_RFM_CRYSTAL_ERROR((byte) 0x4f),
|
||||
ALARM_CALST_TIMEOUT((byte) 0x50),
|
||||
ALARM_TICKCNT_ERROR((byte) 0x51),
|
||||
ALARM_BAD_RFM_XTAL_START((byte) 0x52),
|
||||
ALARM_BAD_RX_SENSENSITIVITY((byte) 0x53),
|
||||
ALARM_BAD_TX_PKT_SIZE((byte) 0x54),
|
||||
ALARM_TICK_LOW_PHASE_EXCEEDED((byte) 0x55),
|
||||
ALARM_TICK_HIGH_PHASE_EXCEEDED((byte) 0x56),
|
||||
ALARM_OCCL_CRITVAR_FAIL((byte) 0x57),
|
||||
ALARM_OCCL_PARAM((byte) 0x58),
|
||||
ALARM_PROG_OCCL_FAIL((byte) 0x59),
|
||||
ALARM_PW_TO_HIGH_FOR_OCCL_DET((byte) 0x5a),
|
||||
ALARM_OCCL_CSUM((byte) 0x5b),
|
||||
ALARM_PRIME_OPEN_CNT_TO_LOW((byte) 0x5c),
|
||||
ALARM_BAD_RF_CDTHR((byte) 0x5d),
|
||||
ALARM_FLASH_NOT_SECURE((byte) 0x5e),
|
||||
ALARM_WIRE_TEST_OPEN_GROUND((byte) 0x5f),
|
||||
ALARM_OCCL_STARTUP1((byte) 0x60),
|
||||
ALARM_OCCL_STARTUP2((byte) 0x61),
|
||||
ALARM_OCCL_EXCESS_TIMEOUTS1((byte) 0x62),
|
||||
ALARM_SPARE99((byte) 0x63),
|
||||
ALARM_SPARE100((byte) 0x64),
|
||||
ALARM_SPARE101((byte) 0x65),
|
||||
ALARM_OCCL_EXCESS_TIMEOUTS2((byte) 0x66),
|
||||
ALARM_OCCL_EXCESS_TIMEOUTS3((byte) 0x67),
|
||||
ALARM_OCCL_NOISY_PULSE_WIDTHS((byte) 0x68),
|
||||
ALARM_OCCL_AT_BOLUS_END((byte) 0x69),
|
||||
ALARM_OCCL_ABOVE_THRESHOLD((byte) 0x6a),
|
||||
ALARM_BASAL_UNDERINFUSION((byte) 0x80),
|
||||
ALARM_BASAL_OVERINFUSION((byte) 0x81),
|
||||
ALARM_TEMP_UNDERINFUSION((byte) 0x82),
|
||||
ALARM_TEMP_OVERINFUSION((byte) 0x83),
|
||||
ALARM_BOLUS_UNDERINFUSION((byte) 0x84),
|
||||
ALARM_BOLUS_OVERINFUSION((byte) 0x85),
|
||||
ALARM_BASAL_OVERINFUSION_PULSE((byte) 0x86),
|
||||
ALARM_TEMP_OVERINFUSION_PULSE((byte) 0x87),
|
||||
ALARM_BOLUS_OVERINFUSION_PULSE((byte) 0x88),
|
||||
ALARM_IMMBOLUS_UNDERINFUSION_PULSE((byte) 0x89),
|
||||
ALARM_EXTBOLUS_OVERINFUSION_PULSE((byte) 0x8a),
|
||||
ALARM_PROGRAM_CSUM((byte) 0x8b),
|
||||
ALARM_UNUSED_140((byte) 0x8c),
|
||||
ALARM_UNRECOGNIZED_PULSE((byte) 0x8d),
|
||||
ALARM_SYNC_WITHOUT_TEMP_ACTIVE((byte) 0x8e),
|
||||
ALARM_INTERLOCK_LOAD((byte) 0x8f),
|
||||
ALARM_ILLEGAL_CHAN_PARAM((byte) 0x90),
|
||||
ALARM_BASAL_PULSE_CHAN_INACTIVE((byte) 0x91),
|
||||
ALARM_TEMP_PULSE_CHAN_INACTIVE((byte) 0x92),
|
||||
ALARM_BOLUS_PULSE_CHAN_INACTIVE((byte) 0x93),
|
||||
ALARM_INT_SEMAPHORE_NOT_SET((byte) 0x94),
|
||||
ALARM_ILLEGAL_INTERLOCK_CHAN((byte) 0x95),
|
||||
ALARM_TERMINATE_BOLUS((byte) 0x96),
|
||||
ALARM_OPEN_TRANSITIONS_COUNT((byte) 0x97),
|
||||
ALARM_BLE_TO((byte) 0xa0),
|
||||
ALARM_BLE_INITIATED((byte) 0xa1),
|
||||
ALARM_BLE_UNK_ALARM((byte) 0xa2),
|
||||
ALARM_UNUSED_163((byte) 0xa3),
|
||||
ALARM_UNUSED_164((byte) 0xa4),
|
||||
ALARM_UNUSED_165((byte) 0xa5),
|
||||
ALARM_BLE_IAAS((byte) 0xa6),
|
||||
ALARM_UNUSED_167((byte) 0xa7),
|
||||
ALARM_CRC_FAILURE((byte) 0xa8),
|
||||
ALARM_BLE_WD_PING_TIMEOUT((byte) 0xa9),
|
||||
ALARM_BLE_EXCESSIVE_RESETS((byte) 0xaa),
|
||||
ALARM_BLE_NAK_ERROR((byte) 0xab),
|
||||
ALARM_BLE_REQ_HIGH_TIMEOUT((byte) 0xac),
|
||||
ALARM_BLE_UNKNOWN_RESP((byte) 0xad),
|
||||
ALARM_BLE_UNUSED_174((byte) 0xae),
|
||||
ALARM_BLE_REQ_STUCK_HIGH((byte) 0xaf),
|
||||
ALARM_BLE_STATE_MACHINE_1((byte) 0xb1),
|
||||
ALARM_BLE_STATE_MACHINE_2((byte) 0xb2),
|
||||
ALARM_BLE_UNUSED_179((byte) 0xb3),
|
||||
ALARM_BLE_ARB_LOST((byte) 0xb4),
|
||||
ALARM_BLE_ER48_DUAL_NACK((byte) 0xc0),
|
||||
ALARM_BLE_QN_EXCEED_MAX_RETRY((byte) 0xc1),
|
||||
ALARM_BLE_QN_CRIT_VAR_FAIL((byte) 0xc2),
|
||||
UNKNOWN((byte) 0xff);
|
||||
|
||||
private byte value;
|
||||
|
||||
AlarmType(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static AlarmType byValue(byte value) {
|
||||
for (AlarmType type : values()) {
|
||||
if (type.value == value) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||
|
||||
enum class AlarmType(
|
||||
private val value: Byte
|
||||
) {
|
||||
|
||||
NONE(0x00.toByte()),
|
||||
ALARM_PW_FLASH_ERASE(0x01.toByte()),
|
||||
ALARM_PW_FLASH_WRITE(0x02.toByte()),
|
||||
ALARM_BASAL_CKSUM(0x03.toByte()),
|
||||
ALARM_BASAL_PPULSE(0x04.toByte()),
|
||||
ALARM_BASAL_STEP(0x05.toByte()),
|
||||
ALARM_AUTO_WAKEUP_TIMEOUT(0x06.toByte()),
|
||||
ALARM_WIRE_OVERDRIVEN(0x07.toByte()),
|
||||
ALARM_BEEP_REP_INVALID_INDEX(0x08.toByte()),
|
||||
ALARM_INVALID_REP_PATTERN(0x09.toByte()),
|
||||
ALARM_TEMP_BASAL_STEP(0x0a.toByte()),
|
||||
ALARM_TEMP_BASAL_CKSUM(0x0b.toByte()),
|
||||
ALARM_BOLUS_OVERFLOW(0x0c.toByte()),
|
||||
ALARM_COP_RESET(0x0d.toByte()),
|
||||
ALARM_ILOP_RESET(0x0e.toByte()),
|
||||
ALARM_ILAD_RESET(0x0f.toByte()),
|
||||
ALARM_SAWCOP_RESET(0x10.toByte()),
|
||||
ALARM_BOLUS_STEP(0x11.toByte()),
|
||||
ALARM_LVD_RESET(0x12.toByte()),
|
||||
ALARM_INVALID_RF_MSG_LENGTH(0x13.toByte()),
|
||||
ALARM_OCCLUDED(0x14.toByte()),
|
||||
ALARM_BOLUSPROG_CHKSUM(0x15.toByte()),
|
||||
ALARM_BOLUS_LOG(0x16.toByte()),
|
||||
ALARM_CRITICAL_VAR(0x17.toByte()),
|
||||
ALARM_EMPTY_RESERVOIR(0x18.toByte()),
|
||||
ALARM_LOADERR(0x19.toByte()),
|
||||
ALARM_PSA_FAILURE(0x1a.toByte()),
|
||||
ALARM_TICKCNT_NOT_CLEARED(0x1b.toByte()),
|
||||
ALARM_PUMP_EXPIRED(0x1c.toByte()),
|
||||
ALARM_COMD_BIT_NOT_SET(0x1d.toByte()),
|
||||
ALARM_INVALID_COMD_SET(0x1e.toByte()),
|
||||
ALARM_ALERTS_ARRAY_CKSM(0x1f.toByte()),
|
||||
ALARM_UNIT_TEST(0x20.toByte()),
|
||||
ALARM_TICK_TIME_ERROR(0x21.toByte()),
|
||||
ALARM_CRITICAL_HAZARD(0x22.toByte()),
|
||||
ALARM_PIEZO_FREQ(0x23.toByte()),
|
||||
ALARM_TICKCNT_ERROR_RTC(0x24.toByte()),
|
||||
ALARM_TICK_FAILURE(0x25.toByte()),
|
||||
ALARM_INVALID(0x26.toByte()),
|
||||
ALARM_LUMP_ALERT_PROGRAM(0x27.toByte()),
|
||||
ALARM_INVALID_PASS_CODE(0x28.toByte()),
|
||||
ALARM_ALERT0(0x29.toByte()),
|
||||
ALARM_ALERT1(0x2a.toByte()),
|
||||
ALARM_ALERT2(0x2b.toByte()),
|
||||
ALARM_ALERT3(0x2c.toByte()),
|
||||
ALARM_ALERT4(0x2d.toByte()),
|
||||
ALARM_ALERT5(0x2e.toByte()),
|
||||
ALARM_ALERT6(0x2f.toByte()),
|
||||
ALARM_ALERT7(0x30.toByte()),
|
||||
ALARM_ILLEGAL_PUMP_STATE(0x31.toByte()),
|
||||
ALARM_COP_TEST_FAILURE(0x32.toByte()),
|
||||
ALARM_MCTF(0x33.toByte()),
|
||||
ALARM_ILLEGAL_RESET(0x34.toByte()),
|
||||
ALARM_VETO_NOT_SET(0x35.toByte()),
|
||||
ALARM_ILLEGAL_PIN_RESET(0x36.toByte()),
|
||||
ALARM_INVALID_BEEP_PATTERN(0x37.toByte()),
|
||||
ALARM_WIRE_STATE_MACHINE(0x38.toByte()),
|
||||
ALARM_VETO_TEST_DEFAULT(0x39.toByte()),
|
||||
ALARM_ALERT_INVALID_INDEX(0x3a.toByte()),
|
||||
ALARM_SAWCOP_TEST_FAIL(0x3b.toByte()),
|
||||
ALARM_MCUCOP_TEST_FAIL(0x3c.toByte()),
|
||||
ALARM_STEP_SENSOR_SHORTED(0x3d.toByte()),
|
||||
ALARM_FLASH_FAILURE(0x3e.toByte()),
|
||||
ALARM_SPARE63(0x3f.toByte()),
|
||||
ALARM_SS_OPEN_CNT_EXCEEDED(0x40.toByte()),
|
||||
ALARM_SS_EXCESSIVE_SUMMED(0x41.toByte()),
|
||||
ALARM_SS_MIN_PULSE_TRANSITION(0x42.toByte()),
|
||||
ALARM_SS_DEFAULT(0x43.toByte()),
|
||||
ALARM_OPEN_WIRE1(0x44.toByte()),
|
||||
ALARM_OPEN_WIRE2(0x45.toByte()),
|
||||
ALARM_LOADERR_FAILURE(0x46.toByte()),
|
||||
ALARM_SAW_VETO_FAILURE(0x47.toByte()),
|
||||
ALARM_BAD_RFM_CLOCK(0x48.toByte()),
|
||||
ALARM_BAD_TICK_HIGH(0x49.toByte()),
|
||||
ALARM_BAD_TICK_PERIOD(0x4a.toByte()),
|
||||
ALARM_BAD_TRIM_VALUE(0x4b.toByte()),
|
||||
ALARM_BAD_BUS_CLOCK(0x4c.toByte()),
|
||||
ALARM_BAD_CAL_MODE(0x4d.toByte()),
|
||||
ALARM_SAW_TRIM_ERROR(0x4e.toByte()),
|
||||
ALARM_RFM_CRYSTAL_ERROR(0x4f.toByte()),
|
||||
ALARM_CALST_TIMEOUT(0x50.toByte()),
|
||||
ALARM_TICKCNT_ERROR(0x51.toByte()),
|
||||
ALARM_BAD_RFM_XTAL_START(0x52.toByte()),
|
||||
ALARM_BAD_RX_SENSENSITIVITY(0x53.toByte()),
|
||||
ALARM_BAD_TX_PKT_SIZE(0x54.toByte()),
|
||||
ALARM_TICK_LOW_PHASE_EXCEEDED(0x55.toByte()),
|
||||
ALARM_TICK_HIGH_PHASE_EXCEEDED(0x56.toByte()),
|
||||
ALARM_OCCL_CRITVAR_FAIL(0x57.toByte()),
|
||||
ALARM_OCCL_PARAM(0x58.toByte()),
|
||||
ALARM_PROG_OCCL_FAIL(0x59.toByte()),
|
||||
ALARM_PW_TO_HIGH_FOR_OCCL_DET(0x5a.toByte()),
|
||||
ALARM_OCCL_CSUM(0x5b.toByte()),
|
||||
ALARM_PRIME_OPEN_CNT_TO_LOW(0x5c.toByte()),
|
||||
ALARM_BAD_RF_CDTHR(0x5d.toByte()),
|
||||
ALARM_FLASH_NOT_SECURE(0x5e.toByte()),
|
||||
ALARM_WIRE_TEST_OPEN_GROUND(0x5f.toByte()),
|
||||
ALARM_OCCL_STARTUP1(0x60.toByte()),
|
||||
ALARM_OCCL_STARTUP2(0x61.toByte()),
|
||||
ALARM_OCCL_EXCESS_TIMEOUTS1(0x62.toByte()),
|
||||
ALARM_SPARE99(0x63.toByte()),
|
||||
ALARM_SPARE100(0x64.toByte()),
|
||||
ALARM_SPARE101(0x65.toByte()),
|
||||
ALARM_OCCL_EXCESS_TIMEOUTS2(0x66.toByte()),
|
||||
ALARM_OCCL_EXCESS_TIMEOUTS3(0x67.toByte()),
|
||||
ALARM_OCCL_NOISY_PULSE_WIDTHS(0x68.toByte()),
|
||||
ALARM_OCCL_AT_BOLUS_END(0x69.toByte()),
|
||||
ALARM_OCCL_ABOVE_THRESHOLD(0x6a.toByte()),
|
||||
ALARM_BASAL_UNDERINFUSION(0x80.toByte()),
|
||||
ALARM_BASAL_OVERINFUSION(0x81.toByte()),
|
||||
ALARM_TEMP_UNDERINFUSION(0x82.toByte()),
|
||||
ALARM_TEMP_OVERINFUSION(0x83.toByte()),
|
||||
ALARM_BOLUS_UNDERINFUSION(0x84.toByte()),
|
||||
ALARM_BOLUS_OVERINFUSION(0x85.toByte()),
|
||||
ALARM_BASAL_OVERINFUSION_PULSE(0x86.toByte()),
|
||||
ALARM_TEMP_OVERINFUSION_PULSE(0x87.toByte()),
|
||||
ALARM_BOLUS_OVERINFUSION_PULSE(0x88.toByte()),
|
||||
ALARM_IMMBOLUS_UNDERINFUSION_PULSE(0x89.toByte()),
|
||||
ALARM_EXTBOLUS_OVERINFUSION_PULSE(0x8a.toByte()),
|
||||
ALARM_PROGRAM_CSUM(0x8b.toByte()),
|
||||
ALARM_UNUSED_140(0x8c.toByte()),
|
||||
ALARM_UNRECOGNIZED_PULSE(0x8d.toByte()),
|
||||
ALARM_SYNC_WITHOUT_TEMP_ACTIVE(0x8e.toByte()),
|
||||
ALARM_INTERLOCK_LOAD(0x8f.toByte()),
|
||||
ALARM_ILLEGAL_CHAN_PARAM(0x90.toByte()),
|
||||
ALARM_BASAL_PULSE_CHAN_INACTIVE(0x91.toByte()),
|
||||
ALARM_TEMP_PULSE_CHAN_INACTIVE(0x92.toByte()),
|
||||
ALARM_BOLUS_PULSE_CHAN_INACTIVE(0x93.toByte()),
|
||||
ALARM_INT_SEMAPHORE_NOT_SET(0x94.toByte()),
|
||||
ALARM_ILLEGAL_INTERLOCK_CHAN(0x95.toByte()),
|
||||
ALARM_TERMINATE_BOLUS(0x96.toByte()),
|
||||
ALARM_OPEN_TRANSITIONS_COUNT(0x97.toByte()),
|
||||
ALARM_BLE_TO(0xa0.toByte()),
|
||||
ALARM_BLE_INITIATED(0xa1.toByte()),
|
||||
ALARM_BLE_UNK_ALARM(0xa2.toByte()),
|
||||
ALARM_UNUSED_163(0xa3.toByte()),
|
||||
ALARM_UNUSED_164(0xa4.toByte()),
|
||||
ALARM_UNUSED_165(0xa5.toByte()),
|
||||
ALARM_BLE_IAAS(0xa6.toByte()),
|
||||
ALARM_UNUSED_167(0xa7.toByte()),
|
||||
ALARM_CRC_FAILURE(0xa8.toByte()),
|
||||
ALARM_BLE_WD_PING_TIMEOUT(0xa9.toByte()),
|
||||
ALARM_BLE_EXCESSIVE_RESETS(0xaa.toByte()),
|
||||
ALARM_BLE_NAK_ERROR(0xab.toByte()),
|
||||
ALARM_BLE_REQ_HIGH_TIMEOUT(0xac.toByte()),
|
||||
ALARM_BLE_UNKNOWN_RESP(0xad.toByte()),
|
||||
ALARM_BLE_UNUSED_174(0xae.toByte()),
|
||||
ALARM_BLE_REQ_STUCK_HIGH(0xaf.toByte()),
|
||||
ALARM_BLE_STATE_MACHINE_1(0xb1.toByte()),
|
||||
ALARM_BLE_STATE_MACHINE_2(0xb2.toByte()),
|
||||
ALARM_BLE_UNUSED_179(0xb3.toByte()),
|
||||
ALARM_BLE_ARB_LOST(0xb4.toByte()),
|
||||
ALARM_BLE_ER48_DUAL_NACK(0xc0.toByte()),
|
||||
ALARM_BLE_QN_EXCEED_MAX_RETRY(0xc1.toByte()),
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class AlertConfiguration implements Encodable {
|
||||
private AlertSlot slot;
|
||||
private boolean enabled;
|
||||
private short durationInMinutes;
|
||||
private boolean autoOff;
|
||||
private AlertTriggerType triggerType;
|
||||
private short offsetInMinutesOrThresholdInMicroLiters;
|
||||
private BeepType beepType;
|
||||
private BeepRepetitionType beepRepetition;
|
||||
|
||||
public AlertConfiguration(AlertSlot slot, boolean enabled, short durationInMinutes, boolean autoOff, AlertTriggerType triggerType, short offsetInMinutesOrThresholdInMicroLiters, BeepType beepType, BeepRepetitionType beepRepetition) {
|
||||
this.slot = slot;
|
||||
this.enabled = enabled;
|
||||
this.durationInMinutes = durationInMinutes;
|
||||
this.autoOff = autoOff;
|
||||
this.triggerType = triggerType;
|
||||
this.offsetInMinutesOrThresholdInMicroLiters = offsetInMinutesOrThresholdInMicroLiters;
|
||||
this.beepType = beepType;
|
||||
this.beepRepetition = beepRepetition;
|
||||
}
|
||||
|
||||
@Override public byte[] getEncoded() {
|
||||
byte firstByte = (byte) (slot.getValue() << 4);
|
||||
if (enabled) {
|
||||
firstByte |= 1 << 3;
|
||||
}
|
||||
if (triggerType == AlertTriggerType.RESERVOIR_VOLUME_TRIGGER) {
|
||||
firstByte |= 1 << 2;
|
||||
}
|
||||
if (autoOff) {
|
||||
firstByte |= 1 << 1;
|
||||
}
|
||||
firstByte |= ((durationInMinutes >> 8) & 0x01);
|
||||
|
||||
return ByteBuffer.allocate(6) //
|
||||
.put(firstByte)
|
||||
.put((byte) durationInMinutes) //
|
||||
.putShort(offsetInMinutesOrThresholdInMicroLiters) //
|
||||
.put(beepRepetition.getValue()) //
|
||||
.put(beepType.getValue()) //
|
||||
.array();
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "AlertConfiguration{" +
|
||||
"slot=" + slot +
|
||||
", enabled=" + enabled +
|
||||
", durationInMinutes=" + durationInMinutes +
|
||||
", autoOff=" + autoOff +
|
||||
", triggerType=" + triggerType +
|
||||
", offsetInMinutesOrThresholdInMicroLiters=" + offsetInMinutesOrThresholdInMicroLiters +
|
||||
", beepType=" + beepType +
|
||||
", beepRepetition=" + beepRepetition +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||
|
||||
import java.nio.ByteBuffer
|
||||
import kotlin.experimental.or
|
||||
|
||||
class AlertConfiguration(
|
||||
private val slot: AlertSlot,
|
||||
private val enabled: Boolean,
|
||||
private val durationInMinutes: Short,
|
||||
private val autoOff: Boolean,
|
||||
private val triggerType: AlertTriggerType,
|
||||
private val offsetInMinutesOrThresholdInMicroLiters: Short,
|
||||
private val beepType: BeepType,
|
||||
private val beepRepetition: BeepRepetitionType
|
||||
) : Encodable {
|
||||
|
||||
override val encoded: ByteArray
|
||||
get() {
|
||||
var firstByte = (slot.value.toInt() shl 4).toByte()
|
||||
if (enabled) {
|
||||
firstByte = firstByte or (1 shl 3)
|
||||
}
|
||||
if (triggerType == AlertTriggerType.RESERVOIR_VOLUME_TRIGGER) {
|
||||
firstByte = firstByte or (1 shl 2)
|
||||
}
|
||||
if (autoOff) {
|
||||
firstByte = firstByte or (1 shl 1)
|
||||
}
|
||||
firstByte = firstByte or ((durationInMinutes.toInt() shr 8 and 0x01).toByte()) //Todo bitstuff
|
||||
return ByteBuffer.allocate(6) //
|
||||
.put(firstByte)
|
||||
.put(durationInMinutes.toByte()) //
|
||||
.putShort(offsetInMinutesOrThresholdInMicroLiters) //
|
||||
.put(beepRepetition.value) //
|
||||
.put(beepType.value) //
|
||||
.array()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "AlertConfiguration{" +
|
||||
"slot=" + slot +
|
||||
", enabled=" + enabled +
|
||||
", durationInMinutes=" + durationInMinutes +
|
||||
", autoOff=" + autoOff +
|
||||
", triggerType=" + triggerType +
|
||||
", offsetInMinutesOrThresholdInMicroLiters=" + offsetInMinutesOrThresholdInMicroLiters +
|
||||
", beepType=" + beepType +
|
||||
", beepRepetition=" + beepRepetition +
|
||||
'}'
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
||||
|
||||
public enum AlertSlot {
|
||||
AUTO_OFF((byte) 0x00),
|
||||
MULTI_COMMAND((byte) 0x01),
|
||||
EXPIRATION_IMMINENT((byte) 0x02),
|
||||
USER_SET_EXPIRATION((byte) 0x03),
|
||||
LOW_RESERVOIR((byte) 0x04),
|
||||
SUSPEND_IN_PROGRESS((byte) 0x05),
|
||||
SUSPEND_ENDED((byte) 0x06),
|
||||
EXPIRATION((byte) 0x07),
|
||||
UNKNOWN((byte) 0xff);
|
||||
|
||||
private byte value;
|
||||
|
||||
AlertSlot(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static AlertSlot byValue(byte value) {
|
||||
for (AlertSlot slot : values()) {
|
||||
if (slot.value == value) {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
public byte getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||
|
||||
enum class AlertSlot(
|
||||
val value: Byte
|
||||
) {
|
||||
|
||||
AUTO_OFF(0x00.toByte()),
|
||||
MULTI_COMMAND(0x01.toByte()),
|
||||
EXPIRATION_IMMINENT(0x02.toByte()),
|
||||
USER_SET_EXPIRATION(0x03.toByte()),
|
||||
LOW_RESERVOIR(0x04.toByte()),
|
||||
SUSPEND_IN_PROGRESS(0x05.toByte()),
|
||||
SUSPEND_ENDED(0x06.toByte()),
|
||||
EXPIRATION(0x07.toByte()),
|
||||
UNKNOWN(0xff.toByte());
|
||||
|
||||
companion object {
|
||||
|
||||
fun byValue(value: Byte): AlertSlot {
|
||||
for (slot in values()) {
|
||||
if (slot.value == value) {
|
||||
return slot
|
||||
}
|
||||
}
|
||||
return UNKNOWN
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||
|
||||
public enum AlertTriggerType {
|
||||
enum class AlertTriggerType {
|
||||
TIME_TRIGGER,
|
||||
RESERVOIR_VOLUME_TRIGGER
|
||||
}
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class BasalProgram {
|
||||
private final List<Segment> segments;
|
||||
|
||||
public BasalProgram(List<Segment> segments) {
|
||||
if (segments == null) {
|
||||
throw new IllegalArgumentException("segments can not be null");
|
||||
}
|
||||
|
||||
// TODO validate segments
|
||||
|
||||
this.segments = new ArrayList<>(segments);
|
||||
}
|
||||
|
||||
public void addSegment(Segment segment) {
|
||||
segments.add(segment);
|
||||
}
|
||||
|
||||
public List<Segment> getSegments() {
|
||||
return Collections.unmodifiableList(segments);
|
||||
}
|
||||
|
||||
public boolean isZeroBasal() {
|
||||
int total = 0;
|
||||
for (Segment segment : segments) {
|
||||
total += segment.getBasalRateInHundredthUnitsPerHour();
|
||||
}
|
||||
return total == 0;
|
||||
}
|
||||
|
||||
public boolean hasZeroUnitSegments() {
|
||||
for (Segment segment : segments) {
|
||||
if (segment.getBasalRateInHundredthUnitsPerHour() == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static class Segment {
|
||||
private static final byte PULSES_PER_UNIT = 20;
|
||||
|
||||
private final short startSlotIndex;
|
||||
private final short endSlotIndex;
|
||||
private final int basalRateInHundredthUnitsPerHour;
|
||||
|
||||
public Segment(short startSlotIndex, short endSlotIndex, int basalRateInHundredthUnitsPerHour) {
|
||||
this.startSlotIndex = startSlotIndex;
|
||||
this.endSlotIndex = endSlotIndex;
|
||||
this.basalRateInHundredthUnitsPerHour = basalRateInHundredthUnitsPerHour;
|
||||
}
|
||||
|
||||
public short getStartSlotIndex() {
|
||||
return startSlotIndex;
|
||||
}
|
||||
|
||||
public short getEndSlotIndex() {
|
||||
return endSlotIndex;
|
||||
}
|
||||
|
||||
public int getBasalRateInHundredthUnitsPerHour() {
|
||||
return basalRateInHundredthUnitsPerHour;
|
||||
}
|
||||
|
||||
public short getPulsesPerHour() {
|
||||
return (short) (basalRateInHundredthUnitsPerHour * PULSES_PER_UNIT / 100);
|
||||
}
|
||||
|
||||
public short getNumberOfSlots() {
|
||||
return (short) (endSlotIndex - startSlotIndex);
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "Segment{" +
|
||||
"startSlotIndex=" + startSlotIndex +
|
||||
", endSlotIndex=" + endSlotIndex +
|
||||
", basalRateInHundredthUnitsPerHour=" + basalRateInHundredthUnitsPerHour +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "BasalProgram{" +
|
||||
"segments=" + segments +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||
|
||||
import java.util.*
|
||||
|
||||
class BasalProgram(
|
||||
segments: List<Segment>
|
||||
) {
|
||||
|
||||
val segments: MutableList<Segment> = segments.toMutableList()
|
||||
get() = Collections.unmodifiableList(field) // TODO Adrian: moved method here
|
||||
|
||||
fun addSegment(segment: Segment) {
|
||||
segments.add(segment)
|
||||
}
|
||||
|
||||
fun hasZeroUnitSegments() = segments.any { it.basalRateInHundredthUnitsPerHour == 0 }
|
||||
|
||||
fun isZeroBasal() = segments.sumBy(Segment::basalRateInHundredthUnitsPerHour) == 0
|
||||
|
||||
fun rateAt(date: Date): Double = 0.0 // TODO
|
||||
|
||||
class Segment(val startSlotIndex: Short, val endSlotIndex: Short, val basalRateInHundredthUnitsPerHour: Int) {
|
||||
|
||||
fun getPulsesPerHour(): Short {
|
||||
return (basalRateInHundredthUnitsPerHour * PULSES_PER_UNIT / 100).toShort()
|
||||
}
|
||||
|
||||
fun getNumberOfSlots(): Short {
|
||||
return (endSlotIndex - startSlotIndex).toShort()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "Segment{" +
|
||||
"startSlotIndex=" + startSlotIndex +
|
||||
", endSlotIndex=" + endSlotIndex +
|
||||
", basalRateInHundredthUnitsPerHour=" + basalRateInHundredthUnitsPerHour +
|
||||
'}'
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val PULSES_PER_UNIT: Byte = 20
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "BasalProgram{" +
|
||||
"segments=" + segments +
|
||||
'}'
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
||||
|
||||
// FIXME names
|
||||
public enum BeepRepetitionType {
|
||||
XXX((byte) 0x01), // Used in low reservoir alert
|
||||
XXX2((byte) 0x03), // Used in user pod expiration alert
|
||||
XXX3((byte) 0x05), // Used in pod expiration alert
|
||||
XXX4((byte) 0x06), // Used in imminent pod expiration alert
|
||||
XXX5((byte) 0x08); // Used in lump of coal alert
|
||||
|
||||
private byte value;
|
||||
|
||||
BeepRepetitionType(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public byte getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||
|
||||
// FIXME names
|
||||
enum class BeepRepetitionType(
|
||||
val value: Byte
|
||||
) {
|
||||
|
||||
XXX(0x01.toByte()), // Used in lump of coal alert
|
||||
XXX2(0x03.toByte()), // Used in low reservoir alert
|
||||
XXX3(0x05.toByte()), // Used in user pod expiration alert
|
||||
XXX4(0x06.toByte()), // Used in pod expiration alert
|
||||
XXX5(0x08.toByte()); // Used in imminent pod expiration alert
|
||||
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
||||
|
||||
public enum BeepType {
|
||||
SILENT((byte) 0x00),
|
||||
FOUR_TIMES_BIP_BEEP((byte) 0x02), // Used in low reservoir alert, user expiration alert, expiration alert, imminent expiration alert, lump of coal alert
|
||||
LONG_SINGLE_BEEP((byte) 0x06); // Used in stop delivery command
|
||||
|
||||
private byte value;
|
||||
|
||||
BeepType(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public byte getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||
|
||||
enum class BeepType( // Used in stop delivery command
|
||||
val value: Byte
|
||||
) {
|
||||
|
||||
SILENT(0x00.toByte()),
|
||||
FOUR_TIMES_BIP_BEEP(0x02.toByte()), // Used in low reservoir alert, user expiration alert, expiration alert, imminent expiration alert, lump of coal alert
|
||||
LONG_SINGLE_BEEP(0x06.toByte());
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
||||
|
||||
public enum DeliveryStatus {
|
||||
SUSPENDED((byte) 0x00),
|
||||
BASAL_ACTIVE((byte) 0x01),
|
||||
TEMP_BASAL_ACTIVE((byte) 0x02),
|
||||
PRIMING((byte) 0x04),
|
||||
BOLUS_AND_BASAL_ACTIVE((byte) 0x05),
|
||||
BOLUS_AND_TEMP_BASAL_ACTIVE((byte) 0x06),
|
||||
UNKNOWN((byte) 0xff);
|
||||
|
||||
private byte value;
|
||||
|
||||
DeliveryStatus(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static DeliveryStatus byValue(byte value) {
|
||||
for (DeliveryStatus status : values()) {
|
||||
if (status.value == value) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||
|
||||
enum class DeliveryStatus(
|
||||
private val value: Byte
|
||||
) {
|
||||
|
||||
SUSPENDED(0x00.toByte()),
|
||||
BASAL_ACTIVE(0x01.toByte()),
|
||||
TEMP_BASAL_ACTIVE(0x02.toByte()),
|
||||
PRIMING(0x04.toByte()),
|
||||
BOLUS_AND_BASAL_ACTIVE(0x05.toByte()),
|
||||
BOLUS_AND_TEMP_BASAL_ACTIVE(0x06.toByte()),
|
||||
UNKNOWN(0xff.toByte());
|
||||
|
||||
companion object {
|
||||
|
||||
fun byValue(value: Byte): DeliveryStatus {
|
||||
for (status in values()) {
|
||||
if (status.value == value) {
|
||||
return status
|
||||
}
|
||||
}
|
||||
return UNKNOWN
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
||||
|
||||
public interface Encodable {
|
||||
byte[] getEncoded();
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||
|
||||
interface Encodable {
|
||||
|
||||
val encoded: ByteArray
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
||||
|
||||
public enum NakErrorType {
|
||||
FLASH_WRITE((byte) 0x01),
|
||||
FLASH_ERASE((byte) 0x02),
|
||||
FLASH_OPERATION((byte) 0x03),
|
||||
FLASH_ADDR((byte) 0x04),
|
||||
POD_STATE((byte) 0x05),
|
||||
CRITICAL_VARIABLE((byte) 0x06),
|
||||
ILLEGAL_PARAM((byte) 0x07),
|
||||
BOLUS_CRITICAL_VAR((byte) 0x08),
|
||||
INT_ILLEGAL_PARAM((byte) 0x09),
|
||||
ILLEGAL_CHECKSUM((byte) 0x0a),
|
||||
INVALID_MSG_LEN((byte) 0x0b),
|
||||
PUMP_STATE((byte) 0x0c),
|
||||
ILLEGAL_COMMAND((byte) 0x0d),
|
||||
ILLEGAL_FILL_STATE((byte) 0x0e),
|
||||
MAX_READWRITE_SIZE((byte) 0x0f),
|
||||
ILLEGAL_READ_ADDRESS((byte) 0x10),
|
||||
ILLEGAL_READ_MEM_TYPE((byte) 0x11),
|
||||
INIT_POD((byte) 0x12),
|
||||
ILLEGAL_CMD_STATE((byte) 0x13),
|
||||
ILLEGAL_SECURITY_CODE((byte) 0x14),
|
||||
POD_IN_ALARM((byte) 0x15),
|
||||
COMD_NOT_SET((byte) 0x16),
|
||||
ILLEGAL_RX_SENS_VALUE((byte) 0x17),
|
||||
ILLEGAL_TX_PKT_SIZE((byte) 0x18),
|
||||
OCCL_PARAMS_ALREADY_SET((byte) 0x19),
|
||||
OCCL_PARAM((byte) 0x1a),
|
||||
ILLEGAL_CDTHR_VALUE((byte) 0x1b),
|
||||
IGNORE_COMMAND((byte) 0x1c),
|
||||
INVALID_CRC((byte) 0x1d),
|
||||
UNKNOWN((byte) 0xff);
|
||||
|
||||
private byte value;
|
||||
|
||||
NakErrorType(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static NakErrorType byValue(byte value) {
|
||||
for (NakErrorType type : values()) {
|
||||
if (type.value == value) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||
|
||||
enum class NakErrorType(
|
||||
private val value: Byte
|
||||
) {
|
||||
|
||||
FLASH_WRITE(0x01.toByte()),
|
||||
FLASH_ERASE(0x02.toByte()),
|
||||
FLASH_OPERATION(0x03.toByte()),
|
||||
FLASH_ADDR(0x04.toByte()),
|
||||
POD_STATE(0x05.toByte()),
|
||||
CRITICAL_VARIABLE(0x06.toByte()),
|
||||
ILLEGAL_PARAM(0x07.toByte()),
|
||||
BOLUS_CRITICAL_VAR(0x08.toByte()),
|
||||
INT_ILLEGAL_PARAM(0x09.toByte()),
|
||||
ILLEGAL_CHECKSUM(0x0a.toByte()),
|
||||
INVALID_MSG_LEN(0x0b.toByte()),
|
||||
PUMP_STATE(0x0c.toByte()),
|
||||
ILLEGAL_COMMAND(0x0d.toByte()),
|
||||
ILLEGAL_FILL_STATE(0x0e.toByte()),
|
||||
MAX_READWRITE_SIZE(0x0f.toByte()),
|
||||
ILLEGAL_READ_ADDRESS(0x10.toByte()),
|
||||
ILLEGAL_READ_MEM_TYPE(0x11.toByte()),
|
||||
INIT_POD(0x12.toByte()),
|
||||
ILLEGAL_CMD_STATE(0x13.toByte()),
|
||||
ILLEGAL_SECURITY_CODE(0x14.toByte()),
|
||||
POD_IN_ALARM(0x15.toByte()),
|
||||
COMD_NOT_SET(0x16.toByte()),
|
||||
ILLEGAL_RX_SENS_VALUE(0x17.toByte()),
|
||||
ILLEGAL_TX_PKT_SIZE(0x18.toByte()),
|
||||
OCCL_PARAMS_ALREADY_SET(0x19.toByte()),
|
||||
OCCL_PARAM(0x1a.toByte()),
|
||||
ILLEGAL_CDTHR_VALUE(0x1b.toByte()),
|
||||
IGNORE_COMMAND(0x1c.toByte()),
|
||||
INVALID_CRC(0x1d.toByte()),
|
||||
UNKNOWN(0xff.toByte());
|
||||
|
||||
companion object {
|
||||
|
||||
fun byValue(value: Byte): NakErrorType {
|
||||
for (type in values()) {
|
||||
if (type.value == value) {
|
||||
return type
|
||||
}
|
||||
}
|
||||
return UNKNOWN
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
||||
|
||||
public class OmnipodEvent {
|
||||
public enum OmnipodEventType {
|
||||
CONNECTED,
|
||||
ALREADY_CONNECTED,
|
||||
FAILED_TO_CONNECT,
|
||||
DISCONNECTED,
|
||||
COMMAND_SENT,
|
||||
GOT_POD_VERSION,
|
||||
SET_UNIQUE_ID,
|
||||
PRIMED_PUMP,
|
||||
FINISHED_ACTIVATION_1,
|
||||
PROGRAMMED_BASAL,
|
||||
PROGRAMMED_ALERTS,
|
||||
SET_BEEPS,
|
||||
INSERTED_CANNULA,
|
||||
FINISHED_ACTIVATION_2,
|
||||
PROGRAMMED_TEMP_BASAL,
|
||||
STARTED_BOLUS,
|
||||
STOPPED_DELIVERY,
|
||||
SILENCED_ALERTS,
|
||||
DEACTIVATED,
|
||||
COMMAND_SENDING,
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
||||
|
||||
public enum PodStatus {
|
||||
UNINITIALIZED((byte) 0x00),
|
||||
MFG_TEST((byte) 0x01),
|
||||
FILLED((byte) 0x02),
|
||||
UID_SET((byte) 0x03),
|
||||
ENGAGING_CLUTCH_DRIVE((byte) 0x04),
|
||||
CLUTCH_DRIVE_ENGAGED((byte) 0x05),
|
||||
BASAL_PROGRAM_RUNNING((byte) 0x06),
|
||||
PRIMING((byte) 0x07),
|
||||
RUNNING_ABOVE_MIN_VOLUME((byte) 0x08),
|
||||
RUNNING_BELOW_MIN_VOLUME((byte) 0x09),
|
||||
UNUSED_10((byte) 0x0a),
|
||||
UNUSED_11((byte) 0x0b),
|
||||
UNUSED_12((byte) 0x0c),
|
||||
ALARM((byte) 0x0d),
|
||||
LUMP_OF_COAL((byte) 0x0e),
|
||||
DEACTIVATED((byte) 0x0f),
|
||||
UNKNOWN((byte) 0xff);
|
||||
|
||||
private byte value;
|
||||
|
||||
PodStatus(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static PodStatus byValue(byte value) {
|
||||
for (PodStatus status : values()) {
|
||||
if (status.value == value) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||
|
||||
enum class PodStatus(
|
||||
private val value: Byte
|
||||
) {
|
||||
|
||||
UNINITIALIZED(0x00.toByte()),
|
||||
MFG_TEST(0x01.toByte()),
|
||||
FILLED(0x02.toByte()),
|
||||
UID_SET(0x03.toByte()),
|
||||
ENGAGING_CLUTCH_DRIVE(0x04.toByte()),
|
||||
CLUTCH_DRIVE_ENGAGED(0x05.toByte()),
|
||||
BASAL_PROGRAM_SET(0x06.toByte()),
|
||||
PRIMING(0x07.toByte()),
|
||||
RUNNING_ABOVE_MIN_VOLUME(0x08.toByte()),
|
||||
RUNNING_BELOW_MIN_VOLUME(0x09.toByte()),
|
||||
UNUSED_10(0x0a.toByte()),
|
||||
UNUSED_11(0x0b.toByte()),
|
||||
UNUSED_12(0x0c.toByte()),
|
||||
ALARM(0x0d.toByte()),
|
||||
LUMP_OF_COAL(0x0e.toByte()),
|
||||
DEACTIVATED(0x0f.toByte()),
|
||||
UNKNOWN(0xff.toByte());
|
||||
|
||||
companion object {
|
||||
|
||||
fun byValue(value: Byte): PodStatus {
|
||||
for (status in values()) {
|
||||
if (status.value == value) {
|
||||
return status
|
||||
}
|
||||
}
|
||||
return UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
fun isRunning(): Boolean = this == RUNNING_ABOVE_MIN_VOLUME || this == RUNNING_BELOW_MIN_VOLUME
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition;
|
||||
|
||||
public class ProgramReminder implements Encodable {
|
||||
private final boolean atStart;
|
||||
private final boolean atEnd;
|
||||
private final byte atInterval;
|
||||
|
||||
public ProgramReminder(boolean atStart, boolean atEnd, byte atIntervalInMinutes) {
|
||||
this.atStart = atStart;
|
||||
this.atEnd = atEnd;
|
||||
this.atInterval = atIntervalInMinutes;
|
||||
}
|
||||
|
||||
@Override public byte[] getEncoded() {
|
||||
return new byte[]{(byte) (((this.atStart ? 1 : 0) << 7)
|
||||
| ((this.atEnd ? 1 : 0) << 6)
|
||||
| (this.atInterval & 0x3f))};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||
|
||||
import java.io.Serializable
|
||||
import kotlin.experimental.and
|
||||
|
||||
class ProgramReminder(
|
||||
private val atStart: Boolean,
|
||||
private val atEnd: Boolean,
|
||||
private val atInterval: Byte
|
||||
) : Encodable, Serializable {
|
||||
|
||||
override val encoded: ByteArray
|
||||
get() = byteArrayOf(((if (atStart) 1 else 0) shl 7
|
||||
or ((if (atEnd) 1 else 0) shl 6)
|
||||
or ((atInterval and 0x3f).toInt())).toByte())
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
data class SoftwareVersion(
|
||||
private val major: Short,
|
||||
private val minor: Short,
|
||||
private val interim: Short
|
||||
) : Serializable {
|
||||
|
||||
override fun toString(): String {
|
||||
return "$major.$minor.$interim"
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response;
|
||||
|
||||
abstract class ActivationResponseBase extends ResponseBase {
|
||||
final ResponseType.ActivationResponseType activationResponseType;
|
||||
|
||||
ActivationResponseBase(ResponseType.ActivationResponseType activationResponseType, byte[] encoded) {
|
||||
super(ResponseType.ACTIVATION_RESPONSE, encoded);
|
||||
this.activationResponseType = activationResponseType;
|
||||
}
|
||||
|
||||
public ResponseType.ActivationResponseType getActivationResponseType() {
|
||||
return activationResponseType;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.ResponseType.ActivationResponseType
|
||||
|
||||
abstract class ActivationResponseBase(
|
||||
val activationResponseType: ActivationResponseType,
|
||||
encoded: ByteArray
|
||||
) : ResponseBase(ResponseType.ACTIVATION_RESPONSE, encoded)
|
|
@ -1,14 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response;
|
||||
|
||||
public class AdditionalStatusResponseBase extends ResponseBase {
|
||||
final ResponseType.AdditionalStatusResponseType statusResponseType;
|
||||
|
||||
AdditionalStatusResponseBase(ResponseType.AdditionalStatusResponseType statusResponseType, byte[] encoded) {
|
||||
super(ResponseType.ADDITIONAL_STATUS_RESPONSE, encoded);
|
||||
this.statusResponseType = statusResponseType;
|
||||
}
|
||||
|
||||
public ResponseType.AdditionalStatusResponseType getStatusResponseType() {
|
||||
return statusResponseType;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,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
|
||||
|
||||
open class AdditionalStatusResponseBase internal constructor(
|
||||
val statusResponseType: AdditionalStatusResponseType,
|
||||
encoded: ByteArray
|
||||
) : ResponseBase(ResponseType.ADDITIONAL_STATUS_RESPONSE, encoded)
|
|
@ -1,240 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlarmType;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.DeliveryStatus;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus;
|
||||
|
||||
public class AlarmStatusResponse extends AdditionalStatusResponseBase {
|
||||
private final byte messageType;
|
||||
private final short messageLength;
|
||||
private final byte additionalStatusResponseType;
|
||||
private final PodStatus podStatus;
|
||||
private final DeliveryStatus deliveryStatus;
|
||||
private final short bolusPulsesRemaining;
|
||||
private final short sequenceNumberOfLastProgrammingCommand;
|
||||
private final short totalPulsesDelivered;
|
||||
private final AlarmType alarmType;
|
||||
private final short alarmTime;
|
||||
private final short reservoirPulsesRemaining;
|
||||
private final short minutesSinceActivation;
|
||||
private final boolean alert0Active;
|
||||
private final boolean alert1Active;
|
||||
private final boolean alert2Active;
|
||||
private final boolean alert3Active;
|
||||
private final boolean alert4Active;
|
||||
private final boolean alert5Active;
|
||||
private final boolean alert6Active;
|
||||
private final boolean alert7Active;
|
||||
private final boolean occlusionAlarm;
|
||||
private final boolean pulseInfoInvalid;
|
||||
private final PodStatus podStatusWhenAlarmOccurred;
|
||||
private final boolean immediateBolusWhenAlarmOccurred;
|
||||
private final byte occlusionType;
|
||||
private final boolean occurredWhenFetchingImmediateBolusActiveInformation;
|
||||
private final short rssi;
|
||||
private final short receiverLowerGain;
|
||||
private final PodStatus podStatusWhenAlarmOccurred2;
|
||||
private final short returnAddressOfPodAlarmHandlerCaller;
|
||||
|
||||
public AlarmStatusResponse(byte[] encoded) {
|
||||
super(ResponseType.AdditionalStatusResponseType.ALARM_STATUS, encoded);
|
||||
messageType = encoded[0];
|
||||
messageLength = (short) (encoded[1] & 0xff);
|
||||
additionalStatusResponseType = encoded[2];
|
||||
podStatus = PodStatus.byValue((byte) (encoded[3] & 0x0f));
|
||||
deliveryStatus = DeliveryStatus.byValue((byte) (encoded[4] & 0x0f));
|
||||
bolusPulsesRemaining = (short) (ByteBuffer.wrap(new byte[]{encoded[5], encoded[6]}).getShort() & 2047);
|
||||
sequenceNumberOfLastProgrammingCommand = (short) (encoded[7] & 0x0f);
|
||||
totalPulsesDelivered = ByteBuffer.wrap(new byte[]{encoded[8], encoded[9]}).getShort();
|
||||
alarmType = AlarmType.byValue(encoded[10]);
|
||||
alarmTime = ByteBuffer.wrap(new byte[]{encoded[11], encoded[12]}).getShort();
|
||||
reservoirPulsesRemaining = ByteBuffer.wrap(new byte[]{encoded[13], encoded[14]}).getShort();
|
||||
minutesSinceActivation = ByteBuffer.wrap(new byte[]{encoded[15], encoded[16]}).getShort();
|
||||
|
||||
byte activeAlerts = encoded[17];
|
||||
alert0Active = (activeAlerts & 1) == 1;
|
||||
alert1Active = ((activeAlerts >>> 1) & 1) == 1;
|
||||
alert2Active = ((activeAlerts >>> 2) & 1) == 1;
|
||||
alert3Active = ((activeAlerts >>> 3) & 1) == 1;
|
||||
alert4Active = ((activeAlerts >>> 4) & 1) == 1;
|
||||
alert5Active = ((activeAlerts >>> 5) & 1) == 1;
|
||||
alert6Active = ((activeAlerts >>> 6) & 1) == 1;
|
||||
alert7Active = ((activeAlerts >>> 7) & 1) == 1;
|
||||
|
||||
byte alarmFlags = encoded[18];
|
||||
occlusionAlarm = (alarmFlags & 1) == 1;
|
||||
pulseInfoInvalid = ((alarmFlags >> 1) & 1) == 1;
|
||||
|
||||
byte byte19 = encoded[19];
|
||||
byte byte20 = encoded[20];
|
||||
podStatusWhenAlarmOccurred = PodStatus.byValue((byte) (byte19 & 0x0f));
|
||||
immediateBolusWhenAlarmOccurred = ((byte19 >> 4) & 1) == 1;
|
||||
occlusionType = (byte) ((byte19 >> 5) & 3);
|
||||
occurredWhenFetchingImmediateBolusActiveInformation = ((byte19 >> 7) & 1) == 1;
|
||||
rssi = (short) (byte20 & 0x3f);
|
||||
receiverLowerGain = (short) ((byte20 >> 6) & 0x03);
|
||||
podStatusWhenAlarmOccurred2 = PodStatus.byValue((byte) (encoded[21] & 0x0f));
|
||||
returnAddressOfPodAlarmHandlerCaller = ByteBuffer.wrap(new byte[]{encoded[22], encoded[23]}).getShort();
|
||||
}
|
||||
|
||||
public byte getMessageType() {
|
||||
return messageType;
|
||||
}
|
||||
|
||||
public short getMessageLength() {
|
||||
return messageLength;
|
||||
}
|
||||
|
||||
public byte getAdditionalStatusResponseType() {
|
||||
return additionalStatusResponseType;
|
||||
}
|
||||
|
||||
public PodStatus getPodStatus() {
|
||||
return podStatus;
|
||||
}
|
||||
|
||||
public DeliveryStatus getDeliveryStatus() {
|
||||
return deliveryStatus;
|
||||
}
|
||||
|
||||
public short getBolusPulsesRemaining() {
|
||||
return bolusPulsesRemaining;
|
||||
}
|
||||
|
||||
public short getSequenceNumberOfLastProgrammingCommand() {
|
||||
return sequenceNumberOfLastProgrammingCommand;
|
||||
}
|
||||
|
||||
public short getTotalPulsesDelivered() {
|
||||
return totalPulsesDelivered;
|
||||
}
|
||||
|
||||
public AlarmType getAlarmType() {
|
||||
return alarmType;
|
||||
}
|
||||
|
||||
public short getAlarmTime() {
|
||||
return alarmTime;
|
||||
}
|
||||
|
||||
public short getReservoirPulsesRemaining() {
|
||||
return reservoirPulsesRemaining;
|
||||
}
|
||||
|
||||
public short getMinutesSinceActivation() {
|
||||
return minutesSinceActivation;
|
||||
}
|
||||
|
||||
public boolean isAlert0Active() {
|
||||
return alert0Active;
|
||||
}
|
||||
|
||||
public boolean isAlert1Active() {
|
||||
return alert1Active;
|
||||
}
|
||||
|
||||
public boolean isAlert2Active() {
|
||||
return alert2Active;
|
||||
}
|
||||
|
||||
public boolean isAlert3Active() {
|
||||
return alert3Active;
|
||||
}
|
||||
|
||||
public boolean isAlert4Active() {
|
||||
return alert4Active;
|
||||
}
|
||||
|
||||
public boolean isAlert5Active() {
|
||||
return alert5Active;
|
||||
}
|
||||
|
||||
public boolean isAlert6Active() {
|
||||
return alert6Active;
|
||||
}
|
||||
|
||||
public boolean isAlert7Active() {
|
||||
return alert7Active;
|
||||
}
|
||||
|
||||
public boolean isOcclusionAlarm() {
|
||||
return occlusionAlarm;
|
||||
}
|
||||
|
||||
public boolean isPulseInfoInvalid() {
|
||||
return pulseInfoInvalid;
|
||||
}
|
||||
|
||||
public PodStatus getPodStatusWhenAlarmOccurred() {
|
||||
return podStatusWhenAlarmOccurred;
|
||||
}
|
||||
|
||||
public boolean isImmediateBolusWhenAlarmOccurred() {
|
||||
return immediateBolusWhenAlarmOccurred;
|
||||
}
|
||||
|
||||
public byte getOcclusionType() {
|
||||
return occlusionType;
|
||||
}
|
||||
|
||||
public boolean isOccurredWhenFetchingImmediateBolusActiveInformation() {
|
||||
return occurredWhenFetchingImmediateBolusActiveInformation;
|
||||
}
|
||||
|
||||
public short getRssi() {
|
||||
return rssi;
|
||||
}
|
||||
|
||||
public short getReceiverLowerGain() {
|
||||
return receiverLowerGain;
|
||||
}
|
||||
|
||||
public PodStatus getPodStatusWhenAlarmOccurred2() {
|
||||
return podStatusWhenAlarmOccurred2;
|
||||
}
|
||||
|
||||
public short getReturnAddressOfPodAlarmHandlerCaller() {
|
||||
return returnAddressOfPodAlarmHandlerCaller;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "AlarmStatusResponse{" +
|
||||
"messageType=" + messageType +
|
||||
", messageLength=" + messageLength +
|
||||
", additionalStatusResponseType=" + additionalStatusResponseType +
|
||||
", podStatus=" + podStatus +
|
||||
", deliveryStatus=" + deliveryStatus +
|
||||
", bolusPulsesRemaining=" + bolusPulsesRemaining +
|
||||
", sequenceNumberOfLastProgrammingCommand=" + sequenceNumberOfLastProgrammingCommand +
|
||||
", totalPulsesDelivered=" + totalPulsesDelivered +
|
||||
", alarmType=" + alarmType +
|
||||
", alarmTime=" + alarmTime +
|
||||
", reservoirPulsesRemaining=" + reservoirPulsesRemaining +
|
||||
", minutesSinceActivation=" + minutesSinceActivation +
|
||||
", alert0Active=" + alert0Active +
|
||||
", alert1Active=" + alert1Active +
|
||||
", alert2Active=" + alert2Active +
|
||||
", alert3Active=" + alert3Active +
|
||||
", alert4Active=" + alert4Active +
|
||||
", alert5Active=" + alert5Active +
|
||||
", alert6Active=" + alert6Active +
|
||||
", alert7Active=" + alert7Active +
|
||||
", occlusionAlarm=" + occlusionAlarm +
|
||||
", pulseInfoInvalid=" + pulseInfoInvalid +
|
||||
", podStatusWhenAlarmOccurred=" + podStatusWhenAlarmOccurred +
|
||||
", immediateBolusWhenAlarmOccurred=" + immediateBolusWhenAlarmOccurred +
|
||||
", occlusionType=" + occlusionType +
|
||||
", occurredWhenFetchingImmediateBolusActiveInformation=" + occurredWhenFetchingImmediateBolusActiveInformation +
|
||||
", rssi=" + rssi +
|
||||
", receiverLowerGain=" + receiverLowerGain +
|
||||
", podStatusWhenAlarmOccurred2=" + podStatusWhenAlarmOccurred2 +
|
||||
", returnAddressOfPodAlarmHandlerCaller=" + returnAddressOfPodAlarmHandlerCaller +
|
||||
", statusResponseType=" + statusResponseType +
|
||||
", responseType=" + responseType +
|
||||
", encoded=" + Arrays.toString(encoded) +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,248 @@
|
|||
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 java.nio.ByteBuffer
|
||||
import java.util.*
|
||||
import kotlin.experimental.and
|
||||
|
||||
class AlarmStatusResponse(
|
||||
encoded: ByteArray
|
||||
) : AdditionalStatusResponseBase(AdditionalStatusResponseType.ALARM_STATUS, encoded) {
|
||||
|
||||
private val messageType: Byte
|
||||
private val messageLength: Short
|
||||
private val additionalStatusResponseType: Byte
|
||||
private val podStatus: PodStatus
|
||||
private val deliveryStatus: DeliveryStatus
|
||||
private val bolusPulsesRemaining: Short
|
||||
private val sequenceNumberOfLastProgrammingCommand: Short
|
||||
private val totalPulsesDelivered: Short
|
||||
private val alarmType: AlarmType
|
||||
private val alarmTime: Short
|
||||
private val reservoirPulsesRemaining: Short
|
||||
private val minutesSinceActivation: Short
|
||||
private val alert0Active: Boolean
|
||||
private val alert1Active: Boolean
|
||||
private val alert2Active: Boolean
|
||||
private val alert3Active: Boolean
|
||||
private val alert4Active: Boolean
|
||||
private val alert5Active: Boolean
|
||||
private val alert6Active: Boolean
|
||||
private val alert7Active: Boolean
|
||||
private val occlusionAlarm: Boolean
|
||||
private val pulseInfoInvalid: Boolean
|
||||
private val podStatusWhenAlarmOccurred: PodStatus
|
||||
private val immediateBolusWhenAlarmOccurred: Boolean
|
||||
private val occlusionType: Byte
|
||||
private val occurredWhenFetchingImmediateBolusActiveInformation: Boolean
|
||||
private val rssi: Short
|
||||
private val receiverLowerGain: Short
|
||||
private val podStatusWhenAlarmOccurred2: PodStatus
|
||||
private val returnAddressOfPodAlarmHandlerCaller: Short
|
||||
|
||||
fun getMessageType(): Byte {
|
||||
return messageType
|
||||
}
|
||||
|
||||
fun getMessageLength(): Short {
|
||||
return messageLength
|
||||
}
|
||||
|
||||
fun getAdditionalStatusResponseType(): Byte {
|
||||
return additionalStatusResponseType
|
||||
}
|
||||
|
||||
fun getPodStatus(): PodStatus {
|
||||
return podStatus
|
||||
}
|
||||
|
||||
fun getDeliveryStatus(): DeliveryStatus {
|
||||
return deliveryStatus
|
||||
}
|
||||
|
||||
fun getBolusPulsesRemaining(): Short {
|
||||
return bolusPulsesRemaining
|
||||
}
|
||||
|
||||
fun getSequenceNumberOfLastProgrammingCommand(): Short {
|
||||
return sequenceNumberOfLastProgrammingCommand
|
||||
}
|
||||
|
||||
fun getTotalPulsesDelivered(): Short {
|
||||
return totalPulsesDelivered
|
||||
}
|
||||
|
||||
fun getAlarmType(): AlarmType {
|
||||
return alarmType
|
||||
}
|
||||
|
||||
fun getAlarmTime(): Short {
|
||||
return alarmTime
|
||||
}
|
||||
|
||||
fun getReservoirPulsesRemaining(): Short {
|
||||
return reservoirPulsesRemaining
|
||||
}
|
||||
|
||||
fun getMinutesSinceActivation(): Short {
|
||||
return minutesSinceActivation
|
||||
}
|
||||
|
||||
fun isAlert0Active(): Boolean {
|
||||
return alert0Active
|
||||
}
|
||||
|
||||
fun isAlert1Active(): Boolean {
|
||||
return alert1Active
|
||||
}
|
||||
|
||||
fun isAlert2Active(): Boolean {
|
||||
return alert2Active
|
||||
}
|
||||
|
||||
fun isAlert3Active(): Boolean {
|
||||
return alert3Active
|
||||
}
|
||||
|
||||
fun isAlert4Active(): Boolean {
|
||||
return alert4Active
|
||||
}
|
||||
|
||||
fun isAlert5Active(): Boolean {
|
||||
return alert5Active
|
||||
}
|
||||
|
||||
fun isAlert6Active(): Boolean {
|
||||
return alert6Active
|
||||
}
|
||||
|
||||
fun isAlert7Active(): Boolean {
|
||||
return alert7Active
|
||||
}
|
||||
|
||||
fun isOcclusionAlarm(): Boolean {
|
||||
return occlusionAlarm
|
||||
}
|
||||
|
||||
fun isPulseInfoInvalid(): Boolean {
|
||||
return pulseInfoInvalid
|
||||
}
|
||||
|
||||
fun getPodStatusWhenAlarmOccurred(): PodStatus {
|
||||
return podStatusWhenAlarmOccurred
|
||||
}
|
||||
|
||||
fun isImmediateBolusWhenAlarmOccurred(): Boolean {
|
||||
return immediateBolusWhenAlarmOccurred
|
||||
}
|
||||
|
||||
fun getOcclusionType(): Byte {
|
||||
return occlusionType
|
||||
}
|
||||
|
||||
fun isOccurredWhenFetchingImmediateBolusActiveInformation(): Boolean {
|
||||
return occurredWhenFetchingImmediateBolusActiveInformation
|
||||
}
|
||||
|
||||
fun getRssi(): Short {
|
||||
return rssi
|
||||
}
|
||||
|
||||
fun getReceiverLowerGain(): Short {
|
||||
return receiverLowerGain
|
||||
}
|
||||
|
||||
fun getPodStatusWhenAlarmOccurred2(): PodStatus {
|
||||
return podStatusWhenAlarmOccurred2
|
||||
}
|
||||
|
||||
fun getReturnAddressOfPodAlarmHandlerCaller(): Short {
|
||||
return returnAddressOfPodAlarmHandlerCaller
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "AlarmStatusResponse{" +
|
||||
"messageType=" + messageType +
|
||||
", messageLength=" + messageLength +
|
||||
", additionalStatusResponseType=" + additionalStatusResponseType +
|
||||
", podStatus=" + podStatus +
|
||||
", deliveryStatus=" + deliveryStatus +
|
||||
", bolusPulsesRemaining=" + bolusPulsesRemaining +
|
||||
", sequenceNumberOfLastProgrammingCommand=" + sequenceNumberOfLastProgrammingCommand +
|
||||
", totalPulsesDelivered=" + totalPulsesDelivered +
|
||||
", alarmType=" + alarmType +
|
||||
", alarmTime=" + alarmTime +
|
||||
", reservoirPulsesRemaining=" + reservoirPulsesRemaining +
|
||||
", minutesSinceActivation=" + minutesSinceActivation +
|
||||
", alert0Active=" + alert0Active +
|
||||
", alert1Active=" + alert1Active +
|
||||
", alert2Active=" + alert2Active +
|
||||
", alert3Active=" + alert3Active +
|
||||
", alert4Active=" + alert4Active +
|
||||
", alert5Active=" + alert5Active +
|
||||
", alert6Active=" + alert6Active +
|
||||
", alert7Active=" + alert7Active +
|
||||
", occlusionAlarm=" + occlusionAlarm +
|
||||
", pulseInfoInvalid=" + pulseInfoInvalid +
|
||||
", podStatusWhenAlarmOccurred=" + podStatusWhenAlarmOccurred +
|
||||
", immediateBolusWhenAlarmOccurred=" + immediateBolusWhenAlarmOccurred +
|
||||
", occlusionType=" + occlusionType +
|
||||
", occurredWhenFetchingImmediateBolusActiveInformation=" + occurredWhenFetchingImmediateBolusActiveInformation +
|
||||
", rssi=" + rssi +
|
||||
", receiverLowerGain=" + receiverLowerGain +
|
||||
", podStatusWhenAlarmOccurred2=" + podStatusWhenAlarmOccurred2 +
|
||||
", returnAddressOfPodAlarmHandlerCaller=" + returnAddressOfPodAlarmHandlerCaller +
|
||||
", statusResponseType=" + statusResponseType +
|
||||
", responseType=" + responseType +
|
||||
", encoded=" + Arrays.toString(encoded) +
|
||||
'}'
|
||||
}
|
||||
|
||||
init {
|
||||
messageType = encoded[0]
|
||||
messageLength = (encoded[1].toInt() and 0xff).toShort()
|
||||
additionalStatusResponseType = encoded[2]
|
||||
podStatus = PodStatus.byValue((encoded[3] and 0x0f))
|
||||
deliveryStatus = DeliveryStatus.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
|
||||
|
||||
}
|
||||
|
|
@ -1,136 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.DeliveryStatus;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus;
|
||||
|
||||
public class DefaultStatusResponse extends ResponseBase {
|
||||
private final byte messageType;
|
||||
private final DeliveryStatus deliveryStatus;
|
||||
private final PodStatus podStatus;
|
||||
private final short totalPulsesDelivered;
|
||||
private final short sequenceNumberOfLastProgrammingCommand;
|
||||
private final short bolusPulsesRemaining;
|
||||
private final boolean occlusionAlertActive;
|
||||
private final boolean alert1Active;
|
||||
private final boolean alert2Active;
|
||||
private final boolean alert3Active;
|
||||
private final boolean alert4Active;
|
||||
private final boolean alert5Active;
|
||||
private final boolean alert6Active;
|
||||
private final boolean alert7Active;
|
||||
private final short minutesSinceActivation;
|
||||
private final short reservoirPulsesRemaining;
|
||||
|
||||
public DefaultStatusResponse(byte[] encoded) {
|
||||
super(ResponseType.DEFAULT_STATUS_RESPONSE, encoded);
|
||||
|
||||
messageType = encoded[0];
|
||||
deliveryStatus = DeliveryStatus.byValue((byte) ((encoded[1] >> 4) & 0x0f));
|
||||
podStatus = PodStatus.byValue((byte) (encoded[1] & 0x0f));
|
||||
totalPulsesDelivered = (short) (((encoded[2] & 0x0f) << 12) | ((encoded[3] & 0xff) << 1) | ((encoded[4] & 0xff) >>> 7));
|
||||
sequenceNumberOfLastProgrammingCommand = (byte) ((encoded[4] >>> 3) & 0x0f);
|
||||
bolusPulsesRemaining = (short) ((((encoded[4] & 0x07) << 10) | (encoded[5] & 0xff)) & 2047);
|
||||
|
||||
short activeAlerts = (short) (((encoded[6] & 0xff) << 1) | (encoded[7] >>> 7));
|
||||
occlusionAlertActive = (activeAlerts & 1) == 1;
|
||||
alert1Active = ((activeAlerts >> 1) & 1) == 1;
|
||||
alert2Active = ((activeAlerts >> 2) & 1) == 1;
|
||||
alert3Active = ((activeAlerts >> 3) & 1) == 1;
|
||||
alert4Active = ((activeAlerts >> 4) & 1) == 1;
|
||||
alert5Active = ((activeAlerts >> 5) & 1) == 1;
|
||||
alert6Active = ((activeAlerts >> 6) & 1) == 1;
|
||||
alert7Active = ((activeAlerts >> 7) & 1) == 1;
|
||||
|
||||
minutesSinceActivation = (short) (((encoded[7] & 0x7f) << 6) | (((encoded[8] & 0xff) >>> 2) & 0x3f));
|
||||
reservoirPulsesRemaining = (short) (((encoded[8] << 8) | encoded[9]) & 0x3ff);
|
||||
}
|
||||
|
||||
public byte getMessageType() {
|
||||
return messageType;
|
||||
}
|
||||
|
||||
public DeliveryStatus getDeliveryStatus() {
|
||||
return deliveryStatus;
|
||||
}
|
||||
|
||||
public PodStatus getPodStatus() {
|
||||
return podStatus;
|
||||
}
|
||||
|
||||
public short getTotalPulsesDelivered() {
|
||||
return totalPulsesDelivered;
|
||||
}
|
||||
|
||||
public short getSequenceNumberOfLastProgrammingCommand() {
|
||||
return sequenceNumberOfLastProgrammingCommand;
|
||||
}
|
||||
|
||||
public short getBolusPulsesRemaining() {
|
||||
return bolusPulsesRemaining;
|
||||
}
|
||||
|
||||
public boolean isOcclusionAlertActive() {
|
||||
return occlusionAlertActive;
|
||||
}
|
||||
|
||||
public boolean isAlert1Active() {
|
||||
return alert1Active;
|
||||
}
|
||||
|
||||
public boolean isAlert2Active() {
|
||||
return alert2Active;
|
||||
}
|
||||
|
||||
public boolean isAlert3Active() {
|
||||
return alert3Active;
|
||||
}
|
||||
|
||||
public boolean isAlert4Active() {
|
||||
return alert4Active;
|
||||
}
|
||||
|
||||
public boolean isAlert5Active() {
|
||||
return alert5Active;
|
||||
}
|
||||
|
||||
public boolean isAlert6Active() {
|
||||
return alert6Active;
|
||||
}
|
||||
|
||||
public boolean isAlert7Active() {
|
||||
return alert7Active;
|
||||
}
|
||||
|
||||
public short getMinutesSinceActivation() {
|
||||
return minutesSinceActivation;
|
||||
}
|
||||
|
||||
public short getReservoirPulsesRemaining() {
|
||||
return reservoirPulsesRemaining;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "DefaultStatusResponse{" +
|
||||
"messageType=" + messageType +
|
||||
", deliveryStatus=" + deliveryStatus +
|
||||
", podStatus=" + podStatus +
|
||||
", totalPulsesDelivered=" + totalPulsesDelivered +
|
||||
", sequenceNumberOfLastProgrammingCommand=" + sequenceNumberOfLastProgrammingCommand +
|
||||
", bolusPulsesRemaining=" + bolusPulsesRemaining +
|
||||
", occlusionAlertActive=" + occlusionAlertActive +
|
||||
", alert1Active=" + alert1Active +
|
||||
", alert2Active=" + alert2Active +
|
||||
", alert3Active=" + alert3Active +
|
||||
", alert4Active=" + alert4Active +
|
||||
", alert5Active=" + alert5Active +
|
||||
", alert6Active=" + alert6Active +
|
||||
", alert7Active=" + alert7Active +
|
||||
", minutesSinceActivation=" + minutesSinceActivation +
|
||||
", reservoirPulsesRemaining=" + reservoirPulsesRemaining +
|
||||
", responseType=" + responseType +
|
||||
", encoded=" + Arrays.toString(encoded) +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.DeliveryStatus
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus
|
||||
import kotlin.experimental.and
|
||||
|
||||
class DefaultStatusResponse(
|
||||
encoded: ByteArray
|
||||
) : ResponseBase(ResponseType.DEFAULT_STATUS_RESPONSE, encoded) {
|
||||
|
||||
// TODO: Here is a lot of bitshifting that had to be changed. we should go over it.
|
||||
private val messageType: Byte = encoded[0]
|
||||
private val deliveryStatus: DeliveryStatus = DeliveryStatus.byValue((encoded[1].toInt() shr 4 and 0x0f).toByte())
|
||||
private val podStatus: PodStatus = PodStatus.byValue((encoded[1] and 0x0f) as Byte)
|
||||
private val totalPulsesDelivered: Short = ((encoded[2] and 0x0f shl 12 or (encoded[3].toInt() and 0xff shl 1) or (encoded[4].toInt() and 0xff ushr 7)).toShort())
|
||||
private val sequenceNumberOfLastProgrammingCommand: Short = (encoded[4] ushr 3 and 0x0f).toShort()
|
||||
private val bolusPulsesRemaining: Short = ((encoded[4] and 0x07 shl 10 or (encoded[5].toInt() and 0xff) and 2047).toShort())
|
||||
private val activeAlerts = (encoded[6].toInt() and 0xff shl 1 or (encoded[7] ushr 7)).toShort()
|
||||
private val occlusionAlertActive: Boolean = (activeAlerts and 1).toInt() == 1
|
||||
private val alert1Active: Boolean = activeAlerts shr 1 and 1 == 1
|
||||
private val alert2Active: Boolean = activeAlerts shr 2 and 1 == 1
|
||||
private val alert3Active: Boolean = activeAlerts shr 3 and 1 == 1
|
||||
private val alert4Active: Boolean = activeAlerts shr 4 and 1 == 1
|
||||
private val alert5Active: Boolean = activeAlerts shr 5 and 1 == 1
|
||||
private val alert6Active: Boolean = activeAlerts shr 6 and 1 == 1
|
||||
private val alert7Active: Boolean = activeAlerts shr 7 and 1 == 1
|
||||
private val minutesSinceActivation: Short = (encoded[7] and 0x7f shl 6 or (encoded[8].toInt() and 0xff ushr 2 and 0x3f)).toShort()
|
||||
private val reservoirPulsesRemaining: Short = (encoded[8] shl 8 or encoded[9].toInt() and 0x3ff).toShort()
|
||||
fun getMessageType(): Byte {
|
||||
return messageType
|
||||
}
|
||||
|
||||
fun getDeliveryStatus(): DeliveryStatus {
|
||||
return deliveryStatus
|
||||
}
|
||||
|
||||
fun getPodStatus(): PodStatus {
|
||||
return podStatus
|
||||
}
|
||||
|
||||
fun getTotalPulsesDelivered(): Short {
|
||||
return totalPulsesDelivered
|
||||
}
|
||||
|
||||
fun getSequenceNumberOfLastProgrammingCommand(): Short {
|
||||
return sequenceNumberOfLastProgrammingCommand
|
||||
}
|
||||
|
||||
fun getBolusPulsesRemaining(): Short {
|
||||
return bolusPulsesRemaining
|
||||
}
|
||||
|
||||
fun isOcclusionAlertActive(): Boolean {
|
||||
return occlusionAlertActive
|
||||
}
|
||||
|
||||
fun isAlert1Active(): Boolean {
|
||||
return alert1Active
|
||||
}
|
||||
|
||||
fun isAlert2Active(): Boolean {
|
||||
return alert2Active
|
||||
}
|
||||
|
||||
fun isAlert3Active(): Boolean {
|
||||
return alert3Active
|
||||
}
|
||||
|
||||
fun isAlert4Active(): Boolean {
|
||||
return alert4Active
|
||||
}
|
||||
|
||||
fun isAlert5Active(): Boolean {
|
||||
return alert5Active
|
||||
}
|
||||
|
||||
fun isAlert6Active(): Boolean {
|
||||
return alert6Active
|
||||
}
|
||||
|
||||
fun isAlert7Active(): Boolean {
|
||||
return alert7Active
|
||||
}
|
||||
|
||||
fun getMinutesSinceActivation(): Short {
|
||||
return minutesSinceActivation
|
||||
}
|
||||
|
||||
fun getReservoirPulsesRemaining(): Short {
|
||||
return reservoirPulsesRemaining
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "DefaultStatusResponse{" +
|
||||
"messageType=" + messageType +
|
||||
", deliveryStatus=" + deliveryStatus +
|
||||
", podStatus=" + podStatus +
|
||||
", totalPulsesDelivered=" + totalPulsesDelivered +
|
||||
", sequenceNumberOfLastProgrammingCommand=" + sequenceNumberOfLastProgrammingCommand +
|
||||
", bolusPulsesRemaining=" + bolusPulsesRemaining +
|
||||
", occlusionAlertActive=" + occlusionAlertActive +
|
||||
", alert1Active=" + alert1Active +
|
||||
", alert2Active=" + alert2Active +
|
||||
", alert3Active=" + alert3Active +
|
||||
", alert4Active=" + alert4Active +
|
||||
", alert5Active=" + alert5Active +
|
||||
", alert6Active=" + alert6Active +
|
||||
", alert7Active=" + alert7Active +
|
||||
", minutesSinceActivation=" + minutesSinceActivation +
|
||||
", reservoirPulsesRemaining=" + reservoirPulsesRemaining +
|
||||
", responseType=" + responseType +
|
||||
", encoded=" + encoded.contentToString() +
|
||||
'}'
|
||||
}
|
||||
}
|
||||
|
||||
//TODO autoconvert to Int ok?
|
||||
private infix fun Byte.ushr(i: Int) = toInt() ushr i
|
||||
private infix fun Short.shr(i: Int): Int = toInt() shr i
|
||||
private infix fun Byte.shl(i: Int): Int = toInt() shl i
|
|
@ -1,71 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlarmType;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.NakErrorType;
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus;
|
||||
|
||||
public class NakResponse extends ResponseBase {
|
||||
private final byte messageType;
|
||||
private final short messageLength;
|
||||
private final NakErrorType nakErrorType;
|
||||
private final AlarmType alarmType;
|
||||
private final PodStatus podStatus;
|
||||
private final short securityNakSyncCount;
|
||||
|
||||
public NakResponse(byte[] encoded) {
|
||||
super(ResponseType.NAK_RESPONSE, encoded);
|
||||
this.messageType = encoded[0];
|
||||
this.messageLength = encoded[1];
|
||||
this.nakErrorType = NakErrorType.byValue(encoded[2]);
|
||||
byte byte3 = encoded[3];
|
||||
byte byte4 = encoded[4];
|
||||
if (nakErrorType == NakErrorType.ILLEGAL_SECURITY_CODE) {
|
||||
this.securityNakSyncCount = (short) ((byte3 << 8) | byte4);
|
||||
this.alarmType = null;
|
||||
this.podStatus = null;
|
||||
} else {
|
||||
this.securityNakSyncCount = 0;
|
||||
this.alarmType = AlarmType.byValue(byte3);
|
||||
this.podStatus = PodStatus.byValue(byte4);
|
||||
}
|
||||
}
|
||||
|
||||
public byte getMessageType() {
|
||||
return messageType;
|
||||
}
|
||||
|
||||
public short getMessageLength() {
|
||||
return messageLength;
|
||||
}
|
||||
|
||||
public NakErrorType getNakErrorType() {
|
||||
return nakErrorType;
|
||||
}
|
||||
|
||||
public AlarmType getAlarmType() {
|
||||
return alarmType;
|
||||
}
|
||||
|
||||
public PodStatus getPodStatus() {
|
||||
return podStatus;
|
||||
}
|
||||
|
||||
public short getSecurityNakSyncCount() {
|
||||
return securityNakSyncCount;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "NakResponse{" +
|
||||
"messageType=" + messageType +
|
||||
", messageLength=" + messageLength +
|
||||
", nakErrorType=" + nakErrorType +
|
||||
", alarmType=" + alarmType +
|
||||
", podStatus=" + podStatus +
|
||||
", securityNakSyncCount=" + securityNakSyncCount +
|
||||
", responseType=" + responseType +
|
||||
", encoded=" + Arrays.toString(encoded) +
|
||||
'}';
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue