Merge branch 'omnipod_eros' of https://github.com/AAPS-Omnipod/AndroidAPS into omnipod_eros

This commit is contained in:
Andy Rozman 2019-12-25 19:24:47 +01:00
commit b80fc3851c
11 changed files with 80 additions and 71 deletions

View file

@ -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.MessageBlock;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.OmnipodMessage; 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.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.ErrorResponse;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.StatusResponse; 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.comm.message.response.podinfo.PodInfoFaultEvent;
@ -149,7 +150,9 @@ public class OmnipodCommunicationService extends RileyLinkCommunicationManager {
boolean firstPacket = true; boolean firstPacket = true;
byte[] encodedMessage; 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); OmnipodMessage paddedMessage = new OmnipodMessage(message);
// If messages are nonce resyncable, we want do distinguish between certain and uncertain failures for verification purposes // 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, // However, some commands (e.g. cancel delivery) are single packet command by nature. When we get a timeout with a single packet,

View file

@ -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.SetTempBasalAction;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.service.InsertCannulaService; 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.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.command.CancelDeliveryCommand;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.StatusResponse; 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.comm.message.response.podinfo.PodInfoResponse;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.BeepType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.BeepType;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.DeliveryStatus; 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) { public synchronized void setTemporaryBasal(TempBasalPair tempBasalPair, boolean acknowledgementBeep, boolean completionBeep) {
assertReadyForDelivery(); assertReadyForDelivery();
logStartingCommandExecution("setTemporaryBasal [tempBasalPair=" + tempBasalPair + ", acknowledgementBeep=" + acknowledgementBeep + ", completionBeep=" + completionBeep + "]"); logStartingCommandExecution("setTemporaryBasal [tempBasalPair=" + tempBasalPair + ", acknowledgementBeep=" + acknowledgementBeep + ", completionBeep=" + completionBeep + "]");
try { 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()), podState, tempBasalPair.getInsulinRate(), Duration.standardMinutes(tempBasalPair.getDurationMinutes()),
acknowledgementBeep, completionBeep))); 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 { } finally {
logCommandExecutionFinished("setTemporaryBasal"); logCommandExecutionFinished("setTemporaryBasal");
} }
@ -401,9 +416,21 @@ public class OmnipodManager {
logStartingCommandExecution("deactivatePod"); 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 { try {
// Always send acknowledgement beeps here. Matches the PDM's behavior // 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) { } catch (PodFaultException ex) {
if (isLoggingEnabled()) { if (isLoggingEnabled()) {
LOG.info("Ignoring PodFaultException in deactivatePod", ex); LOG.info("Ignoring PodFaultException in deactivatePod", ex);

View file

@ -34,11 +34,6 @@ public class CancelDeliveryAction implements OmnipodAction<StatusResponse> {
this.acknowledgementBeep = acknowledgementBeep; this.acknowledgementBeep = acknowledgementBeep;
} }
public CancelDeliveryAction(PodSessionState podState, DeliveryType deliveryType,
boolean acknowledgementBeep) {
this(podState, EnumSet.of(deliveryType), acknowledgementBeep);
}
@Override @Override
public StatusResponse execute(OmnipodCommunicationService communicationService) { public StatusResponse execute(OmnipodCommunicationService communicationService) {
List<MessageBlock> messageBlocks = new ArrayList<>(); List<MessageBlock> messageBlocks = new ArrayList<>();

View file

@ -28,7 +28,6 @@ public class DeactivatePodAction implements OmnipodAction<StatusResponse> {
EnumSet.allOf(DeliveryType.class), acknowledgementBeep)); EnumSet.allOf(DeliveryType.class), acknowledgementBeep));
} }
DeactivatePodCommand deactivatePodCommand = new DeactivatePodCommand(podState.getCurrentNonce()); return communicationService.sendCommand(StatusResponse.class, podState, new DeactivatePodCommand(podState.getCurrentNonce()));
return communicationService.sendCommand(StatusResponse.class, podState, deactivatePodCommand);
} }
} }

View file

