Merge pull request #9 from AAPS-Omnipod/omnipod_eros_dev_properly_decode_pod_info_02

Properly decode Pod info response type 02 + pairing fixes for Activation Time Exceeded errors
This commit is contained in:
bartsopers 2020-10-17 20:43:25 +02:00 committed by GitHub
commit f3ec652893
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 774 additions and 567 deletions

View file

@ -30,6 +30,7 @@ import info.nightscout.androidaps.plugins.profile.local.LocalProfileFragment
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
import info.nightscout.androidaps.plugins.profile.ns.NSProfileFragment import info.nightscout.androidaps.plugins.profile.ns.NSProfileFragment
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin
import info.nightscout.androidaps.plugins.pump.common.events.EventRileyLinkDeviceStatusChange
import info.nightscout.androidaps.plugins.pump.omnipod.OmnipodPumpPlugin import info.nightscout.androidaps.plugins.pump.omnipod.OmnipodPumpPlugin
import info.nightscout.androidaps.setupwizard.elements.* import info.nightscout.androidaps.setupwizard.elements.*
import info.nightscout.androidaps.setupwizard.events.EventSWUpdate import info.nightscout.androidaps.setupwizard.events.EventSWUpdate
@ -324,6 +325,12 @@ class SWDefinition @Inject constructor(
val activePump = activePlugin.activePump val activePump = activePlugin.activePump
activePump is OmnipodPumpPlugin && !activePump.isRileyLinkReady activePump is OmnipodPumpPlugin && !activePump.isRileyLinkReady
})) }))
.add( // Omnipod only
SWEventListener(injector, EventRileyLinkDeviceStatusChange::class.java)
.label(R.string.setupwizard_pump_riley_link_status)
.visibility(SWValidator {
activePlugin.activePump is OmnipodPumpPlugin
}))
.add(SWButton(injector) .add(SWButton(injector)
.text(R.string.readstatus) .text(R.string.readstatus)
.action(Runnable { commandQueue.readStatus("Clicked connect to pump", null) }) .action(Runnable { commandQueue.readStatus("Clicked connect to pump", null) })
@ -332,7 +339,8 @@ class SWDefinition @Inject constructor(
// Getting the status might not be possible // Getting the status might not be possible
activePlugin.activePump !is OmnipodPumpPlugin activePlugin.activePump !is OmnipodPumpPlugin
})) }))
.add(SWEventListener(injector, EventPumpStatusChanged::class.java)) .add(SWEventListener(injector, EventPumpStatusChanged::class.java)
.visibility(SWValidator { activePlugin.activePump !is OmnipodPumpPlugin }))
.validator(SWValidator { .validator(SWValidator {
isPumpInitialized() isPumpInitialized()
}) })

View file

