diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/OmnipodCommunicationService.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/OmnipodCommunicationService.java index 6a7c135565..21c5459a91 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/OmnipodCommunicationService.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/OmnipodCommunicationService.java @@ -18,6 +18,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.OmnipodAction import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.MessageBlock; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.OmnipodMessage; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.OmnipodPacket; +import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.command.DeactivatePodCommand; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.ErrorResponse; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.StatusResponse; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.podinfo.PodInfoFaultEvent; @@ -149,7 +150,9 @@ public class OmnipodCommunicationService extends RileyLinkCommunicationManager { boolean firstPacket = true; byte[] encodedMessage; - if (message.isNonceResyncable()) { + // this does not work well with the deactivate pod command, we somehow either + // receive an ACK instead of a normal response, or a partial response and a communication timeout + if (message.isNonceResyncable() && !message.containsBlock(DeactivatePodCommand.class)) { OmnipodMessage paddedMessage = new OmnipodMessage(message); // If messages are nonce resyncable, we want do distinguish between certain and uncertain failures for verification purposes // However, some commands (e.g. cancel delivery) are single packet command by nature. When we get a timeout with a single packet, diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/OmnipodManager.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/OmnipodManager.java index 1e115d1156..3262014a58 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/OmnipodManager.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/OmnipodManager.java @@ -26,9 +26,9 @@ import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.SetBasalSched import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.SetTempBasalAction; import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.service.InsertCannulaService; import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.service.PrimeService; -import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.service.SetTempBasalService; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.command.CancelDeliveryCommand; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.StatusResponse; +import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.podinfo.PodInfoRecentHighFlashLogDump; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.podinfo.PodInfoResponse; import info.nightscout.androidaps.plugins.pump.omnipod.defs.BeepType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.DeliveryStatus; @@ -202,15 +202,30 @@ public class OmnipodManager { } } + // CAUTION: cancels temp basal and then sets new temp basal. An OmnipodException[certainFailure=false] indicates that the pod might have cancelled the previous temp basal, but did not set a new temp basal public synchronized void setTemporaryBasal(TempBasalPair tempBasalPair, boolean acknowledgementBeep, boolean completionBeep) { assertReadyForDelivery(); logStartingCommandExecution("setTemporaryBasal [tempBasalPair=" + tempBasalPair + ", acknowledgementBeep=" + acknowledgementBeep + ", completionBeep=" + completionBeep + "]"); try { - executeAndVerify(() -> communicationService.executeAction(new SetTempBasalAction(new SetTempBasalService(), + // Never emit a beep for cancelling temp basal, so if the user has beeps enabled, + // they can verify that setting the temp basal succeeded (and not cancelling it) + cancelDelivery(EnumSet.of(DeliveryType.TEMP_BASAL), false); + } catch (Exception ex) { + logCommandExecutionFinished("setTemporaryBasal"); + throw ex; + } + + try { + executeAndVerify(() -> communicationService.executeAction(new SetTempBasalAction( podState, tempBasalPair.getInsulinRate(), Duration.standardMinutes(tempBasalPair.getDurationMinutes()), acknowledgementBeep, completionBeep))); + } catch (OmnipodException ex) { + // Treat all exceptions as uncertain failures, because all delivery has been suspended here. + // Setting this to an uncertain failure will enable for the user to get an appropriate warning + ex.setCertainFailure(false); + throw ex; } finally { logCommandExecutionFinished("setTemporaryBasal"); } @@ -401,9 +416,21 @@ public class OmnipodManager { logStartingCommandExecution("deactivatePod"); + // Try to get pulse log for diagnostics + // FIXME replace by storing to file + if (isLoggingEnabled()) { + try { + PodInfoResponse podInfoResponse = communicationService.executeAction(new GetPodInfoAction(podState, PodInfoType.RECENT_HIGH_FLASH_LOG_DUMP)); + PodInfoRecentHighFlashLogDump pulseLogInfo = podInfoResponse.getPodInfo(); + LOG.info("Retrieved pulse log from the pod: {}", pulseLogInfo.toString()); + } catch (Exception ex) { + LOG.warn("Failed to retrieve pulse log from the pod", ex); + } + } + try { // Always send acknowledgement beeps here. Matches the PDM's behavior - executeAndVerify(() -> communicationService.executeAction(new DeactivatePodAction(podState, true))); + communicationService.executeAction(new DeactivatePodAction(podState, true)); } catch (PodFaultException ex) { if (isLoggingEnabled()) { LOG.info("Ignoring PodFaultException in deactivatePod", ex); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/action/CancelDeliveryAction.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/action/CancelDeliveryAction.java index edff5b48dd..686fc0036b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/action/CancelDeliveryAction.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/action/CancelDeliveryAction.java @@ -34,11 +34,6 @@ public class CancelDeliveryAction implements OmnipodAction { this.acknowledgementBeep = acknowledgementBeep; } - public CancelDeliveryAction(PodSessionState podState, DeliveryType deliveryType, - boolean acknowledgementBeep) { - this(podState, EnumSet.of(deliveryType), acknowledgementBeep); - } - @Override public StatusResponse execute(OmnipodCommunicationService communicationService) { List messageBlocks = new ArrayList<>(); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/action/DeactivatePodAction.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/action/DeactivatePodAction.java index 059ed0645d..24dc6cbcb0 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/action/DeactivatePodAction.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/action/DeactivatePodAction.java @@ -28,7 +28,6 @@ public class DeactivatePodAction implements OmnipodAction { EnumSet.allOf(DeliveryType.class), acknowledgementBeep)); } - DeactivatePodCommand deactivatePodCommand = new DeactivatePodCommand(podState.getCurrentNonce()); - return communicationService.sendCommand(StatusResponse.class, podState, deactivatePodCommand); + return communicationService.sendCommand(StatusResponse.class, podState, new DeactivatePodCommand(podState.getCurrentNonce())); } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/action/SetBasalScheduleAction.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/action/SetBasalScheduleAction.java index 2f36a93c27..f954a2c466 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/action/SetBasalScheduleAction.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/action/SetBasalScheduleAction.java @@ -9,9 +9,12 @@ import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.OmnipodMessa import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.command.BasalScheduleExtraCommand; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.command.SetInsulinScheduleCommand; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.StatusResponse; +import info.nightscout.androidaps.plugins.pump.omnipod.defs.DeliveryStatus; +import info.nightscout.androidaps.plugins.pump.omnipod.defs.DeliveryType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.schedule.BasalSchedule; import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodSessionState; import info.nightscout.androidaps.plugins.pump.omnipod.exception.ActionInitializationException; +import info.nightscout.androidaps.plugins.pump.omnipod.exception.IllegalDeliveryStatusException; public class SetBasalScheduleAction implements OmnipodAction { private final PodSessionState podState; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/action/SetTempBasalAction.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/action/SetTempBasalAction.java index 7007fdb741..52c37d329c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/action/SetTempBasalAction.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/action/SetTempBasalAction.java @@ -2,34 +2,33 @@ package info.nightscout.androidaps.plugins.pump.omnipod.comm.action; import org.joda.time.Duration; +import java.util.Arrays; +import java.util.List; + import info.nightscout.androidaps.plugins.pump.omnipod.comm.OmnipodCommunicationService; -import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.service.SetTempBasalService; +import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.MessageBlock; +import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.OmnipodMessage; +import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.command.SetInsulinScheduleCommand; +import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.command.TempBasalExtraCommand; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.StatusResponse; -import info.nightscout.androidaps.plugins.pump.omnipod.defs.DeliveryStatus; import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodSessionState; import info.nightscout.androidaps.plugins.pump.omnipod.exception.ActionInitializationException; -import info.nightscout.androidaps.plugins.pump.omnipod.exception.IllegalDeliveryStatusException; public class SetTempBasalAction implements OmnipodAction { - private final SetTempBasalService service; private final PodSessionState podState; private final double rate; private final Duration duration; private final boolean acknowledgementBeep; private final boolean completionBeep; - public SetTempBasalAction(SetTempBasalService setTempBasalService, PodSessionState podState, - double rate, Duration duration, boolean acknowledgementBeep, boolean completionBeep) { - if (setTempBasalService == null) { - throw new ActionInitializationException("Set temp basal service cannot be null"); - } + public SetTempBasalAction(PodSessionState podState, double rate, Duration duration, + boolean acknowledgementBeep, boolean completionBeep) { if (podState == null) { throw new ActionInitializationException("Pod state cannot be null"); } if (duration == null) { throw new ActionInitializationException("Duration cannot be null"); } - this.service = setTempBasalService; this.podState = podState; this.rate = rate; this.duration = duration; @@ -39,13 +38,11 @@ public class SetTempBasalAction implements OmnipodAction { @Override public StatusResponse execute(OmnipodCommunicationService communicationService) { - StatusResponse statusResponse = service.cancelTempBasal(communicationService, podState); + List messageBlocks = Arrays.asList( // + new SetInsulinScheduleCommand(podState.getCurrentNonce(), rate, duration), + new TempBasalExtraCommand(rate, duration, acknowledgementBeep, completionBeep, Duration.ZERO)); - if (statusResponse.getDeliveryStatus() != DeliveryStatus.NORMAL) { - throw new IllegalDeliveryStatusException(DeliveryStatus.NORMAL, statusResponse.getDeliveryStatus()); - } - - return service.executeTempBasalCommand(communicationService, podState, rate, duration, - acknowledgementBeep, completionBeep); + OmnipodMessage message = new OmnipodMessage(podState.getAddress(), messageBlocks, podState.getMessageNumber()); + return communicationService.exchangeMessages(StatusResponse.class, podState, message); } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/action/service/SetTempBasalService.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/action/service/SetTempBasalService.java deleted file mode 100644 index 540217f4c6..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/action/service/SetTempBasalService.java +++ /dev/null @@ -1,33 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.comm.action.service; - -import org.joda.time.Duration; - -import java.util.Arrays; -import java.util.List; - -import info.nightscout.androidaps.plugins.pump.omnipod.comm.OmnipodCommunicationService; -import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.CancelDeliveryAction; -import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.MessageBlock; -import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.OmnipodMessage; -import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.command.SetInsulinScheduleCommand; -import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.command.TempBasalExtraCommand; -import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.StatusResponse; -import info.nightscout.androidaps.plugins.pump.omnipod.defs.DeliveryType; -import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodSessionState; - -public class SetTempBasalService { - public StatusResponse cancelTempBasal(OmnipodCommunicationService communicationService, PodSessionState podState) { - return communicationService.executeAction(new CancelDeliveryAction(podState, DeliveryType.TEMP_BASAL, false)); - } - - public StatusResponse executeTempBasalCommand(OmnipodCommunicationService communicationService, - PodSessionState podState, double rate, Duration duration, - boolean acknowledgementBeep, boolean completionBeep) { - List messageBlocks = Arrays.asList( // - new SetInsulinScheduleCommand(podState.getCurrentNonce(), rate, duration), - new TempBasalExtraCommand(rate, duration, acknowledgementBeep, completionBeep, Duration.ZERO)); - - OmnipodMessage message = new OmnipodMessage(podState.getAddress(), messageBlocks, podState.getMessageNumber()); - return communicationService.exchangeMessages(StatusResponse.class, podState, message); - } -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/message/OmnipodMessage.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/message/OmnipodMessage.java index d5329ac312..68b43d96d4 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/message/OmnipodMessage.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/message/OmnipodMessage.java @@ -115,12 +115,7 @@ public class OmnipodMessage { } public boolean isNonceResyncable() { - for (MessageBlock messageBlock : messageBlocks) { - if (messageBlock instanceof NonceResyncableMessageBlock) { - return true; - } - } - return false; + return containsBlock(NonceResyncableMessageBlock.class); } public int getSentNonce() { @@ -139,4 +134,13 @@ public class OmnipodMessage { } } } + + public boolean containsBlock(Class blockType) { + for (MessageBlock messageBlock : messageBlocks) { + if (blockType.isInstance(messageBlock)) { + return true; + } + } + return false; + } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/state/PodSessionState.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/state/PodSessionState.java index 081281b570..05501acaa3 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/state/PodSessionState.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/state/PodSessionState.java @@ -5,10 +5,13 @@ import com.google.gson.Gson; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.joda.time.Duration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.Map; +import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.StatusResponse; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.podinfo.PodInfoFaultEvent; import info.nightscout.androidaps.plugins.pump.omnipod.defs.AlertSet; @@ -26,6 +29,8 @@ import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.SP; public class PodSessionState extends PodState { + private static final Logger LOG = LoggerFactory.getLogger(L.PUMPCOMM); + private final Map configuredAlerts; private transient PodStateChangedHandler stateChangedHandler; private DateTime activatedAt; @@ -234,7 +239,11 @@ public class PodSessionState extends PodState { expiresAt = expiresAtCalculated; } - suspended = (statusResponse.getDeliveryStatus() == DeliveryStatus.SUSPENDED); + boolean newSuspendedState = statusResponse.getDeliveryStatus() == DeliveryStatus.SUSPENDED; + if (suspended != newSuspendedState) { + LOG.info("Updating pod suspended state in updateFromStatusResponse. newSuspendedState={}, statusResponse={}", newSuspendedState, statusResponse.toString()); + suspended = newSuspendedState; + } activeAlerts = statusResponse.getAlerts(); lastDeliveryStatus = statusResponse.getDeliveryStatus(); reservoirLevel = statusResponse.getReservoirLevel(); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/comm/AapsOmnipodManager.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/comm/AapsOmnipodManager.java index c95f3b1c77..dc9d16cf6c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/comm/AapsOmnipodManager.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/comm/AapsOmnipodManager.java @@ -316,7 +316,7 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface try { delegate.cancelBolus(isBolusBeepsEnabled()); addSuccessToHistory(time, PodHistoryEntryType.CancelBolus, null); - } catch(PodFaultException ex) { + } catch (PodFaultException ex) { showNotificationWithDialog(createPodFaultErrorMessage(ex.getFaultEvent().getFaultEventType()), Notification.URGENT, null); } catch (Exception ex) { String comment = handleAndTranslateException(ex); @@ -335,6 +335,10 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface delegate.setTemporaryBasal(tempBasalPair, beepsEnabled, beepsEnabled); addSuccessToHistory(time, PodHistoryEntryType.SetTemporaryBasal, tempBasalPair); } catch (Exception ex) { + if ((ex instanceof OmnipodException) && !((OmnipodException) ex).isCertainFailure()) { + addToHistory(time, PodHistoryEntryType.SetTemporaryBasal, "Uncertain failure", false); + return new PumpEnactResult().success(false).enacted(false).comment(getStringResource(R.string.omnipod_error_set_temp_basal_failed_uncertain)); + } String comment = handleAndTranslateException(ex); addFailureToHistory(time, PodHistoryEntryType.SetTemporaryBasal, comment); return new PumpEnactResult().success(false).enacted(false).comment(comment); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fe66fd32c0..4bca04829b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1760,8 +1760,9 @@ Shutdown is imminent Low reservoir Unknown alert - Setting basal profile failed. Delivery might be suspended! Please refresh pod status. - Setting time failed. Delivery might be suspended! Please refresh pod status. + Setting basal profile might have failed. Delivery might be suspended! Please refresh pod status. + Setting temp basal might have failed. If there was a temp basal already running, that may have been cancelled! Please refresh pod status. + Setting time might have failed. Delivery might be suspended! Please refresh pod status. Unable to verify whether the bolus succeeded. Please verify that your pod is bolusing or cancel the bolus.