@ -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.BasalScheduleExtraCommand;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.command.SetInsulinScheduleCommand; 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.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.schedule.BasalSchedule;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodSessionState; 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.ActionInitializationException;
import info.nightscout.androidaps.plugins.pump.omnipod.exception.IllegalDeliveryStatusException;
public class SetBasalScheduleAction implements OmnipodAction<StatusResponse> { public class SetBasalScheduleAction implements OmnipodAction<StatusResponse> {
private final PodSessionState podState; private final PodSessionState podState;

View file

@ -2,34 +2,33 @@ package info.nightscout.androidaps.plugins.pump.omnipod.comm.action;
import org.joda.time.Duration; 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.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.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.defs.state.PodSessionState;
import info.nightscout.androidaps.plugins.pump.omnipod.exception.ActionInitializationException; import info.nightscout.androidaps.plugins.pump.omnipod.exception.ActionInitializationException;
import info.nightscout.androidaps.plugins.pump.omnipod.exception.IllegalDeliveryStatusException;
public class SetTempBasalAction implements OmnipodAction<StatusResponse> { public class SetTempBasalAction implements OmnipodAction<StatusResponse> {
private final SetTempBasalService service;
private final PodSessionState podState; private final PodSessionState podState;
private final double rate; private final double rate;
private final Duration duration; private final Duration duration;
private final boolean acknowledgementBeep; private final boolean acknowledgementBeep;
private final boolean completionBeep; private final boolean completionBeep;
public SetTempBasalAction(SetTempBasalService setTempBasalService, PodSessionState podState, public SetTempBasalAction(PodSessionState podState, double rate, Duration duration,
double rate, Duration duration, boolean acknowledgementBeep, boolean completionBeep) { boolean acknowledgementBeep, boolean completionBeep) {
if (setTempBasalService == null) {
throw new ActionInitializationException("Set temp basal service cannot be null");
}
if (podState == null) { if (podState == null) {
throw new ActionInitializationException("Pod state cannot be null"); throw new ActionInitializationException("Pod state cannot be null");
} }
if (duration == null) { if (duration == null) {
throw new ActionInitializationException("Duration cannot be null"); throw new ActionInitializationException("Duration cannot be null");
} }
this.service = setTempBasalService;
this.podState = podState; this.podState = podState;
this.rate = rate; this.rate = rate;
this.duration = duration; this.duration = duration;
@ -39,13 +38,11 @@ public class SetTempBasalAction implements OmnipodAction<StatusResponse> {
@Override @Override
public StatusResponse execute(OmnipodCommunicationService communicationService) { public StatusResponse execute(OmnipodCommunicationService communicationService) {
StatusResponse statusResponse = service.cancelTempBasal(communicationService, podState); List<MessageBlock> messageBlocks = Arrays.asList( //
new SetInsulinScheduleCommand(podState.getCurrentNonce(), rate, duration),
new TempBasalExtraCommand(rate, duration, acknowledgementBeep, completionBeep, Duration.ZERO));
if (statusResponse.getDeliveryStatus() != DeliveryStatus.NORMAL) { OmnipodMessage message = new OmnipodMessage(podState.getAddress(), messageBlocks, podState.getMessageNumber());
throw new IllegalDeliveryStatusException(DeliveryStatus.NORMAL, statusResponse.getDeliveryStatus()); return communicationService.exchangeMessages(StatusResponse.class, podState, message);
}
return service.executeTempBasalCommand(communicationService, podState, rate, duration,
acknowledgementBeep, completionBeep);
} }
} }

View file

@ -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<MessageBlock> 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);
}
}

View file

@ -115,12 +115,7 @@ public class OmnipodMessage {
} }
public boolean isNonceResyncable() { public boolean isNonceResyncable() {
for (MessageBlock messageBlock : messageBlocks) { return containsBlock(NonceResyncableMessageBlock.class);
if (messageBlock instanceof NonceResyncableMessageBlock) {
return true;
}
}
return false;
} }
public int getSentNonce() { public int getSentNonce() {
@ -139,4 +134,13 @@ public class OmnipodMessage {
} }
} }
} }
public boolean containsBlock(Class<? extends MessageBlock> blockType) {
for (MessageBlock messageBlock : messageBlocks) {
if (blockType.isInstance(messageBlock)) {
return true;
}
}
return false;
}
} }

View file

