Merge branch 'omnipod_eros_dev' into omnipod_eros_dev_dagger_with_initialization_fixes

This commit is contained in:
Bart Sopers 2020-05-05 00:15:44 +02:00
commit 7fa1ebfe38
37 changed files with 440 additions and 247 deletions

View file

@ -1017,7 +1017,6 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
// Don't trigger an alert when we exceeded the thresholds, but the last communication was successful // Don't trigger an alert when we exceeded the thresholds, but the last communication was successful
// This happens when we simply didn't need to send any commands to the pump // This happens when we simply didn't need to send any commands to the pump
return false;
} }
} }

View file

@ -23,6 +23,8 @@ import info.nightscout.androidaps.plugins.pump.medtronic.defs.PumpDeviceState;
import info.nightscout.androidaps.plugins.pump.omnipod.OmnipodPumpPlugin; import info.nightscout.androidaps.plugins.pump.omnipod.OmnipodPumpPlugin;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.OmnipodAction; import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.OmnipodAction;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.CommunicationException; import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.CommunicationException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalMessageAddressException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalMessageSequenceNumberException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalPacketTypeException; import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalPacketTypeException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalResponseException; import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalResponseException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.NonceOutOfSyncException; import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.NonceOutOfSyncException;
@ -38,13 +40,13 @@ import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.Err
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.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.ErrorResponseType;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.MessageBlockType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.MessageBlockType;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.PacketType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.PacketType;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodInfoType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodInfoType;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodState; import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodState;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.OmnipodPumpStatus; import info.nightscout.androidaps.plugins.pump.omnipod.driver.OmnipodPumpStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.exception.OmnipodException; import info.nightscout.androidaps.plugins.pump.omnipod.exception.OmnipodException;
import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodConst;
/** /**
* Created by andy on 6/29/18. * Created by andy on 6/29/18.
@ -149,7 +151,7 @@ public class OmnipodCommunicationManager extends RileyLinkCommunicationManager {
} else { } else {
if (responseMessageBlock.getType() == MessageBlockType.ERROR_RESPONSE) { if (responseMessageBlock.getType() == MessageBlockType.ERROR_RESPONSE) {
ErrorResponse error = (ErrorResponse) responseMessageBlock; ErrorResponse error = (ErrorResponse) responseMessageBlock;
if (error.getErrorResponseType() == ErrorResponseType.BAD_NONCE) { if (error.getErrorResponseCode() == ErrorResponse.ERROR_RESPONSE_CODE_BAD_NONCE) {
podState.resyncNonce(error.getNonceSearchKey(), message.getSentNonce(), message.getSequenceNumber()); podState.resyncNonce(error.getNonceSearchKey(), message.getSentNonce(), message.getSequenceNumber());
if (automaticallyResyncNonce) { if (automaticallyResyncNonce) {
message.resyncNonce(podState.getCurrentNonce()); message.resyncNonce(podState.getCurrentNonce());
@ -157,7 +159,7 @@ public class OmnipodCommunicationManager extends RileyLinkCommunicationManager {
throw new NonceOutOfSyncException(); throw new NonceOutOfSyncException();
} }
} else { } else {
throw new PodReturnedErrorResponseException((ErrorResponse) responseMessageBlock); 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.FAULT_EVENT) {
PodInfoFaultEvent faultEvent = ((PodInfoResponse) responseMessageBlock).getPodInfo(); PodInfoFaultEvent faultEvent = ((PodInfoResponse) responseMessageBlock).getPodInfo();
@ -178,6 +180,8 @@ public class OmnipodCommunicationManager extends RileyLinkCommunicationManager {
packetAddress = addressOverride; packetAddress = addressOverride;
} }
podState.increaseMessageNumber();
boolean firstPacket = true; boolean firstPacket = true;
byte[] encodedMessage; byte[] encodedMessage;
// this does not work well with the deactivate pod command, we somehow either // this does not work well with the deactivate pod command, we somehow either
@ -230,7 +234,6 @@ public class OmnipodCommunicationManager extends RileyLinkCommunicationManager {
} }
if (response.getPacketType() == PacketType.ACK) { if (response.getPacketType() == PacketType.ACK) {
podState.increasePacketNumber(1);
throw new IllegalPacketTypeException(null, PacketType.ACK); throw new IllegalPacketTypeException(null, PacketType.ACK);
} }
@ -239,6 +242,12 @@ public class OmnipodCommunicationManager extends RileyLinkCommunicationManager {
while (receivedMessage == null) { while (receivedMessage == null) {
try { try {
receivedMessage = OmnipodMessage.decodeMessage(receivedMessageData); receivedMessage = OmnipodMessage.decodeMessage(receivedMessageData);
if (receivedMessage.getAddress() != message.getAddress()) {
throw new IllegalMessageAddressException(message.getAddress(), receivedMessage.getAddress());
}
if (receivedMessage.getSequenceNumber() != podState.getMessageNumber()) {
throw new IllegalMessageSequenceNumberException(podState.getMessageNumber(), receivedMessage.getSequenceNumber());
}
} catch (NotEnoughDataException ex) { } catch (NotEnoughDataException ex) {
// Message is (probably) not complete yet // Message is (probably) not complete yet
OmnipodPacket ackForCon = createAckPacket(podState, packetAddress, ackAddressOverride); OmnipodPacket ackForCon = createAckPacket(podState, packetAddress, ackAddressOverride);
@ -258,8 +267,6 @@ public class OmnipodCommunicationManager extends RileyLinkCommunicationManager {
} }
} }
podState.increaseMessageNumber(2);
ackUntilQuiet(podState, packetAddress, ackAddressOverride); ackUntilQuiet(podState, packetAddress, ackAddressOverride);
List<MessageBlock> messageBlocks = receivedMessage.getMessageBlocks(); List<MessageBlock> messageBlocks = receivedMessage.getMessageBlocks();
@ -271,19 +278,23 @@ public class OmnipodCommunicationManager extends RileyLinkCommunicationManager {
aapsLogger.error(LTag.PUMPBTCOMM, "Received more than one message block: {}", messageBlocks.toString()); aapsLogger.error(LTag.PUMPBTCOMM, "Received more than one message block: {}", messageBlocks.toString());
} }
return messageBlocks.get(0); MessageBlock messageBlock = messageBlocks.get(0);
if (messageBlock.getType() != MessageBlockType.ERROR_RESPONSE) {
podState.increaseMessageNumber();
}
return messageBlock;
} }
private OmnipodPacket createAckPacket(PodState podState, Integer packetAddress, Integer messageAddress) { private OmnipodPacket createAckPacket(PodState podState, Integer packetAddress, Integer messageAddress) {
int pktAddress = podState.getAddress(); if (packetAddress == null) {
int msgAddress = podState.getAddress(); packetAddress = podState.getAddress();
if (packetAddress != null) {
pktAddress = packetAddress;
} }
if (messageAddress != null) { if (messageAddress == null) {
msgAddress = messageAddress; messageAddress = podState.getAddress();
} }
return new OmnipodPacket(pktAddress, PacketType.ACK, podState.getPacketNumber(), ByteUtil.getBytesFromInt(msgAddress)); return new OmnipodPacket(packetAddress, PacketType.ACK, podState.getPacketNumber(), ByteUtil.getBytesFromInt(messageAddress));
} }
private void ackUntilQuiet(PodState podState, Integer packetAddress, Integer messageAddress) { private void ackUntilQuiet(PodState podState, Integer packetAddress, Integer messageAddress) {
@ -303,7 +314,7 @@ public class OmnipodCommunicationManager extends RileyLinkCommunicationManager {
throw new CommunicationException(CommunicationException.Type.UNEXPECTED_EXCEPTION, ex); throw new CommunicationException(CommunicationException.Type.UNEXPECTED_EXCEPTION, ex);
} }
podState.increasePacketNumber(1); podState.increasePacketNumber();
} }
private OmnipodPacket exchangePackets(PodState podState, OmnipodPacket packet) { private OmnipodPacket exchangePackets(PodState podState, OmnipodPacket packet) {
@ -317,26 +328,38 @@ public class OmnipodCommunicationManager extends RileyLinkCommunicationManager {
private OmnipodPacket exchangePackets(PodState podState, OmnipodPacket packet, int repeatCount, int responseTimeoutMilliseconds, int exchangeTimeoutMilliseconds, int preambleExtensionMilliseconds) { private OmnipodPacket exchangePackets(PodState podState, OmnipodPacket packet, int repeatCount, int responseTimeoutMilliseconds, int exchangeTimeoutMilliseconds, int preambleExtensionMilliseconds) {
long timeoutTime = System.currentTimeMillis() + exchangeTimeoutMilliseconds; long timeoutTime = System.currentTimeMillis() + exchangeTimeoutMilliseconds;
podState.increasePacketNumber();
while (System.currentTimeMillis() < timeoutTime) { while (System.currentTimeMillis() < timeoutTime) {
OmnipodPacket response = null; OmnipodPacket response = null;
try { try {
response = sendAndListen(packet, responseTimeoutMilliseconds, repeatCount, 9, preambleExtensionMilliseconds, OmnipodPacket.class); response = sendAndListen(packet, responseTimeoutMilliseconds, repeatCount, 9, preambleExtensionMilliseconds, OmnipodPacket.class);
} catch (RileyLinkCommunicationException | OmnipodException ex) { } catch (RileyLinkCommunicationException | OmnipodException ex) {
aapsLogger.debug(LTag.PUMPBTCOMM, "Ignoring exception in exchangePackets", ex); aapsLogger.debug(LTag.PUMPBTCOMM, "Ignoring exception in exchangePackets: " + ex.getClass().getSimpleName() + ": " + ex.getMessage());
} catch (Exception ex) { } catch (Exception ex) {
throw new CommunicationException(CommunicationException.Type.UNEXPECTED_EXCEPTION, ex); throw new CommunicationException(CommunicationException.Type.UNEXPECTED_EXCEPTION, ex);
} }
if (response == null || !response.isValid()) { if (response == null) {
aapsLogger.debug(LTag.PUMPBTCOMM, "exchangePackets response is null");
continue;
} else if (!response.isValid()) {
aapsLogger.debug(LTag.PUMPBTCOMM, "exchangePackets response is invalid: " + response);
continue; continue;
} }
if (response.getAddress() != packet.getAddress()) { if (response.getAddress() != packet.getAddress() &&
continue; response.getAddress() != OmnipodConst.DEFAULT_ADDRESS) { // In some (strange) cases, the Pod remains a packet address of 0xffffffff during it's lifetime
} aapsLogger.debug(LTag.PUMPBTCOMM, "Packet address " + response.getAddress() + " doesn't match " + packet.getAddress());
if (response.getSequenceNumber() != ((podState.getPacketNumber() + 1) & 0b11111)) {
continue; continue;
} }
podState.increasePacketNumber(2); if (response.getSequenceNumber() != podState.getPacketNumber()) {
aapsLogger.debug(LTag.PUMPBTCOMM, "Packet sequence number " + response.getSequenceNumber() + " does not match " + podState.getPacketNumber());
continue;
}
// Once we have verification that the POD heard us, we can increment our counters
podState.increasePacketNumber();
return response; return response;
} }
throw new CommunicationException(CommunicationException.Type.TIMEOUT); throw new CommunicationException(CommunicationException.Type.TIMEOUT);

View file

@ -5,6 +5,7 @@ import org.joda.time.DateTimeZone;
import org.joda.time.Duration; import org.joda.time.Duration;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Random;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -14,7 +15,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.AcknowledgeAl
import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.AssignAddressAction; import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.AssignAddressAction;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.BolusAction; import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.BolusAction;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.CancelDeliveryAction; import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.CancelDeliveryAction;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.ConfigurePodAction;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.DeactivatePodAction; import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.DeactivatePodAction;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.GetPodInfoAction; import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.GetPodInfoAction;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.GetStatusAction; import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.GetStatusAction;
@ -22,6 +22,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.InsertCannula
import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.PrimeAction; import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.PrimeAction;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.SetBasalScheduleAction; import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.SetBasalScheduleAction;
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.SetupPodAction;
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.exception.CommunicationException; import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.CommunicationException;
@ -82,19 +83,18 @@ public class OmnipodManager {
this.podStateChangedHandler = podStateChangedHandler; this.podStateChangedHandler = podStateChangedHandler;
} }
public synchronized Single<SetupActionResult> pairAndPrime() { public synchronized Single<SetupActionResult> pairAndPrime(int address) {
logStartingCommandExecution("pairAndPrime"); logStartingCommandExecution("pairAndPrime");
try { try {
if (podState == null) { if (podState == null || podState.getSetupProgress().isBefore(SetupProgress.POD_CONFIGURED)) {
// Always send both 0x07 and 0x03 on retries
podState = communicationService.executeAction( podState = communicationService.executeAction(
new AssignAddressAction(podStateChangedHandler)); new AssignAddressAction(podStateChangedHandler, address));
} else if (SetupProgress.PRIMING.isBefore(podState.getSetupProgress())) {
throw new IllegalSetupProgressException(SetupProgress.ADDRESS_ASSIGNED, podState.getSetupProgress());
}
if (SetupProgress.ADDRESS_ASSIGNED.equals(podState.getSetupProgress())) { communicationService.executeAction(new SetupPodAction(podState));
communicationService.executeAction(new ConfigurePodAction(podState)); } else if (SetupProgress.PRIMING.isBefore(podState.getSetupProgress())) {
throw new IllegalSetupProgressException(SetupProgress.POD_CONFIGURED, podState.getSetupProgress());
} }
communicationService.executeAction(new PrimeAction(new PrimeService(), podState)); communicationService.executeAction(new PrimeAction(new PrimeService(), podState));
@ -564,6 +564,15 @@ public class OmnipodManager {
return ex instanceof OmnipodException && ((OmnipodException) ex).isCertainFailure(); return ex instanceof OmnipodException && ((OmnipodException) ex).isCertainFailure();
} }
public static int generateRandomAddress() {
// Create random address with 20 bits to match PDM, could easily use 24 bits instead
return 0x1f000000 | (new Random().nextInt() & 0x000fffff);
}
public static boolean isValidAddress(int address) {
return (0x1f000000 | (address & 0x000fffff)) == address;
}
public static class BolusCommandResult { public static class BolusCommandResult {
private final CommandDeliveryStatus commandDeliveryStatus; private final CommandDeliveryStatus commandDeliveryStatus;
private final SingleSubject<BolusDeliveryResult> deliveryResultSubject; private final SingleSubject<BolusDeliveryResult> deliveryResultSubject;

View file

@ -3,9 +3,10 @@ package info.nightscout.androidaps.plugins.pump.omnipod.comm.action;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
import java.util.Collections; import java.util.Collections;
import java.util.Random;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.OmnipodCommunicationManager; import info.nightscout.androidaps.plugins.pump.omnipod.comm.OmnipodCommunicationManager;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalMessageAddressException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalVersionResponseTypeException;
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.command.AssignAddressCommand; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.command.AssignAddressCommand;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.VersionResponse; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.VersionResponse;
@ -18,15 +19,11 @@ public class AssignAddressAction implements OmnipodAction<PodSessionState> {
private final int address; private final int address;
private final PodStateChangedHandler podStateChangedHandler; private final PodStateChangedHandler podStateChangedHandler;
public AssignAddressAction(PodStateChangedHandler podStateChangedHandler) { public AssignAddressAction(PodStateChangedHandler podStateChangedHandler, int address) {
this.address = generateRandomAddress(); this.address = address;
this.podStateChangedHandler = podStateChangedHandler; this.podStateChangedHandler = podStateChangedHandler;
} }
private static int generateRandomAddress() {
return 0x1f000000 | (new Random().nextInt() & 0x000fffff);
}
@Override @Override
public PodSessionState execute(OmnipodCommunicationManager communicationService) { public PodSessionState execute(OmnipodCommunicationManager communicationService) {
PodSetupState setupState = new PodSetupState(address, 0x00, 0x00); PodSetupState setupState = new PodSetupState(address, 0x00, 0x00);
@ -38,6 +35,13 @@ public class AssignAddressAction implements OmnipodAction<PodSessionState> {
VersionResponse assignAddressResponse = communicationService.exchangeMessages(VersionResponse.class, setupState, assignAddressMessage, VersionResponse assignAddressResponse = communicationService.exchangeMessages(VersionResponse.class, setupState, assignAddressMessage,
OmnipodConst.DEFAULT_ADDRESS, setupState.getAddress()); OmnipodConst.DEFAULT_ADDRESS, setupState.getAddress());
if (!assignAddressResponse.isAssignAddressVersionResponse()) {
throw new IllegalVersionResponseTypeException("assignAddress", "setupPod");
}
if (assignAddressResponse.getAddress() != address) {
throw new IllegalMessageAddressException(address, assignAddressResponse.getAddress());
}
DateTimeZone timeZone = DateTimeZone.getDefault(); DateTimeZone timeZone = DateTimeZone.getDefault();
PodSessionState podState = new PodSessionState(timeZone, address, assignAddressResponse.getPiVersion(), PodSessionState podState = new PodSessionState(timeZone, address, assignAddressResponse.getPiVersion(),

View file

@ -28,7 +28,7 @@ public class PrimeAction implements OmnipodAction<StatusResponse> {
} }
public static void updatePrimingStatus(PodSessionState podState, StatusResponse statusResponse, AAPSLogger aapsLogger) { public static void updatePrimingStatus(PodSessionState podState, StatusResponse statusResponse, AAPSLogger aapsLogger) {
if (podState.getSetupProgress().equals(SetupProgress.PRIMING) && statusResponse.getPodProgressStatus().equals(PodProgressStatus.READY_FOR_BASAL_SCHEDULE)) { if (podState.getSetupProgress().equals(SetupProgress.PRIMING) && statusResponse.getPodProgressStatus().equals(PodProgressStatus.PRIMING_COMPLETED)) {
aapsLogger.debug(LTag.PUMPBTCOMM, "Updating SetupProgress from PRIMING to PRIMING_FINISHED"); aapsLogger.debug(LTag.PUMPBTCOMM, "Updating SetupProgress from PRIMING to PRIMING_FINISHED");
podState.setSetupProgress(SetupProgress.PRIMING_FINISHED); podState.setSetupProgress(SetupProgress.PRIMING_FINISHED);
} }

View file

@ -5,22 +5,24 @@ import org.joda.time.DateTime;
import java.util.Collections; import java.util.Collections;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.OmnipodCommunicationManager; import info.nightscout.androidaps.plugins.pump.omnipod.comm.OmnipodCommunicationManager;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalMessageAddressException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalPacketTypeException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalPodProgressException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalSetupProgressException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalVersionResponseTypeException;
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.command.ConfigurePodCommand; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.command.SetupPodCommand;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.VersionResponse; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.VersionResponse;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.PacketType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.PacketType;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodProgressStatus; import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodProgressStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.SetupProgress; import info.nightscout.androidaps.plugins.pump.omnipod.defs.SetupProgress;
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.comm.exception.IllegalPacketTypeException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalPodProgressException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalSetupProgressException;
import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodConst; import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodConst;
public class ConfigurePodAction implements OmnipodAction<VersionResponse> { public class SetupPodAction implements OmnipodAction<VersionResponse> {
private final PodSessionState podState; private final PodSessionState podState;
public ConfigurePodAction(PodSessionState podState) { public SetupPodAction(PodSessionState podState) {
this.podState = podState; this.podState = podState;
} }
@ -31,13 +33,13 @@ public class ConfigurePodAction implements OmnipodAction<VersionResponse> {
} }
DateTime activationDate = DateTime.now(podState.getTimeZone()); DateTime activationDate = DateTime.now(podState.getTimeZone());
ConfigurePodCommand configurePodCommand = new ConfigurePodCommand(podState.getAddress(), activationDate, SetupPodCommand setupPodCommand = new SetupPodCommand(podState.getAddress(), activationDate,
podState.getLot(), podState.getTid()); podState.getLot(), podState.getTid());
OmnipodMessage message = new OmnipodMessage(OmnipodConst.DEFAULT_ADDRESS, OmnipodMessage message = new OmnipodMessage(OmnipodConst.DEFAULT_ADDRESS,
Collections.singletonList(configurePodCommand), podState.getMessageNumber()); Collections.singletonList(setupPodCommand), podState.getMessageNumber());
VersionResponse configurePodResponse; VersionResponse setupPodResponse;
try { try {
configurePodResponse = communicationService.exchangeMessages(VersionResponse.class, podState, setupPodResponse = communicationService.exchangeMessages(VersionResponse.class, podState,
message, OmnipodConst.DEFAULT_ADDRESS, podState.getAddress()); message, OmnipodConst.DEFAULT_ADDRESS, podState.getAddress());
} catch (IllegalPacketTypeException ex) { } catch (IllegalPacketTypeException ex) {
if (PacketType.ACK.equals(ex.getActual())) { if (PacketType.ACK.equals(ex.getActual())) {
@ -48,12 +50,18 @@ public class ConfigurePodAction implements OmnipodAction<VersionResponse> {
throw ex; throw ex;
} }
if (configurePodResponse.getPodProgressStatus() != PodProgressStatus.PAIRING_SUCCESS) { if (!setupPodResponse.isSetupPodVersionResponse()) {
throw new IllegalPodProgressException(PodProgressStatus.PAIRING_SUCCESS, configurePodResponse.getPodProgressStatus()); throw new IllegalVersionResponseTypeException("setupPod", "assignAddress");
}
if (setupPodResponse.getAddress() != podState.getAddress()) {
throw new IllegalMessageAddressException(podState.getAddress(), setupPodResponse.getAddress());
}
if (setupPodResponse.getPodProgressStatus() != PodProgressStatus.PAIRING_COMPLETED) {
throw new IllegalPodProgressException(PodProgressStatus.PAIRING_COMPLETED, setupPodResponse.getPodProgressStatus());
} }
podState.setSetupProgress(SetupProgress.POD_CONFIGURED); podState.setSetupProgress(SetupProgress.POD_CONFIGURED);
return configurePodResponse; return setupPodResponse;
} }
} }

View file

@ -0,0 +1,22 @@
package info.nightscout.androidaps.plugins.pump.omnipod.comm.exception;
import info.nightscout.androidaps.plugins.pump.omnipod.exception.OmnipodException;
public class IllegalMessageAddressException extends OmnipodException {
private final int expected;
private final int actual;
public IllegalMessageAddressException(int expected, int actual) {
super("Invalid message address. Expected="+ expected +", actual="+ actual, false);
this.expected = expected;
this.actual = actual;
}
public int getExpected() {
return expected;
}
public int getActual() {
return actual;
}
}

View file

@ -0,0 +1,22 @@
package info.nightscout.androidaps.plugins.pump.omnipod.comm.exception;
import info.nightscout.androidaps.plugins.pump.omnipod.exception.OmnipodException;
public class IllegalMessageSequenceNumberException extends OmnipodException {
private final int expected;
private final int actual;
public IllegalMessageSequenceNumberException(int expected, int actual) {
super("Invalid message sequence number. Expected="+ expected +", actual="+ actual, false);
this.expected = expected;
this.actual = actual;
}
public int getExpected() {
return expected;
}
public int getActual() {
return actual;
}
}

View file

@ -0,0 +1,9 @@
package info.nightscout.androidaps.plugins.pump.omnipod.comm.exception;
import info.nightscout.androidaps.plugins.pump.omnipod.exception.OmnipodException;
public class IllegalVersionResponseTypeException extends OmnipodException {
public IllegalVersionResponseTypeException(String expected, String actual) {
super("Invalid Version Response type. Expected="+ expected +", actual="+ actual, false);
}
}

View file

@ -7,7 +7,7 @@ public class PodFaultException extends OmnipodException {
private final PodInfoFaultEvent faultEvent; private final PodInfoFaultEvent faultEvent;
public PodFaultException(PodInfoFaultEvent faultEvent) { public PodFaultException(PodInfoFaultEvent faultEvent) {
super(faultEvent.getFaultEventType().toString(), true); super(faultEvent.getFaultEventCode().toString(), true);
this.faultEvent = faultEvent; this.faultEvent = faultEvent;
} }

View file

@ -7,7 +7,7 @@ public class PodReturnedErrorResponseException extends OmnipodException {
private final ErrorResponse errorResponse; private final ErrorResponse errorResponse;
public PodReturnedErrorResponseException(ErrorResponse errorResponse) { public PodReturnedErrorResponseException(ErrorResponse errorResponse) {
super("Pod returned error response: " + errorResponse.getErrorResponseType(), true); super("Pod returned error response: " + errorResponse, true);
this.errorResponse = errorResponse; this.errorResponse = errorResponse;
} }

View file

@ -97,6 +97,10 @@ public class OmnipodMessage {
} }
} }
public int getAddress() {
return address;
}
public List<MessageBlock> getMessageBlocks() { public List<MessageBlock> getMessageBlocks() {
return messageBlocks; return messageBlocks;
} }
@ -135,7 +139,6 @@ public class OmnipodMessage {
return false; return false;
} }
@Override @Override
public String toString() { public String toString() {
return "OmnipodMessage{" + return "OmnipodMessage{" +

View file

@ -1,5 +1,7 @@
package info.nightscout.androidaps.plugins.pump.omnipod.comm.message; package info.nightscout.androidaps.plugins.pump.omnipod.comm.message;
import java.util.Arrays;
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.RLMessage; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.RLMessage;
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.defs.PacketType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.PacketType;
@ -79,4 +81,14 @@ public class OmnipodPacket implements RLMessage {
return valid; return valid;
} }
@Override
public String toString() {
return "OmnipodPacket{" +
"packetAddress=" + packetAddress +
", packetType=" + packetType +
", sequenceNumber=" + sequenceNumber +
", encodedMessage=" + ByteUtil.shortHexStringWithoutSpaces(encodedMessage) +
", valid=" + valid +
'}';
}
} }

View file

@ -6,7 +6,7 @@ import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil;
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.defs.MessageBlockType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.MessageBlockType;
public class ConfigurePodCommand extends MessageBlock { public class SetupPodCommand extends MessageBlock {
private static final byte PACKET_TIMEOUT_LIMIT = 0x04; private static final byte PACKET_TIMEOUT_LIMIT = 0x04;
@ -15,7 +15,7 @@ public class ConfigurePodCommand extends MessageBlock {
private final DateTime date; private final DateTime date;
private final int address; private final int address;
public ConfigurePodCommand(int address, DateTime date, int lot, int tid) { public SetupPodCommand(int address, DateTime date, int lot, int tid) {
this.address = address; this.address = address;
this.lot = lot; this.lot = lot;
this.tid = tid; this.tid = tid;
@ -46,7 +46,7 @@ public class ConfigurePodCommand extends MessageBlock {
@Override @Override
public String toString() { public String toString() {
return "ConfigurePodCommand{" + return "SetupPodCommand{" +
"lot=" + lot + "lot=" + lot +
", tid=" + tid + ", tid=" + tid +
", date=" + date + ", date=" + date +

View file

@ -2,14 +2,19 @@ package info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response;
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.comm.message.MessageBlock; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.MessageBlock;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.ErrorResponseType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.FaultEventCode;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.MessageBlockType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.MessageBlockType;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodProgressStatus;
public class ErrorResponse extends MessageBlock { public class ErrorResponse extends MessageBlock {
public static final byte ERROR_RESPONSE_CODE_BAD_NONCE = (byte) 0x14;
private static final int MESSAGE_LENGTH = 5; private static final int MESSAGE_LENGTH = 5;
private final ErrorResponseType errorResponseType; private final byte errorResponseCode;
private final int nonceSearchKey; private Integer nonceSearchKey; // only valid for BAD_NONCE
private FaultEventCode faultEventCode; // valid for all but BAD_NONCE
private 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) {
@ -17,14 +22,14 @@ public class ErrorResponse extends MessageBlock {
} }
this.encodedData = ByteUtil.substring(encodedData, 2, MESSAGE_LENGTH - 2); this.encodedData = ByteUtil.substring(encodedData, 2, MESSAGE_LENGTH - 2);
ErrorResponseType errorResponseType = null; errorResponseCode = encodedData[2];
try {
errorResponseType = ErrorResponseType.fromByte(encodedData[2]);
} catch (IllegalArgumentException ex) {
}
this.errorResponseType = errorResponseType; if (this.errorResponseCode == ERROR_RESPONSE_CODE_BAD_NONCE) {
this.nonceSearchKey = ByteUtil.makeUnsignedShort((int) encodedData[3], (int) encodedData[4]); nonceSearchKey = ByteUtil.makeUnsignedShort(encodedData[3], encodedData[4]);
} else {
faultEventCode = FaultEventCode.fromByte(encodedData[3]);
podProgressStatus = PodProgressStatus.fromByte(encodedData[4]);
}
} }
@Override @Override
@ -32,19 +37,29 @@ public class ErrorResponse extends MessageBlock {
return MessageBlockType.ERROR_RESPONSE; return MessageBlockType.ERROR_RESPONSE;
} }
public ErrorResponseType getErrorResponseType() { public byte getErrorResponseCode() {
return errorResponseType; return errorResponseCode;
} }
public int getNonceSearchKey() { public FaultEventCode getFaultEventCode() {
return faultEventCode;
}
public PodProgressStatus getPodProgressStatus() {
return podProgressStatus;
}
public Integer getNonceSearchKey() {
return nonceSearchKey; return nonceSearchKey;
} }
@Override @Override
public String toString() { public String toString() {
return "ErrorResponse{" + return "ErrorResponse{" +
"errorResponseType=" + errorResponseType + "errorResponseCode=" + errorResponseCode +
", nonceSearchKey=" + nonceSearchKey + ", nonceSearchKey=" + nonceSearchKey +
", faultEventCode=" + faultEventCode +
", podProgressStatus=" + podProgressStatus +
'}'; '}';
} }
} }

View file

@ -31,20 +31,20 @@ public class StatusResponse extends MessageBlock {
} }
this.encodedData = ByteUtil.substring(encodedData, 1, MESSAGE_LENGTH - 1); this.encodedData = ByteUtil.substring(encodedData, 1, MESSAGE_LENGTH - 1);
this.deliveryStatus = DeliveryStatus.fromByte((byte) (ByteUtil.convertUnsignedByteToInt(encodedData[1]) >>> 4)); deliveryStatus = DeliveryStatus.fromByte((byte) (ByteUtil.convertUnsignedByteToInt(encodedData[1]) >>> 4));
this.podProgressStatus = PodProgressStatus.fromByte((byte) (encodedData[1] & 0x0F)); podProgressStatus = PodProgressStatus.fromByte((byte) (encodedData[1] & 0x0F));
int minutes = ((encodedData[7] & 0x7F) << 6) | ((encodedData[8] & 0xFC) >>> 2); int minutes = ((encodedData[7] & 0x7F) << 6) | ((encodedData[8] & 0xFC) >>> 2);
this.timeActive = Duration.standardMinutes(minutes); timeActive = Duration.standardMinutes(minutes);
int highInsulinBits = (encodedData[2] & 0xF) << 9; int highInsulinBits = (encodedData[2] & 0xF) << 9;
int middleInsulinBits = ByteUtil.convertUnsignedByteToInt(encodedData[3]) << 1; int middleInsulinBits = ByteUtil.convertUnsignedByteToInt(encodedData[3]) << 1;
int lowInsulinBits = ByteUtil.convertUnsignedByteToInt(encodedData[4]) >>> 7; int lowInsulinBits = ByteUtil.convertUnsignedByteToInt(encodedData[4]) >>> 7;
this.insulinDelivered = OmnipodConst.POD_PULSE_SIZE * (highInsulinBits | middleInsulinBits | lowInsulinBits); insulinDelivered = OmnipodConst.POD_PULSE_SIZE * (highInsulinBits | middleInsulinBits | lowInsulinBits);
this.podMessageCounter = (byte) ((encodedData[4] >>> 3) & 0xf); podMessageCounter = (byte) ((encodedData[4] >>> 3) & 0xf);
this.insulinNotDelivered = OmnipodConst.POD_PULSE_SIZE * (((encodedData[4] & 0x03) << 8) | ByteUtil.convertUnsignedByteToInt(encodedData[5])); insulinNotDelivered = OmnipodConst.POD_PULSE_SIZE * (((encodedData[4] & 0x03) << 8) | ByteUtil.convertUnsignedByteToInt(encodedData[5]));
this.alerts = new AlertSet((byte) (((encodedData[6] & 0x7f) << 1) | (ByteUtil.convertUnsignedByteToInt(encodedData[7]) >>> 7))); alerts = new AlertSet((byte) (((encodedData[6] & 0x7f) << 1) | (ByteUtil.convertUnsignedByteToInt(encodedData[7]) >>> 7)));
double reservoirValue = (((encodedData[8] & 0x3) << 8) + ByteUtil.convertUnsignedByteToInt(encodedData[9])) * OmnipodConst.POD_PULSE_SIZE; double reservoirValue = (((encodedData[8] & 0x3) << 8) + ByteUtil.convertUnsignedByteToInt(encodedData[9])) * OmnipodConst.POD_PULSE_SIZE;
if (reservoirValue > OmnipodConst.MAX_RESERVOIR_READING) { if (reservoirValue > OmnipodConst.MAX_RESERVOIR_READING) {
@ -94,7 +94,7 @@ public class StatusResponse extends MessageBlock {
public byte[] getRawData() { public byte[] getRawData() {
ByteArrayOutputStream stream = new ByteArrayOutputStream(); ByteArrayOutputStream stream = new ByteArrayOutputStream();
try { try {
stream.write(this.getType().getValue()); stream.write(getType().getValue());
stream.write(encodedData); stream.write(encodedData);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();

View file

@ -7,45 +7,51 @@ import info.nightscout.androidaps.plugins.pump.omnipod.defs.MessageBlockType;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodProgressStatus; import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodProgressStatus;
public class VersionResponse extends MessageBlock { public class VersionResponse extends MessageBlock {
private static final int ASSIGN_ADDRESS_VERSION_RESPONSE_LENGTH = 0x15;
private static final int SETUP_POD_VERSION_RESPONSE_LENGTH = 0x1b;
private final PodProgressStatus podProgressStatus; private final PodProgressStatus podProgressStatus;
private final FirmwareVersion pmVersion; private final FirmwareVersion pmVersion;
private final FirmwareVersion piVersion; private final FirmwareVersion piVersion;
private final int lot; private final int lot;
private final int tid; private final int tid;
private Byte gain; // Only in the assign address version response
private Byte rssi; // Only in the assign address version response
private final int address; private final int address;
public VersionResponse(byte[] encodedData) { public VersionResponse(byte[] data) {
int length = ByteUtil.convertUnsignedByteToInt(encodedData[1]) + 2; int length = ByteUtil.convertUnsignedByteToInt(data[1]);
this.encodedData = ByteUtil.substring(encodedData, 2, length - 2); this.encodedData = ByteUtil.substring(data, 2, length);
boolean extraByte;
byte[] truncatedData;
switch (length) { switch (length) {
case 0x17: case ASSIGN_ADDRESS_VERSION_RESPONSE_LENGTH:
truncatedData = ByteUtil.substring(encodedData, 2); podProgressStatus = PodProgressStatus.fromByte(data[9]);
extraByte = true; pmVersion = new FirmwareVersion(data[2], data[3], data[4]);
piVersion = new FirmwareVersion(data[5], data[6], data[7]);
lot = ByteUtil.toInt((int) data[10], (int) data[11],
(int) data[12], (int) data[13], ByteUtil.BitConversion.BIG_ENDIAN);
tid = ByteUtil.toInt((int) data[14], (int) data[15],
(int) data[16], (int) data[17], ByteUtil.BitConversion.BIG_ENDIAN);
gain = (byte) ((data[18] & 0xc0) >>> 6);
rssi = (byte) (data[18] & 0x3f);
address = ByteUtil.toInt((int) data[19], (int) data[20],
(int) data[21], (int) data[22], ByteUtil.BitConversion.BIG_ENDIAN);
break; break;
case 0x1D: case SETUP_POD_VERSION_RESPONSE_LENGTH:
truncatedData = ByteUtil.substring(encodedData, 9); podProgressStatus = PodProgressStatus.fromByte(data[16]);
extraByte = false; pmVersion = new FirmwareVersion(data[9], data[10], data[11]);
piVersion = new FirmwareVersion(data[12], data[13], data[14]);
lot = ByteUtil.toInt((int) data[17], (int) data[18],
(int) data[19], (int) data[20], ByteUtil.BitConversion.BIG_ENDIAN);
tid = ByteUtil.toInt((int) data[21], (int) data[22],
(int) data[23], (int) data[24], ByteUtil.BitConversion.BIG_ENDIAN);
address = ByteUtil.toInt((int) data[25], (int) data[26],
(int) data[27], (int) data[28], ByteUtil.BitConversion.BIG_ENDIAN);
break; break;
default: default:
throw new IllegalArgumentException("Unrecognized VersionResponse message length: " + length); throw new IllegalArgumentException("Unrecognized VersionResponse message length: " + length);
} }
this.podProgressStatus = PodProgressStatus.fromByte(truncatedData[7]);
this.pmVersion = new FirmwareVersion(truncatedData[0], truncatedData[1], truncatedData[2]);
this.piVersion = new FirmwareVersion(truncatedData[3], truncatedData[4], truncatedData[5]);
this.lot = ByteUtil.toInt((int) truncatedData[8], (int) truncatedData[9],
(int) truncatedData[10], (int) truncatedData[11], ByteUtil.BitConversion.BIG_ENDIAN);
this.tid = ByteUtil.toInt((int) truncatedData[12], (int) truncatedData[13],
(int) truncatedData[14], (int) truncatedData[15], ByteUtil.BitConversion.BIG_ENDIAN);
int indexIncrementor = extraByte ? 1 : 0;
this.address = ByteUtil.toInt((int) truncatedData[16 + indexIncrementor], (int) truncatedData[17 + indexIncrementor],
(int) truncatedData[18 + indexIncrementor], (int) truncatedData[19 + indexIncrementor], ByteUtil.BitConversion.BIG_ENDIAN);
} }
@Override @Override
@ -73,6 +79,22 @@ public class VersionResponse extends MessageBlock {
return tid; return tid;
} }
public Byte getGain() {
return gain;
}
public Byte getRssi() {
return rssi;
}
public boolean isAssignAddressVersionResponse() {
return encodedData.length == ASSIGN_ADDRESS_VERSION_RESPONSE_LENGTH;
}
public boolean isSetupPodVersionResponse() {
return encodedData.length == SETUP_POD_VERSION_RESPONSE_LENGTH;
}
public int getAddress() { public int getAddress() {
return address; return address;
} }

View file

@ -7,12 +7,12 @@ import java.util.Collections;
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;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.FaultEventType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.FaultEventCode;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodInfoType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodInfoType;
public class PodInfoDataLog extends PodInfo { public class PodInfoDataLog extends PodInfo {
private static final int MINIMUM_MESSAGE_LENGTH = 8; private static final int MINIMUM_MESSAGE_LENGTH = 8;
private final FaultEventType faultEventType; private final FaultEventCode faultEventCode;
private final Duration timeFaultEvent; private final Duration timeFaultEvent;
private final Duration timeSinceActivation; private final Duration timeSinceActivation;
private final byte dataChunkSize; private final byte dataChunkSize;
@ -26,7 +26,7 @@ public class PodInfoDataLog extends PodInfo {
throw new IllegalArgumentException("Not enough data"); throw new IllegalArgumentException("Not enough data");
} }
faultEventType = FaultEventType.fromByte(encodedData[1]); faultEventCode = FaultEventCode.fromByte(encodedData[1]);
timeFaultEvent = Duration.standardMinutes(ByteUtil.toInt(encodedData[2], encodedData[3])); timeFaultEvent = Duration.standardMinutes(ByteUtil.toInt(encodedData[2], encodedData[3]));
timeSinceActivation = Duration.standardMinutes(ByteUtil.toInt(encodedData[4], encodedData[5])); timeSinceActivation = Duration.standardMinutes(ByteUtil.toInt(encodedData[4], encodedData[5]));
dataChunkSize = encodedData[6]; dataChunkSize = encodedData[6];
@ -45,8 +45,8 @@ public class PodInfoDataLog extends PodInfo {
return PodInfoType.DATA_LOG; return PodInfoType.DATA_LOG;
} }
public FaultEventType getFaultEventType() { public FaultEventCode getFaultEventCode() {
return faultEventType; return faultEventCode;
} }
public Duration getTimeFaultEvent() { public Duration getTimeFaultEvent() {
@ -72,7 +72,7 @@ public class PodInfoDataLog extends PodInfo {
@Override @Override
public String toString() { public String toString() {
return "PodInfoDataLog{" + return "PodInfoDataLog{" +
"faultEventType=" + faultEventType + "faultEventCode=" + faultEventCode +
", timeFaultEvent=" + timeFaultEvent + ", timeFaultEvent=" + timeFaultEvent +
", timeSinceActivation=" + timeSinceActivation + ", timeSinceActivation=" + timeSinceActivation +
", dataChunkSize=" + dataChunkSize + ", dataChunkSize=" + dataChunkSize +

View file

@ -3,12 +3,12 @@ package info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.po
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.Duration; import org.joda.time.Duration;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.FaultEventType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.FaultEventCode;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodInfoType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodInfoType;
public class PodInfoFaultAndInitializationTime extends PodInfo { public class PodInfoFaultAndInitializationTime extends PodInfo {
private static final int MINIMUM_MESSAGE_LENGTH = 17; private static final int MINIMUM_MESSAGE_LENGTH = 17;
private final FaultEventType faultEventType; private final FaultEventCode faultEventCode;
private final Duration timeFaultEvent; private final Duration timeFaultEvent;
private final DateTime initializationTime; private final DateTime initializationTime;
@ -19,7 +19,7 @@ public class PodInfoFaultAndInitializationTime extends PodInfo {
throw new IllegalArgumentException("Not enough data"); throw new IllegalArgumentException("Not enough data");
} }
faultEventType = FaultEventType.fromByte(encodedData[1]); faultEventCode = FaultEventCode.fromByte(encodedData[1]);
timeFaultEvent = Duration.standardMinutes(((encodedData[2] & 0b1) << 8) + encodedData[3]); timeFaultEvent = Duration.standardMinutes(((encodedData[2] & 0b1) << 8) + encodedData[3]);
// We ignore time zones here because we don't keep the time zone in which the pod was initially set up // We ignore time zones here because we don't keep the time zone in which the pod was initially set up
// Which is fine because we don't use the initialization time for anything important anyway // Which is fine because we don't use the initialization time for anything important anyway
@ -31,8 +31,8 @@ public class PodInfoFaultAndInitializationTime extends PodInfo {
return PodInfoType.FAULT_AND_INITIALIZATION_TIME; return PodInfoType.FAULT_AND_INITIALIZATION_TIME;
} }
public FaultEventType getFaultEventType() { public FaultEventCode getFaultEventCode() {
return faultEventType; return faultEventCode;
} }
public Duration getTimeFaultEvent() { public Duration getTimeFaultEvent() {
@ -46,7 +46,7 @@ public class PodInfoFaultAndInitializationTime extends PodInfo {
@Override @Override
public String toString() { public String toString() {
return "PodInfoFaultAndInitializationTime{" + return "PodInfoFaultAndInitializationTime{" +
"faultEventType=" + faultEventType + "faultEventCode=" + faultEventCode +
", timeFaultEvent=" + timeFaultEvent + ", timeFaultEvent=" + timeFaultEvent +
", initializationTime=" + initializationTime + ", initializationTime=" + initializationTime +
'}'; '}';

View file

@ -5,7 +5,7 @@ import org.joda.time.Duration;
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.defs.AlertSet; import info.nightscout.androidaps.plugins.pump.omnipod.defs.AlertSet;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.DeliveryStatus; import info.nightscout.androidaps.plugins.pump.omnipod.defs.DeliveryStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.FaultEventType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.FaultEventCode;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.LogEventErrorCode; import info.nightscout.androidaps.plugins.pump.omnipod.defs.LogEventErrorCode;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodInfoType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodInfoType;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodProgressStatus; import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodProgressStatus;
@ -19,7 +19,7 @@ public class PodInfoFaultEvent extends PodInfo {
private final double insulinNotDelivered; private final double insulinNotDelivered;
private final byte podMessageCounter; private final byte podMessageCounter;
private final double totalInsulinDelivered; private final double totalInsulinDelivered;
private final FaultEventType faultEventType; private final FaultEventCode faultEventCode;
private final Duration faultEventTime; private final Duration faultEventTime;
private final Double reservoirLevel; private final Double reservoirLevel;
private final Duration timeSinceActivation; private final Duration timeSinceActivation;
@ -44,7 +44,7 @@ public class PodInfoFaultEvent extends PodInfo {
insulinNotDelivered = OmnipodConst.POD_PULSE_SIZE * ByteUtil.toInt(encodedData[3], encodedData[4]); insulinNotDelivered = OmnipodConst.POD_PULSE_SIZE * ByteUtil.toInt(encodedData[3], encodedData[4]);
podMessageCounter = encodedData[5]; podMessageCounter = encodedData[5];
totalInsulinDelivered = OmnipodConst.POD_PULSE_SIZE * ByteUtil.toInt(encodedData[6], encodedData[7]); totalInsulinDelivered = OmnipodConst.POD_PULSE_SIZE * ByteUtil.toInt(encodedData[6], encodedData[7]);
faultEventType = FaultEventType.fromByte(encodedData[8]); faultEventCode = FaultEventCode.fromByte(encodedData[8]);
int minutesSinceActivation = ByteUtil.toInt(encodedData[9], encodedData[10]); int minutesSinceActivation = ByteUtil.toInt(encodedData[9], encodedData[10]);
if (minutesSinceActivation == 0xffff) { if (minutesSinceActivation == 0xffff) {
@ -99,8 +99,8 @@ public class PodInfoFaultEvent extends PodInfo {
return totalInsulinDelivered; return totalInsulinDelivered;
} }
public FaultEventType getFaultEventType() { public FaultEventCode getFaultEventCode() {
return faultEventType; return faultEventCode;
} }
public Duration getFaultEventTime() { public Duration getFaultEventTime() {
@ -155,7 +155,7 @@ public class PodInfoFaultEvent extends PodInfo {
", insulinNotDelivered=" + insulinNotDelivered + ", insulinNotDelivered=" + insulinNotDelivered +
", podMessageCounter=" + podMessageCounter + ", podMessageCounter=" + podMessageCounter +
", totalInsulinDelivered=" + totalInsulinDelivered + ", totalInsulinDelivered=" + totalInsulinDelivered +
", faultEventType=" + faultEventType + ", faultEventCode=" + faultEventCode +
", faultEventTime=" + faultEventTime + ", faultEventTime=" + faultEventTime +
", reservoirLevel=" + reservoirLevel + ", reservoirLevel=" + reservoirLevel +
", timeSinceActivation=" + timeSinceActivation + ", timeSinceActivation=" + timeSinceActivation +

View file

@ -1,24 +0,0 @@
package info.nightscout.androidaps.plugins.pump.omnipod.defs;
public enum ErrorResponseType {
BAD_NONCE((byte) 0x14);
private byte value;
ErrorResponseType(byte value) {
this.value = value;
}
public static ErrorResponseType fromByte(byte value) {
for (ErrorResponseType type : values()) {
if (type.value == value) {
return type;
}
}
throw new IllegalArgumentException("Unknown ErrorResponseType: " + value);
}
public byte getValue() {
return value;
}
}

View file

@ -2,7 +2,7 @@ package info.nightscout.androidaps.plugins.pump.omnipod.defs;
import java.util.Locale; import java.util.Locale;
public enum FaultEventType { public enum FaultEventCode {
NO_FAULTS((byte) 0x00), NO_FAULTS((byte) 0x00),
FAILED_FLASH_ERASE((byte) 0x01), FAILED_FLASH_ERASE((byte) 0x01),
FAILED_FLASH_STORE((byte) 0x02), FAILED_FLASH_STORE((byte) 0x02),
@ -124,17 +124,17 @@ public enum FaultEventType {
private byte value; private byte value;
FaultEventType(byte value) { FaultEventCode(byte value) {
this.value = value; this.value = value;
} }
public static FaultEventType fromByte(byte value) { public static FaultEventCode fromByte(byte value) {
for (FaultEventType type : values()) { for (FaultEventCode type : values()) {
if (type.value == value) { if (type.value == value) {
return type; return type;
} }
} }
throw new IllegalArgumentException("Unknown FaultEventType: " + value); throw new IllegalArgumentException("Unknown FaultEventCode: " + value);
} }
public byte getValue() { public byte getValue() {

View file

@ -1,22 +1,22 @@
package info.nightscout.androidaps.plugins.pump.omnipod.defs; package info.nightscout.androidaps.plugins.pump.omnipod.defs;
public enum PodProgressStatus { public enum PodProgressStatus {
INITIAL_VALUE((byte) 0x00), INITIALIZED((byte) 0x00),
TANK_POWER_ACTIVATED((byte) 0x01), MEMORY_INITIALIZED((byte) 0x01),
TANK_FILL_COMPLETED((byte) 0x02), REMINDER_INITIALIZED((byte) 0x02),
PAIRING_SUCCESS((byte) 0x03), PAIRING_COMPLETED((byte) 0x03),
PRIMING((byte) 0x04), PRIMING((byte) 0x04),
READY_FOR_BASAL_SCHEDULE((byte) 0x05), PRIMING_COMPLETED((byte) 0x05),
READY_FOR_CANNULA_INSERTION((byte) 0x06), BASAL_INITIALIZED((byte) 0x06),
CANNULA_INSERTING((byte) 0x07), INSERTING_CANNULA((byte) 0x07),
RUNNING_ABOVE_FIFTY_UNITS((byte) 0x08), ABOVE_FIFTY_UNITS((byte) 0x08),
RUNNING_BELOW_FIFTY_UNITS((byte) 0x09), FIFTY_OR_LESS_UNITS((byte) 0x09),
ONE_NOT_USED_BUT_IN_33((byte) 0x0a), ONE_NOT_USED((byte) 0x0a),
TWO_NOT_USED_BUT_IN_33((byte) 0x0b), TWO_NOT_USED((byte) 0x0b),
THREE_NOT_USED_BUT_IN_33((byte) 0x0c), THREE_NOT_USED((byte) 0x0c),
FAULT_EVENT_OCCURRED((byte) 0x0d), FAULT_EVENT_OCCURRED((byte) 0x0d), // Fault event occurred (a "screamer")
FAILED_TO_INITIALIZE_IN_TIME((byte) 0x0e), ACTIVATION_TIME_EXCEEDED((byte) 0x0e), // Took > 2 hours from progress 2 to 3 or > 1 hour from 3 to 8
INACTIVE((byte) 0x0f); INACTIVE((byte) 0x0f); // Pod deactivated or a fatal packet state error
private byte value; private byte value;
@ -38,6 +38,6 @@ public enum PodProgressStatus {
} }
public boolean isReadyForDelivery() { public boolean isReadyForDelivery() {
return this == RUNNING_ABOVE_FIFTY_UNITS || this == RUNNING_BELOW_FIFTY_UNITS; return this == ABOVE_FIFTY_UNITS || this == FIFTY_OR_LESS_UNITS;
} }
} }

View file

@ -46,12 +46,12 @@ public abstract class PodState {
this.packetNumber = packetNumber; this.packetNumber = packetNumber;
} }
public void increaseMessageNumber(int increment) { public void increaseMessageNumber() {
setMessageNumber((messageNumber + increment) & 0b1111); setMessageNumber((messageNumber + 1) & 0b1111);
} }
public void increasePacketNumber(int increment) { public void increasePacketNumber() {
setPacketNumber((packetNumber + increment) & 0b11111); setPacketNumber((packetNumber + 1) & 0b11111);
} }
public boolean hasFaultEvent() { public boolean hasFaultEvent() {

View file

@ -157,7 +157,7 @@ class PodManagementActivity : NoSplashAppCompatActivity() {
val isPodSessionActive = (omnipodUtil.getPodSessionState() != null) val isPodSessionActive = (omnipodUtil.getPodSessionState() != null)
initpod_remove_pod.isEnabled = isPodSessionActive initpod_remove_pod.isEnabled = isPodSessionActive
initpod_reset_pod.isEnabled = isPodSessionActive initpod_reset_pod.isEnabled = isPodSessionActive || OmnipodUtil.hasNextPodAddress()
if (omnipodUtil.getDriverState() == OmnipodDriverState.NotInitalized) { if (omnipodUtil.getDriverState() == OmnipodDriverState.NotInitalized) {
// if rileylink is not running we disable all operations // if rileylink is not running we disable all operations

View file

@ -44,10 +44,13 @@ import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.CommandIni
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.CommunicationException; import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.CommunicationException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.CrcMismatchException; import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.CrcMismatchException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalDeliveryStatusException; import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalDeliveryStatusException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalMessageAddressException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalMessageSequenceNumberException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalPacketTypeException; import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalPacketTypeException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalPodProgressException; import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalPodProgressException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalResponseException; import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalResponseException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalSetupProgressException; import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalSetupProgressException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.IllegalVersionResponseTypeException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.MessageDecodingException; import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.MessageDecodingException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.NonceOutOfSyncException; import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.NonceOutOfSyncException;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.NonceResyncException; import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.NonceResyncException;
@ -59,7 +62,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.pod
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.AlertSlot; 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.AlertType;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.FaultEventType; 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.OmnipodCommunicationManagerInterface;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodInfoType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodInfoType;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodInitActionType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodInitActionType;
@ -194,8 +197,13 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
if (PodInitActionType.PairAndPrimeWizardStep.equals(podInitActionType)) { if (PodInitActionType.PairAndPrimeWizardStep.equals(podInitActionType)) {
try { try {
Disposable disposable = delegate.pairAndPrime().subscribe(res -> // int address = obtainNextPodAddress();
Disposable disposable = delegate.pairAndPrime(address).subscribe(res -> //
handleSetupActionResult(podInitActionType, podInitReceiver, res, time, null)); handleSetupActionResult(podInitActionType, podInitReceiver, res, time, null));
removeNextPodAddress();
return new PumpEnactResult(injector).success(true).enacted(true); return new PumpEnactResult(injector).success(true).enacted(true);
} catch (Exception ex) { } catch (Exception ex) {
String comment = handleAndTranslateException(ex); String comment = handleAndTranslateException(ex);
@ -299,6 +307,7 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
reportImplicitlyCanceledTbr(); reportImplicitlyCanceledTbr();
this.omnipodUtil.setPodSessionState(null); this.omnipodUtil.setPodSessionState(null);
this.omnipodUtil.removeNextPodAddress();
addSuccessToHistory(System.currentTimeMillis(), PodHistoryEntryType.ResetPodState, null); addSuccessToHistory(System.currentTimeMillis(), PodHistoryEntryType.ResetPodState, null);
@ -355,7 +364,7 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
activePlugin.getActiveTreatments().addToHistoryTreatment(detailedBolusInfo, false); activePlugin.getActiveTreatments().addToHistoryTreatment(detailedBolusInfo, false);
if (delegate.getPodState().hasFaultEvent()) { if (delegate.getPodState().hasFaultEvent()) {
showPodFaultErrorDialog(delegate.getPodState().getFaultEvent().getFaultEventType(), R.raw.urgentalarm); showPodFaultErrorDialog(delegate.getPodState().getFaultEvent().getFaultEventCode(), R.raw.urgentalarm);
} }
return new PumpEnactResult(injector).success(true).enacted(true).bolusDelivered(unitsDelivered); return new PumpEnactResult(injector).success(true).enacted(true).bolusDelivered(unitsDelivered);
@ -371,7 +380,7 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
addSuccessToHistory(time, PodHistoryEntryType.CancelBolus, null); addSuccessToHistory(time, PodHistoryEntryType.CancelBolus, null);
return new PumpEnactResult(injector).success(true).enacted(true); return new PumpEnactResult(injector).success(true).enacted(true);
} catch (PodFaultException ex) { } catch (PodFaultException ex) {
showPodFaultErrorDialog(ex.getFaultEvent().getFaultEventType(), null); showPodFaultErrorDialog(ex.getFaultEvent().getFaultEventCode(), null);
addSuccessToHistory(time, PodHistoryEntryType.CancelBolus, null); addSuccessToHistory(time, PodHistoryEntryType.CancelBolus, null);
return new PumpEnactResult(injector).success(true).enacted(true); return new PumpEnactResult(injector).success(true).enacted(true);
} catch (Exception ex) { } catch (Exception ex) {
@ -562,18 +571,15 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
} }
} }
private long addSuccessToHistory(long requestTime, PodHistoryEntryType entryType, Object data) {
public long addSuccessToHistory(long requestTime, PodHistoryEntryType entryType, Object data) {
return addToHistory(requestTime, entryType, data, true); return addToHistory(requestTime, entryType, data, true);
} }
public long addFailureToHistory(long requestTime, PodHistoryEntryType entryType, Object data) { private long addFailureToHistory(long requestTime, PodHistoryEntryType entryType, Object data) {
return addToHistory(requestTime, entryType, data, false); return addToHistory(requestTime, entryType, data, false);
} }
private long addToHistory(long requestTime, PodHistoryEntryType entryType, Object data, boolean success) {
public long addToHistory(long requestTime, PodHistoryEntryType entryType, Object data, boolean success) {
PodHistory podHistory = new PodHistory(requestTime, entryType); PodHistory podHistory = new PodHistory(requestTime, entryType);
if (data != null) { if (data != null) {
@ -590,7 +596,20 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
MainApp.getDbHelper().createOrUpdate(podHistory); MainApp.getDbHelper().createOrUpdate(podHistory);
return podHistory.getPumpId(); return podHistory.getPumpId();
}
private int obtainNextPodAddress() {
Integer nextPodAddress = this.omnipodUtil.getNextPodAddress();
if (nextPodAddress == null) {
nextPodAddress = OmnipodManager.generateRandomAddress();
this.omnipodUtil.setNextPodAddress(nextPodAddress);
}
return nextPodAddress;
}
private void removeNextPodAddress() {
this.omnipodUtil.removeNextPodAddress();
} }
private void handleSetupActionResult(PodInitActionType podInitActionType, PodInitReceiver podInitReceiver, SetupActionResult res, long time, Profile profile) { private void handleSetupActionResult(PodInitActionType podInitActionType, PodInitReceiver podInitReceiver, SetupActionResult res, long time, Profile profile) {
@ -624,7 +643,11 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
if (ex instanceof ActionInitializationException || ex instanceof CommandInitializationException) { if (ex instanceof ActionInitializationException || ex instanceof CommandInitializationException) {
comment = getStringResource(R.string.omnipod_driver_error_invalid_parameters); comment = getStringResource(R.string.omnipod_driver_error_invalid_parameters);
} else if (ex instanceof CommunicationException) { } else if (ex instanceof CommunicationException) {
comment = getStringResource(R.string.omnipod_driver_error_communication_failed); if (((CommunicationException) ex).getType() == CommunicationException.Type.TIMEOUT) {
comment = getStringResource(R.string.omnipod_driver_error_communication_failed_timeout);
} else {
comment = getStringResource(R.string.omnipod_driver_error_communication_failed_unexpected_exception);
}
} else if (ex instanceof CrcMismatchException) { } else if (ex instanceof CrcMismatchException) {
comment = getStringResource(R.string.omnipod_driver_error_crc_mismatch); comment = getStringResource(R.string.omnipod_driver_error_crc_mismatch);
} else if (ex instanceof IllegalPacketTypeException) { } else if (ex instanceof IllegalPacketTypeException) {
@ -632,8 +655,14 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
} else if (ex instanceof IllegalPodProgressException || ex instanceof IllegalSetupProgressException } else if (ex instanceof IllegalPodProgressException || ex instanceof IllegalSetupProgressException
|| ex instanceof IllegalDeliveryStatusException) { || ex instanceof IllegalDeliveryStatusException) {
comment = getStringResource(R.string.omnipod_driver_error_invalid_progress_state); comment = getStringResource(R.string.omnipod_driver_error_invalid_progress_state);
} else if (ex instanceof IllegalVersionResponseTypeException) {
comment = getStringResource(R.string.omnipod_driver_error_invalid_response);
} else if (ex instanceof IllegalResponseException) { } else if (ex instanceof IllegalResponseException) {
comment = getStringResource(R.string.omnipod_driver_error_invalid_response); comment = getStringResource(R.string.omnipod_driver_error_invalid_response);
} else if (ex instanceof IllegalMessageSequenceNumberException) {
comment = getStringResource(R.string.omnipod_driver_error_invalid_message_sequence_number);
} else if (ex instanceof IllegalMessageAddressException) {
comment = getStringResource(R.string.omnipod_driver_error_invalid_message_address);
} else if (ex instanceof MessageDecodingException) { } else if (ex instanceof MessageDecodingException) {
comment = getStringResource(R.string.omnipod_driver_error_message_decoding_failed); comment = getStringResource(R.string.omnipod_driver_error_message_decoding_failed);
} else if (ex instanceof NonceOutOfSyncException) { } else if (ex instanceof NonceOutOfSyncException) {
@ -643,9 +672,9 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
} else if (ex instanceof NotEnoughDataException) { } else if (ex instanceof NotEnoughDataException) {
comment = getStringResource(R.string.omnipod_driver_error_not_enough_data); comment = getStringResource(R.string.omnipod_driver_error_not_enough_data);
} else if (ex instanceof PodFaultException) { } else if (ex instanceof PodFaultException) {
FaultEventType faultEventType = ((PodFaultException) ex).getFaultEvent().getFaultEventType(); FaultEventCode faultEventCode = ((PodFaultException) ex).getFaultEvent().getFaultEventCode();
showPodFaultErrorDialog(faultEventType, R.raw.urgentalarm); showPodFaultErrorDialog(faultEventCode, R.raw.urgentalarm);
comment = createPodFaultErrorMessage(faultEventType); comment = createPodFaultErrorMessage(faultEventCode);
} else if (ex instanceof PodReturnedErrorResponseException) { } else if (ex instanceof PodReturnedErrorResponseException) {
comment = getStringResource(R.string.omnipod_driver_error_pod_returned_error_response); comment = getStringResource(R.string.omnipod_driver_error_pod_returned_error_response);
} else { } else {
@ -661,10 +690,10 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
return comment; return comment;
} }
private String createPodFaultErrorMessage(FaultEventType faultEventType) { private String createPodFaultErrorMessage(FaultEventCode faultEventCode) {
String comment; String comment;
comment = getStringResource(R.string.omnipod_driver_error_pod_fault, comment = getStringResource(R.string.omnipod_driver_error_pod_fault,
ByteUtil.convertUnsignedByteToInt(faultEventType.getValue()), faultEventType.name()); ByteUtil.convertUnsignedByteToInt(faultEventCode.getValue()), faultEventCode.name());
return comment; return comment;
} }
@ -672,8 +701,8 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
rxBus.send(event); rxBus.send(event);
} }
private void showPodFaultErrorDialog(FaultEventType faultEventType, Integer sound) { private void showPodFaultErrorDialog(FaultEventCode faultEventCode, Integer sound) {
showErrorDialog(createPodFaultErrorMessage(faultEventType), sound); showErrorDialog(createPodFaultErrorMessage(faultEventCode), sound);
} }
private void showErrorDialog(String message, Integer sound) { private void showErrorDialog(String message, Integer sound) {

View file

@ -14,6 +14,7 @@ public class OmnipodConst {
public class Prefs { public class Prefs {
public static final String PodState = Prefix + "pod_state"; public static final String PodState = Prefix + "pod_state";
public static final String NextPodAddress = Prefix + "next_pod_address";
public static final int BeepBasalEnabled = R.string.key_omnipod_beep_basal_enabled; public static final int BeepBasalEnabled = R.string.key_omnipod_beep_basal_enabled;
public static final int BeepBolusEnabled = R.string.key_omnipod_beep_bolus_enabled; public static final int BeepBolusEnabled = R.string.key_omnipod_beep_bolus_enabled;
public static final int BeepSMBEnabled = R.string.key_omnipod_beep_smb_enabled; public static final int BeepSMBEnabled = R.string.key_omnipod_beep_smb_enabled;

View file

@ -23,6 +23,7 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; import info.nightscout.androidaps.plugins.pump.common.defs.PumpType;
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkUtil; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkUtil;
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.data.RLHistoryItem; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.data.RLHistoryItem;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.OmnipodManager;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.OmnipodCommandType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.OmnipodCommandType;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.OmnipodPodType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.OmnipodPodType;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodDeviceState; import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodDeviceState;
@ -30,6 +31,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodSessionStat
import info.nightscout.androidaps.plugins.pump.omnipod.driver.OmnipodDriverState; import info.nightscout.androidaps.plugins.pump.omnipod.driver.OmnipodDriverState;
import info.nightscout.androidaps.plugins.pump.omnipod.driver.OmnipodPumpStatus; import info.nightscout.androidaps.plugins.pump.omnipod.driver.OmnipodPumpStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.events.EventOmnipodDeviceStatusChange; import info.nightscout.androidaps.plugins.pump.omnipod.events.EventOmnipodDeviceStatusChange;
import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.alertDialogs.OKDialog; import info.nightscout.androidaps.utils.alertDialogs.OKDialog;
/** /**
@ -44,7 +46,6 @@ public class OmnipodUtil {
private final OmnipodPumpStatus omnipodPumpStatus; private final OmnipodPumpStatus omnipodPumpStatus;
private final ActivePluginProvider activePlugins; private final ActivePluginProvider activePlugins;
private boolean lowLevelDebug = true; private boolean lowLevelDebug = true;
private OmnipodCommandType currentCommand; private OmnipodCommandType currentCommand;
private Gson gsonInstance = createGson(); private Gson gsonInstance = createGson();
@ -92,7 +93,6 @@ public class OmnipodUtil {
rileyLinkUtil.getRileyLinkHistory().add(new RLHistoryItem(currentCommand)); rileyLinkUtil.getRileyLinkHistory().add(new RLHistoryItem(currentCommand));
} }
public static void displayNotConfiguredDialog(Context context) { public static void displayNotConfiguredDialog(Context context) {
OKDialog.showConfirmation(context, MainApp.gs(R.string.combo_warning), OKDialog.showConfirmation(context, MainApp.gs(R.string.combo_warning),
MainApp.gs(R.string.omnipod_error_operation_not_possible_no_configuration), (Runnable) null); MainApp.gs(R.string.omnipod_error_operation_not_possible_no_configuration), (Runnable) null);
@ -182,7 +182,6 @@ public class OmnipodUtil {
omnipodPumpStatus.pumpType = pumpType_; omnipodPumpStatus.pumpType = pumpType_;
} }
public PumpType getPumpType() { public PumpType getPumpType() {
return omnipodPumpStatus.pumpType; return omnipodPumpStatus.pumpType;
} }
@ -192,4 +191,25 @@ public class OmnipodUtil {
return this.gsonInstance; return this.gsonInstance;
} }
public Integer getNextPodAddress() {
if(SP.contains(OmnipodConst.Prefs.NextPodAddress)) {
int nextPodAddress = SP.getInt(OmnipodConst.Prefs.NextPodAddress, 0);
if (OmnipodManager.isValidAddress(nextPodAddress)) {
return nextPodAddress;
}
}
return null;
}
public boolean hasNextPodAddress() {
return getNextPodAddress() != null;
}
public void setNextPodAddress(int address) {
SP.putInt(OmnipodConst.Prefs.NextPodAddress, address);
}
public void removeNextPodAddress() {
SP.remove(OmnipodConst.Prefs.NextPodAddress);
}
} }

View file

@ -1873,13 +1873,16 @@
<string name="omnipod_error_pod_not_attached">No active pod.</string> <string name="omnipod_error_pod_not_attached">No active pod.</string>
<string name="omnipod_driver_error_setup_action_verification_failed">Command verification failed.</string> <string name="omnipod_driver_error_setup_action_verification_failed">Command verification failed.</string>
<string name="omnipod_driver_error_unexpected_exception_type">An unexpected error occured. Please report! (type: %1$s).</string> <string name="omnipod_driver_error_unexpected_exception_type">An unexpected error occurred. Please report! (type: %1$s).</string>
<string name="omnipod_driver_error_invalid_parameters">Communication failed: received invalid input parameters.</string> <string name="omnipod_driver_error_invalid_parameters">Communication failed: received invalid input parameters.</string>
<string name="omnipod_driver_error_communication_failed">Communication failed.</string> <string name="omnipod_driver_error_communication_failed_timeout">Communication failed: timeout.</string>
<string name="omnipod_driver_error_communication_failed_unexpected_exception">Communication failed: an unexpected error occurred. Please report!</string>
<string name="omnipod_driver_error_crc_mismatch">Communication failed: message integrity verification failed.</string> <string name="omnipod_driver_error_crc_mismatch">Communication failed: message integrity verification failed.</string>
<string name="omnipod_driver_error_invalid_packet_type">Communication failed: received an invalid packet from the Pod.</string> <string name="omnipod_driver_error_invalid_packet_type">Communication failed: received an invalid packet from the Pod.</string>
<string name="omnipod_driver_error_invalid_progress_state">Communication failed: the Pod is in a wrong state.</string> <string name="omnipod_driver_error_invalid_progress_state">Communication failed: the Pod is in a wrong state.</string>
<string name="omnipod_driver_error_invalid_response">Communication failed: received an invalid response from the Pod.</string> <string name="omnipod_driver_error_invalid_response">Communication failed: received an invalid response from the Pod.</string>
<string name="omnipod_driver_error_invalid_message_sequence_number">Communication failed: received a message with an invalid sequence number from the Pod.</string>
<string name="omnipod_driver_error_invalid_message_address">Communication failed: received a message with an invalid address from the Pod.</string>
<string name="omnipod_driver_error_message_decoding_failed">Communication failed: failed to decode message from the Pod.</string> <string name="omnipod_driver_error_message_decoding_failed">Communication failed: failed to decode message from the Pod.</string>
<string name="omnipod_driver_error_nonce_resync_failed">Communication failed: nonce resync failed.</string> <string name="omnipod_driver_error_nonce_resync_failed">Communication failed: nonce resync failed.</string>
<string name="omnipod_driver_error_nonce_out_of_sync">Communication failed: nonce out of sync.</string> <string name="omnipod_driver_error_nonce_out_of_sync">Communication failed: nonce out of sync.</string>

View file

@ -7,10 +7,10 @@ import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
public class ConfigurePodCommandTest { public class SetupPodCommandTest {
@Test @Test
public void testEncoding() { public void testEncoding() {
ConfigurePodCommand configurePodCommand = new ConfigurePodCommand( // SetupPodCommand setupPodCommand = new SetupPodCommand( //
0x1f00ee87, // 0x1f00ee87, //
new DateTime(2013, 4, 5, 22, 52, 0), // new DateTime(2013, 4, 5, 22, 52, 0), //
41847, // 41847, //
@ -18,7 +18,7 @@ public class ConfigurePodCommandTest {
assertArrayEquals( // assertArrayEquals( //
ByteUtil.fromHexString("03131f00ee87140404050d16340000a3770003ab37"), // From https://github.com/openaps/openomni/wiki/Command-03-Setup-Pod ByteUtil.fromHexString("03131f00ee87140404050d16340000a3770003ab37"), // From https://github.com/openaps/openomni/wiki/Command-03-Setup-Pod
configurePodCommand.getRawData()); setupPodCommand.getRawData());
} }
// TODO add tests // TODO add tests

View file

@ -3,7 +3,8 @@ package info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response;
import org.junit.Test; import org.junit.Test;
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.defs.ErrorResponseType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.FaultEventCode;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodProgressStatus;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@ -33,14 +34,19 @@ public class ErrorResponseTest {
byte[] encodedData = ByteUtil.fromHexString("060314fa92"); byte[] encodedData = ByteUtil.fromHexString("060314fa92");
ErrorResponse errorResponse = new ErrorResponse(encodedData); ErrorResponse errorResponse = new ErrorResponse(encodedData);
assertEquals(ErrorResponseType.BAD_NONCE, errorResponse.getErrorResponseType()); assertEquals(ErrorResponse.ERROR_RESPONSE_CODE_BAD_NONCE, errorResponse.getErrorResponseCode());
// TODO add assertion one nonce search key (obtain captures first) // TODO add assertion on nonce search key (obtain captures first)
assertNull(errorResponse.getFaultEventCode());
assertNull(errorResponse.getPodProgressStatus());
} }
@Test @Test
public void testUnknownError() { public void testOtherError() {
ErrorResponse errorResponse = new ErrorResponse(ByteUtil.fromHexString("060307fa92")); ErrorResponse errorResponse = new ErrorResponse(ByteUtil.fromHexString("0603101308"));
assertEquals(0x10, errorResponse.getErrorResponseCode());
assertEquals(FaultEventCode.MESSAGE_LENGTH_TOO_LONG, errorResponse.getFaultEventCode());
assertEquals(PodProgressStatus.ABOVE_FIFTY_UNITS, errorResponse.getPodProgressStatus());
assertNull(errorResponse.getErrorResponseType()); assertNull(errorResponse.getNonceSearchKey());
} }
} }

View file

@ -42,7 +42,7 @@ public class StatusResponseTest {
StatusResponse statusResponse = new StatusResponse(bytes); StatusResponse statusResponse = new StatusResponse(bytes);
assertEquals(DeliveryStatus.NORMAL, statusResponse.getDeliveryStatus()); assertEquals(DeliveryStatus.NORMAL, statusResponse.getDeliveryStatus());
assertEquals(PodProgressStatus.RUNNING_ABOVE_FIFTY_UNITS, statusResponse.getPodProgressStatus()); assertEquals(PodProgressStatus.ABOVE_FIFTY_UNITS, statusResponse.getPodProgressStatus());
assertNull("Reservoir level should be null", statusResponse.getReservoirLevel()); assertNull("Reservoir level should be null", statusResponse.getReservoirLevel());
assertEquals(Duration.standardMinutes(1307).getMillis(), statusResponse.getTimeActive().getMillis()); assertEquals(Duration.standardMinutes(1307).getMillis(), statusResponse.getTimeActive().getMillis());
assertEquals(60.05, statusResponse.getInsulinDelivered(), 0.000001); assertEquals(60.05, statusResponse.getInsulinDelivered(), 0.000001);
@ -59,7 +59,7 @@ public class StatusResponseTest {
StatusResponse statusResponse = new StatusResponse(bytes); StatusResponse statusResponse = new StatusResponse(bytes);
assertEquals(DeliveryStatus.NORMAL, statusResponse.getDeliveryStatus()); assertEquals(DeliveryStatus.NORMAL, statusResponse.getDeliveryStatus());
assertEquals(PodProgressStatus.RUNNING_BELOW_FIFTY_UNITS, statusResponse.getPodProgressStatus()); assertEquals(PodProgressStatus.FIFTY_OR_LESS_UNITS, statusResponse.getPodProgressStatus());
assertEquals(24.4, statusResponse.getReservoirLevel(), 0.000001); assertEquals(24.4, statusResponse.getReservoirLevel(), 0.000001);
assertEquals(Duration.standardMinutes(4261).getMillis(), statusResponse.getTimeActive().getMillis()); assertEquals(Duration.standardMinutes(4261).getMillis(), statusResponse.getTimeActive().getMillis());
assertEquals(156.7, statusResponse.getInsulinDelivered(), 0.000001); assertEquals(156.7, statusResponse.getInsulinDelivered(), 0.000001);
@ -93,7 +93,7 @@ public class StatusResponseTest {
assertTrue(Duration.standardMinutes(3547).isEqual(statusResponse.getTimeActive())); assertTrue(Duration.standardMinutes(3547).isEqual(statusResponse.getTimeActive()));
assertEquals(DeliveryStatus.NORMAL, statusResponse.getDeliveryStatus()); assertEquals(DeliveryStatus.NORMAL, statusResponse.getDeliveryStatus());
assertEquals(PodProgressStatus.RUNNING_BELOW_FIFTY_UNITS, statusResponse.getPodProgressStatus()); assertEquals(PodProgressStatus.FIFTY_OR_LESS_UNITS, statusResponse.getPodProgressStatus());
assertEquals(129.45, statusResponse.getInsulinDelivered(), 0.00001); assertEquals(129.45, statusResponse.getInsulinDelivered(), 0.00001);
assertEquals(46.00, statusResponse.getReservoirLevel(), 0.00001); assertEquals(46.00, statusResponse.getReservoirLevel(), 0.00001);
assertEquals(2.2, statusResponse.getInsulinNotDelivered(), 0.0001); assertEquals(2.2, statusResponse.getInsulinNotDelivered(), 0.0001);

View file

@ -7,10 +7,14 @@ import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodProgressStatus;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
public class VersionResponseTest { public class VersionResponseTest {
@Test @Test
public void testRawDataShortResponse() { public void testRawDataAssignAddressVersionResponse() {
byte[] encodedData = ByteUtil.fromHexString("011502070002070002020000a64000097c279c1f08ced2"); byte[] encodedData = ByteUtil.fromHexString("011502070002070002020000a64000097c279c1f08ced2");
VersionResponse versionResponse = new VersionResponse(encodedData); VersionResponse versionResponse = new VersionResponse(encodedData);
@ -18,7 +22,7 @@ public class VersionResponseTest {
} }
@Test @Test
public void testRawDataShortResponseWithLongerMessage() { public void testRawDataAssignAddressVersionResponseWithLongerMessage() {
byte[] encodedData = ByteUtil.fromHexString("011502070002070002020000a64000097c279c1f08ced201"); byte[] encodedData = ByteUtil.fromHexString("011502070002070002020000a64000097c279c1f08ced201");
byte[] expected = ByteUtil.fromHexString("011502070002070002020000a64000097c279c1f08ced2"); byte[] expected = ByteUtil.fromHexString("011502070002070002020000a64000097c279c1f08ced2");
@ -27,7 +31,7 @@ public class VersionResponseTest {
} }
@Test @Test
public void testRawDataLongResponse() { public void testRawDataSetupPodVersionResponse() {
byte[] encodedData = ByteUtil.fromHexString("011b13881008340a5002070002070002030000a3770003ab371f00ee87"); byte[] encodedData = ByteUtil.fromHexString("011b13881008340a5002070002070002030000a3770003ab371f00ee87");
VersionResponse versionResponse = new VersionResponse(encodedData); VersionResponse versionResponse = new VersionResponse(encodedData);
@ -36,7 +40,7 @@ public class VersionResponseTest {
} }
@Test @Test
public void testRawDataLongResponseWithLongerMessage() { public void testRawDataSetupPodVersionResponseWithLongerMessage() {
byte[] encodedData = ByteUtil.fromHexString("011b13881008340a5002070002070002030000a3770003ab371f00ee8701"); byte[] encodedData = ByteUtil.fromHexString("011b13881008340a5002070002070002030000a3770003ab371f00ee8701");
byte[] expected = ByteUtil.fromHexString("011b13881008340a5002070002070002030000a3770003ab371f00ee87"); byte[] expected = ByteUtil.fromHexString("011b13881008340a5002070002070002030000a3770003ab371f00ee87");
@ -45,25 +49,33 @@ public class VersionResponseTest {
} }
@Test @Test
public void testVersionResponse() { public void testAssignAddressVersionResponse() {
VersionResponse versionResponse = new VersionResponse(ByteUtil.fromHexString("011502070002070002020000a64000097c279c1f08ced2")); VersionResponse versionResponse = new VersionResponse(ByteUtil.fromHexString("011502070002070002020000a64000097c279c1f08ced2"));
assertTrue(versionResponse.isAssignAddressVersionResponse());
assertFalse(versionResponse.isSetupPodVersionResponse());
assertEquals(0x1f08ced2, versionResponse.getAddress()); assertEquals(0x1f08ced2, versionResponse.getAddress());
assertEquals(42560, versionResponse.getLot()); assertEquals(42560, versionResponse.getLot());
assertEquals(621607, versionResponse.getTid()); assertEquals(621607, versionResponse.getTid());
assertEquals("2.7.0", versionResponse.getPiVersion().toString()); assertEquals("2.7.0", versionResponse.getPiVersion().toString());
assertEquals("2.7.0", versionResponse.getPmVersion().toString()); assertEquals("2.7.0", versionResponse.getPmVersion().toString());
assertNotNull(versionResponse.getRssi());
assertNotNull(versionResponse.getGain());
} }
@Test @Test
public void testLongVersionResponse() { public void testSetupPodVersionResponse() {
VersionResponse versionResponse = new VersionResponse(ByteUtil.fromHexString("011b13881008340a5002070002070002030000a3770003ab371f00ee87")); VersionResponse versionResponse = new VersionResponse(ByteUtil.fromHexString("011b13881008340a5002070002070002030000a3770003ab371f00ee87"));
assertFalse(versionResponse.isAssignAddressVersionResponse());
assertTrue(versionResponse.isSetupPodVersionResponse());
assertEquals(0x1f00ee87, versionResponse.getAddress()); assertEquals(0x1f00ee87, versionResponse.getAddress());
assertEquals(41847, versionResponse.getLot()); assertEquals(41847, versionResponse.getLot());
assertEquals(240439, versionResponse.getTid()); assertEquals(240439, versionResponse.getTid());
assertEquals(PodProgressStatus.PAIRING_SUCCESS, versionResponse.getPodProgressStatus()); assertEquals(PodProgressStatus.PAIRING_COMPLETED, versionResponse.getPodProgressStatus());
assertEquals("2.7.0", versionResponse.getPiVersion().toString()); assertEquals("2.7.0", versionResponse.getPiVersion().toString());
assertEquals("2.7.0", versionResponse.getPmVersion().toString()); assertEquals("2.7.0", versionResponse.getPmVersion().toString());
assertNull(versionResponse.getRssi());
assertNull(versionResponse.getGain());
} }
} }

View file

@ -4,7 +4,7 @@ import org.joda.time.Duration;
import org.junit.Test; import org.junit.Test;
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.defs.FaultEventType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.FaultEventCode;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@ -14,7 +14,7 @@ public class PodInfoDataLogTest {
public void testDecoding() { public void testDecoding() {
PodInfoDataLog podInfoDataLog = new PodInfoDataLog(ByteUtil.fromHexString("030100010001043c"), 8); // From https://github.com/ps2/rileylink_ios/blob/omnipod-testing/OmniKitTests/PodInfoTests.swift PodInfoDataLog podInfoDataLog = new PodInfoDataLog(ByteUtil.fromHexString("030100010001043c"), 8); // From https://github.com/ps2/rileylink_ios/blob/omnipod-testing/OmniKitTests/PodInfoTests.swift
assertEquals(FaultEventType.FAILED_FLASH_ERASE, podInfoDataLog.getFaultEventType()); assertEquals(FaultEventCode.FAILED_FLASH_ERASE, podInfoDataLog.getFaultEventCode());
assertTrue(Duration.standardMinutes(1).isEqual(podInfoDataLog.getTimeFaultEvent())); assertTrue(Duration.standardMinutes(1).isEqual(podInfoDataLog.getTimeFaultEvent()));
assertTrue(Duration.standardMinutes(1).isEqual(podInfoDataLog.getTimeSinceActivation())); assertTrue(Duration.standardMinutes(1).isEqual(podInfoDataLog.getTimeSinceActivation()));
assertEquals(4, podInfoDataLog.getDataChunkSize()); assertEquals(4, podInfoDataLog.getDataChunkSize());

View file

@ -5,7 +5,7 @@ import org.joda.time.Duration;
import org.junit.Test; import org.junit.Test;
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.defs.FaultEventType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.FaultEventCode;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@ -15,7 +15,7 @@ public class PodInfoFaultAndInitializationTimeTest {
public void testDecoding() { public void testDecoding() {
PodInfoFaultAndInitializationTime podInfoFaultAndInitializationTime = new PodInfoFaultAndInitializationTime(ByteUtil.fromHexString("059200010000000000000000091912170e")); // From https://github.com/ps2/rileylink_ios/blob/omnipod-testing/OmniKitTests/PodInfoTests.swift PodInfoFaultAndInitializationTime podInfoFaultAndInitializationTime = new PodInfoFaultAndInitializationTime(ByteUtil.fromHexString("059200010000000000000000091912170e")); // From https://github.com/ps2/rileylink_ios/blob/omnipod-testing/OmniKitTests/PodInfoTests.swift
assertEquals(FaultEventType.BAD_PUMP_REQ_2_STATE, podInfoFaultAndInitializationTime.getFaultEventType()); assertEquals(FaultEventCode.BAD_PUMP_REQ_2_STATE, podInfoFaultAndInitializationTime.getFaultEventCode());
assertTrue(Duration.standardMinutes(1).isEqual(podInfoFaultAndInitializationTime.getTimeFaultEvent())); assertTrue(Duration.standardMinutes(1).isEqual(podInfoFaultAndInitializationTime.getTimeFaultEvent()));
DateTime dateTime = podInfoFaultAndInitializationTime.getInitializationTime(); DateTime dateTime = podInfoFaultAndInitializationTime.getInitializationTime();

View file

@ -5,7 +5,7 @@ import org.junit.Test;
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.defs.DeliveryStatus; import info.nightscout.androidaps.plugins.pump.omnipod.defs.DeliveryStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.FaultEventType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.FaultEventCode;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.LogEventErrorCode; import info.nightscout.androidaps.plugins.pump.omnipod.defs.LogEventErrorCode;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodProgressStatus; import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodProgressStatus;
@ -20,11 +20,11 @@ public class PodInfoFaultEventTest {
public void testPodInfoFaultEventNoFaultAlerts() { public void testPodInfoFaultEventNoFaultAlerts() {
PodInfoFaultEvent podInfoFaultEvent = new PodInfoFaultEvent(ByteUtil.fromHexString("02080100000a003800000003ff008700000095ff0000")); PodInfoFaultEvent podInfoFaultEvent = new PodInfoFaultEvent(ByteUtil.fromHexString("02080100000a003800000003ff008700000095ff0000"));
assertEquals(PodProgressStatus.RUNNING_ABOVE_FIFTY_UNITS, podInfoFaultEvent.getPodProgressStatus()); assertEquals(PodProgressStatus.ABOVE_FIFTY_UNITS, podInfoFaultEvent.getPodProgressStatus());
assertEquals(DeliveryStatus.NORMAL, podInfoFaultEvent.getDeliveryStatus()); assertEquals(DeliveryStatus.NORMAL, podInfoFaultEvent.getDeliveryStatus());
assertEquals(0, podInfoFaultEvent.getInsulinNotDelivered(), 0.000001); assertEquals(0, podInfoFaultEvent.getInsulinNotDelivered(), 0.000001);
assertEquals(0x0a, podInfoFaultEvent.getPodMessageCounter()); assertEquals(0x0a, podInfoFaultEvent.getPodMessageCounter());
assertEquals(FaultEventType.NO_FAULTS, podInfoFaultEvent.getFaultEventType()); assertEquals(FaultEventCode.NO_FAULTS, podInfoFaultEvent.getFaultEventCode());
assertTrue(Duration.ZERO.isEqual(podInfoFaultEvent.getFaultEventTime())); assertTrue(Duration.ZERO.isEqual(podInfoFaultEvent.getFaultEventTime()));
assertNull(podInfoFaultEvent.getReservoirLevel()); assertNull(podInfoFaultEvent.getReservoirLevel());
assertTrue(Duration.standardSeconds(8100).isEqual(podInfoFaultEvent.getTimeSinceActivation())); assertTrue(Duration.standardSeconds(8100).isEqual(podInfoFaultEvent.getTimeSinceActivation()));
@ -44,14 +44,14 @@ public class PodInfoFaultEventTest {
assertEquals(DeliveryStatus.SUSPENDED, podInfoFaultEvent.getDeliveryStatus()); assertEquals(DeliveryStatus.SUSPENDED, podInfoFaultEvent.getDeliveryStatus());
assertEquals(0, podInfoFaultEvent.getInsulinNotDelivered(), 0.000001); assertEquals(0, podInfoFaultEvent.getInsulinNotDelivered(), 0.000001);
assertEquals(0x09, podInfoFaultEvent.getPodMessageCounter()); assertEquals(0x09, podInfoFaultEvent.getPodMessageCounter());
assertEquals(FaultEventType.PRIME_OPEN_COUNT_TOO_LOW, podInfoFaultEvent.getFaultEventType()); assertEquals(FaultEventCode.PRIME_OPEN_COUNT_TOO_LOW, podInfoFaultEvent.getFaultEventCode());
assertTrue(Duration.standardSeconds(60).isEqual(podInfoFaultEvent.getFaultEventTime())); assertTrue(Duration.standardSeconds(60).isEqual(podInfoFaultEvent.getFaultEventTime()));
assertNull(podInfoFaultEvent.getReservoirLevel()); assertNull(podInfoFaultEvent.getReservoirLevel());
assertTrue(Duration.standardSeconds(60).isEqual(podInfoFaultEvent.getTimeSinceActivation())); assertTrue(Duration.standardSeconds(60).isEqual(podInfoFaultEvent.getTimeSinceActivation()));
assertEquals(0, podInfoFaultEvent.getUnacknowledgedAlerts().getRawValue()); assertEquals(0, podInfoFaultEvent.getUnacknowledgedAlerts().getRawValue());
assertFalse(podInfoFaultEvent.isFaultAccessingTables()); assertFalse(podInfoFaultEvent.isFaultAccessingTables());
assertEquals(LogEventErrorCode.NONE, podInfoFaultEvent.getLogEventErrorType()); assertEquals(LogEventErrorCode.NONE, podInfoFaultEvent.getLogEventErrorType());
assertEquals(PodProgressStatus.READY_FOR_BASAL_SCHEDULE, podInfoFaultEvent.getPodProgressStatusAtTimeOfFirstLoggedFaultEvent()); assertEquals(PodProgressStatus.PRIMING_COMPLETED, podInfoFaultEvent.getPodProgressStatusAtTimeOfFirstLoggedFaultEvent());
assertEquals(2, podInfoFaultEvent.getReceiverLowGain()); assertEquals(2, podInfoFaultEvent.getReceiverLowGain());
assertEquals(46, podInfoFaultEvent.getRadioRSSI()); assertEquals(46, podInfoFaultEvent.getRadioRSSI());
} }
@ -65,13 +65,13 @@ public class PodInfoFaultEventTest {
assertEquals(101.7, podInfoFaultEvent.getTotalInsulinDelivered(), 0.000001); assertEquals(101.7, podInfoFaultEvent.getTotalInsulinDelivered(), 0.000001);
assertEquals(0, podInfoFaultEvent.getInsulinNotDelivered(), 0.000001); assertEquals(0, podInfoFaultEvent.getInsulinNotDelivered(), 0.000001);
assertEquals(0x04, podInfoFaultEvent.getPodMessageCounter()); assertEquals(0x04, podInfoFaultEvent.getPodMessageCounter());
assertEquals(FaultEventType.BASAL_OVER_INFUSION_PULSE, podInfoFaultEvent.getFaultEventType()); assertEquals(FaultEventCode.BASAL_OVER_INFUSION_PULSE, podInfoFaultEvent.getFaultEventCode());
assertTrue(Duration.standardMinutes(2559).isEqual(podInfoFaultEvent.getFaultEventTime())); assertTrue(Duration.standardMinutes(2559).isEqual(podInfoFaultEvent.getFaultEventTime()));
assertNull(podInfoFaultEvent.getReservoirLevel()); assertNull(podInfoFaultEvent.getReservoirLevel());
assertEquals(0, podInfoFaultEvent.getUnacknowledgedAlerts().getRawValue()); assertEquals(0, podInfoFaultEvent.getUnacknowledgedAlerts().getRawValue());
assertFalse(podInfoFaultEvent.isFaultAccessingTables()); assertFalse(podInfoFaultEvent.isFaultAccessingTables());
assertEquals(LogEventErrorCode.NONE, podInfoFaultEvent.getLogEventErrorType()); assertEquals(LogEventErrorCode.NONE, podInfoFaultEvent.getLogEventErrorType());
assertEquals(PodProgressStatus.RUNNING_ABOVE_FIFTY_UNITS, podInfoFaultEvent.getPodProgressStatusAtTimeOfFirstLoggedFaultEvent()); assertEquals(PodProgressStatus.ABOVE_FIFTY_UNITS, podInfoFaultEvent.getPodProgressStatusAtTimeOfFirstLoggedFaultEvent());
assertEquals(0, podInfoFaultEvent.getReceiverLowGain()); assertEquals(0, podInfoFaultEvent.getReceiverLowGain());
assertEquals(35, podInfoFaultEvent.getRadioRSSI()); assertEquals(35, podInfoFaultEvent.getRadioRSSI());
} }
@ -85,13 +85,13 @@ public class PodInfoFaultEventTest {
assertEquals(11.8, podInfoFaultEvent.getTotalInsulinDelivered(), 0.000001); assertEquals(11.8, podInfoFaultEvent.getTotalInsulinDelivered(), 0.000001);
assertEquals(0.05, podInfoFaultEvent.getInsulinNotDelivered(), 0.000001); assertEquals(0.05, podInfoFaultEvent.getInsulinNotDelivered(), 0.000001);
assertEquals(0x02, podInfoFaultEvent.getPodMessageCounter()); assertEquals(0x02, podInfoFaultEvent.getPodMessageCounter());
assertEquals(FaultEventType.OCCLUSION_CHECK_ABOVE_THRESHOLD, podInfoFaultEvent.getFaultEventType()); assertEquals(FaultEventCode.OCCLUSION_CHECK_ABOVE_THRESHOLD, podInfoFaultEvent.getFaultEventCode());
assertTrue(Duration.standardMinutes(616).isEqual(podInfoFaultEvent.getFaultEventTime())); assertTrue(Duration.standardMinutes(616).isEqual(podInfoFaultEvent.getFaultEventTime()));
assertNull(podInfoFaultEvent.getReservoirLevel()); assertNull(podInfoFaultEvent.getReservoirLevel());
assertEquals(0, podInfoFaultEvent.getUnacknowledgedAlerts().getRawValue()); assertEquals(0, podInfoFaultEvent.getUnacknowledgedAlerts().getRawValue());
assertFalse(podInfoFaultEvent.isFaultAccessingTables()); assertFalse(podInfoFaultEvent.isFaultAccessingTables());
assertEquals(LogEventErrorCode.INTERNAL_2_BIT_VARIABLE_SET_AND_MANIPULATED_IN_MAIN_LOOP_ROUTINES_2, podInfoFaultEvent.getLogEventErrorType()); assertEquals(LogEventErrorCode.INTERNAL_2_BIT_VARIABLE_SET_AND_MANIPULATED_IN_MAIN_LOOP_ROUTINES_2, podInfoFaultEvent.getLogEventErrorType());
assertEquals(PodProgressStatus.RUNNING_ABOVE_FIFTY_UNITS, podInfoFaultEvent.getPodProgressStatusAtTimeOfFirstLoggedFaultEvent()); assertEquals(PodProgressStatus.ABOVE_FIFTY_UNITS, podInfoFaultEvent.getPodProgressStatusAtTimeOfFirstLoggedFaultEvent());
assertEquals(2, podInfoFaultEvent.getReceiverLowGain()); assertEquals(2, podInfoFaultEvent.getReceiverLowGain());
assertEquals(39, podInfoFaultEvent.getRadioRSSI()); assertEquals(39, podInfoFaultEvent.getRadioRSSI());
} }
@ -105,13 +105,13 @@ public class PodInfoFaultEventTest {
assertEquals(11.8, podInfoFaultEvent.getTotalInsulinDelivered(), 0.000001); assertEquals(11.8, podInfoFaultEvent.getTotalInsulinDelivered(), 0.000001);
assertEquals(3276.75, podInfoFaultEvent.getInsulinNotDelivered(), 0.000001); // Insane and will not happen, but this verifies that we convert it to an unsigned int assertEquals(3276.75, podInfoFaultEvent.getInsulinNotDelivered(), 0.000001); // Insane and will not happen, but this verifies that we convert it to an unsigned int
assertEquals(0x02, podInfoFaultEvent.getPodMessageCounter()); assertEquals(0x02, podInfoFaultEvent.getPodMessageCounter());
assertEquals(FaultEventType.OCCLUSION_CHECK_ABOVE_THRESHOLD, podInfoFaultEvent.getFaultEventType()); assertEquals(FaultEventCode.OCCLUSION_CHECK_ABOVE_THRESHOLD, podInfoFaultEvent.getFaultEventCode());
assertTrue(Duration.standardMinutes(616).isEqual(podInfoFaultEvent.getFaultEventTime())); assertTrue(Duration.standardMinutes(616).isEqual(podInfoFaultEvent.getFaultEventTime()));
assertNull(podInfoFaultEvent.getReservoirLevel()); assertNull(podInfoFaultEvent.getReservoirLevel());
assertEquals(0, podInfoFaultEvent.getUnacknowledgedAlerts().getRawValue()); assertEquals(0, podInfoFaultEvent.getUnacknowledgedAlerts().getRawValue());
assertFalse(podInfoFaultEvent.isFaultAccessingTables()); assertFalse(podInfoFaultEvent.isFaultAccessingTables());
assertEquals(LogEventErrorCode.INTERNAL_2_BIT_VARIABLE_SET_AND_MANIPULATED_IN_MAIN_LOOP_ROUTINES_2, podInfoFaultEvent.getLogEventErrorType()); assertEquals(LogEventErrorCode.INTERNAL_2_BIT_VARIABLE_SET_AND_MANIPULATED_IN_MAIN_LOOP_ROUTINES_2, podInfoFaultEvent.getLogEventErrorType());
assertEquals(PodProgressStatus.RUNNING_ABOVE_FIFTY_UNITS, podInfoFaultEvent.getPodProgressStatusAtTimeOfFirstLoggedFaultEvent()); assertEquals(PodProgressStatus.ABOVE_FIFTY_UNITS, podInfoFaultEvent.getPodProgressStatusAtTimeOfFirstLoggedFaultEvent());
assertEquals(2, podInfoFaultEvent.getReceiverLowGain()); assertEquals(2, podInfoFaultEvent.getReceiverLowGain());
assertEquals(39, podInfoFaultEvent.getRadioRSSI()); assertEquals(39, podInfoFaultEvent.getRadioRSSI());
} }

View file

@ -1,7 +1,6 @@
package info.nightscout.androidaps.plugins.pump.omnipod.driver.comm; package info.nightscout.androidaps.plugins.pump.omnipod.driver.comm;
import org.joda.time.Duration; import org.joda.time.Duration;
import org.junit.Ignore;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
@ -16,12 +15,11 @@ import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.powermock.api.mockito.PowerMockito.when; import static org.powermock.api.mockito.PowerMockito.when;
@Ignore("Not dev/dagger compliant. Needs to be fixed")
public class AapsOmnipodManagerTest { public class AapsOmnipodManagerTest {
@Rule @Rule
public ExpectedException thrown = ExpectedException.none(); public ExpectedException thrown = ExpectedException.none();
//@Test @Test
public void validProfile() { public void validProfile() {
Profile profile = mock(Profile.class); Profile profile = mock(Profile.class);
@ -61,14 +59,14 @@ public class AapsOmnipodManagerTest {
assertEquals(3.05D, entry3.getRate(), 0.000001); assertEquals(3.05D, entry3.getRate(), 0.000001);
} }
//@Test @Test
public void invalidProfileNullProfile() { public void invalidProfileNullProfile() {
thrown.expect(IllegalArgumentException.class); thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Profile can not be null"); thrown.expectMessage("Profile can not be null");
AapsOmnipodManager.mapProfileToBasalSchedule(null); AapsOmnipodManager.mapProfileToBasalSchedule(null);
} }
//@Test @Test
public void invalidProfileNullEntries() { public void invalidProfileNullEntries() {
thrown.expect(IllegalArgumentException.class); thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Basal values can not be null"); thrown.expectMessage("Basal values can not be null");
@ -86,7 +84,7 @@ public class AapsOmnipodManagerTest {
AapsOmnipodManager.mapProfileToBasalSchedule(profile); AapsOmnipodManager.mapProfileToBasalSchedule(profile);
} }
//@Test @Test
public void invalidProfileNonZeroOffset() { public void invalidProfileNonZeroOffset() {
thrown.expect(IllegalArgumentException.class); thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Invalid start time"); thrown.expectMessage("Invalid start time");
@ -94,7 +92,7 @@ public class AapsOmnipodManagerTest {
Profile profile = mock(Profile.class); Profile profile = mock(Profile.class);
Profile.ProfileValue value = mock(Profile.ProfileValue.class); Profile.ProfileValue value = mock(Profile.ProfileValue.class);
value.timeAsSeconds = 500; value.timeAsSeconds = 1800;
value.value = 0.5D; value.value = 0.5D;
when(profile.getBasalValues()).thenReturn(new Profile.ProfileValue[]{ when(profile.getBasalValues()).thenReturn(new Profile.ProfileValue[]{
@ -104,7 +102,7 @@ public class AapsOmnipodManagerTest {
AapsOmnipodManager.mapProfileToBasalSchedule(profile); AapsOmnipodManager.mapProfileToBasalSchedule(profile);
} }
//@Test @Test
public void invalidProfileMoreThan24Hours() { public void invalidProfileMoreThan24Hours() {
thrown.expect(IllegalArgumentException.class); thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Invalid start time"); thrown.expectMessage("Invalid start time");
@ -127,7 +125,7 @@ public class AapsOmnipodManagerTest {
AapsOmnipodManager.mapProfileToBasalSchedule(profile); AapsOmnipodManager.mapProfileToBasalSchedule(profile);
} }
//@Test @Test
public void invalidProfileNegativeOffset() { public void invalidProfileNegativeOffset() {
thrown.expect(IllegalArgumentException.class); thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Invalid start time"); thrown.expectMessage("Invalid start time");
@ -145,21 +143,21 @@ public class AapsOmnipodManagerTest {
AapsOmnipodManager.mapProfileToBasalSchedule(profile); AapsOmnipodManager.mapProfileToBasalSchedule(profile);
} }
//@Test @Test
public void invalidProfileUnsupportedPrecision() { public void roundsToSupportedPrecision() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Unsupported basal rate precision");
Profile profile = mock(Profile.class); Profile profile = mock(Profile.class);
Profile.ProfileValue value = mock(Profile.ProfileValue.class); Profile.ProfileValue value = mock(Profile.ProfileValue.class);
value.timeAsSeconds = 500; value.timeAsSeconds = 0;
value.value = 0.04D; value.value = 0.04D;
when(profile.getBasalValues()).thenReturn(new Profile.ProfileValue[]{ when(profile.getBasalValues()).thenReturn(new Profile.ProfileValue[]{
value, value,
}); });
AapsOmnipodManager.mapProfileToBasalSchedule(profile); BasalSchedule basalSchedule = AapsOmnipodManager.mapProfileToBasalSchedule(profile);
BasalScheduleEntry basalScheduleEntry = basalSchedule.getEntries().get(0);
assertEquals(0.05D, basalScheduleEntry.getRate(), 0.000001);
} }
} }