@ -11,7 +11,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
class SWEventListener constructor( class SWEventListener constructor(
injector:HasAndroidInjector, injector: HasAndroidInjector,
clazz: Class<out EventStatus> clazz: Class<out EventStatus>
) : SWItem(injector, Type.LISTENER) { ) : SWItem(injector, Type.LISTENER) {
@ -19,6 +19,7 @@ class SWEventListener constructor(
private var textLabel = 0 private var textLabel = 0
private var status = "" private var status = ""
private var textView: TextView? = null private var textView: TextView? = null
private var visibilityValidator: SWValidator? = null
// TODO: Adrian how to clear disposable in this case? // TODO: Adrian how to clear disposable in this case?
init { init {
@ -43,6 +44,11 @@ class SWEventListener constructor(
return this return this
} }
fun visibility(visibilityValidator: SWValidator): SWEventListener {
this.visibilityValidator = visibilityValidator
return this
}
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun generateDialog(layout: LinearLayout) { override fun generateDialog(layout: LinearLayout) {
val context = layout.context val context = layout.context
@ -51,4 +57,8 @@ class SWEventListener constructor(
textView?.text = (if (textLabel != 0) resourceHelper.gs(textLabel) else "") + " " + status textView?.text = (if (textLabel != 0) resourceHelper.gs(textLabel) else "") + " " + status
layout.addView(textView) layout.addView(textView)
} }
override fun processVisibility() {
if (visibilityValidator != null && !visibilityValidator!!.isValid) textView?.visibility = View.GONE else textView?.visibility = View.VISIBLE
}
} }

View file

@ -1443,4 +1443,5 @@
<string name="worker_state">Worker State: %s</string> <string name="worker_state">Worker State: %s</string>
<string name="uploaded_data">Uploaded Data</string> <string name="uploaded_data">Uploaded Data</string>
<string name="the_following_data_will_be_uploaded_to_your_open_humans_account">The following data will be uploaded to your Open Humans account: Glucose values, boluses, carbs, careportal events (except notes), extended boluses, profile switches, total daily doses, temporary basals, temp targets, preferences, application version, device model and screen dimensions. Secret or private information such as your Nightscout URL or API secret will not be uploaded.</string> <string name="the_following_data_will_be_uploaded_to_your_open_humans_account">The following data will be uploaded to your Open Humans account: Glucose values, boluses, carbs, careportal events (except notes), extended boluses, profile switches, total daily doses, temporary basals, temp targets, preferences, application version, device model and screen dimensions. Secret or private information such as your Nightscout URL or API secret will not be uploaded.</string>
<string name="setupwizard_pump_riley_link_status">RileyLink status:</string>
</resources> </resources>

View file

@ -72,6 +72,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.definition.OmnipodCustomA
import info.nightscout.androidaps.plugins.pump.omnipod.definition.OmnipodStorageKeys; import info.nightscout.androidaps.plugins.pump.omnipod.definition.OmnipodStorageKeys;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.action.service.ExpirationReminderBuilder; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.action.service.ExpirationReminderBuilder;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoRecentPulseLog; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoRecentPulseLog;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.ActivationProgress;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.AlertConfiguration; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.AlertConfiguration;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager; import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager;
@ -254,6 +255,13 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface,
// When PodStateManager is created, which causes an IllegalArgumentException for DateTimeZones not being recognized // When PodStateManager is created, which causes an IllegalArgumentException for DateTimeZones not being recognized
podStateManager.loadPodState(); podStateManager.loadPodState();
// BS @ 2020-10-17 FIXME: for backwards compatibility; remove before release
if (podStateManager.isPodInitialized() &&
podStateManager.getActivationProgress() == ActivationProgress.NONE &&
podStateManager.getPodProgressStatus().isAtLeast(PodProgressStatus.ABOVE_FIFTY_UNITS)) {
podStateManager.setActivationProgress(ActivationProgress.COMPLETED);
}
lastConnectionTimeMillis = sp.getLong( lastConnectionTimeMillis = sp.getLong(
RileyLinkConst.Prefs.LastGoodDeviceCommunicationTime, 0L); RileyLinkConst.Prefs.LastGoodDeviceCommunicationTime, 0L);
@ -922,7 +930,7 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface,
} }
private void initializeAfterRileyLinkConnection() { private void initializeAfterRileyLinkConnection() {
if (podStateManager.isPodInitialized() && podStateManager.getPodProgressStatus().isAtLeast(PodProgressStatus.PAIRING_COMPLETED)) { if (podStateManager.getActivationProgress().isAtLeast(ActivationProgress.PAIRING_COMPLETED)) {
for (int i = 0; STARTUP_STATUS_REQUEST_TRIES > i; i++) { for (int i = 0; STARTUP_STATUS_REQUEST_TRIES > i; i++) {
PumpEnactResult result = executeCommand(OmnipodCommandType.GET_POD_STATUS, aapsOmnipodManager::getPodStatus); PumpEnactResult result = executeCommand(OmnipodCommandType.GET_POD_STATUS, aapsOmnipodManager::getPodStatus);
if (result.success) { if (result.success) {

View file

@ -5,54 +5,68 @@ import org.joda.time.DateTimeZone;
import java.util.Collections; import java.util.Collections;
import java.util.Random; import java.util.Random;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.OmnipodMessage; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.OmnipodMessage;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.command.AssignAddressCommand; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.command.AssignAddressCommand;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.VersionResponse; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.VersionResponse;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PacketType;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalMessageAddressException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalMessageAddressException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalPodProgressException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalPacketTypeException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalVersionResponseTypeException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalVersionResponseTypeException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager; import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager;
import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager; import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager;
public class AssignAddressAction implements OmnipodAction<VersionResponse> { public class AssignAddressAction implements OmnipodAction<Void> {
private final PodStateManager podStateManager; private final PodStateManager podStateManager;
private final AAPSLogger aapsLogger;
public AssignAddressAction(PodStateManager podStateManager) { public AssignAddressAction(PodStateManager podStateManager, AAPSLogger aapsLogger) {
if (podStateManager == null) { if (podStateManager == null) {
throw new IllegalArgumentException("podStateManager can not be null"); throw new IllegalArgumentException("podStateManager can not be null");
} }
if (aapsLogger == null) {
throw new IllegalArgumentException("Logger can not be null");
}
this.podStateManager = podStateManager; this.podStateManager = podStateManager;
this.aapsLogger = aapsLogger;
} }
@Override @Override
public VersionResponse execute(OmnipodRileyLinkCommunicationManager communicationService) { public Void execute(OmnipodRileyLinkCommunicationManager communicationService) {
if (!podStateManager.hasPodState()) { if (!podStateManager.hasPodState()) {
podStateManager.initState(generateRandomAddress()); podStateManager.initState(generateRandomAddress());
} }
if (podStateManager.isPodInitialized() && podStateManager.getPodProgressStatus().isAfter(PodProgressStatus.REMINDER_INITIALIZED)) {
throw new IllegalPodProgressException(PodProgressStatus.REMINDER_INITIALIZED, podStateManager.getPodProgressStatus()); if (podStateManager.getActivationProgress().needsPairing()) {
AssignAddressCommand assignAddress = new AssignAddressCommand(podStateManager.getAddress());
OmnipodMessage assignAddressMessage = new OmnipodMessage(OmnipodConstants.DEFAULT_ADDRESS,
Collections.singletonList(assignAddress), podStateManager.getMessageNumber());
try {
VersionResponse assignAddressResponse = communicationService.exchangeMessages(VersionResponse.class, podStateManager, assignAddressMessage,
OmnipodConstants.DEFAULT_ADDRESS, podStateManager.getAddress());
if (!assignAddressResponse.isAssignAddressVersionResponse()) {
throw new IllegalVersionResponseTypeException("assignAddress", "setupPod");
}
if (assignAddressResponse.getAddress() != podStateManager.getAddress()) {
throw new IllegalMessageAddressException(podStateManager.getAddress(), assignAddressResponse.getAddress());
}
podStateManager.setInitializationParameters(assignAddressResponse.getLot(), assignAddressResponse.getTid(), //
assignAddressResponse.getPiVersion(), assignAddressResponse.getPmVersion(), DateTimeZone.getDefault(), assignAddressResponse.getPodProgressStatus());
} catch (IllegalPacketTypeException ex) {
if (ex.getActual() == PacketType.ACK && podStateManager.isPodInitialized()) {
// When we already assigned the address before, it's possible to only get an ACK here
aapsLogger.debug("Received ACK instead of response in AssignAddressAction. Ignoring because we already assigned the address successfully");
} else {
throw ex;
}
}
} }
AssignAddressCommand assignAddress = new AssignAddressCommand(podStateManager.getAddress()); return null;
OmnipodMessage assignAddressMessage = new OmnipodMessage(OmnipodConstants.DEFAULT_ADDRESS,
Collections.singletonList(assignAddress), podStateManager.getMessageNumber());
VersionResponse assignAddressResponse = communicationService.exchangeMessages(VersionResponse.class, podStateManager, assignAddressMessage,
OmnipodConstants.DEFAULT_ADDRESS, podStateManager.getAddress());
if (!assignAddressResponse.isAssignAddressVersionResponse()) {
throw new IllegalVersionResponseTypeException("assignAddress", "setupPod");
}
if (assignAddressResponse.getAddress() != podStateManager.getAddress()) {
throw new IllegalMessageAddressException(podStateManager.getAddress(), assignAddressResponse.getAddress());
}
podStateManager.setInitializationParameters(assignAddressResponse.getLot(), assignAddressResponse.getTid(), //
assignAddressResponse.getPiVersion(), assignAddressResponse.getPmVersion(), DateTimeZone.getDefault(), assignAddressResponse.getPodProgressStatus());
return assignAddressResponse;
} }
private static int generateRandomAddress() { private static int generateRandomAddress() {

View file

@ -6,16 +6,15 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.action.service.ExpirationReminderBuilder; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.action.service.ExpirationReminderBuilder;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.StatusResponse; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.ActivationProgress;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.AlertConfiguration; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.AlertConfiguration;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.schedule.BasalSchedule; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.schedule.BasalSchedule;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalPodProgressException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalActivationProgressException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager; import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager;
import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager; import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager;
public class InsertCannulaAction implements OmnipodAction<StatusResponse> { public class InsertCannulaAction implements OmnipodAction<Void> {
private final PodStateManager podStateManager; private final PodStateManager podStateManager;
private final BasalSchedule initialBasalSchedule; private final BasalSchedule initialBasalSchedule;
@ -37,31 +36,33 @@ public class InsertCannulaAction implements OmnipodAction<StatusResponse> {
} }
@Override @Override
public StatusResponse execute(OmnipodRileyLinkCommunicationManager communicationService) { public Void execute(OmnipodRileyLinkCommunicationManager communicationService) {
if (!podStateManager.isPodInitialized() || podStateManager.getPodProgressStatus().isBefore(PodProgressStatus.PRIMING_COMPLETED)) { if (podStateManager.getActivationProgress().isBefore(ActivationProgress.PRIMING_COMPLETED)) {
throw new IllegalPodProgressException(PodProgressStatus.PRIMING_COMPLETED, podStateManager.isPodInitialized() ? podStateManager.getPodProgressStatus() : null); throw new IllegalActivationProgressException(ActivationProgress.PRIMING_COMPLETED, podStateManager.getActivationProgress());
} }
if (podStateManager.getPodProgressStatus().isBefore(PodProgressStatus.BASAL_INITIALIZED)) { if (podStateManager.getActivationProgress().needsBasalSchedule()) {
podStateManager.setBasalSchedule(initialBasalSchedule); podStateManager.setBasalSchedule(initialBasalSchedule);
communicationService.executeAction(new SetBasalScheduleAction(podStateManager, initialBasalSchedule, communicationService.executeAction(new SetBasalScheduleAction(podStateManager, initialBasalSchedule,
true, podStateManager.getScheduleOffset(), false)); true, podStateManager.getScheduleOffset(), false));
podStateManager.setActivationProgress(ActivationProgress.BASAL_INITIALIZED);
} }
if (podStateManager.getPodProgressStatus().isBefore(PodProgressStatus.INSERTING_CANNULA)) { if (podStateManager.getActivationProgress().needsExpirationReminders()) {
communicationService.executeAction(new ConfigureAlertsAction(podStateManager, buildAlertConfigurations())); communicationService.executeAction(new ConfigureAlertsAction(podStateManager, buildAlertConfigurations()));
podStateManager.setExpirationAlertTimeBeforeShutdown(expirationReminderTimeBeforeShutdown); podStateManager.setExpirationAlertTimeBeforeShutdown(expirationReminderTimeBeforeShutdown);
podStateManager.setLowReservoirAlertUnits(lowReservoirAlertUnits); podStateManager.setLowReservoirAlertUnits(lowReservoirAlertUnits);
podStateManager.setActivationProgress(ActivationProgress.EXPIRATION_REMINDERS_SET);
return communicationService.executeAction(new BolusAction(podStateManager, OmnipodConstants.POD_CANNULA_INSERTION_BOLUS_UNITS,
Duration.standardSeconds(1), false, false));
} else if (podStateManager.getPodProgressStatus().equals(PodProgressStatus.INSERTING_CANNULA)) {
// Check status
return communicationService.executeAction(new GetStatusAction(podStateManager));
} else {
throw new IllegalPodProgressException(null, podStateManager.getPodProgressStatus());
} }
if (podStateManager.getActivationProgress().needsCannulaInsertion()) {
communicationService.executeAction(new BolusAction(podStateManager, OmnipodConstants.POD_CANNULA_INSERTION_BOLUS_UNITS,
Duration.standardSeconds(1), false, false));
podStateManager.setActivationProgress(ActivationProgress.INSERTING_CANNULA);
}
return null;
} }
private List<AlertConfiguration> buildAlertConfigurations() { private List<AlertConfiguration> buildAlertConfigurations() {

View file

@ -1,13 +1,12 @@
package info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.action; package info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.action;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.action.service.PrimeService; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.action.service.PrimeService;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.StatusResponse; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.ActivationProgress;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalActivationProgressException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalPodProgressException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager; import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager;
import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager; import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager;
public class PrimeAction implements OmnipodAction<StatusResponse> { public class PrimeAction implements OmnipodAction<Void> {
private final PrimeService service; private final PrimeService service;
private final PodStateManager podStateManager; private final PodStateManager podStateManager;
@ -24,21 +23,27 @@ public class PrimeAction implements OmnipodAction<StatusResponse> {
} }
@Override @Override
public StatusResponse execute(OmnipodRileyLinkCommunicationManager communicationService) { public Void execute(OmnipodRileyLinkCommunicationManager communicationService) {
if (!podStateManager.isPodInitialized() || podStateManager.getPodProgressStatus().isBefore(PodProgressStatus.PAIRING_COMPLETED)) { if (podStateManager.getActivationProgress().isBefore(ActivationProgress.PAIRING_COMPLETED)) {
throw new IllegalPodProgressException(PodProgressStatus.PAIRING_COMPLETED, podStateManager.isPodInitialized() ? podStateManager.getPodProgressStatus() : null); throw new IllegalActivationProgressException(ActivationProgress.PAIRING_COMPLETED, podStateManager.getActivationProgress());
} }
if (podStateManager.getPodProgressStatus().isBefore(PodProgressStatus.PRIMING)) {
if (podStateManager.getActivationProgress().needsDisableTab5Sub16And17()) {
// FaultConfigCommand sets internal pod variables to effectively disable $6x faults which occur more often with a 0 TBR // FaultConfigCommand sets internal pod variables to effectively disable $6x faults which occur more often with a 0 TBR
service.executeDisableTab5Sub16And17FaultConfigCommand(communicationService, podStateManager); service.executeDisableTab5Sub16And17FaultConfigCommand(communicationService, podStateManager);
podStateManager.setActivationProgress(ActivationProgress.TAB_5_SUB_16_AND_17_DISABLED);
service.executeFinishSetupReminderAlertCommand(communicationService, podStateManager);
return service.executePrimeBolusCommand(communicationService, podStateManager);
} else if (podStateManager.getPodProgressStatus().equals(PodProgressStatus.PRIMING)) {
// Check status
return communicationService.executeAction(new GetStatusAction(podStateManager));
} else {
throw new IllegalPodProgressException(null, podStateManager.getPodProgressStatus());
} }
if (podStateManager.getActivationProgress().needsSetupReminders()) {
service.executeFinishSetupReminderAlertCommand(communicationService, podStateManager);
podStateManager.setActivationProgress(ActivationProgress.SETUP_REMINDERS_SET);
}
if (podStateManager.getActivationProgress().needsPriming()) {
service.executePrimeBolusCommand(communicationService, podStateManager);
podStateManager.setActivationProgress(ActivationProgress.PRIMING);
}
return null;
} }
} }

View file

@ -4,49 +4,72 @@ import org.joda.time.DateTime;
import java.util.Collections; import java.util.Collections;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.OmnipodMessage; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.OmnipodMessage;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.command.SetupPodCommand; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.command.SetupPodCommand;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.VersionResponse; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.VersionResponse;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.ActivationProgress;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PacketType;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalMessageAddressException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalMessageAddressException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalPacketTypeException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalPodProgressException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalPodProgressException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalVersionResponseTypeException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalVersionResponseTypeException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager; import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager;
import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager; import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager;
public class SetupPodAction implements OmnipodAction<VersionResponse> { public class SetupPodAction implements OmnipodAction<Void> {
private final PodStateManager podStateManager; private final PodStateManager podStateManager;
private final AAPSLogger aapsLogger;
public SetupPodAction(PodStateManager podStateManager) { public SetupPodAction(PodStateManager podStateManager, AAPSLogger aapsLogger) {
if (podStateManager == null) { if (podStateManager == null) {
throw new IllegalArgumentException("Pod state manager can not be null"); throw new IllegalArgumentException("Pod state manager can not be null");
} }
if (aapsLogger == null) {
throw new IllegalArgumentException("Logger can not be null");
}
this.podStateManager = podStateManager; this.podStateManager = podStateManager;
this.aapsLogger = aapsLogger;
} }
@Override @Override
public VersionResponse execute(OmnipodRileyLinkCommunicationManager communicationService) { public Void execute(OmnipodRileyLinkCommunicationManager communicationService) {
if (!podStateManager.isPodInitialized() || !podStateManager.getPodProgressStatus().equals(PodProgressStatus.REMINDER_INITIALIZED)) { if (!podStateManager.isPodInitialized()) {
throw new IllegalPodProgressException(PodProgressStatus.REMINDER_INITIALIZED, podStateManager.isPodInitialized() ? podStateManager.getPodProgressStatus() : null); throw new IllegalPodProgressException(PodProgressStatus.REMINDER_INITIALIZED, podStateManager.isPodInitialized() ? podStateManager.getPodProgressStatus() : null);
} }
DateTime activationDate = DateTime.now(podStateManager.getTimeZone());
SetupPodCommand setupPodCommand = new SetupPodCommand(podStateManager.getAddress(), activationDate, if (podStateManager.getActivationProgress().needsPairing()) {
podStateManager.getLot(), podStateManager.getTid()); DateTime activationDate = DateTime.now(podStateManager.getTimeZone());
OmnipodMessage message = new OmnipodMessage(OmnipodConstants.DEFAULT_ADDRESS,
Collections.singletonList(setupPodCommand), podStateManager.getMessageNumber());
VersionResponse setupPodResponse;
setupPodResponse = communicationService.exchangeMessages(VersionResponse.class, podStateManager,
message, OmnipodConstants.DEFAULT_ADDRESS, podStateManager.getAddress());
if (!setupPodResponse.isSetupPodVersionResponse()) { SetupPodCommand setupPodCommand = new SetupPodCommand(podStateManager.getAddress(), activationDate,
throw new IllegalVersionResponseTypeException("setupPod", "assignAddress"); podStateManager.getLot(), podStateManager.getTid());
} OmnipodMessage message = new OmnipodMessage(OmnipodConstants.DEFAULT_ADDRESS,
if (setupPodResponse.getAddress() != podStateManager.getAddress()) { Collections.singletonList(setupPodCommand), podStateManager.getMessageNumber());
throw new IllegalMessageAddressException(podStateManager.getAddress(), setupPodResponse.getAddress());
try {
VersionResponse setupPodResponse = communicationService.exchangeMessages(VersionResponse.class, podStateManager,
message, OmnipodConstants.DEFAULT_ADDRESS, podStateManager.getAddress());
if (!setupPodResponse.isSetupPodVersionResponse()) {
throw new IllegalVersionResponseTypeException("setupPod", "assignAddress");
}
if (setupPodResponse.getAddress() != podStateManager.getAddress()) {
throw new IllegalMessageAddressException(podStateManager.getAddress(), setupPodResponse.getAddress());
}
} catch (IllegalPacketTypeException ex) {
if (PacketType.ACK.equals(ex.getActual())) {
// Pod is already configured
aapsLogger.debug("Received ACK instead of response in SetupPodAction. Ignoring");
} else {
throw ex;
}
}
podStateManager.setActivationProgress(ActivationProgress.PAIRING_COMPLETED);
} }
return setupPodResponse; return null;
} }
} }

View file

@ -12,9 +12,11 @@ public class ErrorResponse extends MessageBlock {
private static final int MESSAGE_LENGTH = 5; private static final int MESSAGE_LENGTH = 5;
private final byte errorResponseCode; private final byte errorResponseCode;
private Integer nonceSearchKey; // only valid for BAD_NONCE
private FaultEventCode faultEventCode; // valid for all but BAD_NONCE private final Integer nonceSearchKey; // only valid for BAD_NONCE
private PodProgressStatus podProgressStatus; // valid for all but BAD_NONCE private final FaultEventCode faultEventCode; // valid for all but BAD_NONCE
private final PodProgressStatus podProgressStatus; // valid for all but BAD_NONCE
public ErrorResponse(byte[] encodedData) { public ErrorResponse(byte[] encodedData) {
if (encodedData.length < MESSAGE_LENGTH) { if (encodedData.length < MESSAGE_LENGTH) {
@ -24,11 +26,16 @@ public class ErrorResponse extends MessageBlock {
errorResponseCode = encodedData[2]; errorResponseCode = encodedData[2];
if (this.errorResponseCode == ERROR_RESPONSE_CODE_BAD_NONCE) { if (errorResponseCode == ERROR_RESPONSE_CODE_BAD_NONCE) {
nonceSearchKey = ByteUtil.makeUnsignedShort(encodedData[3], encodedData[4]); nonceSearchKey = ByteUtil.makeUnsignedShort(encodedData[3], encodedData[4]);
faultEventCode = null;
podProgressStatus = null;
} else { } else {
faultEventCode = FaultEventCode.fromByte(encodedData[3]); faultEventCode = FaultEventCode.fromByte(encodedData[3]);
podProgressStatus = PodProgressStatus.fromByte(encodedData[4]); podProgressStatus = PodProgressStatus.fromByte(encodedData[4]);
nonceSearchKey = null;
} }
} }
@ -53,8 +60,7 @@ public class ErrorResponse extends MessageBlock {
return nonceSearchKey; return nonceSearchKey;
} }
@Override @Override public String toString() {
public String toString() {
return "ErrorResponse{" + return "ErrorResponse{" +
"errorResponseCode=" + errorResponseCode + "errorResponseCode=" + errorResponseCode +
", nonceSearchKey=" + nonceSearchKey + ", nonceSearchKey=" + nonceSearchKey +

View file

@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.mes
import org.joda.time.Duration; import org.joda.time.Duration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil;
@ -54,7 +53,7 @@ public class PodInfoActiveAlerts extends PodInfo {
@Override @Override
public String toString() { public String toString() {
return "PodInfoActiveAlerts{" + return "PodInfoActiveAlerts{" +
"word278=" + Arrays.toString(word278) + "word278=" + ByteUtil.shortHexString(word278) +
", alertActivations=" + alertActivations + ", alertActivations=" + alertActivations +
'}'; '}';
} }

View file

@ -6,13 +6,13 @@ import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.StatusUpdatableResponse; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.StatusUpdatableResponse;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.AlertSet; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.AlertSet;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.DeliveryStatus; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.DeliveryStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.ErrorEventInfo;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.FaultEventCode; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.FaultEventCode;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.LogEventErrorCode;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodInfoType; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodInfoType;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus;
public class PodInfoFaultEvent extends PodInfo implements StatusUpdatableResponse { public class PodInfoDetailedStatus extends PodInfo implements StatusUpdatableResponse {
private static final int MINIMUM_MESSAGE_LENGTH = 21; private static final int MINIMUM_MESSAGE_LENGTH = 21;
private final PodProgressStatus podProgressStatus; private final PodProgressStatus podProgressStatus;
@ -27,14 +27,13 @@ public class PodInfoFaultEvent extends PodInfo implements StatusUpdatableRespons
private final Duration timeActive; private final Duration timeActive;
private final AlertSet unacknowledgedAlerts; private final AlertSet unacknowledgedAlerts;
private final boolean faultAccessingTables; private final boolean faultAccessingTables;
private final LogEventErrorCode logEventErrorType; private final ErrorEventInfo errorEventInfo;
private final PodProgressStatus logEventErrorPodProgressStatus;
private final byte receiverLowGain; private final byte receiverLowGain;
private final byte radioRSSI; private final byte radioRSSI;
private final PodProgressStatus podProgressStatusAtTimeOfFirstLoggedFaultEvent; private final PodProgressStatus previousPodProgressStatus;
private final byte[] unknownValue; private final byte[] unknownValue;
public PodInfoFaultEvent(byte[] encodedData) { public PodInfoDetailedStatus(byte[] encodedData) {
super(encodedData); super(encodedData);
if (encodedData.length < MINIMUM_MESSAGE_LENGTH) { if (encodedData.length < MINIMUM_MESSAGE_LENGTH) {
@ -69,27 +68,33 @@ public class PodInfoFaultEvent extends PodInfo implements StatusUpdatableRespons
unacknowledgedAlerts = new AlertSet(encodedData[15]); unacknowledgedAlerts = new AlertSet(encodedData[15]);
faultAccessingTables = encodedData[16] == 0x02; faultAccessingTables = encodedData[16] == 0x02;
int i = ByteUtil.convertUnsignedByteToInt(encodedData[17]); byte rawErrorEventInfo = encodedData[17];
byte value = (byte) (i >>> 4); if (rawErrorEventInfo == 0x00) {
errorEventInfo = null;
// FIXME below line DOES NOT MATCH the OpenOmni Wiki description of the type 2 pod info response } else {
// See https://github.com/openaps/openomni/wiki/Command-02-Pod-Information-Response#type-2 errorEventInfo = ErrorEventInfo.fromByte(rawErrorEventInfo);
// Example of an observed message from the Pod that makes below line throw an IllegalArgumentException: }
// 1F0F038F20180216020D00000000000012FFFF03FF00160000879A070000012E
// the LogEventErrorCode class doesn't make any sense and should be removed. Instead, the a, bb and c bits in byte 17
// should be decoded independently as per the response description on the OpenOmni Wiki
logEventErrorType = LogEventErrorCode.fromByte(value);
logEventErrorPodProgressStatus = PodProgressStatus.fromByte((byte) (encodedData[17] & 0x0f));
receiverLowGain = (byte) (ByteUtil.convertUnsignedByteToInt(encodedData[18]) >>> 6); receiverLowGain = (byte) (ByteUtil.convertUnsignedByteToInt(encodedData[18]) >>> 6);
radioRSSI = (byte) (encodedData[18] & 0x3f); radioRSSI = (byte) (encodedData[18] & 0x3f);
podProgressStatusAtTimeOfFirstLoggedFaultEvent = PodProgressStatus.fromByte((byte) (encodedData[19] & 0x0f)); if (ByteUtil.convertUnsignedByteToInt(encodedData[19]) == 0xff) { // this byte is not valid (no fault has occurred)
previousPodProgressStatus = null;
} else {
previousPodProgressStatus = PodProgressStatus.fromByte((byte) (encodedData[19] & 0x0f));
}
unknownValue = ByteUtil.substring(encodedData, 20, 2); unknownValue = ByteUtil.substring(encodedData, 20, 2);
} }
@Override @Override
public PodInfoType getType() { public PodInfoType getType() {
return PodInfoType.FAULT_EVENT; return PodInfoType.DETAILED_STATUS;
}
public boolean isFaulted() {
return faultEventCode != null;
}
public boolean isActivationTimeExceeded() {
return podProgressStatus == PodProgressStatus.ACTIVATION_TIME_EXCEEDED;
} }
@Override public PodProgressStatus getPodProgressStatus() { @Override public PodProgressStatus getPodProgressStatus() {
@ -140,12 +145,8 @@ public class PodInfoFaultEvent extends PodInfo implements StatusUpdatableRespons
return faultAccessingTables; return faultAccessingTables;
} }
public LogEventErrorCode getLogEventErrorType() { public ErrorEventInfo getErrorEventInfo() {
return logEventErrorType; return errorEventInfo;
}
public PodProgressStatus getLogEventErrorPodProgressStatus() {
return logEventErrorPodProgressStatus;
} }
public byte getReceiverLowGain() { public byte getReceiverLowGain() {
@ -156,8 +157,8 @@ public class PodInfoFaultEvent extends PodInfo implements StatusUpdatableRespons
return radioRSSI; return radioRSSI;
} }
public PodProgressStatus getPodProgressStatusAtTimeOfFirstLoggedFaultEvent() { public PodProgressStatus getPreviousPodProgressStatus() {
return podProgressStatusAtTimeOfFirstLoggedFaultEvent; return previousPodProgressStatus;
} }
public byte[] getUnknownValue() { public byte[] getUnknownValue() {
@ -165,7 +166,7 @@ public class PodInfoFaultEvent extends PodInfo implements StatusUpdatableRespons
} }
@Override public String toString() { @Override public String toString() {
return "PodInfoFaultEvent{" + return "PodInfoDetailedStatus{" +
"podProgressStatus=" + podProgressStatus + "podProgressStatus=" + podProgressStatus +
", deliveryStatus=" + deliveryStatus + ", deliveryStatus=" + deliveryStatus +
", bolusNotDelivered=" + bolusNotDelivered + ", bolusNotDelivered=" + bolusNotDelivered +
@ -178,11 +179,10 @@ public class PodInfoFaultEvent extends PodInfo implements StatusUpdatableRespons
", timeActive=" + timeActive + ", timeActive=" + timeActive +
", unacknowledgedAlerts=" + unacknowledgedAlerts + ", unacknowledgedAlerts=" + unacknowledgedAlerts +
", faultAccessingTables=" + faultAccessingTables + ", faultAccessingTables=" + faultAccessingTables +
", logEventErrorType=" + logEventErrorType + ", errorEventInfo=" + errorEventInfo +
", logEventErrorPodProgressStatus=" + logEventErrorPodProgressStatus +
", receiverLowGain=" + receiverLowGain + ", receiverLowGain=" + receiverLowGain +
", radioRSSI=" + radioRSSI + ", radioRSSI=" + radioRSSI +
", podProgressStatusAtTimeOfFirstLoggedFaultEvent=" + podProgressStatusAtTimeOfFirstLoggedFaultEvent + ", previousPodProgressStatus=" + previousPodProgressStatus +
", unknownValue=" + ByteUtil.shortHexString(unknownValue) + ", unknownValue=" + ByteUtil.shortHexString(unknownValue) +
'}'; '}';
} }

View file

@ -0,0 +1,66 @@
package info.nightscout.androidaps.plugins.pump.omnipod.driver.definition;
public enum ActivationProgress {
NONE,
PAIRING_COMPLETED,
TAB_5_SUB_16_AND_17_DISABLED,
SETUP_REMINDERS_SET,
PRIMING,
PRIMING_COMPLETED,
BASAL_INITIALIZED,
EXPIRATION_REMINDERS_SET,
INSERTING_CANNULA,
COMPLETED;
public boolean needsPairing() {
return this == NONE;
}
public boolean needsDisableTab5Sub16And17() {
return this == PAIRING_COMPLETED;
}
public boolean needsSetupReminders() {
return this == TAB_5_SUB_16_AND_17_DISABLED;
}
public boolean needsPriming() {
return this == SETUP_REMINDERS_SET;
}
public boolean needsPrimingVerification() {
return this == PRIMING;
}
public boolean needsBasalSchedule() {
return this == PRIMING_COMPLETED;
}
public boolean needsExpirationReminders() {
return this == BASAL_INITIALIZED;
}
public boolean needsCannulaInsertion() {
return this == EXPIRATION_REMINDERS_SET;
}
public boolean needsCannulaInsertionVerification() {
return this == INSERTING_CANNULA;
}
public boolean isCompleted() {
return this == COMPLETED;
}
public boolean isBefore(ActivationProgress other) {
return ordinal() < other.ordinal();
}
public boolean isAtLeast(ActivationProgress other) {
return ordinal() >= other.ordinal();
}
public boolean isAfter(ActivationProgress other) {
return ordinal() > other.ordinal();
}
}

View file

@ -0,0 +1,52 @@
package info.nightscout.androidaps.plugins.pump.omnipod.driver.definition;
import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil;
public final class ErrorEventInfo {
private final boolean insulinStateTableCorruption;
private final byte internalVariable;
private final boolean immediateBolusInProgress;
private final PodProgressStatus podProgressStatus;
private ErrorEventInfo(boolean insulinStateTableCorruption, byte internalVariable, boolean immediateBolusInProgress, PodProgressStatus podProgressStatus) {
this.insulinStateTableCorruption = insulinStateTableCorruption;
this.internalVariable = internalVariable;
this.immediateBolusInProgress = immediateBolusInProgress;
this.podProgressStatus = podProgressStatus;
}
public static ErrorEventInfo fromByte(byte faultEventInfo) {
int loggedFaultEventInfo = ByteUtil.convertUnsignedByteToInt(faultEventInfo);
boolean insulinStateTableCorruption = (loggedFaultEventInfo & 0x80) == 0x80;
byte internalVariable = (byte) ((loggedFaultEventInfo >>> 5) & 0x03);
boolean immediateBolusInProgress = (loggedFaultEventInfo & 0x10) == 0x10;
PodProgressStatus podProgressStatus = PodProgressStatus.fromByte((byte) (loggedFaultEventInfo & 0x0f));
return new ErrorEventInfo(insulinStateTableCorruption, internalVariable, immediateBolusInProgress, podProgressStatus);
}
public boolean isInsulinStateTableCorruption() {
return insulinStateTableCorruption;
}
public byte getInternalVariable() {
return internalVariable;
}
public boolean isImmediateBolusInProgress() {
return immediateBolusInProgress;
}
public PodProgressStatus getPodProgressStatus() {
return podProgressStatus;
}
@Override public String toString() {
return "ErrorEventInfo{" +
"insulinStateTableCorruption=" + insulinStateTableCorruption +
", internalVariable=" + internalVariable +
", immediateBolusInProgress=" + immediateBolusInProgress +
", podProgressStatus=" + podProgressStatus +
'}';
}
}

View file

@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.driver.definition;
import java.util.Locale; import java.util.Locale;
public enum FaultEventCode { public enum FaultEventCode {
NO_FAULTS((byte) 0x00),
FAILED_FLASH_ERASE((byte) 0x01), FAILED_FLASH_ERASE((byte) 0x01),
FAILED_FLASH_STORE((byte) 0x02), FAILED_FLASH_STORE((byte) 0x02),
TABLE_CORRUPTION_BASAL_SUBCOMMAND((byte) 0x03), TABLE_CORRUPTION_BASAL_SUBCOMMAND((byte) 0x03),
@ -129,6 +128,9 @@ public enum FaultEventCode {
} }
public static FaultEventCode fromByte(byte value) { public static FaultEventCode fromByte(byte value) {
if (value == 0x00) { // No faults
return null;
}
for (FaultEventCode type : values()) { for (FaultEventCode type : values()) {
if (type.value == value) { if (type.value == value) {
return type; return type;

View file

@ -1,24 +0,0 @@
package info.nightscout.androidaps.plugins.pump.omnipod.driver.definition;
public enum LogEventErrorCode {
NONE((byte) 0x00),
IMMEDIATE_BOLUS_IN_PROGRESS((byte) 0x01),
INTERNAL_2_BIT_VARIABLE_SET_AND_MANIPULATED_IN_MAIN_LOOP_ROUTINES_2((byte) 0x02),
INTERNAL_2_BIT_VARIABLE_SET_AND_MANIPULATED_IN_MAIN_LOOP_ROUTINES_3((byte) 0x03),
INSULIN_STATE_TABLE_CORRUPTION((byte) 0x04);
private final byte value;
LogEventErrorCode(byte value) {
this.value = value;
}
public static LogEventErrorCode fromByte(byte value) {
for (LogEventErrorCode type : values()) {
if (type.value == value) {
return type;
}
}
throw new IllegalArgumentException("Unknown LogEventErrorCode: " + value);
}
}

View file

@ -3,15 +3,15 @@ package info.nightscout.androidaps.plugins.pump.omnipod.driver.definition;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfo; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfo;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoActiveAlerts; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoActiveAlerts;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoDataLog; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoDataLog;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoDetailedStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoFaultAndInitializationTime; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoFaultAndInitializationTime;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoFaultEvent;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoOlderPulseLog; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoOlderPulseLog;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoRecentPulseLog; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoRecentPulseLog;
public enum PodInfoType { public enum PodInfoType {
NORMAL((byte) 0x00), NORMAL((byte) 0x00),
ACTIVE_ALERTS((byte) 0x01), ACTIVE_ALERTS((byte) 0x01),
FAULT_EVENT((byte) 0x02), DETAILED_STATUS((byte) 0x02),
DATA_LOG((byte) 0x03), // Similar to types $50 & $51. Returns up to the last 60 dwords of data. DATA_LOG((byte) 0x03), // Similar to types $50 & $51. Returns up to the last 60 dwords of data.
FAULT_AND_INITIALIZATION_TIME((byte) 0x05), FAULT_AND_INITIALIZATION_TIME((byte) 0x05),
RECENT_PULSE_LOG((byte) 0x50), // Starting at $4200 RECENT_PULSE_LOG((byte) 0x50), // Starting at $4200
@ -44,8 +44,8 @@ public enum PodInfoType {
throw new UnsupportedOperationException("Cannot decode PodInfoType.NORMAL"); throw new UnsupportedOperationException("Cannot decode PodInfoType.NORMAL");
case ACTIVE_ALERTS: case ACTIVE_ALERTS:
return new PodInfoActiveAlerts(encodedData); return new PodInfoActiveAlerts(encodedData);
case FAULT_EVENT: case DETAILED_STATUS:
return new PodInfoFaultEvent(encodedData); return new PodInfoDetailedStatus(encodedData);
case DATA_LOG: case DATA_LOG:
return new PodInfoDataLog(encodedData, bodyLength); return new PodInfoDataLog(encodedData, bodyLength);
case FAULT_AND_INITIALIZATION_TIME: case FAULT_AND_INITIALIZATION_TIME:

View file

@ -0,0 +1,7 @@
package info.nightscout.androidaps.plugins.pump.omnipod.driver.exception;
public class ActivationTimeExceededException extends OmnipodException {
public ActivationTimeExceededException() {
super("The Pod's activation time has been exceeded", true);
}
}

View file

@ -0,0 +1,24 @@
package info.nightscout.androidaps.plugins.pump.omnipod.driver.exception;
import java.util.Locale;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.ActivationProgress;
public class IllegalActivationProgressException extends OmnipodException {
private final ActivationProgress expected;
private final ActivationProgress actual;
public IllegalActivationProgressException(ActivationProgress expected, ActivationProgress actual) {
super(String.format(Locale.getDefault(), "Illegal activation progress: %s, expected: %s", actual, expected), true);
this.expected = expected;
this.actual = actual;
}
public ActivationProgress getExpected() {
return expected;
}
public ActivationProgress getActual() {
return actual;
}
}

View file

@ -9,7 +9,7 @@ public class IllegalPodProgressException extends OmnipodException {
private final PodProgressStatus actual; private final PodProgressStatus actual;
public IllegalPodProgressException(PodProgressStatus expected, PodProgressStatus actual) { public IllegalPodProgressException(PodProgressStatus expected, PodProgressStatus actual) {
super(String.format(Locale.getDefault(), "Illegal setup state: %s, expected: %s", actual, expected), true); super(String.format(Locale.getDefault(), "Illegal Pod progress: %s, expected: %s", actual, expected), true);
this.expected = expected; this.expected = expected;
this.actual = actual; this.actual = actual;
} }

View file

@ -1,16 +1,16 @@
package info.nightscout.androidaps.plugins.pump.omnipod.driver.exception; package info.nightscout.androidaps.plugins.pump.omnipod.driver.exception;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoFaultEvent; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoDetailedStatus;
public class PodFaultException extends OmnipodException { public class PodFaultException extends OmnipodException {
private final PodInfoFaultEvent faultEvent; private final PodInfoDetailedStatus detailedStatus;
public PodFaultException(PodInfoFaultEvent faultEvent) { public PodFaultException(PodInfoDetailedStatus detailedStatus) {
super(faultEvent.getFaultEventCode().toString(), true); super(detailedStatus.getFaultEventCode().toString(), true);
this.faultEvent = faultEvent; this.detailedStatus = detailedStatus;
} }
public PodInfoFaultEvent getFaultEvent() { public PodInfoDetailedStatus getDetailedStatus() {
return faultEvent; return detailedStatus;
} }
} }

View file

@ -31,19 +31,19 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.mess
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.StatusResponse; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.StatusResponse;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoRecentPulseLog; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoRecentPulseLog;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoResponse; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoResponse;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.ActivationProgress;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.AlertConfiguration; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.AlertConfiguration;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.BeepType; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.BeepType;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.DeliveryStatus; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.DeliveryStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.DeliveryType; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.DeliveryType;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PacketType;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodInfoType; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodInfoType;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.schedule.BasalSchedule; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.schedule.BasalSchedule;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.CommandFailedAfterChangingDeliveryStatusException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.CommandFailedAfterChangingDeliveryStatusException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.DeliveryStatusVerificationFailedException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.DeliveryStatusVerificationFailedException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalActivationProgressException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalDeliveryStatusException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalDeliveryStatusException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalPacketTypeException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalPodProgressException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalPodProgressException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.NonceOutOfSyncException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.NonceOutOfSyncException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.OmnipodException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.OmnipodException;
@ -59,7 +59,7 @@ import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.SingleSubject; import io.reactivex.subjects.SingleSubject;
public class OmnipodManager { public class OmnipodManager {
private static final int ACTION_VERIFICATION_TRIES = 2; private static final int ACTION_VERIFICATION_TRIES = 1;
private final OmnipodRileyLinkCommunicationManager communicationService; private final OmnipodRileyLinkCommunicationManager communicationService;
private PodStateManager podStateManager; private PodStateManager podStateManager;
@ -88,76 +88,53 @@ public class OmnipodManager {
} }
public synchronized Single<Boolean> pairAndPrime() { public synchronized Single<Boolean> pairAndPrime() {
logStartingCommandExecution("pairAndPrime"); if (podStateManager.isPodInitialized()) {
if (podStateManager.getActivationProgress().isAfter(ActivationProgress.PRIMING)) {
try { return Single.just(true);
if (!podStateManager.isPodInitialized() || podStateManager.getPodProgressStatus().isBefore(PodProgressStatus.PAIRING_COMPLETED)) { }
// Always send both 0x07 and 0x03 on retries if (podStateManager.getActivationProgress().needsPrimingVerification()) {
try { return Single.fromCallable(() -> verifyPodProgressStatus(PodProgressStatus.PRIMING_COMPLETED, ActivationProgress.PRIMING_COMPLETED));
communicationService.executeAction(
new AssignAddressAction(podStateManager));
} catch (IllegalPacketTypeException ex) {
if (ex.getActual() == PacketType.ACK && podStateManager.isPodInitialized()) {
// When we already assigned the address before, it's possible to only get an ACK here
aapsLogger.debug("Received ACK instead of response in AssignAddressAction. Ignoring because we already assigned the address successfully");
} else {
throw ex;
}
}
try {
communicationService.executeAction(new SetupPodAction(podStateManager));
} catch (IllegalPacketTypeException ex) {
if (PacketType.ACK.equals(ex.getActual())) {
// TODO is this true for the SetupPodCommand?
// Pod is already configured
aapsLogger.debug("Received ACK instead of response in SetupPodAction. Ignoring");
}
}
} else if (podStateManager.getPodProgressStatus().isAfter(PodProgressStatus.PRIMING)) {
throw new IllegalPodProgressException(PodProgressStatus.PAIRING_COMPLETED, podStateManager.getPodProgressStatus());
} }
// Make sure we have an up to date PodProgressStatus
getPodStatus();
communicationService.executeAction(new PrimeAction(new PrimeService(), podStateManager));
} finally {
logCommandExecutionFinished("pairAndPrime");
} }
// Always send both 0x07 and 0x03 on retries
if (podStateManager.getActivationProgress().isBefore(ActivationProgress.PAIRING_COMPLETED)) {
communicationService.executeAction(
new AssignAddressAction(podStateManager, aapsLogger));
communicationService.executeAction(new SetupPodAction(podStateManager, aapsLogger));
}
communicationService.executeAction(new PrimeAction(new PrimeService(), podStateManager));
long delayInMillis = calculateEstimatedBolusDuration(DateTime.now().minus(OmnipodConstants.AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION), OmnipodConstants.POD_PRIME_BOLUS_UNITS, OmnipodConstants.POD_PRIMING_DELIVERY_RATE).getMillis(); long delayInMillis = calculateEstimatedBolusDuration(DateTime.now().minus(OmnipodConstants.AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION), OmnipodConstants.POD_PRIME_BOLUS_UNITS, OmnipodConstants.POD_PRIMING_DELIVERY_RATE).getMillis();
return Single.timer(delayInMillis, TimeUnit.MILLISECONDS) // return Single.timer(delayInMillis, TimeUnit.MILLISECONDS) //
.map(o -> verifyPodProgressStatus(PodProgressStatus.PRIMING_COMPLETED)) // .map(o -> verifyPodProgressStatus(PodProgressStatus.PRIMING_COMPLETED, ActivationProgress.PRIMING_COMPLETED)) //
.subscribeOn(Schedulers.io()); .subscribeOn(Schedulers.io());
} }
public synchronized Single<Boolean> insertCannula( public synchronized Single<Boolean> insertCannula(
BasalSchedule basalSchedule, Duration expirationReminderTimeBeforeShutdown, Integer lowReservoirAlertUnits) { BasalSchedule basalSchedule, Duration expirationReminderTimeBeforeShutdown, Integer lowReservoirAlertUnits) {
if (!podStateManager.isPodInitialized() || podStateManager.getPodProgressStatus().isBefore(PodProgressStatus.PRIMING_COMPLETED)) { if (podStateManager.getActivationProgress().isBefore(ActivationProgress.PRIMING_COMPLETED)) {
throw new IllegalPodProgressException(PodProgressStatus.PRIMING_COMPLETED, !podStateManager.isPodInitialized() ? null : podStateManager.getPodProgressStatus()); throw new IllegalActivationProgressException(ActivationProgress.PRIMING_COMPLETED, podStateManager.getActivationProgress());
} }
// Make sure we have the latest PodProgressStatus if (podStateManager.isPodInitialized()) {
getPodStatus(); if (podStateManager.getActivationProgress().isCompleted()) {
return Single.just(true);
if (podStateManager.getPodProgressStatus().isAfter(PodProgressStatus.INSERTING_CANNULA)) { }
throw new IllegalPodProgressException(PodProgressStatus.PRIMING_COMPLETED, podStateManager.getPodProgressStatus()); if (podStateManager.getActivationProgress().needsCannulaInsertionVerification()) {
return Single.fromCallable(() -> verifyPodProgressStatus(PodProgressStatus.ABOVE_FIFTY_UNITS, ActivationProgress.COMPLETED));
}
} }
logStartingCommandExecution("insertCannula [basalSchedule=" + basalSchedule + "]"); communicationService.executeAction(new InsertCannulaAction(podStateManager, basalSchedule, expirationReminderTimeBeforeShutdown, lowReservoirAlertUnits));
try {
communicationService.executeAction(new InsertCannulaAction(podStateManager, basalSchedule, expirationReminderTimeBeforeShutdown, lowReservoirAlertUnits));
} finally {
logCommandExecutionFinished("insertCannula");
}
long delayInMillis = calculateEstimatedBolusDuration(DateTime.now().minus(OmnipodConstants.AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION), OmnipodConstants.POD_CANNULA_INSERTION_BOLUS_UNITS, OmnipodConstants.POD_CANNULA_INSERTION_DELIVERY_RATE).getMillis(); long delayInMillis = calculateEstimatedBolusDuration(DateTime.now().minus(OmnipodConstants.AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION), OmnipodConstants.POD_CANNULA_INSERTION_BOLUS_UNITS, OmnipodConstants.POD_CANNULA_INSERTION_DELIVERY_RATE).getMillis();
return Single.timer(delayInMillis, TimeUnit.MILLISECONDS) // return Single.timer(delayInMillis, TimeUnit.MILLISECONDS) //
.map(o -> verifyPodProgressStatus(PodProgressStatus.ABOVE_FIFTY_UNITS)) // .map(o -> verifyPodProgressStatus(PodProgressStatus.ABOVE_FIFTY_UNITS, ActivationProgress.COMPLETED)) //
.subscribeOn(Schedulers.io()); .subscribeOn(Schedulers.io());
} }
@ -166,49 +143,29 @@ public class OmnipodManager {
throw new IllegalPodProgressException(PodProgressStatus.REMINDER_INITIALIZED, null); throw new IllegalPodProgressException(PodProgressStatus.REMINDER_INITIALIZED, null);
} }
logStartingCommandExecution("getPodStatus"); return communicationService.executeAction(new GetStatusAction(podStateManager));
try {
return communicationService.executeAction(new GetStatusAction(podStateManager));
} finally {
logCommandExecutionFinished("getPodStatus");
}
} }
public synchronized PodInfoResponse getPodInfo(PodInfoType podInfoType) { public synchronized PodInfoResponse getPodInfo(PodInfoType podInfoType) {
assertReadyForDelivery(); assertReadyForDelivery();
logStartingCommandExecution("getPodInfo"); return communicationService.executeAction(new GetPodInfoAction(podStateManager, podInfoType));
try {
return communicationService.executeAction(new GetPodInfoAction(podStateManager, podInfoType));
} finally {
logCommandExecutionFinished("getPodInfo");
}
} }
public synchronized StatusResponse configureAlerts(List<AlertConfiguration> alertConfigurations) { public synchronized StatusResponse configureAlerts(List<AlertConfiguration> alertConfigurations) {
assertReadyForDelivery(); assertReadyForDelivery();
logStartingCommandExecution("configureAlerts");
try { StatusResponse statusResponse = executeAndVerify(() -> communicationService.executeAction(new ConfigureAlertsAction(podStateManager, alertConfigurations)));
StatusResponse statusResponse = executeAndVerify(() -> communicationService.executeAction(new ConfigureAlertsAction(podStateManager, alertConfigurations))); ConfigureAlertsAction.updateConfiguredAlerts(podStateManager, alertConfigurations);
ConfigureAlertsAction.updateConfiguredAlerts(podStateManager, alertConfigurations); return statusResponse;
return statusResponse;
} finally {
logCommandExecutionFinished("configureAlerts");
}
} }
public synchronized StatusResponse acknowledgeAlerts() { public synchronized StatusResponse acknowledgeAlerts() {
assertReadyForDelivery(); assertReadyForDelivery();
logStartingCommandExecution("acknowledgeAlerts"); return executeAndVerify(() -> communicationService.executeAction(new AcknowledgeAlertsAction(podStateManager, podStateManager.getActiveAlerts())));
try {
return executeAndVerify(() -> communicationService.executeAction(new AcknowledgeAlertsAction(podStateManager, podStateManager.getActiveAlerts())));
} finally {
logCommandExecutionFinished("acknowledgeAlerts");
}
} }
// CAUTION: cancels all delivery // CAUTION: cancels all delivery
@ -216,41 +173,33 @@ public class OmnipodManager {
public synchronized void setBasalSchedule(BasalSchedule schedule, boolean acknowledgementBeep) { public synchronized void setBasalSchedule(BasalSchedule schedule, boolean acknowledgementBeep) {
assertReadyForDelivery(); assertReadyForDelivery();
logStartingCommandExecution("setBasalSchedule [basalSchedule=" + schedule + ", acknowledgementBeep=" + acknowledgementBeep + "]"); boolean wasSuspended = podStateManager.isSuspended();
if (!wasSuspended) {
suspendDelivery(acknowledgementBeep);
}
try { try {
boolean wasSuspended = podStateManager.isSuspended(); executeAndVerify(() -> communicationService.executeAction(new SetBasalScheduleAction(podStateManager, schedule,
if (!wasSuspended) { false, podStateManager.getScheduleOffset(), acknowledgementBeep)));
suspendDelivery(acknowledgementBeep); podStateManager.setBasalSchedule(schedule);
} catch (OmnipodException ex) {
if (ex.isCertainFailure()) {
if (!wasSuspended) {
throw new CommandFailedAfterChangingDeliveryStatusException("Suspending delivery succeeded but setting the new basal schedule did not", ex);
}
throw ex;
} }
try { // verifyDeliveryStatus will throw an exception if verification fails
executeAndVerify(() -> communicationService.executeAction(new SetBasalScheduleAction(podStateManager, schedule, if (verifyDeliveryStatus(DeliveryStatus.NORMAL, ex)) {
false, podStateManager.getScheduleOffset(), acknowledgementBeep)));
podStateManager.setBasalSchedule(schedule); podStateManager.setBasalSchedule(schedule);
} catch (OmnipodException ex) { } else {
if (ex.isCertainFailure()) { if (!wasSuspended) {
if (!wasSuspended) { throw new CommandFailedAfterChangingDeliveryStatusException("Suspending delivery succeeded but setting the new basal schedule did not", ex);
throw new CommandFailedAfterChangingDeliveryStatusException("Suspending delivery succeeded but setting the new basal schedule did not", ex);
}
throw ex;
}
// verifyDeliveryStatus will throw an exception if verification fails
if (verifyDeliveryStatus(DeliveryStatus.NORMAL, ex)) {
podStateManager.setBasalSchedule(schedule);
} else {
if (!wasSuspended) {
throw new CommandFailedAfterChangingDeliveryStatusException("Suspending delivery succeeded but setting the new basal schedule did not", ex);
}
ex.setCertainFailure(true);
throw ex;
} }
ex.setCertainFailure(true);
throw ex;
} }
} finally {
logCommandExecutionFinished("setBasalSchedule");
} }
} }
@ -258,70 +207,64 @@ public class OmnipodManager {
public synchronized void setTemporaryBasal(double rate, Duration duration, boolean acknowledgementBeep, boolean completionBeep) { public synchronized void setTemporaryBasal(double rate, Duration duration, boolean acknowledgementBeep, boolean completionBeep) {
assertReadyForDelivery(); assertReadyForDelivery();
logStartingCommandExecution("setTemporaryBasal [rate=" + rate + ", duration=" + duration + ", acknowledgementBeep=" + acknowledgementBeep + ", completionBeep=" + completionBeep + "]");
boolean cancelCurrentTbr = podStateManager.isTempBasalRunning(); boolean cancelCurrentTbr = podStateManager.isTempBasalRunning();
try { if (cancelCurrentTbr) {
if (cancelCurrentTbr) {
try {
cancelDelivery(EnumSet.of(DeliveryType.TEMP_BASAL), acknowledgementBeep);
} catch (OmnipodException ex) {
if (ex.isCertainFailure()) {
throw ex;
}
try {
if (!verifyDeliveryStatus(DeliveryStatus.NORMAL, ex)) {
ex.setCertainFailure(true);
throw ex;
}
} catch (DeliveryStatusVerificationFailedException ex2) {
podStateManager.setTempBasalCertain(false);
throw ex2;
}
}
}
try { try {
executeAndVerify(() -> communicationService.executeAction(new SetTempBasalAction( cancelDelivery(EnumSet.of(DeliveryType.TEMP_BASAL), acknowledgementBeep);
podStateManager, rate, duration, acknowledgementBeep, completionBeep)));
podStateManager.setTempBasal(DateTime.now().minus(OmnipodConstants.AVERAGE_TEMP_BASAL_COMMAND_COMMUNICATION_DURATION), rate, duration, true);
} catch (OmnipodException ex) { } catch (OmnipodException ex) {
if (ex.isCertainFailure()) { if (ex.isCertainFailure()) {
if (cancelCurrentTbr) {
throw new CommandFailedAfterChangingDeliveryStatusException("Failed to set new TBR while cancelling old TBR succeeded", ex);
}
throw ex; throw ex;
} }
// verifyDeliveryStatus will throw an exception if verification fails
try { try {
if (verifyDeliveryStatus(DeliveryStatus.TEMP_BASAL_RUNNING, ex)) { if (!verifyDeliveryStatus(DeliveryStatus.NORMAL, ex)) {
podStateManager.setTempBasal(DateTime.now().minus(OmnipodConstants.AVERAGE_TEMP_BASAL_COMMAND_COMMUNICATION_DURATION), rate, duration, true);
} else {
if (cancelCurrentTbr) {
throw new CommandFailedAfterChangingDeliveryStatusException("Failed to set new TBR while cancelling old TBR succeeded", ex);
}
ex.setCertainFailure(true); ex.setCertainFailure(true);
throw ex; throw ex;
} }
} catch (CommandFailedAfterChangingDeliveryStatusException ex2) { } catch (DeliveryStatusVerificationFailedException ex2) {
// Don't set temp basal in Pod State for this Exception podStateManager.setTempBasalCertain(false);
throw ex2;
} catch (OmnipodException ex2) {
if (!ex2.isCertainFailure()) {
// We're not sure that setting the new TBR failed, so we assume that it succeeded
// If it didn't, PodStateManager.updateFromResponse() will fix the state
// upon receiving the next StatusResponse
podStateManager.setTempBasal(DateTime.now().minus(OmnipodConstants.AVERAGE_TEMP_BASAL_COMMAND_COMMUNICATION_DURATION), rate, duration, false);
}
throw ex2; throw ex2;
} }
} }
} finally { }
logCommandExecutionFinished("setTemporaryBasal");
try {
executeAndVerify(() -> communicationService.executeAction(new SetTempBasalAction(
podStateManager, rate, duration, acknowledgementBeep, completionBeep)));
podStateManager.setTempBasal(DateTime.now().minus(OmnipodConstants.AVERAGE_TEMP_BASAL_COMMAND_COMMUNICATION_DURATION), rate, duration, true);
} catch (OmnipodException ex) {
if (ex.isCertainFailure()) {
if (cancelCurrentTbr) {
throw new CommandFailedAfterChangingDeliveryStatusException("Failed to set new TBR while cancelling old TBR succeeded", ex);
}
throw ex;
}
// verifyDeliveryStatus will throw an exception if verification fails
try {
if (verifyDeliveryStatus(DeliveryStatus.TEMP_BASAL_RUNNING, ex)) {
podStateManager.setTempBasal(DateTime.now().minus(OmnipodConstants.AVERAGE_TEMP_BASAL_COMMAND_COMMUNICATION_DURATION), rate, duration, true);
} else {
if (cancelCurrentTbr) {
throw new CommandFailedAfterChangingDeliveryStatusException("Failed to set new TBR while cancelling old TBR succeeded", ex);
}
ex.setCertainFailure(true);
throw ex;
}
} catch (CommandFailedAfterChangingDeliveryStatusException ex2) {
// Don't set temp basal in Pod State for this Exception
throw ex2;
} catch (OmnipodException ex2) {
if (!ex2.isCertainFailure()) {
// We're not sure that setting the new TBR failed, so we assume that it succeeded
// If it didn't, PodStateManager.updateFromResponse() will fix the state
// upon receiving the next StatusResponse
podStateManager.setTempBasal(DateTime.now().minus(OmnipodConstants.AVERAGE_TEMP_BASAL_COMMAND_COMMUNICATION_DURATION), rate, duration, false);
}
throw ex2;
}
} }
} }
@ -348,17 +291,11 @@ public class OmnipodManager {
private synchronized StatusResponse cancelDelivery(EnumSet<DeliveryType> deliveryTypes, boolean acknowledgementBeep) { private synchronized StatusResponse cancelDelivery(EnumSet<DeliveryType> deliveryTypes, boolean acknowledgementBeep) {
assertReadyForDelivery(); assertReadyForDelivery();
logStartingCommandExecution("cancelDelivery [deliveryTypes=" + deliveryTypes + ", acknowledgementBeep=" + acknowledgementBeep + "]"); return executeAndVerify(() -> {
StatusResponse statusResponse = communicationService.executeAction(new CancelDeliveryAction(podStateManager, deliveryTypes, acknowledgementBeep));
try { aapsLogger.info(LTag.PUMPCOMM, "Status response after cancel delivery[types={}]: {}", deliveryTypes.toString(), statusResponse.toString());
return executeAndVerify(() -> { return statusResponse;
StatusResponse statusResponse = communicationService.executeAction(new CancelDeliveryAction(podStateManager, deliveryTypes, acknowledgementBeep)); });
aapsLogger.info(LTag.PUMPCOMM, "Status response after cancel delivery[types={}]: {}", deliveryTypes.toString(), statusResponse.toString());
return statusResponse;
});
} finally {
logCommandExecutionFinished("cancelDelivery");
}
} }
// Returns a SingleSubject that returns when the bolus has finished. // Returns a SingleSubject that returns when the bolus has finished.
@ -367,8 +304,6 @@ public class OmnipodManager {
public synchronized BolusCommandResult bolus(Double units, boolean acknowledgementBeep, boolean completionBeep, BiConsumer<Double, Integer> progressIndicationConsumer) { public synchronized BolusCommandResult bolus(Double units, boolean acknowledgementBeep, boolean completionBeep, BiConsumer<Double, Integer> progressIndicationConsumer) {
assertReadyForDelivery(); assertReadyForDelivery();
logStartingCommandExecution("bolus [units=" + units + ", acknowledgementBeep=" + acknowledgementBeep + ", completionBeep=" + completionBeep + "]");
bolusCommandExecutionSubject = SingleSubject.create(); bolusCommandExecutionSubject = SingleSubject.create();
CommandDeliveryStatus commandDeliveryStatus = CommandDeliveryStatus.SUCCESS; CommandDeliveryStatus commandDeliveryStatus = CommandDeliveryStatus.SUCCESS;
@ -437,7 +372,7 @@ public class OmnipodManager {
break; break;
} catch (PodFaultException ex) { } catch (PodFaultException ex) {
// Subtract units not delivered in case of a Pod failure // Subtract units not delivered in case of a Pod failure
bolusNotDelivered = ex.getFaultEvent().getBolusNotDelivered(); bolusNotDelivered = ex.getDetailedStatus().getBolusNotDelivered();
aapsLogger.debug(LTag.PUMPCOMM, "Caught PodFaultException in bolus completion verification", ex); aapsLogger.debug(LTag.PUMPCOMM, "Caught PodFaultException in bolus completion verification", ex);
break; break;
@ -454,8 +389,6 @@ public class OmnipodManager {
}) })
.subscribe()); .subscribe());
logCommandExecutionFinished("bolus");
return new BolusCommandResult(commandDeliveryStatus, bolusCompletionSubject); return new BolusCommandResult(commandDeliveryStatus, bolusCompletionSubject);
} }
@ -467,16 +400,12 @@ public class OmnipodManager {
throw new IllegalDeliveryStatusException(DeliveryStatus.BOLUS_IN_PROGRESS, podStateManager.getLastDeliveryStatus()); throw new IllegalDeliveryStatusException(DeliveryStatus.BOLUS_IN_PROGRESS, podStateManager.getLastDeliveryStatus());
} }
logStartingCommandExecution("cancelBolus [acknowledgementBeep=" + acknowledgementBeep + "]");
try { try {
StatusResponse statusResponse = cancelDelivery(EnumSet.of(DeliveryType.BOLUS), acknowledgementBeep); StatusResponse statusResponse = cancelDelivery(EnumSet.of(DeliveryType.BOLUS), acknowledgementBeep);
discardActiveBolusData(statusResponse.getBolusNotDelivered()); discardActiveBolusData(statusResponse.getBolusNotDelivered());
} catch (PodFaultException ex) { } catch (PodFaultException ex) {
discardActiveBolusData(ex.getFaultEvent().getBolusNotDelivered()); discardActiveBolusData(ex.getDetailedStatus().getBolusNotDelivered());
throw ex; throw ex;
} finally {
logCommandExecutionFinished("cancelBolus");
} }
} }
} }
@ -494,7 +423,6 @@ public class OmnipodManager {
public synchronized void suspendDelivery(boolean acknowledgementBeep) { public synchronized void suspendDelivery(boolean acknowledgementBeep) {
assertReadyForDelivery(); assertReadyForDelivery();
logStartingCommandExecution("suspendDelivery");
try { try {
cancelDelivery(EnumSet.allOf(DeliveryType.class), acknowledgementBeep); cancelDelivery(EnumSet.allOf(DeliveryType.class), acknowledgementBeep);
@ -508,8 +436,6 @@ public class OmnipodManager {
ex.setCertainFailure(true); ex.setCertainFailure(true);
throw ex; throw ex;
} }
} finally {
logCommandExecutionFinished("suspendDelivery");
} }
} }
@ -518,26 +444,20 @@ public class OmnipodManager {
public synchronized void setTime(boolean acknowledgementBeeps) { public synchronized void setTime(boolean acknowledgementBeeps) {
assertReadyForDelivery(); assertReadyForDelivery();
logStartingCommandExecution("setTime [acknowledgementBeeps=" + acknowledgementBeeps + "]"); DateTimeZone oldTimeZone = podStateManager.getTimeZone();
try { try {
DateTimeZone oldTimeZone = podStateManager.getTimeZone(); // Joda seems to cache the default time zone, so we use the JVM's
DateTimeZone.setDefault(DateTimeZone.forTimeZone(TimeZone.getDefault()));
podStateManager.setTimeZone(DateTimeZone.getDefault());
try { setBasalSchedule(podStateManager.getBasalSchedule(), acknowledgementBeeps);
// Joda seems to cache the default time zone, so we use the JVM's } catch (OmnipodException ex) {
DateTimeZone.setDefault(DateTimeZone.forTimeZone(TimeZone.getDefault())); podStateManager.setTimeZone(oldTimeZone);
podStateManager.setTimeZone(DateTimeZone.getDefault()); throw ex;
setBasalSchedule(podStateManager.getBasalSchedule(), acknowledgementBeeps);
} catch (OmnipodException ex) {
podStateManager.setTimeZone(oldTimeZone);
throw ex;
}
podStateManager.updateActivatedAt();
} finally {
logCommandExecutionFinished("setTime");
} }
podStateManager.updateActivatedAt();
} }
public synchronized void deactivatePod() { public synchronized void deactivatePod() {
@ -545,8 +465,6 @@ public class OmnipodManager {
throw new IllegalPodProgressException(PodProgressStatus.REMINDER_INITIALIZED, null); throw new IllegalPodProgressException(PodProgressStatus.REMINDER_INITIALIZED, null);
} }
logStartingCommandExecution("deactivatePod");
// Try to get pulse log for diagnostics // Try to get pulse log for diagnostics
try { try {
PodInfoResponse podInfoResponse = communicationService.executeAction(new GetPodInfoAction(podStateManager, PodInfoType.RECENT_PULSE_LOG)); PodInfoResponse podInfoResponse = communicationService.executeAction(new GetPodInfoAction(podStateManager, PodInfoType.RECENT_PULSE_LOG));
@ -561,8 +479,6 @@ public class OmnipodManager {
communicationService.executeAction(new DeactivatePodAction(podStateManager, true)); communicationService.executeAction(new DeactivatePodAction(podStateManager, true));
} catch (PodFaultException ex) { } catch (PodFaultException ex) {
aapsLogger.info(LTag.PUMPCOMM, "Ignoring PodFaultException in deactivatePod", ex); aapsLogger.info(LTag.PUMPCOMM, "Ignoring PodFaultException in deactivatePod", ex);
} finally {
logCommandExecutionFinished("deactivatePod");
} }
podStateManager.discardState(); podStateManager.discardState();
@ -592,7 +508,6 @@ public class OmnipodManager {
// Only works for commands with nonce resyncable message blocks // Only works for commands with nonce resyncable message blocks
private StatusResponse executeAndVerify(Supplier<StatusResponse> supplier) { private StatusResponse executeAndVerify(Supplier<StatusResponse> supplier) {
logStartingCommandExecution("verifyCommand");
try { try {
return supplier.get(); return supplier.get();
} catch (OmnipodException originalException) { } catch (OmnipodException originalException) {
@ -616,8 +531,6 @@ public class OmnipodManager {
throw originalException; throw originalException;
} }
} }
} finally {
logCommandExecutionFinished("verifyCommand");
} }
} }
@ -632,7 +545,7 @@ public class OmnipodManager {
* @return true if the Pod's progress status matches the expected status, otherwise false * @return true if the Pod's progress status matches the expected status, otherwise false
* @throws PodProgressStatusVerificationFailedException in case reading the Pod status fails * @throws PodProgressStatusVerificationFailedException in case reading the Pod status fails
*/ */
private boolean verifyPodProgressStatus(PodProgressStatus expectedPodProgressStatus) { private boolean verifyPodProgressStatus(PodProgressStatus expectedPodProgressStatus, ActivationProgress activationProgress) {
Boolean result = null; Boolean result = null;
Throwable lastException = null; Throwable lastException = null;
@ -641,6 +554,7 @@ public class OmnipodManager {
StatusResponse statusResponse = getPodStatus(); StatusResponse statusResponse = getPodStatus();
if (statusResponse.getPodProgressStatus().equals(expectedPodProgressStatus)) { if (statusResponse.getPodProgressStatus().equals(expectedPodProgressStatus)) {
podStateManager.setActivationProgress(activationProgress);
return true; return true;
} else { } else {
result = false; result = false;
@ -681,14 +595,6 @@ public class OmnipodManager {
throw new DeliveryStatusVerificationFailedException(expectedStatus, verificationCause); throw new DeliveryStatusVerificationFailedException(expectedStatus, verificationCause);
} }
private void logStartingCommandExecution(String action) {
aapsLogger.debug(LTag.PUMPCOMM, "Starting command execution for action: " + action);
}
private void logCommandExecutionFinished(String action) {
aapsLogger.debug(LTag.PUMPCOMM, "Command execution finished for action: " + action);
}
private Duration calculateEstimatedBolusDuration(DateTime startTime, double units, double deliveryRateInUnitsPerSecond) { private Duration calculateEstimatedBolusDuration(DateTime startTime, double units, double deliveryRateInUnitsPerSecond) {
if (!podStateManager.isPodActivationCompleted()) { if (!podStateManager.isPodActivationCompleted()) {
// No basal or temp basal is active yet // No basal or temp basal is active yet

View file

@ -16,16 +16,19 @@ import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier; import java.util.function.Supplier;
import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.StatusUpdatableResponse; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.StatusUpdatableResponse;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoFaultEvent; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoDetailedStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.ActivationProgress;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.AlertSet; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.AlertSet;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.AlertSlot; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.AlertSlot;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.AlertType; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.AlertType;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.DeliveryStatus; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.DeliveryStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.FaultEventCode;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.FirmwareVersion; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.FirmwareVersion;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodCrc; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodCrc;
@ -79,7 +82,7 @@ public abstract class PodStateManager {
* @return true if we have a Pod state and the Pod activation has been completed. The pod could also be dead at this point * @return true if we have a Pod state and the Pod activation has been completed. The pod could also be dead at this point
*/ */
public final boolean isPodActivationCompleted() { public final boolean isPodActivationCompleted() {
return isPodInitialized() && podState.getPodProgressStatus().isAtLeast(PodProgressStatus.ABOVE_FIFTY_UNITS) && podState.getPodProgressStatus() != PodProgressStatus.ACTIVATION_TIME_EXCEEDED; return getActivationProgress().isCompleted();
} }
/** /**
@ -97,6 +100,13 @@ public abstract class PodStateManager {
return isPodInitialized() && podState.getPodProgressStatus().equals(PodProgressStatus.FAULT_EVENT_OCCURRED); return isPodInitialized() && podState.getPodProgressStatus().equals(PodProgressStatus.FAULT_EVENT_OCCURRED);
} }
/**
* @return true if the Pod's activation time has been exceeded
*/
public boolean isPodActivationTimeExceeded() {
return isPodInitialized() && getPodProgressStatus() == PodProgressStatus.ACTIVATION_TIME_EXCEEDED;
}
/** /**
* @return true if we have a Pod state and the Pod is dead, meaning it is either in a fault state or activation time has been exceeded or it is deactivated * @return true if we have a Pod state and the Pod is dead, meaning it is either in a fault state or activation time has been exceeded or it is deactivated
*/ */
@ -232,16 +242,12 @@ public abstract class PodStateManager {
* a fault event, this does NOT necessarily mean that the Pod is not faulted. For a reliable * a fault event, this does NOT necessarily mean that the Pod is not faulted. For a reliable
* indication on whether or not the pod is faulted, see {@link #isPodFaulted() isPodFaulted()} * indication on whether or not the pod is faulted, see {@link #isPodFaulted() isPodFaulted()}
*/ */
public final boolean hasFaultEvent() { public final boolean isFaulted() {
return podState != null && podState.getFaultEvent() != null; return podState != null && podState.getFaultEventCode() != null;
} }
public final PodInfoFaultEvent getFaultEvent() { public final FaultEventCode getFaultEventCode() {
return getSafe(() -> podState.getFaultEvent()); return getSafe(() -> podState.getFaultEventCode());
}
public final void setFaultEvent(PodInfoFaultEvent faultEvent) {
setAndStore(() -> podState.setFaultEvent(faultEvent));
} }
public final AlertType getConfiguredAlertType(AlertSlot alertSlot) { public final AlertType getConfiguredAlertType(AlertSlot alertSlot) {
@ -331,6 +337,17 @@ public abstract class PodStateManager {
return activatedAt == null ? null : activatedAt.withZone(getSafe(() -> podState.getTimeZone())).plus(OmnipodConstants.NOMINAL_POD_LIFE); return activatedAt == null ? null : activatedAt.withZone(getSafe(() -> podState.getTimeZone())).plus(OmnipodConstants.NOMINAL_POD_LIFE);
} }
public final ActivationProgress getActivationProgress() {
if (hasPodState()) {
return Optional.ofNullable(podState.getActivationProgress()).orElse(ActivationProgress.NONE);
}
return ActivationProgress.NONE;
}
public final void setActivationProgress(ActivationProgress activationProgress) {
setAndStore(() -> podState.setActivationProgress(activationProgress));
}
public final PodProgressStatus getPodProgressStatus() { public final PodProgressStatus getPodProgressStatus() {
return getSafe(() -> podState.getPodProgressStatus()); return getSafe(() -> podState.getPodProgressStatus());
} }
@ -513,20 +530,20 @@ public abstract class PodStateManager {
/** /**
* Does not automatically store pod state in order to decrease I/O load * Does not automatically store pod state in order to decrease I/O load
*/ */
public final void updateFromResponse(StatusUpdatableResponse statusResponse) { public final void updateFromResponse(StatusUpdatableResponse status) {
setSafe(() -> { setSafe(() -> {
if (podState.getActivatedAt() == null) { if (podState.getActivatedAt() == null) {
DateTime activatedAtCalculated = DateTime.now().withZone(podState.getTimeZone()).minus(statusResponse.getTimeActive()); DateTime activatedAtCalculated = DateTime.now().withZone(podState.getTimeZone()).minus(status.getTimeActive());
podState.setActivatedAt(activatedAtCalculated); podState.setActivatedAt(activatedAtCalculated);
} }
podState.setSuspended(statusResponse.getDeliveryStatus() == DeliveryStatus.SUSPENDED); podState.setSuspended(status.getDeliveryStatus() == DeliveryStatus.SUSPENDED);
podState.setActiveAlerts(statusResponse.getUnacknowledgedAlerts()); podState.setActiveAlerts(status.getUnacknowledgedAlerts());
podState.setLastDeliveryStatus(statusResponse.getDeliveryStatus()); podState.setLastDeliveryStatus(status.getDeliveryStatus());
podState.setReservoirLevel(statusResponse.getReservoirLevel()); podState.setReservoirLevel(status.getReservoirLevel());
podState.setTotalTicksDelivered(statusResponse.getTicksDelivered()); podState.setTotalTicksDelivered(status.getTicksDelivered());
podState.setPodProgressStatus(statusResponse.getPodProgressStatus()); podState.setPodProgressStatus(status.getPodProgressStatus());
podState.setTimeActive(statusResponse.getTimeActive()); podState.setTimeActive(status.getTimeActive());
if (statusResponse.getDeliveryStatus().isTbrRunning()) { if (status.getDeliveryStatus().isTbrRunning()) {
if (!isTempBasalCertain() && isTempBasalRunning()) { if (!isTempBasalCertain() && isTempBasalRunning()) {
podState.setTempBasalCertain(true); podState.setTempBasalCertain(true);
} }
@ -535,6 +552,13 @@ public abstract class PodStateManager {
setTempBasal(null, null, null, true, false); setTempBasal(null, null, null, true, false);
} }
podState.setLastUpdatedFromResponse(DateTime.now()); podState.setLastUpdatedFromResponse(DateTime.now());
if (status instanceof PodInfoDetailedStatus) {
PodInfoDetailedStatus detailedStatus = (PodInfoDetailedStatus) status;
if (detailedStatus.isFaulted()) {
podState.setFaultEventCode(detailedStatus.getFaultEventCode());
}
}
}); });
} }
@ -626,11 +650,12 @@ public abstract class PodStateManager {
private DateTimeZone timeZone; private DateTimeZone timeZone;
private DateTime activatedAt; private DateTime activatedAt;
private Duration timeActive; private Duration timeActive;
private PodInfoFaultEvent faultEvent; private FaultEventCode faultEventCode;
private Double reservoirLevel; private Double reservoirLevel;
private Integer totalTicksDelivered; private Integer totalTicksDelivered;
private boolean suspended; private boolean suspended;
private NonceState nonceState; private NonceState nonceState;
private ActivationProgress activationProgress = ActivationProgress.NONE;
private PodProgressStatus podProgressStatus; private PodProgressStatus podProgressStatus;
private DeliveryStatus lastDeliveryStatus; private DeliveryStatus lastDeliveryStatus;
private AlertSet activeAlerts; private AlertSet activeAlerts;
@ -751,12 +776,12 @@ public abstract class PodStateManager {
this.timeActive = timeActive; this.timeActive = timeActive;
} }
PodInfoFaultEvent getFaultEvent() { FaultEventCode getFaultEventCode() {
return faultEvent; return faultEventCode;
} }
void setFaultEvent(PodInfoFaultEvent faultEvent) { void setFaultEventCode(FaultEventCode faultEventCode) {
this.faultEvent = faultEvent; this.faultEventCode = faultEventCode;
} }
Double getReservoirLevel() { Double getReservoirLevel() {
@ -799,6 +824,14 @@ public abstract class PodStateManager {
this.nonceState = nonceState; this.nonceState = nonceState;
} }
ActivationProgress getActivationProgress() {
return activationProgress;
}
void setActivationProgress(ActivationProgress activationProgress) {
this.activationProgress = activationProgress;
}
PodProgressStatus getPodProgressStatus() { PodProgressStatus getPodProgressStatus() {
return podProgressStatus; return podProgressStatus;
} }
@ -930,11 +963,12 @@ public abstract class PodStateManager {
", timeZone=" + timeZone + ", timeZone=" + timeZone +
", activatedAt=" + activatedAt + ", activatedAt=" + activatedAt +
", timeActive=" + timeActive + ", timeActive=" + timeActive +
", faultEvent=" + faultEvent + ", faultEventCode=" + faultEventCode +
", reservoirLevel=" + reservoirLevel + ", reservoirLevel=" + reservoirLevel +
", totalTicksDelivered=" + totalTicksDelivered + ", totalTicksDelivered=" + totalTicksDelivered +
", suspended=" + suspended + ", suspended=" + suspended +
", nonceState=" + nonceState + ", nonceState=" + nonceState +
", activationProgress=" + activationProgress +
", podProgressStatus=" + podProgressStatus + ", podProgressStatus=" + podProgressStatus +
", lastDeliveryStatus=" + lastDeliveryStatus + ", lastDeliveryStatus=" + lastDeliveryStatus +
", activeAlerts=" + activeAlerts + ", activeAlerts=" + activeAlerts +

View file

@ -50,9 +50,9 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.Deliver
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.FaultEventCode; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.FaultEventCode;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodInfoType; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodInfoType;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.schedule.BasalSchedule; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.schedule.BasalSchedule;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.schedule.BasalScheduleEntry; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.schedule.BasalScheduleEntry;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.ActivationTimeExceededException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.CommandFailedAfterChangingDeliveryStatusException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.CommandFailedAfterChangingDeliveryStatusException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.CrcMismatchException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.CrcMismatchException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.DeliveryStatusVerificationFailedException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.DeliveryStatusVerificationFailedException;
@ -62,6 +62,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalM
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalPacketTypeException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalPacketTypeException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalPodProgressException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalPodProgressException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalResponseException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalResponseException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalActivationProgressException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalVersionResponseTypeException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalVersionResponseTypeException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.MessageDecodingException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.MessageDecodingException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.NonceOutOfSyncException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.NonceOutOfSyncException;
@ -758,10 +759,8 @@ public class AapsOmnipodManager {
if (ex instanceof OmnipodException) { if (ex instanceof OmnipodException) {
aapsLogger.error(LTag.PUMP, String.format("Caught OmnipodException[certainFailure=%s] from OmnipodManager", ((OmnipodException) ex).isCertainFailure()), ex); aapsLogger.error(LTag.PUMP, String.format("Caught OmnipodException[certainFailure=%s] from OmnipodManager", ((OmnipodException) ex).isCertainFailure()), ex);
if (ex instanceof PodFaultException) { if (ex instanceof PodFaultException) {
FaultEventCode faultEventCode = ((PodFaultException) ex).getFaultEvent().getFaultEventCode(); FaultEventCode faultEventCode = ((PodFaultException) ex).getDetailedStatus().getFaultEventCode();
if (!(faultEventCode == FaultEventCode.NO_FAULTS && podStateManager.isPodInitialized() && podStateManager.getPodProgressStatus() == PodProgressStatus.ACTIVATION_TIME_EXCEEDED)) { showPodFaultNotification(faultEventCode);
showPodFaultNotification(faultEventCode);
}
} }
} else { } else {
aapsLogger.error(LTag.PUMP, "Caught an unexpected non-OmnipodException from OmnipodManager", ex); aapsLogger.error(LTag.PUMP, "Caught an unexpected non-OmnipodException from OmnipodManager", ex);
@ -775,7 +774,8 @@ public class AapsOmnipodManager {
comment = getStringResource(R.string.omnipod_error_crc_mismatch); comment = getStringResource(R.string.omnipod_error_crc_mismatch);
} else if (ex instanceof IllegalPacketTypeException) { } else if (ex instanceof IllegalPacketTypeException) {
comment = getStringResource(R.string.omnipod_error_invalid_packet_type); comment = getStringResource(R.string.omnipod_error_invalid_packet_type);
} else if (ex instanceof IllegalPodProgressException || ex instanceof IllegalDeliveryStatusException) { } else if (ex instanceof IllegalPodProgressException || ex instanceof IllegalActivationProgressException ||
ex instanceof IllegalDeliveryStatusException) {
comment = getStringResource(R.string.omnipod_error_invalid_progress_state); comment = getStringResource(R.string.omnipod_error_invalid_progress_state);
} else if (ex instanceof IllegalVersionResponseTypeException) { } else if (ex instanceof IllegalVersionResponseTypeException) {
comment = getStringResource(R.string.omnipod_error_invalid_response); comment = getStringResource(R.string.omnipod_error_invalid_response);
@ -794,8 +794,10 @@ public class AapsOmnipodManager {
} else if (ex instanceof NotEnoughDataException) { } else if (ex instanceof NotEnoughDataException) {
comment = getStringResource(R.string.omnipod_error_not_enough_data); comment = getStringResource(R.string.omnipod_error_not_enough_data);
} else if (ex instanceof PodFaultException) { } else if (ex instanceof PodFaultException) {
FaultEventCode faultEventCode = ((PodFaultException) ex).getFaultEvent().getFaultEventCode(); FaultEventCode faultEventCode = ((PodFaultException) ex).getDetailedStatus().getFaultEventCode();
comment = createPodFaultErrorMessage(faultEventCode); comment = createPodFaultErrorMessage(faultEventCode);
} else if (ex instanceof ActivationTimeExceededException) {
comment = getStringResource(R.string.omnipod_error_pod_fault_activation_time_exceeded);
} else if (ex instanceof PodReturnedErrorResponseException) { } else if (ex instanceof PodReturnedErrorResponseException) {
comment = getStringResource(R.string.omnipod_error_pod_returned_error_response); comment = getStringResource(R.string.omnipod_error_pod_returned_error_response);
} else if (ex instanceof RileyLinkUnreachableException) { } else if (ex instanceof RileyLinkUnreachableException) {
@ -816,9 +818,6 @@ public class AapsOmnipodManager {
} }
private String createPodFaultErrorMessage(FaultEventCode faultEventCode) { private String createPodFaultErrorMessage(FaultEventCode faultEventCode) {
if (faultEventCode == FaultEventCode.NO_FAULTS && podStateManager.getPodProgressStatus() == PodProgressStatus.ACTIVATION_TIME_EXCEEDED) {
return getStringResource(R.string.omnipod_error_pod_fault_activation_time_exceeded);
}
return getStringResource(R.string.omnipod_error_pod_fault, return getStringResource(R.string.omnipod_error_pod_fault,
ByteUtil.convertUnsignedByteToInt(faultEventCode.getValue()), faultEventCode.name()); ByteUtil.convertUnsignedByteToInt(faultEventCode.getValue()), faultEventCode.name());
} }

View file

@ -23,12 +23,13 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.mess
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.ErrorResponse; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.ErrorResponse;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.StatusUpdatableResponse; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.StatusUpdatableResponse;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfo; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfo;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoFaultEvent; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoDetailedStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoResponse; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoResponse;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.MessageBlockType; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.MessageBlockType;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PacketType; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PacketType;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodInfoType; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodInfoType;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.ActivationTimeExceededException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalMessageAddressException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalMessageAddressException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalMessageSequenceNumberException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalMessageSequenceNumberException;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalPacketTypeException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalPacketTypeException;
@ -156,12 +157,21 @@ public class OmnipodRileyLinkCommunicationManager extends RileyLinkCommunication
podStateManager.setLastFailedCommunication(DateTime.now()); podStateManager.setLastFailedCommunication(DateTime.now());
throw new PodReturnedErrorResponseException(error); throw new PodReturnedErrorResponseException(error);
} }
} else if (responseMessageBlock.getType() == MessageBlockType.POD_INFO_RESPONSE && ((PodInfoResponse) responseMessageBlock).getSubType() == PodInfoType.FAULT_EVENT) { } else if (responseMessageBlock.getType() == MessageBlockType.POD_INFO_RESPONSE && ((PodInfoResponse) responseMessageBlock).getSubType() == PodInfoType.DETAILED_STATUS) {
PodInfoFaultEvent faultEvent = (PodInfoFaultEvent) ((PodInfoResponse) responseMessageBlock).getPodInfo(); PodInfoDetailedStatus detailedStatus = (PodInfoDetailedStatus) ((PodInfoResponse) responseMessageBlock).getPodInfo();
podStateManager.setFaultEvent(faultEvent); if (detailedStatus.isFaulted()) {
// Treat as successful communication as the user will get notified and can work with this response // Treat as successful communication in order to prevent false positive pump unreachable alarms
podStateManager.setLastSuccessfulCommunication(DateTime.now()); podStateManager.setLastSuccessfulCommunication(DateTime.now());
throw new PodFaultException(faultEvent); throw new PodFaultException(detailedStatus);
} else if (detailedStatus.isActivationTimeExceeded()) {
// Treat as successful communication in order to prevent false positive pump unreachable alarms
podStateManager.setLastSuccessfulCommunication(DateTime.now());
throw new ActivationTimeExceededException();
} else {
// Shouldn't happen
podStateManager.setLastFailedCommunication(DateTime.now());
throw new IllegalResponseException(responseClass.getSimpleName(), responseMessageBlock.getType());
}
} else { } else {
podStateManager.setLastFailedCommunication(DateTime.now()); podStateManager.setLastFailedCommunication(DateTime.now());
throw new IllegalResponseException(responseClass.getSimpleName(), responseMessageBlock.getType()); throw new IllegalResponseException(responseClass.getSimpleName(), responseMessageBlock.getType());
@ -174,6 +184,7 @@ public class OmnipodRileyLinkCommunicationManager extends RileyLinkCommunication
} finally { } finally {
podStateManager.storePodState(); podStateManager.storePodState();
} }
} }
private MessageBlock transportMessages(PodStateManager podStateManager, OmnipodMessage message, Integer addressOverride, Integer ackAddressOverride) { private MessageBlock transportMessages(PodStateManager podStateManager, OmnipodMessage message, Integer addressOverride, Integer ackAddressOverride) {

View file

@ -23,6 +23,7 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.dialog.RileyL
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkServiceData import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkServiceData
import info.nightscout.androidaps.plugins.pump.omnipod.OmnipodPumpPlugin import info.nightscout.androidaps.plugins.pump.omnipod.OmnipodPumpPlugin
import info.nightscout.androidaps.plugins.pump.omnipod.R import info.nightscout.androidaps.plugins.pump.omnipod.R
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.ActivationProgress
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus
import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager
@ -272,8 +273,8 @@ class OmnipodOverviewFragment : DaggerFragment() {
}) })
} }
if (podStateManager.hasFaultEvent()) { if (podStateManager.isFaulted) {
val faultEventCode = podStateManager.faultEvent.faultEventCode val faultEventCode = podStateManager.faultEventCode
errors.add(resourceHelper.gs(R.string.omnipod_pod_status_pod_fault_description, faultEventCode.value, faultEventCode.name)) errors.add(resourceHelper.gs(R.string.omnipod_pod_status_pod_fault_description, faultEventCode.value, faultEventCode.name))
} }
@ -345,9 +346,7 @@ class OmnipodOverviewFragment : DaggerFragment() {
if (!podStateManager.isPodInitialized) { if (!podStateManager.isPodInitialized) {
resourceHelper.gs(R.string.omnipod_pod_status_waiting_for_activation) resourceHelper.gs(R.string.omnipod_pod_status_waiting_for_activation)
} else { } else {
if (PodProgressStatus.ACTIVATION_TIME_EXCEEDED == podStateManager.podProgressStatus) { if (podStateManager.activationProgress.isBefore(ActivationProgress.PRIMING_COMPLETED)) {
resourceHelper.gs(R.string.omnipod_pod_status_activation_time_exceeded)
} else if (podStateManager.podProgressStatus.isBefore(PodProgressStatus.PRIMING_COMPLETED)) {
resourceHelper.gs(R.string.omnipod_pod_status_waiting_for_activation) resourceHelper.gs(R.string.omnipod_pod_status_waiting_for_activation)
} else { } else {
resourceHelper.gs(R.string.omnipod_pod_status_waiting_for_cannula_insertion) resourceHelper.gs(R.string.omnipod_pod_status_waiting_for_cannula_insertion)
@ -454,7 +453,7 @@ class OmnipodOverviewFragment : DaggerFragment() {
} }
private fun updateRefreshStatusButton() { private fun updateRefreshStatusButton() {
omnipod_overview_button_refresh_status.isEnabled = podStateManager.isPodInitialized && podStateManager.podProgressStatus.isAtLeast(PodProgressStatus.PAIRING_COMPLETED) omnipod_overview_button_refresh_status.isEnabled = podStateManager.isPodInitialized && podStateManager.activationProgress.isAtLeast(ActivationProgress.PAIRING_COMPLETED)
&& rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty() && rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty()
} }

View file

@ -9,6 +9,7 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.pump.common.events.EventRileyLinkDeviceStatusChange import info.nightscout.androidaps.plugins.pump.common.events.EventRileyLinkDeviceStatusChange
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkServiceData import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkServiceData
import info.nightscout.androidaps.plugins.pump.omnipod.R import info.nightscout.androidaps.plugins.pump.omnipod.R
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.ActivationProgress
import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager
import info.nightscout.androidaps.plugins.pump.omnipod.event.EventOmnipodPumpValuesChanged import info.nightscout.androidaps.plugins.pump.omnipod.event.EventOmnipodPumpValuesChanged
import info.nightscout.androidaps.plugins.pump.omnipod.manager.AapsOmnipodManager import info.nightscout.androidaps.plugins.pump.omnipod.manager.AapsOmnipodManager
@ -94,7 +95,7 @@ class PodManagementActivity : NoSplashAppCompatActivity() {
if (rileyLinkServiceData.rileyLinkServiceState.isReady) { if (rileyLinkServiceData.rileyLinkServiceState.isReady) {
omnipod_pod_management_button_activate_pod.isEnabled = !podStateManager.isPodActivationCompleted omnipod_pod_management_button_activate_pod.isEnabled = !podStateManager.isPodActivationCompleted
omnipod_pod_management_button_deactivate_pod.isEnabled = podStateManager.isPodInitialized omnipod_pod_management_button_deactivate_pod.isEnabled = podStateManager.activationProgress.isAtLeast(ActivationProgress.PAIRING_COMPLETED)
if (discardButtonEnabled) { if (discardButtonEnabled) {
omnipod_pod_management_button_discard_pod.isEnabled = true omnipod_pod_management_button_discard_pod.isEnabled = true
} }

View file

@ -3,7 +3,7 @@ package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.activation
import android.os.Bundle import android.os.Bundle
import androidx.annotation.IdRes import androidx.annotation.IdRes
import info.nightscout.androidaps.plugins.pump.omnipod.R import info.nightscout.androidaps.plugins.pump.omnipod.R
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.ActivationProgress
import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager
import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.activity.OmnipodWizardActivityBase import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.activity.OmnipodWizardActivityBase
import javax.inject.Inject import javax.inject.Inject
@ -25,7 +25,7 @@ class PodActivationWizardActivity : OmnipodWizardActivityBase() {
setContentView(R.layout.omnipod_pod_activation_wizard_activity) setContentView(R.layout.omnipod_pod_activation_wizard_activity)
startDestination = savedInstanceState?.getInt(KEY_START_DESTINATION, R.id.fillPodInfoFragment) startDestination = savedInstanceState?.getInt(KEY_START_DESTINATION, R.id.fillPodInfoFragment)
?: if (!podStateManager.isPodInitialized || podStateManager.podProgressStatus.isBefore(PodProgressStatus.PRIMING_COMPLETED)) { ?: if (podStateManager.activationProgress.isBefore(ActivationProgress.PRIMING_COMPLETED)) {
R.id.fillPodInfoFragment R.id.fillPodInfoFragment
} else { } else {
R.id.attachPodInfoFragment R.id.attachPodInfoFragment

View file

@ -3,8 +3,7 @@ package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.activation.fra
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import info.nightscout.androidaps.plugins.pump.omnipod.R import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.ActivationProgress
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus
import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager
import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.fragment.ActionFragmentBase import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.fragment.ActionFragmentBase
import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.deactivation.PodDeactivationWizardActivity import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.deactivation.PodDeactivationWizardActivity
@ -27,8 +26,7 @@ abstract class PodActivationActionFragmentBase : ActionFragmentBase() {
} }
override fun onActionFailure() { override fun onActionFailure() {
if (podStateManager.isPodInitialized && podStateManager.podProgressStatus == PodProgressStatus.ACTIVATION_TIME_EXCEEDED) { if (podStateManager.isPodActivationTimeExceeded && podStateManager.activationProgress.isAtLeast(ActivationProgress.PAIRING_COMPLETED)) {
omnipod_wizard_action_error.setText(R.string.omnipod_error_pod_fault_activation_time_exceeded)
omnipod_wizard_button_retry.visibility = View.GONE omnipod_wizard_button_retry.visibility = View.GONE
omnipod_wizard_button_deactivate_pod.visibility = View.VISIBLE omnipod_wizard_button_deactivate_pod.visibility = View.VISIBLE
} }

View file

@ -65,7 +65,8 @@ public class OmnipodPumpPluginTest {
when(activePluginProvider.getActiveTreatments().getTempBasalFromHistory(anyLong())).thenReturn(null); when(activePluginProvider.getActiveTreatments().getTempBasalFromHistory(anyLong())).thenReturn(null);
when(rileyLinkUtil.getRileyLinkHistory()).thenReturn(new ArrayList<>()); when(rileyLinkUtil.getRileyLinkHistory()).thenReturn(new ArrayList<>());
when(injector.androidInjector()).thenReturn(new AndroidInjector<Object>() { when(injector.androidInjector()).thenReturn(new AndroidInjector<Object>() {
@Override public void inject(Object instance) {} @Override public void inject(Object instance) {
}
}); });
Profile profile = mock(Profile.class); Profile profile = mock(Profile.class);
@ -118,7 +119,7 @@ public class OmnipodPumpPluginTest {
// When treatment // When treatment
result1 = plugin.setTempBasalPercent(80, 30, profile, false); result1 = plugin.setTempBasalPercent(80, 30, profile, false);
// Then return sane values // Then return sane values
assertEquals(result1.absolute, PumpType.Insulet_Omnipod.determineCorrectBasalSize(500d * 0.8), 0.01d); assertEquals(result1.absolute, PumpType.Insulet_Omnipod.determineCorrectBasalSize(500d * 0.8), 0.01d);
assertEquals(result1.duration, 30); assertEquals(result1.duration, 30);
// Given weird basal // Given weird basal

View file

@ -24,7 +24,7 @@ public class GetStatusCommandTest {
@Test @Test
public void testPodInfoTypeFaultEvents() { public void testPodInfoTypeFaultEvents() {
GetStatusCommand getStatusCommand = new GetStatusCommand(PodInfoType.FAULT_EVENT); GetStatusCommand getStatusCommand = new GetStatusCommand(PodInfoType.DETAILED_STATUS);
assertArrayEquals(ByteUtil.fromHexString("0e0102"), getStatusCommand.getRawData()); assertArrayEquals(ByteUtil.fromHexString("0e0102"), getStatusCommand.getRawData());
} }

View file

@ -0,0 +1,162 @@
package info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo;
import org.joda.time.Duration;
import org.junit.Test;
import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.DeliveryStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.ErrorEventInfo;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.FaultEventCode;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
// From https://github.com/ps2/rileylink_ios/blob/omnipod-testing/OmniKitTests/PodInfoTests.swift
public class PodInfoDetailedStatusTest {
@Test
public void testPodInfoFaultEventNoFaultAlerts() {
PodInfoDetailedStatus podInfoDetailedStatus = new PodInfoDetailedStatus(ByteUtil.fromHexString("02080100000a003800000003ff008700000095ff0000"));
assertEquals(PodProgressStatus.ABOVE_FIFTY_UNITS, podInfoDetailedStatus.getPodProgressStatus());
assertEquals(DeliveryStatus.NORMAL, podInfoDetailedStatus.getDeliveryStatus());
assertEquals(0, podInfoDetailedStatus.getBolusNotDelivered(), 0.000001);
assertEquals(0x0a, podInfoDetailedStatus.getPodMessageCounter());
assertNull(podInfoDetailedStatus.getFaultEventCode());
assertTrue(Duration.ZERO.isEqual(podInfoDetailedStatus.getFaultEventTime()));
assertNull(podInfoDetailedStatus.getReservoirLevel());
assertTrue(Duration.standardSeconds(8100).isEqual(podInfoDetailedStatus.getTimeActive()));
assertEquals(0, podInfoDetailedStatus.getUnacknowledgedAlerts().getRawValue());
assertFalse(podInfoDetailedStatus.isFaultAccessingTables());
ErrorEventInfo errorEventInfo = podInfoDetailedStatus.getErrorEventInfo();
assertNull(errorEventInfo);
assertNull(podInfoDetailedStatus.getPreviousPodProgressStatus());
assertEquals(2, podInfoDetailedStatus.getReceiverLowGain());
assertEquals(21, podInfoDetailedStatus.getRadioRSSI());
}
@Test
public void testPodInfoFaultEventDeliveryErrorDuringPriming() {
PodInfoDetailedStatus podInfoDetailedStatus = new PodInfoDetailedStatus(ByteUtil.fromHexString("020f0000000900345c000103ff0001000005ae056029"));
assertEquals(PodProgressStatus.INACTIVE, podInfoDetailedStatus.getPodProgressStatus());
assertEquals(DeliveryStatus.SUSPENDED, podInfoDetailedStatus.getDeliveryStatus());
assertEquals(0, podInfoDetailedStatus.getBolusNotDelivered(), 0.000001);
assertEquals(0x09, podInfoDetailedStatus.getPodMessageCounter());
assertEquals(FaultEventCode.PRIME_OPEN_COUNT_TOO_LOW, podInfoDetailedStatus.getFaultEventCode());
assertTrue(Duration.standardSeconds(60).isEqual(podInfoDetailedStatus.getFaultEventTime()));
assertNull(podInfoDetailedStatus.getReservoirLevel());
assertTrue(Duration.standardSeconds(60).isEqual(podInfoDetailedStatus.getTimeActive()));
assertEquals(0, podInfoDetailedStatus.getUnacknowledgedAlerts().getRawValue());
assertFalse(podInfoDetailedStatus.isFaultAccessingTables());
ErrorEventInfo errorEventInfo = podInfoDetailedStatus.getErrorEventInfo();
assertFalse(errorEventInfo.isInsulinStateTableCorruption());
assertEquals(0x00, errorEventInfo.getInternalVariable());
assertFalse(errorEventInfo.isImmediateBolusInProgress());
assertEquals(PodProgressStatus.PRIMING_COMPLETED, errorEventInfo.getPodProgressStatus());
assertEquals(PodProgressStatus.PRIMING_COMPLETED, podInfoDetailedStatus.getPreviousPodProgressStatus());
assertEquals(2, podInfoDetailedStatus.getReceiverLowGain());
assertEquals(46, podInfoDetailedStatus.getRadioRSSI());
}
@Test
public void testPodInfoFaultEventErrorShuttingDown() {
PodInfoDetailedStatus podInfoDetailedStatus = new PodInfoDetailedStatus(ByteUtil.fromHexString("020d0000000407f28609ff03ff0a0200000823080000"));
assertEquals(PodProgressStatus.FAULT_EVENT_OCCURRED, podInfoDetailedStatus.getPodProgressStatus());
assertEquals(DeliveryStatus.SUSPENDED, podInfoDetailedStatus.getDeliveryStatus());
assertEquals(2034, podInfoDetailedStatus.getTicksDelivered());
assertEquals(101.7, podInfoDetailedStatus.getInsulinDelivered(), 0.000001);
assertEquals(0, podInfoDetailedStatus.getBolusNotDelivered(), 0.000001);
assertEquals(0x04, podInfoDetailedStatus.getPodMessageCounter());
assertEquals(FaultEventCode.BASAL_OVER_INFUSION_PULSE, podInfoDetailedStatus.getFaultEventCode());
assertTrue(Duration.standardMinutes(2559).isEqual(podInfoDetailedStatus.getFaultEventTime()));
assertNull(podInfoDetailedStatus.getReservoirLevel());
assertEquals(0, podInfoDetailedStatus.getUnacknowledgedAlerts().getRawValue());
assertFalse(podInfoDetailedStatus.isFaultAccessingTables());
ErrorEventInfo errorEventInfo = podInfoDetailedStatus.getErrorEventInfo();
assertFalse(errorEventInfo.isInsulinStateTableCorruption());
assertEquals(0x00, errorEventInfo.getInternalVariable());
assertFalse(errorEventInfo.isImmediateBolusInProgress());
assertEquals(PodProgressStatus.ABOVE_FIFTY_UNITS, errorEventInfo.getPodProgressStatus());
assertEquals(PodProgressStatus.ABOVE_FIFTY_UNITS, podInfoDetailedStatus.getPreviousPodProgressStatus());
assertEquals(0, podInfoDetailedStatus.getReceiverLowGain());
assertEquals(35, podInfoDetailedStatus.getRadioRSSI());
}
@Test
public void testPodInfoFaultEventInsulinNotDelivered() {
PodInfoDetailedStatus podInfoDetailedStatus = new PodInfoDetailedStatus(ByteUtil.fromHexString("020f0000010200ec6a026803ff026b000028a7082023"));
assertEquals(PodProgressStatus.INACTIVE, podInfoDetailedStatus.getPodProgressStatus());
assertEquals(DeliveryStatus.SUSPENDED, podInfoDetailedStatus.getDeliveryStatus());
assertEquals(236, podInfoDetailedStatus.getTicksDelivered());
assertEquals(11.8, podInfoDetailedStatus.getInsulinDelivered(), 0.000001);
assertEquals(0.05, podInfoDetailedStatus.getBolusNotDelivered(), 0.000001);
assertEquals(0x02, podInfoDetailedStatus.getPodMessageCounter());
assertEquals(FaultEventCode.OCCLUSION_CHECK_ABOVE_THRESHOLD, podInfoDetailedStatus.getFaultEventCode());
assertTrue(Duration.standardMinutes(616).isEqual(podInfoDetailedStatus.getFaultEventTime()));
assertNull(podInfoDetailedStatus.getReservoirLevel());
assertEquals(0, podInfoDetailedStatus.getUnacknowledgedAlerts().getRawValue());
assertFalse(podInfoDetailedStatus.isFaultAccessingTables());
ErrorEventInfo errorEventInfo = podInfoDetailedStatus.getErrorEventInfo();
assertFalse(errorEventInfo.isInsulinStateTableCorruption());
assertEquals(0x01, errorEventInfo.getInternalVariable());
assertFalse(errorEventInfo.isImmediateBolusInProgress());
assertEquals(PodProgressStatus.ABOVE_FIFTY_UNITS, errorEventInfo.getPodProgressStatus());
assertEquals(PodProgressStatus.ABOVE_FIFTY_UNITS, podInfoDetailedStatus.getPreviousPodProgressStatus());
assertEquals(2, podInfoDetailedStatus.getReceiverLowGain());
assertEquals(39, podInfoDetailedStatus.getRadioRSSI());
}
@Test
public void testPodInfoFaultEventMaxBolusNotDelivered() {
PodInfoDetailedStatus podInfoDetailedStatus = new PodInfoDetailedStatus(ByteUtil.fromHexString("020f00ffff0200ec6a026803ff026b000028a7082023"));
assertEquals(PodProgressStatus.INACTIVE, podInfoDetailedStatus.getPodProgressStatus());
assertEquals(DeliveryStatus.SUSPENDED, podInfoDetailedStatus.getDeliveryStatus());
assertEquals(236, podInfoDetailedStatus.getTicksDelivered());
assertEquals(11.8, podInfoDetailedStatus.getInsulinDelivered(), 0.000001);
assertEquals(3276.75, podInfoDetailedStatus.getBolusNotDelivered(), 0.000001); // Insane and will not happen, but this verifies that we convert it to an unsigned int
assertEquals(0x02, podInfoDetailedStatus.getPodMessageCounter());
assertEquals(FaultEventCode.OCCLUSION_CHECK_ABOVE_THRESHOLD, podInfoDetailedStatus.getFaultEventCode());
assertTrue(Duration.standardMinutes(616).isEqual(podInfoDetailedStatus.getFaultEventTime()));
assertNull(podInfoDetailedStatus.getReservoirLevel());
assertEquals(0, podInfoDetailedStatus.getUnacknowledgedAlerts().getRawValue());
assertFalse(podInfoDetailedStatus.isFaultAccessingTables());
ErrorEventInfo errorEventInfo = podInfoDetailedStatus.getErrorEventInfo();
assertFalse(errorEventInfo.isInsulinStateTableCorruption());
assertEquals(0x01, errorEventInfo.getInternalVariable());
assertFalse(errorEventInfo.isImmediateBolusInProgress());
assertEquals(PodProgressStatus.ABOVE_FIFTY_UNITS, errorEventInfo.getPodProgressStatus());
assertEquals(PodProgressStatus.ABOVE_FIFTY_UNITS, podInfoDetailedStatus.getPreviousPodProgressStatus());
assertEquals(2, podInfoDetailedStatus.getReceiverLowGain());
assertEquals(39, podInfoDetailedStatus.getRadioRSSI());
}
@Test
public void testPodInfoFaultEventInsulinStateTableCorruptionFoundDuringErrorLogging() {
PodInfoDetailedStatus podInfoDetailedStatus = new PodInfoDetailedStatus(ByteUtil.fromHexString("020D00000000000012FFFF03FF00160000879A070000"));
assertEquals(PodProgressStatus.FAULT_EVENT_OCCURRED, podInfoDetailedStatus.getPodProgressStatus());
assertEquals(DeliveryStatus.SUSPENDED, podInfoDetailedStatus.getDeliveryStatus());
assertEquals(0, podInfoDetailedStatus.getBolusNotDelivered(), 0.000001);
assertEquals(0x00, podInfoDetailedStatus.getPodMessageCounter());
assertEquals(FaultEventCode.RESET_DUE_TO_LVD, podInfoDetailedStatus.getFaultEventCode());
assertTrue(Duration.ZERO.isEqual(podInfoDetailedStatus.getFaultEventTime()));
assertNull(podInfoDetailedStatus.getReservoirLevel());
assertTrue(Duration.standardSeconds(1320).isEqual(podInfoDetailedStatus.getTimeActive()));
assertEquals(0, podInfoDetailedStatus.getUnacknowledgedAlerts().getRawValue());
assertFalse(podInfoDetailedStatus.isFaultAccessingTables());
ErrorEventInfo errorEventInfo = podInfoDetailedStatus.getErrorEventInfo();
assertTrue(errorEventInfo.isInsulinStateTableCorruption());
assertEquals(0x00, errorEventInfo.getInternalVariable());
assertFalse(errorEventInfo.isImmediateBolusInProgress());
assertEquals(PodProgressStatus.INSERTING_CANNULA, errorEventInfo.getPodProgressStatus());
assertEquals(PodProgressStatus.INSERTING_CANNULA, podInfoDetailedStatus.getPreviousPodProgressStatus());
assertEquals(2, podInfoDetailedStatus.getReceiverLowGain());
assertEquals(26, podInfoDetailedStatus.getRadioRSSI());
}
}

View file

@ -1,121 +0,0 @@
package info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo;
import org.joda.time.Duration;
import org.junit.Test;
import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.DeliveryStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.FaultEventCode;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.LogEventErrorCode;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
// From https://github.com/ps2/rileylink_ios/blob/omnipod-testing/OmniKitTests/PodInfoTests.swift
public class PodInfoFaultEventTest {
@Test
public void testPodInfoFaultEventNoFaultAlerts() {
PodInfoFaultEvent podInfoFaultEvent = new PodInfoFaultEvent(ByteUtil.fromHexString("02080100000a003800000003ff008700000095ff0000"));
assertEquals(PodProgressStatus.ABOVE_FIFTY_UNITS, podInfoFaultEvent.getPodProgressStatus());
assertEquals(DeliveryStatus.NORMAL, podInfoFaultEvent.getDeliveryStatus());
assertEquals(0, podInfoFaultEvent.getBolusNotDelivered(), 0.000001);
assertEquals(0x0a, podInfoFaultEvent.getPodMessageCounter());
assertEquals(FaultEventCode.NO_FAULTS, podInfoFaultEvent.getFaultEventCode());
assertTrue(Duration.ZERO.isEqual(podInfoFaultEvent.getFaultEventTime()));
assertNull(podInfoFaultEvent.getReservoirLevel());
assertTrue(Duration.standardSeconds(8100).isEqual(podInfoFaultEvent.getTimeActive()));
assertEquals(0, podInfoFaultEvent.getUnacknowledgedAlerts().getRawValue());
assertFalse(podInfoFaultEvent.isFaultAccessingTables());
assertEquals(LogEventErrorCode.NONE, podInfoFaultEvent.getLogEventErrorType());
assertEquals(PodProgressStatus.INACTIVE, podInfoFaultEvent.getPodProgressStatusAtTimeOfFirstLoggedFaultEvent());
assertEquals(2, podInfoFaultEvent.getReceiverLowGain());
assertEquals(21, podInfoFaultEvent.getRadioRSSI());
}
@Test
public void testPodInfoFaultEventDeliveryErrorDuringPriming() {
PodInfoFaultEvent podInfoFaultEvent = new PodInfoFaultEvent(ByteUtil.fromHexString("020f0000000900345c000103ff0001000005ae056029"));
assertEquals(PodProgressStatus.INACTIVE, podInfoFaultEvent.getPodProgressStatus());
assertEquals(DeliveryStatus.SUSPENDED, podInfoFaultEvent.getDeliveryStatus());
assertEquals(0, podInfoFaultEvent.getBolusNotDelivered(), 0.000001);
assertEquals(0x09, podInfoFaultEvent.getPodMessageCounter());
assertEquals(FaultEventCode.PRIME_OPEN_COUNT_TOO_LOW, podInfoFaultEvent.getFaultEventCode());
assertTrue(Duration.standardSeconds(60).isEqual(podInfoFaultEvent.getFaultEventTime()));
assertNull(podInfoFaultEvent.getReservoirLevel());
assertTrue(Duration.standardSeconds(60).isEqual(podInfoFaultEvent.getTimeActive()));
assertEquals(0, podInfoFaultEvent.getUnacknowledgedAlerts().getRawValue());
assertFalse(podInfoFaultEvent.isFaultAccessingTables());
assertEquals(LogEventErrorCode.NONE, podInfoFaultEvent.getLogEventErrorType());
assertEquals(PodProgressStatus.PRIMING_COMPLETED, podInfoFaultEvent.getPodProgressStatusAtTimeOfFirstLoggedFaultEvent());
assertEquals(2, podInfoFaultEvent.getReceiverLowGain());
assertEquals(46, podInfoFaultEvent.getRadioRSSI());
}
@Test
public void testPodInfoFaultEventErrorShuttingDown() {
PodInfoFaultEvent podInfoFaultEvent = new PodInfoFaultEvent(ByteUtil.fromHexString("020d0000000407f28609ff03ff0a0200000823080000"));
assertEquals(PodProgressStatus.FAULT_EVENT_OCCURRED, podInfoFaultEvent.getPodProgressStatus());
assertEquals(DeliveryStatus.SUSPENDED, podInfoFaultEvent.getDeliveryStatus());
assertEquals(2034, podInfoFaultEvent.getTicksDelivered());
assertEquals(101.7, podInfoFaultEvent.getInsulinDelivered(), 0.000001);
assertEquals(0, podInfoFaultEvent.getBolusNotDelivered(), 0.000001);
assertEquals(0x04, podInfoFaultEvent.getPodMessageCounter());
assertEquals(FaultEventCode.BASAL_OVER_INFUSION_PULSE, podInfoFaultEvent.getFaultEventCode());
assertTrue(Duration.standardMinutes(2559).isEqual(podInfoFaultEvent.getFaultEventTime()));
assertNull(podInfoFaultEvent.getReservoirLevel());
assertEquals(0, podInfoFaultEvent.getUnacknowledgedAlerts().getRawValue());
assertFalse(podInfoFaultEvent.isFaultAccessingTables());
assertEquals(LogEventErrorCode.NONE, podInfoFaultEvent.getLogEventErrorType());
assertEquals(PodProgressStatus.ABOVE_FIFTY_UNITS, podInfoFaultEvent.getPodProgressStatusAtTimeOfFirstLoggedFaultEvent());
assertEquals(0, podInfoFaultEvent.getReceiverLowGain());
assertEquals(35, podInfoFaultEvent.getRadioRSSI());
}
@Test
public void testPodInfoFaultEventInsulinNotDelivered() {
PodInfoFaultEvent podInfoFaultEvent = new PodInfoFaultEvent(ByteUtil.fromHexString("020f0000010200ec6a026803ff026b000028a7082023"));
assertEquals(PodProgressStatus.INACTIVE, podInfoFaultEvent.getPodProgressStatus());
assertEquals(DeliveryStatus.SUSPENDED, podInfoFaultEvent.getDeliveryStatus());
assertEquals(236, podInfoFaultEvent.getTicksDelivered());
assertEquals(11.8, podInfoFaultEvent.getInsulinDelivered(), 0.000001);
assertEquals(0.05, podInfoFaultEvent.getBolusNotDelivered(), 0.000001);
assertEquals(0x02, podInfoFaultEvent.getPodMessageCounter());
assertEquals(FaultEventCode.OCCLUSION_CHECK_ABOVE_THRESHOLD, podInfoFaultEvent.getFaultEventCode());
assertTrue(Duration.standardMinutes(616).isEqual(podInfoFaultEvent.getFaultEventTime()));
assertNull(podInfoFaultEvent.getReservoirLevel());
assertEquals(0, podInfoFaultEvent.getUnacknowledgedAlerts().getRawValue());
assertFalse(podInfoFaultEvent.isFaultAccessingTables());
assertEquals(LogEventErrorCode.INTERNAL_2_BIT_VARIABLE_SET_AND_MANIPULATED_IN_MAIN_LOOP_ROUTINES_2, podInfoFaultEvent.getLogEventErrorType());
assertEquals(PodProgressStatus.ABOVE_FIFTY_UNITS, podInfoFaultEvent.getPodProgressStatusAtTimeOfFirstLoggedFaultEvent());
assertEquals(2, podInfoFaultEvent.getReceiverLowGain());
assertEquals(39, podInfoFaultEvent.getRadioRSSI());
}
@Test
public void testPodInfoFaultEventMaxBolusNotDelivered() {
PodInfoFaultEvent podInfoFaultEvent = new PodInfoFaultEvent(ByteUtil.fromHexString("020f00ffff0200ec6a026803ff026b000028a7082023"));
assertEquals(PodProgressStatus.INACTIVE, podInfoFaultEvent.getPodProgressStatus());
assertEquals(DeliveryStatus.SUSPENDED, podInfoFaultEvent.getDeliveryStatus());
assertEquals(236, podInfoFaultEvent.getTicksDelivered());
assertEquals(11.8, podInfoFaultEvent.getInsulinDelivered(), 0.000001);
assertEquals(3276.75, podInfoFaultEvent.getBolusNotDelivered(), 0.000001); // Insane and will not happen, but this verifies that we convert it to an unsigned int
assertEquals(0x02, podInfoFaultEvent.getPodMessageCounter());
assertEquals(FaultEventCode.OCCLUSION_CHECK_ABOVE_THRESHOLD, podInfoFaultEvent.getFaultEventCode());
assertTrue(Duration.standardMinutes(616).isEqual(podInfoFaultEvent.getFaultEventTime()));
assertNull(podInfoFaultEvent.getReservoirLevel());
assertEquals(0, podInfoFaultEvent.getUnacknowledgedAlerts().getRawValue());
assertFalse(podInfoFaultEvent.isFaultAccessingTables());
assertEquals(LogEventErrorCode.INTERNAL_2_BIT_VARIABLE_SET_AND_MANIPULATED_IN_MAIN_LOOP_ROUTINES_2, podInfoFaultEvent.getLogEventErrorType());
assertEquals(PodProgressStatus.ABOVE_FIFTY_UNITS, podInfoFaultEvent.getPodProgressStatusAtTimeOfFirstLoggedFaultEvent());
assertEquals(2, podInfoFaultEvent.getReceiverLowGain());
assertEquals(39, podInfoFaultEvent.getRadioRSSI());
}
}

View file

@ -5,7 +5,6 @@ import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.LogEventErrorCode;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodInfoType; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodInfoType;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
@ -39,18 +38,18 @@ public class PodInfoResponseTest {
public void testMessageDecoding() { public void testMessageDecoding() {
PodInfoResponse podInfoResponse = new PodInfoResponse(ByteUtil.fromHexString("0216020d0000000000ab6a038403ff03860000285708030d")); PodInfoResponse podInfoResponse = new PodInfoResponse(ByteUtil.fromHexString("0216020d0000000000ab6a038403ff03860000285708030d"));
assertEquals(PodInfoType.FAULT_EVENT, podInfoResponse.getSubType()); assertEquals(PodInfoType.DETAILED_STATUS, podInfoResponse.getSubType());
PodInfoFaultEvent podInfo = (PodInfoFaultEvent) podInfoResponse.getPodInfo(); PodInfoDetailedStatus podInfo = (PodInfoDetailedStatus) podInfoResponse.getPodInfo();
assertFalse(podInfo.isFaultAccessingTables()); assertFalse(podInfo.isFaultAccessingTables());
assertEquals(LogEventErrorCode.INTERNAL_2_BIT_VARIABLE_SET_AND_MANIPULATED_IN_MAIN_LOOP_ROUTINES_2, podInfo.getLogEventErrorType()); assertEquals(0x01, podInfo.getErrorEventInfo().getInternalVariable());
} }
@Test @Test
public void testInvalidPodInfoTypeMessageDecoding() { public void testInvalidPodInfoTypeMessageDecoding() {
PodInfoResponse podInfoResponse = new PodInfoResponse(ByteUtil.fromHexString("0216020d0000000000ab6a038403ff03860000285708030d")); PodInfoResponse podInfoResponse = new PodInfoResponse(ByteUtil.fromHexString("0216020d0000000000ab6a038403ff03860000285708030d"));
assertEquals(PodInfoType.FAULT_EVENT, podInfoResponse.getSubType()); assertEquals(PodInfoType.DETAILED_STATUS, podInfoResponse.getSubType());
thrown.expect(ClassCastException.class); thrown.expect(ClassCastException.class);
PodInfoActiveAlerts podInfo = (PodInfoActiveAlerts) podInfoResponse.getPodInfo(); PodInfoActiveAlerts podInfo = (PodInfoActiveAlerts) podInfoResponse.getPodInfo();

View file

@ -1,12 +1,15 @@
package info.nightscout.androidaps.plugins.pump.common.events package info.nightscout.androidaps.plugins.pump.common.events
import info.nightscout.androidaps.events.Event import info.nightscout.androidaps.events.EventStatus
import info.nightscout.androidaps.plugins.pump.common.defs.PumpDeviceState import info.nightscout.androidaps.plugins.pump.common.defs.PumpDeviceState
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkError import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkError
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkServiceState import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkServiceState
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkTargetDevice
import info.nightscout.androidaps.utils.resources.ResourceHelper
open class EventRileyLinkDeviceStatusChange : Event { open class EventRileyLinkDeviceStatusChange : EventStatus {
var rileyLinkTargetDevice: RileyLinkTargetDevice? = null
var rileyLinkServiceState: RileyLinkServiceState? = null var rileyLinkServiceState: RileyLinkServiceState? = null
var rileyLinkError: RileyLinkError? = null var rileyLinkError: RileyLinkError? = null
@ -14,11 +17,10 @@ open class EventRileyLinkDeviceStatusChange : Event {
var errorDescription: String? = null var errorDescription: String? = null
constructor() { constructor() {
} }
constructor(rileyLinkTargetDevice: RileyLinkTargetDevice, rileyLinkServiceState: RileyLinkServiceState?, rileyLinkError: RileyLinkError?) {
constructor(rileyLinkServiceState: RileyLinkServiceState?, rileyLinkError: RileyLinkError?) { this.rileyLinkTargetDevice = rileyLinkTargetDevice
this.rileyLinkServiceState = rileyLinkServiceState this.rileyLinkServiceState = rileyLinkServiceState
this.rileyLinkError = rileyLinkError this.rileyLinkError = rileyLinkError
} }
@ -31,4 +33,17 @@ open class EventRileyLinkDeviceStatusChange : Event {
this.pumpDeviceState = pumpDeviceState this.pumpDeviceState = pumpDeviceState
this.errorDescription = errorDescription this.errorDescription = errorDescription
} }
override fun getStatus(resourceHelper: ResourceHelper): String {
val rileyLinkServiceState = this.rileyLinkServiceState ?: return ""
val resourceId = rileyLinkServiceState.resourceId
val rileyLinkError = this.rileyLinkError
if (rileyLinkServiceState.isError && rileyLinkError != null) {
val rileyLinkTargetDevice = this.rileyLinkTargetDevice ?: return ""
return resourceHelper.gs(rileyLinkError.getResourceId(rileyLinkTargetDevice))
}
return resourceHelper.gs(resourceId)
}
} }

View file

@ -24,8 +24,6 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.defs.Rile
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkError; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkError;
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkServiceState; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkServiceState;
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkTargetDevice; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkTargetDevice;
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.data.ServiceResult;
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.data.ServiceTransport;
import info.nightscout.androidaps.utils.resources.ResourceHelper; import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.sharedPreferences.SP; import info.nightscout.androidaps.utils.sharedPreferences.SP;
@ -114,6 +112,10 @@ public abstract class RileyLinkService extends DaggerService {
public abstract RileyLinkCommunicationManager getDeviceCommunicationManager(); public abstract RileyLinkCommunicationManager getDeviceCommunicationManager();
public RileyLinkServiceState getRileyLinkServiceState() {
return rileyLinkServiceData == null ? null : rileyLinkServiceData.rileyLinkServiceState;
}
// Here is where the wake-lock begins: // Here is where the wake-lock begins:
// We've received a service startCommand, we grab the lock. // We've received a service startCommand, we grab the lock.
@Override @Override

View file

@ -33,8 +33,7 @@ public class RileyLinkServiceData {
public RileyLinkServiceState rileyLinkServiceState = RileyLinkServiceState.NotStarted; public RileyLinkServiceState rileyLinkServiceState = RileyLinkServiceState.NotStarted;
private long lastServiceStateChange = 0L; private long lastServiceStateChange = 0L;
public RileyLinkFirmwareVersion firmwareVersion; public RileyLinkFirmwareVersion firmwareVersion;
public RileyLinkTargetFrequency rileyLinkTargetFrequency; // TODO this might not be correct place public RileyLinkTargetFrequency rileyLinkTargetFrequency;
public String rileylinkAddress; public String rileylinkAddress;
long lastTuneUpTime = 0L; long lastTuneUpTime = 0L;
public Double lastGoodFrequency; public Double lastGoodFrequency;
@ -44,7 +43,7 @@ public class RileyLinkServiceData {
// radio version // radio version
public RileyLinkFirmwareVersion versionCC110; public RileyLinkFirmwareVersion versionCC110;
public RileyLinkTargetDevice targetDevice; // TODO this might not be correct place public RileyLinkTargetDevice targetDevice;
// Medtronic Pump // Medtronic Pump
public String pumpID; public String pumpID;
@ -86,7 +85,7 @@ public class RileyLinkServiceData {
aapsLogger.info(LTag.PUMP, "RileyLink State Changed: {} {}", newState, errorCode == null ? "" : " - Error State: " + errorCode.name()); aapsLogger.info(LTag.PUMP, "RileyLink State Changed: {} {}", newState, errorCode == null ? "" : " - Error State: " + errorCode.name());
rileyLinkUtil.getRileyLinkHistory().add(new RLHistoryItem(rileyLinkServiceState, errorCode, targetDevice)); rileyLinkUtil.getRileyLinkHistory().add(new RLHistoryItem(rileyLinkServiceState, errorCode, targetDevice));
rxBus.send(new EventRileyLinkDeviceStatusChange(newState, errorCode)); rxBus.send(new EventRileyLinkDeviceStatusChange(targetDevice, newState, errorCode));
return null; return null;
} else { } else {