@ -5,10 +5,13 @@ import com.google.gson.Gson;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
import org.joda.time.Duration; import org.joda.time.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; 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.StatusResponse;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.podinfo.PodInfoFaultEvent; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.podinfo.PodInfoFaultEvent;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.AlertSet; 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; import info.nightscout.androidaps.utils.SP;
public class PodSessionState extends PodState { public class PodSessionState extends PodState {
private static final Logger LOG = LoggerFactory.getLogger(L.PUMPCOMM);
private final Map<AlertSlot, AlertType> configuredAlerts; private final Map<AlertSlot, AlertType> configuredAlerts;
private transient PodStateChangedHandler stateChangedHandler; private transient PodStateChangedHandler stateChangedHandler;
private DateTime activatedAt; private DateTime activatedAt;
@ -234,7 +239,11 @@ public class PodSessionState extends PodState {
expiresAt = expiresAtCalculated; 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(); activeAlerts = statusResponse.getAlerts();
lastDeliveryStatus = statusResponse.getDeliveryStatus(); lastDeliveryStatus = statusResponse.getDeliveryStatus();
reservoirLevel = statusResponse.getReservoirLevel(); reservoirLevel = statusResponse.getReservoirLevel();

View file

@ -316,7 +316,7 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
try { try {
delegate.cancelBolus(isBolusBeepsEnabled()); delegate.cancelBolus(isBolusBeepsEnabled());
addSuccessToHistory(time, PodHistoryEntryType.CancelBolus, null); addSuccessToHistory(time, PodHistoryEntryType.CancelBolus, null);
} catch(PodFaultException ex) { } catch (PodFaultException ex) {
showNotificationWithDialog(createPodFaultErrorMessage(ex.getFaultEvent().getFaultEventType()), Notification.URGENT, null); showNotificationWithDialog(createPodFaultErrorMessage(ex.getFaultEvent().getFaultEventType()), Notification.URGENT, null);
} catch (Exception ex) { } catch (Exception ex) {
String comment = handleAndTranslateException(ex); String comment = handleAndTranslateException(ex);
@ -335,6 +335,10 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
delegate.setTemporaryBasal(tempBasalPair, beepsEnabled, beepsEnabled); delegate.setTemporaryBasal(tempBasalPair, beepsEnabled, beepsEnabled);
addSuccessToHistory(time, PodHistoryEntryType.SetTemporaryBasal, tempBasalPair); addSuccessToHistory(time, PodHistoryEntryType.SetTemporaryBasal, tempBasalPair);
} catch (Exception ex) { } 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); String comment = handleAndTranslateException(ex);
addFailureToHistory(time, PodHistoryEntryType.SetTemporaryBasal, comment); addFailureToHistory(time, PodHistoryEntryType.SetTemporaryBasal, comment);
return new PumpEnactResult().success(false).enacted(false).comment(comment); return new PumpEnactResult().success(false).enacted(false).comment(comment);

View file

@ -1760,8 +1760,9 @@
<string name="omnipod_alert_shutdown_imminent">Shutdown is imminent</string> <string name="omnipod_alert_shutdown_imminent">Shutdown is imminent</string>
<string name="omnipod_alert_low_reservoir">Low reservoir</string> <string name="omnipod_alert_low_reservoir">Low reservoir</string>
<string name="omnipod_alert_unknown_alert">Unknown alert</string> <string name="omnipod_alert_unknown_alert">Unknown alert</string>
<string name="omnipod_error_set_basal_failed_uncertain">Setting basal profile failed. Delivery might be suspended! Please refresh pod status.</string> <string name="omnipod_error_set_basal_failed_uncertain">Setting basal profile might have failed. Delivery might be suspended! Please refresh pod status.</string>
<string name="omnipod_error_set_time_failed_uncertain">Setting time failed. Delivery might be suspended! Please refresh pod status.</string> <string name="omnipod_error_set_temp_basal_failed_uncertain">Setting temp basal might have failed. If there was a temp basal already running, that may have been cancelled! Please refresh pod status.</string>
<string name="omnipod_error_set_time_failed_uncertain">Setting time might have failed. Delivery might be suspended! Please refresh pod status.</string>
<string name="omnipod_bolus_failed_uncertain">Unable to verify whether the bolus succeeded. Please verify that your pod is bolusing or cancel the bolus.</string> <string name="omnipod_bolus_failed_uncertain">Unable to verify whether the bolus succeeded. Please verify that your pod is bolusing or cancel the bolus.</string>