From 3ecbd3e1bdd95666e3540a41b5b71e5769ab5fc9 Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Mon, 9 Dec 2019 21:45:08 +0100 Subject: [PATCH 1/5] Add logging in OmnipodManager --- .../pump/omnipod/comm/OmnipodManager.java | 142 ++++++++++++++---- .../omnipod/defs/schedule/BasalSchedule.java | 4 +- 2 files changed, 119 insertions(+), 27 deletions(-) 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 442a12e176..d92371c032 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 @@ -83,16 +83,21 @@ public class OmnipodManager { } public synchronized Single pairAndPrime() { - if (podState == null) { - podState = communicationService.executeAction( - new PairAction(new PairService(), podStateChangedHandler)); - } - if (!podState.getSetupProgress().isBefore(SetupProgress.PRIMING_FINISHED)) { - throw new IllegalSetupProgressException(SetupProgress.ADDRESS_ASSIGNED, podState.getSetupProgress()); - } + logStartingCommandExecution("pairAndPrime"); - communicationService.executeAction(new PrimeAction(new PrimeService(), podState)); + try { + if (podState == null) { + podState = communicationService.executeAction( + new PairAction(new PairService(), podStateChangedHandler)); + } + if (!podState.getSetupProgress().isBefore(SetupProgress.PRIMING_FINISHED)) { + throw new IllegalSetupProgressException(SetupProgress.ADDRESS_ASSIGNED, podState.getSetupProgress()); + } + communicationService.executeAction(new PrimeAction(new PrimeService(), podState)); + } finally { + logCommandExecutionFinished("pairAndPrime"); + } long delayInSeconds = calculateBolusDuration(OmnipodConst.POD_PRIME_BOLUS_UNITS, OmnipodConst.POD_PRIMING_DELIVERY_RATE).getStandardSeconds(); return Single.timer(delayInSeconds, TimeUnit.SECONDS) // @@ -108,9 +113,16 @@ public class OmnipodManager { throw new IllegalSetupProgressException(SetupProgress.CANNULA_INSERTING, podState.getSetupProgress()); } - communicationService.executeAction(new InsertCannulaAction(new InsertCannulaService(), podState, basalSchedule)); + logStartingCommandExecution("insertCannula [basalSchedule=" + basalSchedule + "]"); + + try { + communicationService.executeAction(new InsertCannulaAction(new InsertCannulaService(), podState, basalSchedule)); + } finally { + logCommandExecutionFinished("insertCannula"); + } long delayInSeconds = calculateBolusDuration(OmnipodConst.POD_CANNULA_INSERTION_BOLUS_UNITS, OmnipodConst.POD_CANNULA_INSERTION_DELIVERY_RATE).getStandardSeconds(); + return Single.timer(delayInSeconds, TimeUnit.SECONDS) // .map(o -> verifySetupAction(statusResponse -> InsertCannulaAction.updateCannulaInsertionStatus(podState, statusResponse), SetupProgress.COMPLETED)) // @@ -122,40 +134,76 @@ public class OmnipodManager { throw new IllegalSetupProgressException(SetupProgress.PRIMING_FINISHED, null); } - return communicationService.executeAction(new GetStatusAction(podState)); + logStartingCommandExecution("getPodStatus"); + + try { + return communicationService.executeAction(new GetStatusAction(podState)); + } finally { + logCommandExecutionFinished("getPodStatus"); + } } public synchronized PodInfoResponse getPodInfo(PodInfoType podInfoType) { assertReadyForDelivery(); - return communicationService.executeAction(new GetPodInfoAction(podState, podInfoType)); + logStartingCommandExecution("getPodInfo"); + + try { + return communicationService.executeAction(new GetPodInfoAction(podState, podInfoType)); + } finally { + logCommandExecutionFinished("getPodInfo"); + } } public synchronized void acknowledgeAlerts() { assertReadyForDelivery(); - executeAndVerify(() -> communicationService.executeAction(new AcknowledgeAlertsAction(podState, podState.getActiveAlerts()))); + logStartingCommandExecution("acknowledgeAlerts"); + + try { + executeAndVerify(() -> communicationService.executeAction(new AcknowledgeAlertsAction(podState, podState.getActiveAlerts()))); + } finally { + logCommandExecutionFinished("acknowledgeAlerts"); + } } public synchronized void setBasalSchedule(BasalSchedule schedule, boolean acknowledgementBeep) { assertReadyForDelivery(); - executeAndVerify(() -> communicationService.executeAction(new SetBasalScheduleAction(podState, schedule, - false, podState.getScheduleOffset(), acknowledgementBeep))); + logStartingCommandExecution("setBasalSchedule [basalSchedule=" + schedule + ", acknowledgementBeep=" + acknowledgementBeep + "]"); + + try { + executeAndVerify(() -> communicationService.executeAction(new SetBasalScheduleAction(podState, schedule, + false, podState.getScheduleOffset(), acknowledgementBeep))); + } finally { + logCommandExecutionFinished("setBasalSchedule"); + } } public synchronized void setTemporaryBasal(TempBasalPair tempBasalPair, boolean acknowledgementBeep, boolean completionBeep) { assertReadyForDelivery(); - executeAndVerify(() -> communicationService.executeAction(new SetTempBasalAction(new SetTempBasalService(), - podState, tempBasalPair.getInsulinRate(), Duration.standardMinutes(tempBasalPair.getDurationMinutes()), - acknowledgementBeep, completionBeep))); + logStartingCommandExecution("setTemporaryBasal [tempBasalPair=" + tempBasalPair + ", acknowledgementBeep=" + acknowledgementBeep + ", completionBeep=" + completionBeep + "]"); + + try { + executeAndVerify(() -> communicationService.executeAction(new SetTempBasalAction(new SetTempBasalService(), + podState, tempBasalPair.getInsulinRate(), Duration.standardMinutes(tempBasalPair.getDurationMinutes()), + acknowledgementBeep, completionBeep))); + } finally { + logCommandExecutionFinished("setTemporaryBasal"); + } } public synchronized void cancelTemporaryBasal(boolean acknowledgementBeep) { assertReadyForDelivery(); - executeAndVerify(() -> communicationService.executeAction(new CancelDeliveryAction(podState, DeliveryType.TEMP_BASAL, acknowledgementBeep))); + logStartingCommandExecution("cancelTemporaryBasal [acknowledgementBeep=" + acknowledgementBeep + "]"); + + try { + executeAndVerify(() -> communicationService.executeAction(new CancelDeliveryAction(podState, DeliveryType.TEMP_BASAL, acknowledgementBeep))); + } finally { + logCommandExecutionFinished("cancelTemporaryBasal"); + } } // Returns a SingleSubject that returns when the bolus has finished. @@ -164,6 +212,8 @@ public class OmnipodManager { public synchronized BolusCommandResult bolus(Double units, boolean acknowledgementBeep, boolean completionBeep, BolusProgressIndicationConsumer progressIndicationConsumer) { assertReadyForDelivery(); + logStartingCommandExecution("bolus [units=" + units + ", acknowledgementBeep=" + acknowledgementBeep + ", completionBeep=" + completionBeep + "]"); + CommandDeliveryStatus commandDeliveryStatus = CommandDeliveryStatus.SUCCESS; try { @@ -178,6 +228,8 @@ public class OmnipodManager { LOG.error("Caught exception[certainFailure=false] in bolus", ex); } commandDeliveryStatus = CommandDeliveryStatus.UNCERTAIN_FAILURE; + } finally { + logCommandExecutionFinished("bolus"); } DateTime startDate = DateTime.now().minus(OmnipodConst.AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION); @@ -245,12 +297,16 @@ public class OmnipodManager { throw new IllegalDeliveryStatusException(DeliveryStatus.BOLUS_IN_PROGRESS, podState.getLastDeliveryStatus()); } + logStartingCommandExecution("cancelBolus [acknowledgementBeep=" + acknowledgementBeep + "]"); + try { executeAndVerify(() -> communicationService.executeAction(new CancelDeliveryAction(podState, DeliveryType.BOLUS, acknowledgementBeep))); } catch (PodFaultException ex) { if (isLoggingEnabled()) { LOG.info("Ignoring PodFaultException in cancelBolus", ex); } + } finally { + logCommandExecutionFinished("cancelBolus"); } activeBolusData.getDisposables().dispose(); @@ -263,14 +319,26 @@ public class OmnipodManager { public synchronized void suspendDelivery(boolean acknowledgementBeep) { assertReadyForDelivery(); - executeAndVerify(() -> communicationService.executeAction(new CancelDeliveryAction(podState, EnumSet.allOf(DeliveryType.class), acknowledgementBeep))); + logStartingCommandExecution("suspendDelivery [acknowledgementBeep=" + acknowledgementBeep + "]"); + + try { + executeAndVerify(() -> communicationService.executeAction(new CancelDeliveryAction(podState, EnumSet.allOf(DeliveryType.class), acknowledgementBeep))); + } finally { + logCommandExecutionFinished("suspendDelivery"); + } } public synchronized void resumeDelivery(boolean acknowledgementBeep) { assertReadyForDelivery(); - executeAndVerify(() -> communicationService.executeAction(new SetBasalScheduleAction(podState, podState.getBasalSchedule(), - true, podState.getScheduleOffset(), acknowledgementBeep))); + logStartingCommandExecution("resumeDelivery [acknowledgementBeep=" + acknowledgementBeep + "]"); + + try { + executeAndVerify(() -> communicationService.executeAction(new SetBasalScheduleAction(podState, podState.getBasalSchedule(), + true, podState.getScheduleOffset(), acknowledgementBeep))); + } finally { + logCommandExecutionFinished("resumeDelivery"); + } } // CAUTION: cancels TBR and bolus @@ -279,13 +347,19 @@ public class OmnipodManager { public synchronized void setTime(boolean acknowledgementBeeps) { assertReadyForDelivery(); - suspendDelivery(acknowledgementBeeps); + logStartingCommandExecution("setTime [acknowledgementBeeps=" + acknowledgementBeeps + "]"); - // Joda seems to cache the default time zone, so we use the JVM's - DateTimeZone.setDefault(DateTimeZone.forTimeZone(TimeZone.getDefault())); - podState.setTimeZone(DateTimeZone.getDefault()); + try { + suspendDelivery(acknowledgementBeeps); - resumeDelivery(acknowledgementBeeps); + // Joda seems to cache the default time zone, so we use the JVM's + DateTimeZone.setDefault(DateTimeZone.forTimeZone(TimeZone.getDefault())); + podState.setTimeZone(DateTimeZone.getDefault()); + + resumeDelivery(acknowledgementBeeps); + } finally { + logCommandExecutionFinished("setTime"); + } } public synchronized void deactivatePod() { @@ -293,6 +367,8 @@ public class OmnipodManager { throw new IllegalSetupProgressException(SetupProgress.ADDRESS_ASSIGNED, null); } + logStartingCommandExecution("deactivatePod"); + try { // Never send acknowledgement beeps here. Matches the PDM's behavior executeAndVerify(() -> communicationService.executeAction(new DeactivatePodAction(podState, false))); @@ -300,6 +376,8 @@ public class OmnipodManager { if (isLoggingEnabled()) { LOG.info("Ignoring PodFaultException in deactivatePod", ex); } + } finally { + logCommandExecutionFinished("deactivatePod"); } resetPodState(); @@ -416,6 +494,18 @@ public class OmnipodManager { return CommandDeliveryStatus.SUCCESS; } + private void logStartingCommandExecution(String action) { + if (isLoggingEnabled()) { + LOG.debug("Starting command execution for action: " + action); + } + } + + private void logCommandExecutionFinished(String action) { + if (isLoggingEnabled()) { + LOG.debug("Command execution finished for action: " + action); + } + } + private boolean isLoggingEnabled() { return L.isEnabled(L.PUMP); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/schedule/BasalSchedule.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/schedule/BasalSchedule.java index 416eeeb420..61e487e7bd 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/schedule/BasalSchedule.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/schedule/BasalSchedule.java @@ -84,7 +84,9 @@ public class BasalSchedule { @Override public String toString() { - return "BasalSchedule (" + entries.size() + " entries)"; + return "BasalSchedule{" + + "entries=" + entries + + '}'; } public static class BasalScheduleDurationEntry { From f4328912637f86082b7e6e1689d2b74156ffa379 Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Mon, 9 Dec 2019 22:21:44 +0100 Subject: [PATCH 2/5] Log basal schedule entry start time in seconds --- .../plugins/pump/omnipod/defs/schedule/BasalScheduleEntry.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/schedule/BasalScheduleEntry.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/schedule/BasalScheduleEntry.java index 23b491a4bc..6591e0c825 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/schedule/BasalScheduleEntry.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/schedule/BasalScheduleEntry.java @@ -2,7 +2,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.defs.schedule; import org.joda.time.Duration; -import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodConst; public class BasalScheduleEntry { @@ -31,7 +30,7 @@ public class BasalScheduleEntry { public String toString() { return "BasalScheduleEntry{" + "rate=" + rate + - ", startTime=" + startTime + + ", startTime=" + startTime.getStandardSeconds() + "s" + '}'; } } From 9ef83c19f82875cbcc4034d06aa5e85f6263181f Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Tue, 10 Dec 2019 01:11:51 +0100 Subject: [PATCH 3/5] WIP: don't kill the pod when switching profile --- .../comm/OmnipodCommunicationService.java | 13 +-- .../pump/omnipod/comm/OmnipodManager.java | 84 +++++++++++++------ .../pump/omnipod/defs/DeliveryType.java | 3 +- .../driver/comm/AapsOmnipodManager.java | 10 ++- app/src/main/res/values/strings.xml | 2 + 5 files changed, 78 insertions(+), 34 deletions(-) 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 917a4e4bce..81fd2256f5 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 @@ -164,10 +164,6 @@ public class OmnipodCommunicationService extends RileyLinkCommunicationManager { // We actually ignore previous (ack) responses if it was not last packet to send response = exchangePackets(podState, packet); } catch (Exception ex) { - // If this is not the last packet, the message wasn't fully sent, - // so it's impossible for the pod to have received the message - boolean isCertainFailure = encodedMessage.length > 0; - OmnipodException newException; if (ex instanceof OmnipodException) { newException = (OmnipodException) ex; @@ -175,10 +171,15 @@ public class OmnipodCommunicationService extends RileyLinkCommunicationManager { newException = new CommunicationException(CommunicationException.Type.UNEXPECTED_EXCEPTION, ex); } + boolean lastPacket = encodedMessage.length == 0; + + // If this is not the last packet, the message wasn't fully sent, + // so it's impossible for the pod to have received the message + newException.setCertainFailure(!lastPacket); + if (isLoggingEnabled()) { - LOG.debug("Caught exception in transportMessages. Setting certainFailure to {} because encodedMessage.length={}", isCertainFailure, encodedMessage.length); + LOG.debug("Caught exception in transportMessages. Set certainFailure to {} because encodedMessage.length={}", newException.isCertainFailure(), encodedMessage.length); } - newException.setCertainFailure(isCertainFailure); throw newException; } 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 d92371c032..9b0a7280a4 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 @@ -167,14 +167,32 @@ public class OmnipodManager { } } + // CAUTION: cancels all delivery + // CAUTION: suspends and then resumes delivery. An OmnipodException[certainFailure=false] indicates that the pod is or might be suspended public synchronized void setBasalSchedule(BasalSchedule schedule, boolean acknowledgementBeep) { assertReadyForDelivery(); logStartingCommandExecution("setBasalSchedule [basalSchedule=" + schedule + ", acknowledgementBeep=" + acknowledgementBeep + "]"); try { - executeAndVerify(() -> communicationService.executeAction(new SetBasalScheduleAction(podState, schedule, - false, podState.getScheduleOffset(), acknowledgementBeep))); + // Never emit a beep for suspending delivery, so if the user has beeps enabled, + // they can verify that setting the basal schedule succeeded (not suspending the delivery) + cancelDelivery(EnumSet.allOf(DeliveryType.class), false); + } catch (Exception ex) { + logCommandExecutionFinished("setBasalSchedule"); + throw ex; + } + + try { + try { + executeAndVerify(() -> communicationService.executeAction(new SetBasalScheduleAction(podState, schedule, + false, podState.getScheduleOffset(), acknowledgementBeep))); + } 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("setBasalSchedule"); } @@ -195,14 +213,29 @@ public class OmnipodManager { } public synchronized void cancelTemporaryBasal(boolean acknowledgementBeep) { + cancelDelivery(EnumSet.of(DeliveryType.TEMP_BASAL), acknowledgementBeep); + } + + private synchronized void cancelDelivery(EnumSet deliveryTypes, boolean acknowledgementBeep) { assertReadyForDelivery(); - logStartingCommandExecution("cancelTemporaryBasal [acknowledgementBeep=" + acknowledgementBeep + "]"); + logStartingCommandExecution("cancelDelivery [deliveryTypes=" + deliveryTypes + ", acknowledgementBeep=" + acknowledgementBeep + "]"); try { - executeAndVerify(() -> communicationService.executeAction(new CancelDeliveryAction(podState, DeliveryType.TEMP_BASAL, acknowledgementBeep))); + // As the cancel delivery command is a single packet command, + // first verify that the pod is reachable by obtaining a status response + // FIXME is this actually necessary? + StatusResponse podStatus = getPodStatus(); + } catch (OmnipodException ex) { + logCommandExecutionFinished("cancelDelivery"); + ex.setCertainFailure(true); + throw ex; + } + + try { + executeAndVerify(() -> communicationService.executeAction(new CancelDeliveryAction(podState, deliveryTypes, acknowledgementBeep))); } finally { - logCommandExecutionFinished("cancelTemporaryBasal"); + logCommandExecutionFinished("cancelDelivery"); } } @@ -300,7 +333,7 @@ public class OmnipodManager { logStartingCommandExecution("cancelBolus [acknowledgementBeep=" + acknowledgementBeep + "]"); try { - executeAndVerify(() -> communicationService.executeAction(new CancelDeliveryAction(podState, DeliveryType.BOLUS, acknowledgementBeep))); + cancelDelivery(EnumSet.of(DeliveryType.BOLUS), acknowledgementBeep); } catch (PodFaultException ex) { if (isLoggingEnabled()) { LOG.info("Ignoring PodFaultException in cancelBolus", ex); @@ -315,48 +348,51 @@ public class OmnipodManager { } } - // CAUTION: cancels TBR and bolus public synchronized void suspendDelivery(boolean acknowledgementBeep) { - assertReadyForDelivery(); - - logStartingCommandExecution("suspendDelivery [acknowledgementBeep=" + acknowledgementBeep + "]"); - - try { - executeAndVerify(() -> communicationService.executeAction(new CancelDeliveryAction(podState, EnumSet.allOf(DeliveryType.class), acknowledgementBeep))); - } finally { - logCommandExecutionFinished("suspendDelivery"); - } + cancelDelivery(EnumSet.allOf(DeliveryType.class), acknowledgementBeep); } + // Same as setting basal schedule, but without suspending delivery first public synchronized void resumeDelivery(boolean acknowledgementBeep) { assertReadyForDelivery(); - - logStartingCommandExecution("resumeDelivery [acknowledgementBeep=" + acknowledgementBeep + "]"); + logStartingCommandExecution("resumeDelivery"); try { executeAndVerify(() -> communicationService.executeAction(new SetBasalScheduleAction(podState, podState.getBasalSchedule(), - true, podState.getScheduleOffset(), acknowledgementBeep))); + false, podState.getScheduleOffset(), acknowledgementBeep))); } finally { logCommandExecutionFinished("resumeDelivery"); } } - // CAUTION: cancels TBR and bolus - // CAUTION: suspends and then resumes delivery. - // If any error occurs during the command sequence, delivery could be suspended + // CAUTION: cancels all delivery + // CAUTION: suspends and then resumes delivery. An OmnipodException[certainFailure=false] indicates that the pod is or might be suspended public synchronized void setTime(boolean acknowledgementBeeps) { assertReadyForDelivery(); logStartingCommandExecution("setTime [acknowledgementBeeps=" + acknowledgementBeeps + "]"); try { - suspendDelivery(acknowledgementBeeps); + cancelDelivery(EnumSet.allOf(DeliveryType.class), acknowledgementBeeps); + } catch (Exception ex) { + logCommandExecutionFinished("setTime"); + throw ex; + } + DateTimeZone oldTimeZone = podState.getTimeZone(); + + try { // Joda seems to cache the default time zone, so we use the JVM's DateTimeZone.setDefault(DateTimeZone.forTimeZone(TimeZone.getDefault())); podState.setTimeZone(DateTimeZone.getDefault()); - resumeDelivery(acknowledgementBeeps); + setBasalSchedule(podState.getBasalSchedule(), acknowledgementBeeps); + } 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 + podState.setTimeZone(oldTimeZone); + ex.setCertainFailure(false); + throw ex; } finally { logCommandExecutionFinished("setTime"); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/DeliveryType.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/DeliveryType.java index 910031f85e..4d595afc15 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/DeliveryType.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/DeliveryType.java @@ -4,8 +4,7 @@ public enum DeliveryType { NONE((byte) 0x00), BASAL((byte) 0x01), TEMP_BASAL((byte) 0x02), - BOLUS((byte) 0x04), - EXTENDED_BOLUS((byte) 0x08); + BOLUS((byte) 0x04); private byte value; 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 5c33771273..5b78e8a910 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 @@ -200,11 +200,15 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface return new PumpEnactResult().success(true).enacted(true); } + // TODO cancels TBR. Notify treatments plugin @Override public PumpEnactResult setBasalProfile(Profile basalProfile) { try { delegate.setBasalSchedule(mapProfileToBasalSchedule(basalProfile), isBasalBeepsEnabled()); } catch (Exception ex) { + if ((ex instanceof OmnipodException) && !((OmnipodException) ex).isCertainFailure()) { + return new PumpEnactResult().success(false).enacted(false).comment(getStringResource(R.string.omnipod_error_set_basal_failed_uncertain)); + } String comment = handleAndTranslateException(ex); return new PumpEnactResult().success(false).enacted(false).comment(comment); } @@ -358,12 +362,14 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface // TODO should we add this to the OmnipodCommunicationManager interface? // Updates the pods current time based on the device timezone and the pod's time zone + // TODO cancels TBR. Notify treatments plugin public PumpEnactResult setTime() { try { - // CAUTION cancels TBR delegate.setTime(isBasalBeepsEnabled()); } catch (Exception ex) { - // CAUTION pod could be suspended + if ((ex instanceof OmnipodException) && !((OmnipodException) ex).isCertainFailure()) { + return new PumpEnactResult().success(false).enacted(false).comment(getStringResource(R.string.omnipod_error_set_time_failed_uncertain)); + } String comment = handleAndTranslateException(ex); 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 729c512688..3d8669b178 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1742,6 +1742,8 @@ 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. From b3984b796d1d1b864eb788fd5a78e43ca0c3d600 Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Tue, 10 Dec 2019 20:17:05 +0100 Subject: [PATCH 4/5] Report implicitly canceled TBR's to treatment plugin --- .../driver/comm/AapsOmnipodManager.java | 42 ++++++++++++++----- 1 file changed, 32 insertions(+), 10 deletions(-) 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 5b78e8a910..5f7931e98b 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 @@ -18,6 +18,8 @@ import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.PumpEnactResult; +import info.nightscout.androidaps.db.Source; +import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.events.Event; import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.plugins.bus.RxBus; @@ -59,6 +61,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.exception.OmnipodExceptio import info.nightscout.androidaps.plugins.pump.omnipod.exception.PodFaultException; import info.nightscout.androidaps.plugins.pump.omnipod.exception.PodReturnedErrorResponseException; import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodUtil; +import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import io.reactivex.disposables.Disposable; public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface { @@ -200,7 +203,6 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface return new PumpEnactResult().success(true).enacted(true); } - // TODO cancels TBR. Notify treatments plugin @Override public PumpEnactResult setBasalProfile(Profile basalProfile) { try { @@ -213,6 +215,9 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface return new PumpEnactResult().success(false).enacted(false).comment(comment); } + // Because setting a basal profile actually suspends and then resumes delivery, TBR is implicitly cancelled + reportImplicitlyCanceledTbr(); + return new PumpEnactResult().success(true).enacted(true); } @@ -249,7 +254,7 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface return new PumpEnactResult().success(false).enacted(false).comment(comment); } - if (OmnipodManager.CommandDeliveryStatus.UNCERTAIN_FAILURE.equals(bolusCommandResult.getCommandDeliveryStatus()) && !isSmb /* TODO or should we also warn for SMB? */) { + if (OmnipodManager.CommandDeliveryStatus.UNCERTAIN_FAILURE.equals(bolusCommandResult.getCommandDeliveryStatus())) { // TODO notify user about uncertain failure ---> we're unsure whether or not the bolus has been delivered // For safety reasons, we should treat this as a bolus that has been delivered, in order to prevent insulin overdose } @@ -362,7 +367,6 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface // TODO should we add this to the OmnipodCommunicationManager interface? // Updates the pods current time based on the device timezone and the pod's time zone - // TODO cancels TBR. Notify treatments plugin public PumpEnactResult setTime() { try { delegate.setTime(isBasalBeepsEnabled()); @@ -373,6 +377,10 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface String comment = handleAndTranslateException(ex); return new PumpEnactResult().success(false).enacted(false).comment(comment); } + + // Because set time actually suspends and then resumes delivery, TBR is implicitly cancelled + reportImplicitlyCanceledTbr(); + return new PumpEnactResult().success(true).enacted(true); } @@ -392,26 +400,40 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface return delegate.getPodStateAsString(); } + private void reportImplicitlyCanceledTbr() { + TreatmentsPlugin plugin = TreatmentsPlugin.getPlugin(); + if (plugin.isTempBasalInProgress()) { + if (isLoggingEnabled()) { + LOG.debug("Reporting implicitly cancelled TBR to Treatments plugin"); + } + + TemporaryBasal temporaryBasal = new TemporaryBasal() // + .date(System.currentTimeMillis()) // + .duration(0) // + // TODO bs should be Source.PUMP imo, but that doesn't work: + // it says a TEMPBASAL record already exists + .source(Source.USER); + plugin.addToHistoryTempBasal(temporaryBasal); + } + } private void addToHistory(long requestTime, PodHistoryEntryType entryType, String data, boolean success) { // TODO andy needs to be refactored //PodDbEntry entry = new PodDbEntry(requestTime, entryType); - - } private void handleSetupActionResult(PodInitActionType podInitActionType, PodInitReceiver podInitReceiver, SetupActionResult res) { String comment = null; switch (res.getResultType()) { case FAILURE: - if (loggingEnabled()) { + if (isLoggingEnabled()) { LOG.error("Setup action failed: illegal setup progress: {}", res.getSetupProgress()); } comment = getStringResource(R.string.omnipod_driver_error_invalid_progress_state, res.getSetupProgress()); break; case VERIFICATION_FAILURE: - if (loggingEnabled()) { + if (isLoggingEnabled()) { LOG.error("Setup action verification failed: caught exception", res.getException()); } comment = getStringResource(R.string.omnipod_driver_error_setup_action_verification_failed); @@ -455,12 +477,12 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface // Shouldn't be reachable comment = getStringResource(R.string.omnipod_driver_error_unexpected_exception_type, ex.getClass().getName()); } - if (loggingEnabled()) { + if (isLoggingEnabled()) { LOG.error(String.format("Caught OmnipodException[certainFailure=%s] from OmnipodManager (user-friendly error message: %s)", ((OmnipodException) ex).isCertainFailure(), comment), ex); } } else { comment = getStringResource(R.string.omnipod_driver_error_unexpected_exception_type, ex.getClass().getName()); - if (loggingEnabled()) { + if (isLoggingEnabled()) { LOG.error(String.format("Caught unexpected exception type[certainFailure=false] from OmnipodManager (user-friendly error message: %s)", comment), ex); } } @@ -510,7 +532,7 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface return MainApp.gs(id, args); } - private boolean loggingEnabled() { + private boolean isLoggingEnabled() { return L.isEnabled(L.PUMP); } From b12095953203b367360263d79eab97d1dc3396d6 Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Wed, 11 Dec 2019 13:22:29 +0100 Subject: [PATCH 5/5] Show fault code in pod fault error message --- .../pump/omnipod/driver/comm/AapsOmnipodManager.java | 6 +++++- app/src/main/res/values/strings.xml | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) 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 5f7931e98b..45f77b0d89 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 @@ -26,6 +26,7 @@ import info.nightscout.androidaps.plugins.bus.RxBus; import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress; import info.nightscout.androidaps.plugins.pump.common.data.TempBasalPair; import info.nightscout.androidaps.plugins.pump.common.defs.PumpStatusType; +import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; import info.nightscout.androidaps.plugins.pump.omnipod.comm.OmnipodCommunicationService; import info.nightscout.androidaps.plugins.pump.omnipod.comm.OmnipodManager; import info.nightscout.androidaps.plugins.pump.omnipod.comm.SetupActionResult; @@ -33,6 +34,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.Sta import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.podinfo.PodInfoResponse; import info.nightscout.androidaps.plugins.pump.omnipod.defs.AlertSlot; import info.nightscout.androidaps.plugins.pump.omnipod.defs.AlertType; +import info.nightscout.androidaps.plugins.pump.omnipod.defs.FaultEventCode; import info.nightscout.androidaps.plugins.pump.omnipod.defs.OmnipodCommunicationManagerInterface; import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodInfoType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodInitActionType; @@ -470,7 +472,9 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface comment = getStringResource(R.string.omnipod_driver_error_not_enough_data); } else if (ex instanceof PodFaultException) { // TODO handle pod fault with some kind of dialog that has a button to start pod deactivation - comment = getStringResource(R.string.omnipod_driver_error_pod_fault, ((PodFaultException) ex).getFaultEvent().getFaultEventCode().name()); + FaultEventCode faultEventCode = ((PodFaultException) ex).getFaultEvent().getFaultEventCode(); + comment = getStringResource(R.string.omnipod_driver_error_pod_fault, + ByteUtil.convertUnsignedByteToInt(faultEventCode.getValue()), faultEventCode.name()); } else if (ex instanceof PodReturnedErrorResponseException) { comment = getStringResource(R.string.omnipod_driver_error_pod_returned_error_response); } else { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3d8669b178..30595b698d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1686,7 +1686,7 @@ Communication failed: nonce resync failed. Communication failed: nonce out of sync. Communication failed: not enough data received from the pod. - A pod fault (%1$s) has been detected. Please deactivate your pod and start a new one. + A pod fault (%1$03d %2$s) has been detected. Please deactivate your pod and start a new one. Communication failed: the pod returned an error response.