- Extract abstract class for PodStateManager on driver level
- Remove PodStateChangedHandler - Add new fields to PodState - Add Lot, Tid and Firmware Version in Pod tab - Various small improvements - Add some FIXMEs
This commit is contained in:
parent
31938547a5
commit
e5274e2d3a
17 changed files with 1039 additions and 834 deletions
|
@ -11,7 +11,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dialogs.wizard.initpod.In
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dialogs.wizard.pages.InitPodRefreshAction
|
import info.nightscout.androidaps.plugins.pump.omnipod.dialogs.wizard.pages.InitPodRefreshAction
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dialogs.wizard.pages.PodInfoFragment
|
import info.nightscout.androidaps.plugins.pump.omnipod.dialogs.wizard.pages.PodInfoFragment
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dialogs.wizard.removepod.RemoveActionFragment
|
import info.nightscout.androidaps.plugins.pump.omnipod.dialogs.wizard.removepod.RemoveActionFragment
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.driver.comm.AapsOmnipodManager
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.driver.comm.AapsPodStateManager
|
import info.nightscout.androidaps.plugins.pump.omnipod.driver.comm.AapsPodStateManager
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.driver.ui.OmnipodUITask
|
import info.nightscout.androidaps.plugins.pump.omnipod.driver.ui.OmnipodUITask
|
||||||
|
|
||||||
|
@ -20,24 +19,25 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.ui.OmnipodUITask
|
||||||
abstract class OmnipodModule {
|
abstract class OmnipodModule {
|
||||||
|
|
||||||
// Activities
|
// Activities
|
||||||
@ContributesAndroidInjector abstract fun contributesPodManagementActivity(): PodManagementActivity
|
@ContributesAndroidInjector
|
||||||
|
abstract fun contributesPodManagementActivity(): PodManagementActivity
|
||||||
@ContributesAndroidInjector abstract fun contributesPodHistoryActivity(): PodHistoryActivity
|
@ContributesAndroidInjector abstract fun contributesPodHistoryActivity(): PodHistoryActivity
|
||||||
|
|
||||||
// Fragments
|
// Fragments
|
||||||
@ContributesAndroidInjector abstract fun initActionFragment() : InitActionFragment
|
@ContributesAndroidInjector abstract fun initActionFragment(): InitActionFragment
|
||||||
@ContributesAndroidInjector abstract fun removeActionFragment() : RemoveActionFragment
|
@ContributesAndroidInjector abstract fun removeActionFragment(): RemoveActionFragment
|
||||||
@ContributesAndroidInjector abstract fun podInfoFragment() : PodInfoFragment
|
@ContributesAndroidInjector abstract fun podInfoFragment(): PodInfoFragment
|
||||||
|
|
||||||
// Service
|
// Service
|
||||||
@ContributesAndroidInjector abstract fun omnipodCommunicationManagerProvider(): OmnipodCommunicationManager
|
@ContributesAndroidInjector
|
||||||
@ContributesAndroidInjector abstract fun aapsOmnipodManagerProvider(): AapsOmnipodManager
|
abstract fun omnipodCommunicationManagerProvider(): OmnipodCommunicationManager
|
||||||
|
|
||||||
// Data
|
// Data
|
||||||
@ContributesAndroidInjector abstract fun omnipodUITaskProvider(): OmnipodUITask
|
@ContributesAndroidInjector abstract fun omnipodUITaskProvider(): OmnipodUITask
|
||||||
@ContributesAndroidInjector abstract fun initPodRefreshAction(): InitPodRefreshAction
|
@ContributesAndroidInjector abstract fun initPodRefreshAction(): InitPodRefreshAction
|
||||||
@ContributesAndroidInjector abstract fun podStateManager(): PodStateManager
|
@ContributesAndroidInjector abstract fun podStateManager(): PodStateManager
|
||||||
@ContributesAndroidInjector abstract fun initPodTask() : InitPodTask
|
@ContributesAndroidInjector abstract fun initPodTask(): InitPodTask
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract fun initAapsPodStateManager() : AapsPodStateManager
|
@ContributesAndroidInjector abstract fun initAapsPodStateManager(): AapsPodStateManager
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,16 +207,10 @@ class OmnipodFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
private fun setDeviceStatus(event : EventOmnipodDeviceStatusChange) {
|
private fun setDeviceStatus(event: EventOmnipodDeviceStatusChange) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
private fun setDeviceStatus() {
|
private fun setDeviceStatus() {
|
||||||
//val omnipodPumpStatus: OmnipodPumpStatus = OmnipodUtil.getPumpStatus()
|
//val omnipodPumpStatus: OmnipodPumpStatus = OmnipodUtil.getPumpStatus()
|
||||||
|
@ -250,20 +244,31 @@ class OmnipodFragment : DaggerFragment() {
|
||||||
|
|
||||||
aapsLogger.info(LTag.PUMP, "getDriverState: [driverState={}]", driverState)
|
aapsLogger.info(LTag.PUMP, "getDriverState: [driverState={}]", driverState)
|
||||||
|
|
||||||
|
// FIXME for displaying pod info, we should look at PodStateManager instead of this driverState,
|
||||||
|
// because that way, we can also show the Pod info when the RL isn't initialized yet
|
||||||
if (driverState == OmnipodDriverState.NotInitalized) {
|
if (driverState == OmnipodDriverState.NotInitalized) {
|
||||||
omnipod_pod_address.text = resourceHelper.gs(R.string.omnipod_pod_name_no_info)
|
omnipod_pod_address.text = resourceHelper.gs(R.string.omnipod_pod_name_no_info)
|
||||||
|
omnipod_pod_lot.text = "-"
|
||||||
|
omnipod_pod_tid.text = "-"
|
||||||
|
omnipod_pod_fw_version.text = "-"
|
||||||
omnipod_pod_expiry.text = "-"
|
omnipod_pod_expiry.text = "-"
|
||||||
omnipod_pod_status.text = resourceHelper.gs(R.string.omnipod_pod_not_initalized)
|
omnipod_pod_status.text = resourceHelper.gs(R.string.omnipod_pod_not_initalized)
|
||||||
omnipodPumpStatus.podAvailable = false
|
omnipodPumpStatus.podAvailable = false
|
||||||
omnipodPumpStatus.podNumber == null
|
omnipodPumpStatus.podNumber == null
|
||||||
} else if (driverState == OmnipodDriverState.Initalized_NoPod) {
|
} else if (driverState == OmnipodDriverState.Initalized_NoPod) {
|
||||||
omnipod_pod_address.text = resourceHelper.gs(R.string.omnipod_pod_name_no_info)
|
omnipod_pod_address.text = resourceHelper.gs(R.string.omnipod_pod_name_no_info)
|
||||||
|
omnipod_pod_lot.text = "-"
|
||||||
|
omnipod_pod_tid.text = "-"
|
||||||
|
omnipod_pod_fw_version.text = "-"
|
||||||
omnipod_pod_expiry.text = "-"
|
omnipod_pod_expiry.text = "-"
|
||||||
omnipod_pod_status.text = resourceHelper.gs(R.string.omnipod_pod_no_pod_connected)
|
omnipod_pod_status.text = resourceHelper.gs(R.string.omnipod_pod_no_pod_connected)
|
||||||
omnipodPumpStatus.podAvailable = false
|
omnipodPumpStatus.podAvailable = false
|
||||||
omnipodPumpStatus.podNumber == null
|
omnipodPumpStatus.podNumber == null
|
||||||
} else if (driverState == OmnipodDriverState.Initalized_PodInitializing) {
|
} else if (driverState == OmnipodDriverState.Initalized_PodInitializing) {
|
||||||
omnipod_pod_address.text = omnipodPumpStatus.podStateManager.address.toString()
|
omnipod_pod_address.text = omnipodPumpStatus.podStateManager.address.toString()
|
||||||
|
omnipod_pod_lot.text = "-"
|
||||||
|
omnipod_pod_tid.text = "-"
|
||||||
|
omnipod_pod_fw_version.text = "-"
|
||||||
omnipod_pod_expiry.text = "-"
|
omnipod_pod_expiry.text = "-"
|
||||||
omnipod_pod_status.text = resourceHelper.gs(R.string.omnipod_pod_status_initalizing) + " (" + omnipodPumpStatus.podStateManager.getSetupProgress().name + ")"
|
omnipod_pod_status.text = resourceHelper.gs(R.string.omnipod_pod_status_initalizing) + " (" + omnipodPumpStatus.podStateManager.getSetupProgress().name + ")"
|
||||||
omnipodPumpStatus.podAvailable = false
|
omnipodPumpStatus.podAvailable = false
|
||||||
|
@ -272,13 +277,21 @@ class OmnipodFragment : DaggerFragment() {
|
||||||
omnipodPumpStatus.podLotNumber = "" + omnipodPumpStatus.podStateManager.lot
|
omnipodPumpStatus.podLotNumber = "" + omnipodPumpStatus.podStateManager.lot
|
||||||
omnipodPumpStatus.podAvailable = true
|
omnipodPumpStatus.podAvailable = true
|
||||||
omnipod_pod_address.text = omnipodPumpStatus.podStateManager.address.toString()
|
omnipod_pod_address.text = omnipodPumpStatus.podStateManager.address.toString()
|
||||||
|
omnipod_pod_lot.text = if (omnipodPumpStatus.podStateManager.lot == null) "" else omnipodPumpStatus.podStateManager.lot.toString()
|
||||||
|
omnipod_pod_tid.text = if (omnipodPumpStatus.podStateManager.tid == null) "" else omnipodPumpStatus.podStateManager.tid.toString()
|
||||||
|
if (omnipodPumpStatus.podStateManager.pmVersion == null || omnipodPumpStatus.podStateManager.piVersion == null) {
|
||||||
|
omnipod_pod_fw_version.text = ""
|
||||||
|
} else {
|
||||||
|
omnipod_pod_fw_version.text = omnipodPumpStatus.podStateManager.pmVersion.toString() + " / " + omnipodPumpStatus.podStateManager.piVersion.toString()
|
||||||
|
}
|
||||||
omnipod_pod_expiry.text = omnipodPumpStatus.podStateManager.expiryDateAsString
|
omnipod_pod_expiry.text = omnipodPumpStatus.podStateManager.expiryDateAsString
|
||||||
omnipodPumpStatus.podNumber = omnipodPumpStatus.podStateManager.address.toString()
|
omnipodPumpStatus.podNumber = omnipodPumpStatus.podStateManager.address.toString()
|
||||||
|
|
||||||
var podDeviceState = omnipodPumpStatus.podDeviceState
|
var podDeviceState = omnipodPumpStatus.podDeviceState
|
||||||
|
|
||||||
var stateText : String?
|
var stateText: String?
|
||||||
|
|
||||||
|
// FIXME this PodDeviceState doesn't make much sense. We should use info from PodStateManager
|
||||||
when (podDeviceState) {
|
when (podDeviceState) {
|
||||||
null,
|
null,
|
||||||
PodDeviceState.Sleeping -> stateText = "{fa-bed} " // + pumpStatus.pumpDeviceState.name());
|
PodDeviceState.Sleeping -> stateText = "{fa-bed} " // + pumpStatus.pumpDeviceState.name());
|
||||||
|
@ -308,18 +321,19 @@ class OmnipodFragment : DaggerFragment() {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
aapsLogger.warn(LTag.PUMP, "Unknown pump state: " + omnipodPumpStatus.podDeviceState)
|
aapsLogger.warn(LTag.PUMP, "Unknown pump state: " + omnipodPumpStatus.podDeviceState)
|
||||||
stateText = resourceHelper.gs(R.string.omnipod_pod_status_unknown)
|
stateText = resourceHelper.gs(R.string.omnipod_pod_status_unknown)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SetupProgress.COMPLETED.equals(omnipodPumpStatus.podStateManager.getSetupProgress())) {
|
if (omnipodPumpStatus.podStateManager.isSetupCompleted) {
|
||||||
if(omnipodPumpStatus.podStateManager.lastDeliveryStatus != null) {
|
if (omnipodPumpStatus.podStateManager.lastDeliveryStatus != null) {
|
||||||
stateText += " (last delivery status: " + omnipodPumpStatus.podStateManager.lastDeliveryStatus.name + ")"
|
stateText += " (last delivery status: " + omnipodPumpStatus.podStateManager.lastDeliveryStatus.name + ")"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(omnipodPumpStatus.podStateManager.setupProgress != null) {
|
if (omnipodPumpStatus.podStateManager.isPaired) {
|
||||||
stateText += " (setup progress: " + omnipodPumpStatus.podStateManager.setupProgress.name + ")"
|
stateText += " (setup progress: " + omnipodPumpStatus.podStateManager.setupProgress.name + ")"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.comm;
|
package info.nightscout.androidaps.plugins.pump.omnipod.comm;
|
||||||
|
|
||||||
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -144,6 +146,7 @@ public class OmnipodCommunicationManager extends RileyLinkCommunicationManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (responseClass.isInstance(responseMessageBlock)) {
|
if (responseClass.isInstance(responseMessageBlock)) {
|
||||||
|
podStateManager.setLastSuccessfulCommunication(DateTime.now());
|
||||||
return (T) responseMessageBlock;
|
return (T) responseMessageBlock;
|
||||||
} else {
|
} else {
|
||||||
if (responseMessageBlock.getType() == MessageBlockType.ERROR_RESPONSE) {
|
if (responseMessageBlock.getType() == MessageBlockType.ERROR_RESPONSE) {
|
||||||
|
@ -153,21 +156,26 @@ public class OmnipodCommunicationManager extends RileyLinkCommunicationManager {
|
||||||
if (automaticallyResyncNonce) {
|
if (automaticallyResyncNonce) {
|
||||||
message.resyncNonce(podStateManager.getCurrentNonce());
|
message.resyncNonce(podStateManager.getCurrentNonce());
|
||||||
} else {
|
} else {
|
||||||
|
podStateManager.setLastFailedCommunication(DateTime.now());
|
||||||
throw new NonceOutOfSyncException();
|
throw new NonceOutOfSyncException();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
podStateManager.setLastFailedCommunication(DateTime.now());
|
||||||
throw new PodReturnedErrorResponseException(error);
|
throw new PodReturnedErrorResponseException(error);
|
||||||
}
|
}
|
||||||
} else if (responseMessageBlock.getType() == MessageBlockType.POD_INFO_RESPONSE && ((PodInfoResponse) responseMessageBlock).getSubType() == PodInfoType.FAULT_EVENT) {
|
} else if (responseMessageBlock.getType() == MessageBlockType.POD_INFO_RESPONSE && ((PodInfoResponse) responseMessageBlock).getSubType() == PodInfoType.FAULT_EVENT) {
|
||||||
PodInfoFaultEvent faultEvent = ((PodInfoResponse) responseMessageBlock).getPodInfo();
|
PodInfoFaultEvent faultEvent = ((PodInfoResponse) responseMessageBlock).getPodInfo();
|
||||||
podStateManager.setFaultEvent(faultEvent);
|
podStateManager.setFaultEvent(faultEvent);
|
||||||
|
podStateManager.setLastFailedCommunication(DateTime.now());
|
||||||
throw new PodFaultException(faultEvent);
|
throw new PodFaultException(faultEvent);
|
||||||
} else {
|
} else {
|
||||||
|
podStateManager.setLastFailedCommunication(DateTime.now());
|
||||||
throw new IllegalResponseException(responseClass.getSimpleName(), responseMessageBlock.getType());
|
throw new IllegalResponseException(responseClass.getSimpleName(), responseMessageBlock.getType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
podStateManager.setLastFailedCommunication(DateTime.now());
|
||||||
throw new NonceResyncException();
|
throw new NonceResyncException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -208,9 +208,10 @@ public class OmnipodManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return executeAndVerify(() -> communicationService.executeAction(new SetTempBasalAction(
|
StatusResponse statusResponse = executeAndVerify(() -> communicationService.executeAction(new SetTempBasalAction(
|
||||||
podStateManager, rate, duration,
|
podStateManager, rate, duration,
|
||||||
acknowledgementBeep, completionBeep)));
|
acknowledgementBeep, completionBeep)));
|
||||||
|
return statusResponse;
|
||||||
} catch (OmnipodException ex) {
|
} catch (OmnipodException ex) {
|
||||||
// Treat all exceptions as uncertain failures, because all delivery has been suspended here.
|
// Treat all exceptions as uncertain failures, because all delivery has been suspended here.
|
||||||
// Setting this to an uncertain failure will enable for the user to get an appropriate warning
|
// Setting this to an uncertain failure will enable for the user to get an appropriate warning
|
||||||
|
@ -266,6 +267,7 @@ public class OmnipodManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
DateTime startDate = DateTime.now().minus(OmnipodConst.AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION);
|
DateTime startDate = DateTime.now().minus(OmnipodConst.AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION);
|
||||||
|
podStateManager.setLastBolus(startDate, units);
|
||||||
|
|
||||||
CompositeDisposable disposables = new CompositeDisposable();
|
CompositeDisposable disposables = new CompositeDisposable();
|
||||||
Duration bolusDuration = calculateBolusDuration(units, OmnipodConst.POD_BOLUS_DELIVERY_RATE);
|
Duration bolusDuration = calculateBolusDuration(units, OmnipodConst.POD_BOLUS_DELIVERY_RATE);
|
||||||
|
@ -352,8 +354,10 @@ public class OmnipodManager {
|
||||||
|
|
||||||
private void discardActiveBolusData(double unitsNotDelivered) {
|
private void discardActiveBolusData(double unitsNotDelivered) {
|
||||||
synchronized (bolusDataMutex) {
|
synchronized (bolusDataMutex) {
|
||||||
|
double unitsDelivered = activeBolusData.getUnits() - unitsNotDelivered;
|
||||||
|
podStateManager.setLastBolus(activeBolusData.getStartDate(), unitsDelivered);
|
||||||
activeBolusData.getDisposables().dispose();
|
activeBolusData.getDisposables().dispose();
|
||||||
activeBolusData.getBolusCompletionSubject().onSuccess(new BolusDeliveryResult(activeBolusData.getUnits() - unitsNotDelivered));
|
activeBolusData.getBolusCompletionSubject().onSuccess(new BolusDeliveryResult(unitsDelivered));
|
||||||
activeBolusData = null;
|
activeBolusData = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -446,7 +450,7 @@ public class OmnipodManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isReadyForDelivery() {
|
public boolean isReadyForDelivery() {
|
||||||
return podStateManager.isPaired() && podStateManager.getSetupProgress() == SetupProgress.COMPLETED;
|
return podStateManager.isSetupCompleted();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasActiveBolus() {
|
public boolean hasActiveBolus() {
|
||||||
|
|
|
@ -50,7 +50,11 @@ public class CancelDeliveryAction implements OmnipodAction<StatusResponse> {
|
||||||
acknowledgementBeep && deliveryTypes.size() == 1 ? BeepType.BEEP : BeepType.NO_BEEP, deliveryTypes));
|
acknowledgementBeep && deliveryTypes.size() == 1 ? BeepType.BEEP : BeepType.NO_BEEP, deliveryTypes));
|
||||||
}
|
}
|
||||||
|
|
||||||
return communicationService.exchangeMessages(StatusResponse.class, podStateManager,
|
StatusResponse statusResponse = communicationService.exchangeMessages(StatusResponse.class, podStateManager,
|
||||||
new OmnipodMessage(podStateManager.getAddress(), messageBlocks, podStateManager.getMessageNumber()));
|
new OmnipodMessage(podStateManager.getAddress(), messageBlocks, podStateManager.getMessageNumber()));
|
||||||
|
if (deliveryTypes.contains(DeliveryType.TEMP_BASAL)) {
|
||||||
|
podStateManager.setLastTempBasal(null, null, null);
|
||||||
|
}
|
||||||
|
return statusResponse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.comm.action;
|
package info.nightscout.androidaps.plugins.pump.omnipod.comm.action;
|
||||||
|
|
||||||
|
import org.joda.time.DateTime;
|
||||||
import org.joda.time.Duration;
|
import org.joda.time.Duration;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -13,6 +14,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.command.SetI
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.command.TempBasalExtraCommand;
|
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.command.TempBasalExtraCommand;
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.StatusResponse;
|
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.StatusResponse;
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodStateManager;
|
import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodStateManager;
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodConst;
|
||||||
|
|
||||||
public class SetTempBasalAction implements OmnipodAction<StatusResponse> {
|
public class SetTempBasalAction implements OmnipodAction<StatusResponse> {
|
||||||
private final PodStateManager podStateManager;
|
private final PodStateManager podStateManager;
|
||||||
|
@ -43,6 +45,8 @@ public class SetTempBasalAction implements OmnipodAction<StatusResponse> {
|
||||||
new TempBasalExtraCommand(rate, duration, acknowledgementBeep, completionBeep, Duration.ZERO));
|
new TempBasalExtraCommand(rate, duration, acknowledgementBeep, completionBeep, Duration.ZERO));
|
||||||
|
|
||||||
OmnipodMessage message = new OmnipodMessage(podStateManager.getAddress(), messageBlocks, podStateManager.getMessageNumber());
|
OmnipodMessage message = new OmnipodMessage(podStateManager.getAddress(), messageBlocks, podStateManager.getMessageNumber());
|
||||||
return communicationService.exchangeMessages(StatusResponse.class, podStateManager, message);
|
StatusResponse statusResponse = communicationService.exchangeMessages(StatusResponse.class, podStateManager, message);
|
||||||
|
podStateManager.setLastTempBasal(new DateTime().minus(OmnipodConst.AVERAGE_TEMP_BASAL_COMMAND_COMMUNICATION_DURATION), rate, duration);
|
||||||
|
return statusResponse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,12 @@ public class AlertSet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AlertSet(AlertSet alertSet) {
|
||||||
|
this(alertSet == null ? new ArrayList<>() : alertSet.getAlertSlots());
|
||||||
|
}
|
||||||
|
|
||||||
public AlertSet(List<AlertSlot> alertSlots) {
|
public AlertSet(List<AlertSlot> alertSlots) {
|
||||||
this.alertSlots = alertSlots;
|
this.alertSlots = alertSlots == null ? new ArrayList<>() : new ArrayList<>(alertSlots);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<AlertSlot> getAlertSlots() {
|
public List<AlertSlot> getAlertSlots() {
|
||||||
|
|
|
@ -71,9 +71,5 @@ public interface OmnipodCommunicationManagerInterface {
|
||||||
*/
|
*/
|
||||||
PumpEnactResult setTime();
|
PumpEnactResult setTime();
|
||||||
|
|
||||||
|
|
||||||
void setPumpStatus(OmnipodPumpStatus pumpStatusLocal);
|
|
||||||
|
|
||||||
|
|
||||||
PodInfoRecentPulseLog readPulseLog();
|
PodInfoRecentPulseLog readPulseLog();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.defs.state;
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface PodStateChangedHandler {
|
|
||||||
void handle(PodStateManager podStateManager);
|
|
||||||
}
|
|
|
@ -1,9 +1,23 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.defs.state;
|
package info.nightscout.androidaps.plugins.pump.omnipod.defs.state;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonDeserializer;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
|
import com.google.gson.JsonSerializer;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.joda.time.DateTimeZone;
|
import org.joda.time.DateTimeZone;
|
||||||
import org.joda.time.Duration;
|
import org.joda.time.Duration;
|
||||||
|
import org.joda.time.format.ISODateTimeFormat;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||||
|
import info.nightscout.androidaps.logging.LTag;
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.StatusResponse;
|
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.StatusResponse;
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.podinfo.PodInfoFaultEvent;
|
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.podinfo.PodInfoFaultEvent;
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.defs.AlertSet;
|
import info.nightscout.androidaps.plugins.pump.omnipod.defs.AlertSet;
|
||||||
|
@ -13,92 +27,726 @@ import info.nightscout.androidaps.plugins.pump.omnipod.defs.DeliveryStatus;
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.defs.FirmwareVersion;
|
import info.nightscout.androidaps.plugins.pump.omnipod.defs.FirmwareVersion;
|
||||||
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.schedule.BasalSchedule;
|
import info.nightscout.androidaps.plugins.pump.omnipod.defs.schedule.BasalSchedule;
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.util.OmniCRC;
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodConst;
|
||||||
|
import info.nightscout.androidaps.utils.DateUtil;
|
||||||
|
|
||||||
public interface PodStateManager {
|
public abstract class PodStateManager {
|
||||||
|
|
||||||
boolean hasState();
|
private final AAPSLogger aapsLogger;
|
||||||
|
private final Gson gsonInstance;
|
||||||
|
private PodState podState;
|
||||||
|
|
||||||
void removeState();
|
public PodStateManager(AAPSLogger aapsLogger) {
|
||||||
|
this.aapsLogger = aapsLogger;
|
||||||
|
this.gsonInstance = createGson();
|
||||||
|
}
|
||||||
|
|
||||||
void initState(int address);
|
public final boolean hasState() {
|
||||||
|
return podState != null;
|
||||||
|
}
|
||||||
|
|
||||||
boolean isPaired();
|
public final void removeState() {
|
||||||
|
this.podState = null;
|
||||||
|
storePodState();
|
||||||
|
notifyPodStateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void setPairingParameters(int lot, int tid, FirmwareVersion piVersion, FirmwareVersion pmVersion, DateTimeZone timeZone);
|
public final void initState(int address) {
|
||||||
|
if (hasState()) {
|
||||||
|
throw new IllegalStateException("Can not init a new pod state: podState <> null");
|
||||||
|
}
|
||||||
|
podState = new PodState(address);
|
||||||
|
storePodState();
|
||||||
|
notifyPodStateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
int getAddress();
|
public final boolean isPaired() {
|
||||||
|
return hasState() //
|
||||||
|
&& podState.getLot() != null && podState.getTid() != null //
|
||||||
|
&& podState.getPiVersion() != null && podState.getPmVersion() != null //
|
||||||
|
&& podState.getTimeZone() != null //
|
||||||
|
&& podState.getSetupProgress() != null;
|
||||||
|
}
|
||||||
|
|
||||||
int getMessageNumber();
|
public final boolean isSetupCompleted() {
|
||||||
|
return isPaired() && SetupProgress.COMPLETED.equals(podState.getSetupProgress());
|
||||||
|
}
|
||||||
|
|
||||||
void setMessageNumber(int messageNumber);
|
public final void setPairingParameters(int lot, int tid, FirmwareVersion piVersion, FirmwareVersion pmVersion, DateTimeZone timeZone) {
|
||||||
|
if (!hasState()) {
|
||||||
|
throw new IllegalStateException("Cannot set pairing parameters: podState is null");
|
||||||
|
}
|
||||||
|
if (isPaired()) {
|
||||||
|
throw new IllegalStateException("Cannot set pairing parameters: pairing parameters have already been set");
|
||||||
|
}
|
||||||
|
if (piVersion == null) {
|
||||||
|
throw new IllegalArgumentException("Cannot set pairing parameters: piVersion can not be null");
|
||||||
|
}
|
||||||
|
if (pmVersion == null) {
|
||||||
|
throw new IllegalArgumentException("Cannot set pairing parameters: pmVersion can not be null");
|
||||||
|
}
|
||||||
|
if (timeZone == null) {
|
||||||
|
throw new IllegalArgumentException("Cannot set pairing parameters: timeZone can not be null");
|
||||||
|
}
|
||||||
|
|
||||||
int getPacketNumber();
|
setAndStore(() -> {
|
||||||
|
podState.setLot(lot);
|
||||||
|
podState.setTid(tid);
|
||||||
|
podState.setPiVersion(piVersion);
|
||||||
|
podState.setPmVersion(pmVersion);
|
||||||
|
podState.setTimeZone(timeZone);
|
||||||
|
podState.setNonceState(new NonceState(lot, tid));
|
||||||
|
podState.setSetupProgress(SetupProgress.ADDRESS_ASSIGNED);
|
||||||
|
podState.getConfiguredAlerts().put(AlertSlot.SLOT7, AlertType.FINISH_SETUP_REMINDER);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void setPacketNumber(int packetNumber);
|
public final int getAddress() {
|
||||||
|
return getSafe(() -> podState.getAddress());
|
||||||
|
}
|
||||||
|
|
||||||
void increaseMessageNumber();
|
public final int getMessageNumber() {
|
||||||
|
return getSafe(() -> podState.getMessageNumber());
|
||||||
|
}
|
||||||
|
|
||||||
void increasePacketNumber();
|
public final void setMessageNumber(int messageNumber) {
|
||||||
|
setAndStore(() -> podState.setMessageNumber(messageNumber));
|
||||||
|
}
|
||||||
|
|
||||||
void resyncNonce(int syncWord, int sentNonce, int sequenceNumber);
|
public final int getPacketNumber() {
|
||||||
|
return getSafe(() -> podState.getPacketNumber());
|
||||||
|
}
|
||||||
|
|
||||||
int getCurrentNonce();
|
public final void setPacketNumber(int packetNumber) {
|
||||||
|
setAndStore(() -> podState.setPacketNumber(packetNumber));
|
||||||
|
}
|
||||||
|
|
||||||
void advanceToNextNonce();
|
public final void increaseMessageNumber() {
|
||||||
|
setAndStore(() -> podState.setMessageNumber((podState.getMessageNumber() + 1) & 0b1111));
|
||||||
|
}
|
||||||
|
|
||||||
boolean hasFaultEvent();
|
public final void increasePacketNumber() {
|
||||||
|
setAndStore(() -> podState.setPacketNumber((podState.getPacketNumber() + 1) & 0b11111));
|
||||||
|
}
|
||||||
|
|
||||||
PodInfoFaultEvent getFaultEvent();
|
public final synchronized void resyncNonce(int syncWord, int sentNonce, int sequenceNumber) {
|
||||||
|
if (!isPaired()) {
|
||||||
|
throw new IllegalStateException("Cannot resync nonce: Pod is not paired yet");
|
||||||
|
}
|
||||||
|
|
||||||
void setFaultEvent(PodInfoFaultEvent faultEvent);
|
int sum = (sentNonce & 0xFFFF)
|
||||||
|
+ OmniCRC.crc16lookup[sequenceNumber]
|
||||||
|
+ (podState.getLot() & 0xFFFF)
|
||||||
|
+ (podState.getTid() & 0xFFFF);
|
||||||
|
int seed = ((sum & 0xFFFF) ^ syncWord);
|
||||||
|
NonceState nonceState = new NonceState(podState.getLot(), podState.getTid(), (byte) (seed & 0xFF));
|
||||||
|
|
||||||
AlertType getConfiguredAlertType(AlertSlot alertSlot);
|
setAndStore(() -> podState.setNonceState(nonceState));
|
||||||
|
}
|
||||||
|
|
||||||
void putConfiguredAlert(AlertSlot alertSlot, AlertType alertType);
|
public final synchronized int getCurrentNonce() {
|
||||||
|
if (!isPaired()) {
|
||||||
|
throw new IllegalStateException("Cannot get current nonce: Pod is not paired yet");
|
||||||
|
}
|
||||||
|
return podState.getNonceState().getCurrentNonce();
|
||||||
|
}
|
||||||
|
|
||||||
void removeConfiguredAlert(AlertSlot alertSlot);
|
public final synchronized void advanceToNextNonce() {
|
||||||
|
if (!isPaired()) {
|
||||||
|
throw new IllegalStateException("Cannot advance to next nonce: Pod is not paired yet");
|
||||||
|
}
|
||||||
|
setAndStore(() -> podState.getNonceState().advanceToNextNonce());
|
||||||
|
}
|
||||||
|
|
||||||
boolean hasActiveAlerts();
|
public final DateTime getLastSuccessfulCommunication() {
|
||||||
|
return getSafe(() -> podState.getLastSuccessfulCommunication());
|
||||||
|
}
|
||||||
|
|
||||||
AlertSet getActiveAlerts();
|
public final void setLastSuccessfulCommunication(DateTime dateTime) {
|
||||||
|
setAndStore(() -> podState.setLastSuccessfulCommunication(dateTime));
|
||||||
|
}
|
||||||
|
|
||||||
Integer getLot();
|
public final DateTime getLastFailedCommunication() {
|
||||||
|
return getSafe(() -> podState.getLastFailedCommunication());
|
||||||
|
}
|
||||||
|
|
||||||
Integer getTid();
|
public final void setLastFailedCommunication(DateTime dateTime) {
|
||||||
|
setAndStore(() -> podState.setLastFailedCommunication(dateTime));
|
||||||
|
}
|
||||||
|
|
||||||
FirmwareVersion getPiVersion();
|
public final boolean hasFaultEvent() {
|
||||||
|
return getSafe(() -> podState.getFaultEvent()) != null;
|
||||||
|
}
|
||||||
|
|
||||||
FirmwareVersion getPmVersion();
|
public final PodInfoFaultEvent getFaultEvent() {
|
||||||
|
return getSafe(() -> podState.getFaultEvent());
|
||||||
|
}
|
||||||
|
|
||||||
DateTimeZone getTimeZone();
|
public final void setFaultEvent(PodInfoFaultEvent faultEvent) {
|
||||||
|
setAndStore(() -> podState.setFaultEvent(faultEvent));
|
||||||
|
}
|
||||||
|
|
||||||
void setTimeZone(DateTimeZone timeZone);
|
public final AlertType getConfiguredAlertType(AlertSlot alertSlot) {
|
||||||
|
return getSafe(() -> podState.getConfiguredAlerts().get(alertSlot));
|
||||||
|
}
|
||||||
|
|
||||||
DateTime getTime();
|
public final void putConfiguredAlert(AlertSlot alertSlot, AlertType alertType) {
|
||||||
|
setAndStore(() -> podState.getConfiguredAlerts().put(alertSlot, alertType));
|
||||||
|
}
|
||||||
|
|
||||||
DateTime getActivatedAt();
|
public final void removeConfiguredAlert(AlertSlot alertSlot) {
|
||||||
|
setAndStore(() -> podState.getConfiguredAlerts().remove(alertSlot));
|
||||||
|
}
|
||||||
|
|
||||||
DateTime getExpiresAt();
|
public final boolean hasActiveAlerts() {
|
||||||
|
AlertSet activeAlerts = podState.getActiveAlerts();
|
||||||
|
return activeAlerts != null && activeAlerts.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
String getExpiryDateAsString();
|
public final AlertSet getActiveAlerts() {
|
||||||
|
return new AlertSet(getSafe(() -> podState.getActiveAlerts()));
|
||||||
|
}
|
||||||
|
|
||||||
SetupProgress getSetupProgress();
|
public final Integer getLot() {
|
||||||
|
return getSafe(() -> podState.getLot());
|
||||||
|
}
|
||||||
|
|
||||||
void setSetupProgress(SetupProgress setupProgress);
|
public final Integer getTid() {
|
||||||
|
return getSafe(() -> podState.getTid());
|
||||||
|
}
|
||||||
|
|
||||||
boolean isSuspended();
|
public final FirmwareVersion getPiVersion() {
|
||||||
|
return getSafe(() -> podState.getPiVersion());
|
||||||
|
}
|
||||||
|
|
||||||
Double getReservoirLevel();
|
public final FirmwareVersion getPmVersion() {
|
||||||
|
return getSafe(() -> podState.getPmVersion());
|
||||||
|
}
|
||||||
|
|
||||||
Duration getScheduleOffset();
|
public final DateTimeZone getTimeZone() {
|
||||||
|
return getSafe(() -> podState.getTimeZone());
|
||||||
|
}
|
||||||
|
|
||||||
BasalSchedule getBasalSchedule();
|
public final void setTimeZone(DateTimeZone timeZone) {
|
||||||
|
if (timeZone == null) {
|
||||||
|
throw new IllegalArgumentException("Time zone can not be null");
|
||||||
|
}
|
||||||
|
setAndStore(() -> podState.setTimeZone(timeZone));
|
||||||
|
}
|
||||||
|
|
||||||
void setBasalSchedule(BasalSchedule basalSchedule);
|
public final DateTime getTime() {
|
||||||
|
DateTime now = DateTime.now();
|
||||||
|
return now.withZone(getSafe(() -> podState.getTimeZone()));
|
||||||
|
}
|
||||||
|
|
||||||
DeliveryStatus getLastDeliveryStatus();
|
public final DateTime getActivatedAt() {
|
||||||
|
DateTime activatedAt = getSafe(() -> podState.getActivatedAt());
|
||||||
|
return activatedAt == null ? null : activatedAt.withZone(getSafe(() -> podState.getTimeZone()));
|
||||||
|
}
|
||||||
|
|
||||||
void updateFromStatusResponse(StatusResponse statusResponse);
|
public final DateTime getExpiresAt() {
|
||||||
|
DateTime expiresAt = getSafe(() -> podState.getExpiresAt());
|
||||||
|
return expiresAt == null ? null : expiresAt.withZone(getSafe(() -> podState.getTimeZone()));
|
||||||
|
}
|
||||||
|
|
||||||
void setStateChangedHandler(PodStateChangedHandler handler);
|
// TODO doesn't belong here
|
||||||
|
public final String getExpiryDateAsString() {
|
||||||
|
DateTime expiresAt = getExpiresAt();
|
||||||
|
return expiresAt == null ? "???" : DateUtil.dateAndTimeString(expiresAt.toDate());
|
||||||
|
}
|
||||||
|
|
||||||
|
public final SetupProgress getSetupProgress() {
|
||||||
|
return getSafe(() -> podState.getSetupProgress());
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setSetupProgress(SetupProgress setupProgress) {
|
||||||
|
if (setupProgress == null) {
|
||||||
|
throw new IllegalArgumentException("Setup progress can not be null");
|
||||||
|
}
|
||||||
|
setAndStore(() -> podState.setSetupProgress(setupProgress));
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean isSuspended() {
|
||||||
|
return getSafe(() -> podState.isSuspended());
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Double getReservoirLevel() {
|
||||||
|
return getSafe(() -> podState.getReservoirLevel());
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Duration getScheduleOffset() {
|
||||||
|
DateTime now = getTime();
|
||||||
|
DateTime startOfDay = new DateTime(now.getYear(), now.getMonthOfYear(), now.getDayOfMonth(),
|
||||||
|
0, 0, 0, getSafe(() -> podState.getTimeZone()));
|
||||||
|
return new Duration(startOfDay, now);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final BasalSchedule getBasalSchedule() {
|
||||||
|
return getSafe(() -> podState.getBasalSchedule());
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setBasalSchedule(BasalSchedule basalSchedule) {
|
||||||
|
setAndStore(() -> podState.setBasalSchedule(basalSchedule));
|
||||||
|
}
|
||||||
|
|
||||||
|
public final DateTime getLastBolusStartTime() {
|
||||||
|
return getSafe(() -> podState.getLastBolusStartTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Double getLastBolusAmount() {
|
||||||
|
return getSafe(() -> podState.getLastBolusAmount());
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setLastBolus(DateTime startTime, double amount) {
|
||||||
|
setAndStore(() -> {
|
||||||
|
podState.setLastBolusStartTime(startTime);
|
||||||
|
podState.setLastBolusAmount(amount);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public final DateTime getLastTempBasalStartTime() {
|
||||||
|
return getSafe(() -> podState.getLastTempBasalStartTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Double getLastTempBasalAmount() {
|
||||||
|
return getSafe(() -> podState.getLastTempBasalAmount());
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Duration getLastTempBasalDuration() {
|
||||||
|
return getSafe(() -> podState.getLastTempBasalDuration());
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setLastTempBasal(DateTime startTime, Double amount, Duration duration) {
|
||||||
|
setAndStore(() -> {
|
||||||
|
podState.setLastTempBasalStartTime(startTime);
|
||||||
|
podState.setLastTempBasalAmount(amount);
|
||||||
|
podState.setLastTempBasalDuration(duration);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public final DeliveryStatus getLastDeliveryStatus() {
|
||||||
|
return getSafe(() -> podState.getLastDeliveryStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void updateFromStatusResponse(StatusResponse statusResponse) {
|
||||||
|
if (!hasState()) {
|
||||||
|
throw new IllegalStateException("Cannot update from status response: podState is null");
|
||||||
|
}
|
||||||
|
setAndStore(() -> {
|
||||||
|
if (podState.getActivatedAt() == null) {
|
||||||
|
DateTime activatedAtCalculated = getTime().minus(statusResponse.getTimeActive());
|
||||||
|
podState.setActivatedAt(activatedAtCalculated);
|
||||||
|
}
|
||||||
|
DateTime expiresAt = podState.getExpiresAt();
|
||||||
|
DateTime expiresAtCalculated = podState.getActivatedAt().plus(OmnipodConst.NOMINAL_POD_LIFE);
|
||||||
|
if (expiresAt == null || expiresAtCalculated.isBefore(expiresAt) || expiresAtCalculated.isAfter(expiresAt.plusMinutes(1))) {
|
||||||
|
podState.setExpiresAt(expiresAtCalculated);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean newSuspendedState = statusResponse.getDeliveryStatus() == DeliveryStatus.SUSPENDED;
|
||||||
|
if (podState.isSuspended() != newSuspendedState) {
|
||||||
|
aapsLogger.info(LTag.PUMPCOMM, "Updating pod suspended state in updateFromStatusResponse. newSuspendedState={}, statusResponse={}", newSuspendedState, statusResponse.toString());
|
||||||
|
podState.setSuspended(newSuspendedState);
|
||||||
|
}
|
||||||
|
podState.setActiveAlerts(statusResponse.getAlerts());
|
||||||
|
podState.setLastDeliveryStatus(statusResponse.getDeliveryStatus());
|
||||||
|
podState.setReservoirLevel(statusResponse.getReservoirLevel());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setAndStore(Runnable runnable) {
|
||||||
|
if (!hasState()) {
|
||||||
|
throw new IllegalStateException("Cannot mutate PodState: podState is null");
|
||||||
|
}
|
||||||
|
runnable.run();
|
||||||
|
storePodState();
|
||||||
|
notifyPodStateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void storePodState() {
|
||||||
|
String podState = gsonInstance.toJson(this.podState);
|
||||||
|
aapsLogger.info(LTag.PUMP, "storePodState: storing podState: " + podState);
|
||||||
|
storePodState(podState);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void storePodState(String podState);
|
||||||
|
|
||||||
|
protected abstract String readPodState();
|
||||||
|
|
||||||
|
// Should be called after initializing the object
|
||||||
|
public final void loadPodState() {
|
||||||
|
podState = null;
|
||||||
|
|
||||||
|
String storedPodState = readPodState();
|
||||||
|
|
||||||
|
if (StringUtils.isEmpty(storedPodState)) {
|
||||||
|
aapsLogger.info(LTag.PUMP, "loadPodState: no Pod state was provided");
|
||||||
|
} else {
|
||||||
|
aapsLogger.info(LTag.PUMP, "loadPodState: serialized Pod state was provided: " + storedPodState);
|
||||||
|
try {
|
||||||
|
podState = gsonInstance.fromJson(storedPodState, PodState.class);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
aapsLogger.error(LTag.PUMP, "loadPodState: could not deserialize PodState: " + storedPodState, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyPodStateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void notifyPodStateChanged();
|
||||||
|
|
||||||
|
// Not actually "safe" as it throws an Exception, but it prevents NPEs
|
||||||
|
private <T> T getSafe(Supplier<T> supplier) {
|
||||||
|
if (!hasState()) {
|
||||||
|
throw new IllegalStateException("Cannot read from PodState: podState is null");
|
||||||
|
}
|
||||||
|
return supplier.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Gson createGson() {
|
||||||
|
GsonBuilder gsonBuilder = new GsonBuilder()
|
||||||
|
.registerTypeAdapter(DateTime.class, (JsonSerializer<DateTime>) (dateTime, typeOfSrc, context) ->
|
||||||
|
new JsonPrimitive(ISODateTimeFormat.dateTime().print(dateTime)))
|
||||||
|
.registerTypeAdapter(DateTime.class, (JsonDeserializer<DateTime>) (json, typeOfT, context) ->
|
||||||
|
ISODateTimeFormat.dateTime().parseDateTime(json.getAsString()))
|
||||||
|
.registerTypeAdapter(DateTimeZone.class, (JsonSerializer<DateTimeZone>) (timeZone, typeOfSrc, context) ->
|
||||||
|
new JsonPrimitive(timeZone.getID()))
|
||||||
|
.registerTypeAdapter(DateTimeZone.class, (JsonDeserializer<DateTimeZone>) (json, typeOfT, context) ->
|
||||||
|
DateTimeZone.forID(json.getAsString()));
|
||||||
|
|
||||||
|
return gsonBuilder.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String toString() {
|
||||||
|
return "AapsPodStateManager{" +
|
||||||
|
"podState=" + podState +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class PodState {
|
||||||
|
private final int address;
|
||||||
|
private Integer lot;
|
||||||
|
private Integer tid;
|
||||||
|
private FirmwareVersion piVersion;
|
||||||
|
private FirmwareVersion pmVersion;
|
||||||
|
private int packetNumber;
|
||||||
|
private int messageNumber;
|
||||||
|
private DateTime lastSuccessfulCommunication;
|
||||||
|
private DateTime lastFailedCommunication;
|
||||||
|
private DateTimeZone timeZone;
|
||||||
|
private DateTime activatedAt;
|
||||||
|
private DateTime expiresAt;
|
||||||
|
private PodInfoFaultEvent faultEvent;
|
||||||
|
private Double reservoirLevel;
|
||||||
|
private boolean suspended;
|
||||||
|
private NonceState nonceState;
|
||||||
|
private SetupProgress setupProgress;
|
||||||
|
private DeliveryStatus lastDeliveryStatus;
|
||||||
|
private AlertSet activeAlerts;
|
||||||
|
private BasalSchedule basalSchedule;
|
||||||
|
private DateTime lastBolusStartTime;
|
||||||
|
private Double lastBolusAmount;
|
||||||
|
private Double lastTempBasalAmount;
|
||||||
|
private DateTime lastTempBasalStartTime;
|
||||||
|
private Duration lastTempBasalDuration;
|
||||||
|
private final Map<AlertSlot, AlertType> configuredAlerts = new HashMap<>();
|
||||||
|
|
||||||
|
private PodState(int address) {
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer getLot() {
|
||||||
|
return lot;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLot(int lot) {
|
||||||
|
this.lot = lot;
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer getTid() {
|
||||||
|
return tid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTid(int tid) {
|
||||||
|
this.tid = tid;
|
||||||
|
}
|
||||||
|
|
||||||
|
FirmwareVersion getPiVersion() {
|
||||||
|
return piVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPiVersion(FirmwareVersion piVersion) {
|
||||||
|
if (this.piVersion != null) {
|
||||||
|
throw new IllegalStateException("piVersion has already been set");
|
||||||
|
}
|
||||||
|
if (piVersion == null) {
|
||||||
|
throw new IllegalArgumentException("piVersion can not be null");
|
||||||
|
}
|
||||||
|
this.piVersion = piVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
FirmwareVersion getPmVersion() {
|
||||||
|
return pmVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPmVersion(FirmwareVersion pmVersion) {
|
||||||
|
this.pmVersion = pmVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getPacketNumber() {
|
||||||
|
return packetNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPacketNumber(int packetNumber) {
|
||||||
|
this.packetNumber = packetNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getMessageNumber() {
|
||||||
|
return messageNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMessageNumber(int messageNumber) {
|
||||||
|
this.messageNumber = messageNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime getLastSuccessfulCommunication() {
|
||||||
|
return lastSuccessfulCommunication;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLastSuccessfulCommunication(DateTime lastSuccessfulCommunication) {
|
||||||
|
this.lastSuccessfulCommunication = lastSuccessfulCommunication;
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime getLastFailedCommunication() {
|
||||||
|
return lastFailedCommunication;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLastFailedCommunication(DateTime lastFailedCommunication) {
|
||||||
|
this.lastFailedCommunication = lastFailedCommunication;
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTimeZone getTimeZone() {
|
||||||
|
return timeZone;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTimeZone(DateTimeZone timeZone) {
|
||||||
|
this.timeZone = timeZone;
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime getActivatedAt() {
|
||||||
|
return activatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setActivatedAt(DateTime activatedAt) {
|
||||||
|
this.activatedAt = activatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime getExpiresAt() {
|
||||||
|
return expiresAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setExpiresAt(DateTime expiresAt) {
|
||||||
|
this.expiresAt = expiresAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
PodInfoFaultEvent getFaultEvent() {
|
||||||
|
return faultEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setFaultEvent(PodInfoFaultEvent faultEvent) {
|
||||||
|
this.faultEvent = faultEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
Double getReservoirLevel() {
|
||||||
|
return reservoirLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setReservoirLevel(Double reservoirLevel) {
|
||||||
|
this.reservoirLevel = reservoirLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSuspended() {
|
||||||
|
return suspended;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSuspended(boolean suspended) {
|
||||||
|
this.suspended = suspended;
|
||||||
|
}
|
||||||
|
|
||||||
|
NonceState getNonceState() {
|
||||||
|
return nonceState;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setNonceState(NonceState nonceState) {
|
||||||
|
this.nonceState = nonceState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SetupProgress getSetupProgress() {
|
||||||
|
return setupProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSetupProgress(SetupProgress setupProgress) {
|
||||||
|
this.setupProgress = setupProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeliveryStatus getLastDeliveryStatus() {
|
||||||
|
return lastDeliveryStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLastDeliveryStatus(DeliveryStatus lastDeliveryStatus) {
|
||||||
|
this.lastDeliveryStatus = lastDeliveryStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
AlertSet getActiveAlerts() {
|
||||||
|
return activeAlerts;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setActiveAlerts(AlertSet activeAlerts) {
|
||||||
|
this.activeAlerts = activeAlerts;
|
||||||
|
}
|
||||||
|
|
||||||
|
BasalSchedule getBasalSchedule() {
|
||||||
|
return basalSchedule;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBasalSchedule(BasalSchedule basalSchedule) {
|
||||||
|
this.basalSchedule = basalSchedule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime getLastBolusStartTime() {
|
||||||
|
return lastBolusStartTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLastBolusStartTime(DateTime lastBolusStartTime) {
|
||||||
|
this.lastBolusStartTime = lastBolusStartTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
Double getLastBolusAmount() {
|
||||||
|
return lastBolusAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLastBolusAmount(Double lastBolusAmount) {
|
||||||
|
this.lastBolusAmount = lastBolusAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
Double getLastTempBasalAmount() {
|
||||||
|
return lastTempBasalAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLastTempBasalAmount(Double lastTempBasalAmount) {
|
||||||
|
this.lastTempBasalAmount = lastTempBasalAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime getLastTempBasalStartTime() {
|
||||||
|
return lastTempBasalStartTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLastTempBasalStartTime(DateTime lastTempBasalStartTime) {
|
||||||
|
this.lastTempBasalStartTime = lastTempBasalStartTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
Duration getLastTempBasalDuration() {
|
||||||
|
return lastTempBasalDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLastTempBasalDuration(Duration lastTempBasalDuration) {
|
||||||
|
this.lastTempBasalDuration = lastTempBasalDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<AlertSlot, AlertType> getConfiguredAlerts() {
|
||||||
|
return configuredAlerts;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String toString() {
|
||||||
|
return "PodState{" +
|
||||||
|
"address=" + address +
|
||||||
|
", lot=" + lot +
|
||||||
|
", tid=" + tid +
|
||||||
|
", piVersion=" + piVersion +
|
||||||
|
", pmVersion=" + pmVersion +
|
||||||
|
", packetNumber=" + packetNumber +
|
||||||
|
", messageNumber=" + messageNumber +
|
||||||
|
", lastSuccessfulCommunication=" + lastSuccessfulCommunication +
|
||||||
|
", lastFailedCommunication=" + lastFailedCommunication +
|
||||||
|
", timeZone=" + timeZone +
|
||||||
|
", activatedAt=" + activatedAt +
|
||||||
|
", expiresAt=" + expiresAt +
|
||||||
|
", faultEvent=" + faultEvent +
|
||||||
|
", reservoirLevel=" + reservoirLevel +
|
||||||
|
", suspended=" + suspended +
|
||||||
|
", nonceState=" + nonceState +
|
||||||
|
", setupProgress=" + setupProgress +
|
||||||
|
", lastDeliveryStatus=" + lastDeliveryStatus +
|
||||||
|
", activeAlerts=" + activeAlerts +
|
||||||
|
", basalSchedule=" + basalSchedule +
|
||||||
|
", lastBolusStartTime=" + lastBolusStartTime +
|
||||||
|
", lastBolusAmount=" + lastBolusAmount +
|
||||||
|
", lastTempBasalAmount=" + lastTempBasalAmount +
|
||||||
|
", lastTempBasalStartTime=" + lastTempBasalStartTime +
|
||||||
|
", lastTempBasalDuration=" + lastTempBasalDuration +
|
||||||
|
", configuredAlerts=" + configuredAlerts +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class NonceState {
|
||||||
|
private final long[] table = new long[21];
|
||||||
|
private int index;
|
||||||
|
|
||||||
|
private NonceState(int lot, int tid) {
|
||||||
|
initializeTable(lot, tid, (byte) 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
private NonceState(int lot, int tid, byte seed) {
|
||||||
|
initializeTable(lot, tid, seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeTable(int lot, int tid, byte seed) {
|
||||||
|
table[0] = (long) (lot & 0xFFFF) + 0x55543DC3L + (((long) (lot) & 0xFFFFFFFFL) >> 16);
|
||||||
|
table[0] = table[0] & 0xFFFFFFFFL;
|
||||||
|
table[1] = (tid & 0xFFFF) + 0xAAAAE44EL + (((long) (tid) & 0xFFFFFFFFL) >> 16);
|
||||||
|
table[1] = table[1] & 0xFFFFFFFFL;
|
||||||
|
index = 0;
|
||||||
|
table[0] += seed;
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
table[2 + i] = generateEntry();
|
||||||
|
}
|
||||||
|
index = (int) ((table[0] + table[1]) & 0X0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int generateEntry() {
|
||||||
|
table[0] = (((table[0] >> 16) + (table[0] & 0xFFFF) * 0x5D7FL) & 0xFFFFFFFFL);
|
||||||
|
table[1] = (((table[1] >> 16) + (table[1] & 0xFFFF) * 0x8CA0L) & 0xFFFFFFFFL);
|
||||||
|
return (int) ((table[1] + (table[0] << 16)) & 0xFFFFFFFFL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCurrentNonce() {
|
||||||
|
return (int) table[(2 + index)];
|
||||||
|
}
|
||||||
|
|
||||||
|
void advanceToNextNonce() {
|
||||||
|
int nonce = getCurrentNonce();
|
||||||
|
table[(2 + index)] = generateEntry();
|
||||||
|
index = (nonce & 0x0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "NonceState{" +
|
||||||
|
"table=" + Arrays.toString(table) +
|
||||||
|
", index=" + index +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO replace with java.util.function.Supplier<T> when min API level >= 24
|
||||||
|
@FunctionalInterface
|
||||||
|
private interface Supplier<T> {
|
||||||
|
T get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,13 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.driver.comm;
|
package info.nightscout.androidaps.plugins.pump.omnipod.driver.comm;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.joda.time.Duration;
|
import org.joda.time.Duration;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector;
|
import dagger.android.HasAndroidInjector;
|
||||||
import info.nightscout.androidaps.MainApp;
|
import info.nightscout.androidaps.MainApp;
|
||||||
|
@ -22,7 +19,6 @@ import info.nightscout.androidaps.data.PumpEnactResult;
|
||||||
import info.nightscout.androidaps.db.Source;
|
import info.nightscout.androidaps.db.Source;
|
||||||
import info.nightscout.androidaps.db.TemporaryBasal;
|
import info.nightscout.androidaps.db.TemporaryBasal;
|
||||||
import info.nightscout.androidaps.events.Event;
|
import info.nightscout.androidaps.events.Event;
|
||||||
import info.nightscout.androidaps.events.EventRefreshOverview;
|
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
||||||
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
|
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||||
|
@ -32,7 +28,6 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotifi
|
||||||
import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress;
|
import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress;
|
||||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
|
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
|
||||||
import info.nightscout.androidaps.plugins.pump.common.data.TempBasalPair;
|
import info.nightscout.androidaps.plugins.pump.common.data.TempBasalPair;
|
||||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpStatusType;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType;
|
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType;
|
||||||
import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil;
|
import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil;
|
||||||
import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil;
|
import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil;
|
||||||
|
@ -60,9 +55,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.comm.exception.PodReturne
|
||||||
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.PodInfoRecentPulseLog;
|
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.podinfo.PodInfoRecentPulseLog;
|
||||||
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.AlertSet;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.defs.AlertSlot;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.defs.AlertType;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.defs.FaultEventCode;
|
import info.nightscout.androidaps.plugins.pump.omnipod.defs.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;
|
||||||
|
@ -74,8 +66,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodStateManage
|
||||||
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.driver.db.PodHistory;
|
import info.nightscout.androidaps.plugins.pump.omnipod.driver.db.PodHistory;
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.driver.db.PodHistoryEntryType;
|
import info.nightscout.androidaps.plugins.pump.omnipod.driver.db.PodHistoryEntryType;
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.events.EventOmnipodAcknowledgeAlertsChanged;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.events.EventOmnipodPumpValuesChanged;
|
|
||||||
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.OmnipodUtil;
|
import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodUtil;
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||||
|
@ -97,9 +87,6 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
|
||||||
|
|
||||||
private static AapsOmnipodManager instance;
|
private static AapsOmnipodManager instance;
|
||||||
|
|
||||||
private Date lastBolusTime;
|
|
||||||
private Double lastBolusUnits;
|
|
||||||
|
|
||||||
public static AapsOmnipodManager getInstance() {
|
public static AapsOmnipodManager getInstance() {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
@ -126,12 +113,6 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
|
||||||
this.activePlugin = activePlugin;
|
this.activePlugin = activePlugin;
|
||||||
this.pumpStatus = _pumpStatus;
|
this.pumpStatus = _pumpStatus;
|
||||||
|
|
||||||
podStateManager.setStateChangedHandler(manager -> {
|
|
||||||
// Handle pod state changes
|
|
||||||
updatePumpStatus(manager);
|
|
||||||
omnipodUtil.notifyDeviceStatusChanged();
|
|
||||||
});
|
|
||||||
|
|
||||||
delegate = new OmnipodManager(aapsLogger, sp, communicationService, podStateManager);
|
delegate = new OmnipodManager(aapsLogger, sp, communicationService, podStateManager);
|
||||||
instance = this;
|
instance = this;
|
||||||
}
|
}
|
||||||
|
@ -140,74 +121,6 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
|
||||||
return podStateManager;
|
return podStateManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePumpStatus(PodStateManager podStateManager) {
|
|
||||||
if (pumpStatus != null) {
|
|
||||||
if (!podStateManager.hasState()) {
|
|
||||||
pumpStatus.ackAlertsText = null;
|
|
||||||
pumpStatus.ackAlertsAvailable = false;
|
|
||||||
pumpStatus.lastBolusTime = null;
|
|
||||||
pumpStatus.lastBolusAmount = null;
|
|
||||||
pumpStatus.reservoirRemainingUnits = 0.0;
|
|
||||||
pumpStatus.pumpStatusType = PumpStatusType.Suspended;
|
|
||||||
sendEvent(new EventOmnipodAcknowledgeAlertsChanged());
|
|
||||||
sendEvent(new EventOmnipodPumpValuesChanged());
|
|
||||||
sendEvent(new EventRefreshOverview("Omnipod Pump", false));
|
|
||||||
} else {
|
|
||||||
// Update active alerts
|
|
||||||
if (podStateManager.hasActiveAlerts()) {
|
|
||||||
List<String> alerts = translateActiveAlerts(podStateManager);
|
|
||||||
String alertsText = TextUtils.join("\n", alerts);
|
|
||||||
|
|
||||||
if (!pumpStatus.ackAlertsAvailable || !alertsText.equals(pumpStatus.ackAlertsText)) {
|
|
||||||
pumpStatus.ackAlertsAvailable = true;
|
|
||||||
pumpStatus.ackAlertsText = TextUtils.join("\n", alerts);
|
|
||||||
|
|
||||||
sendEvent(new EventOmnipodAcknowledgeAlertsChanged());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (pumpStatus.ackAlertsAvailable || StringUtils.isNotEmpty(pumpStatus.ackAlertsText)) {
|
|
||||||
pumpStatus.ackAlertsText = null;
|
|
||||||
pumpStatus.ackAlertsAvailable = false;
|
|
||||||
sendEvent(new EventOmnipodAcknowledgeAlertsChanged());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update other info: last bolus, units remaining, suspended
|
|
||||||
if (!Objects.equals(lastBolusTime, pumpStatus.lastBolusTime) //
|
|
||||||
|| !Objects.equals(lastBolusUnits, pumpStatus.lastBolusAmount) //
|
|
||||||
|| !isReservoirStatusUpToDate(pumpStatus, podStateManager.getReservoirLevel())
|
|
||||||
|| podStateManager.isSuspended() != PumpStatusType.Suspended.equals(pumpStatus.pumpStatusType)) {
|
|
||||||
pumpStatus.lastBolusTime = lastBolusTime;
|
|
||||||
pumpStatus.lastBolusAmount = lastBolusUnits;
|
|
||||||
pumpStatus.reservoirRemainingUnits = podStateManager.getReservoirLevel() == null ? 75.0 : podStateManager.getReservoirLevel();
|
|
||||||
pumpStatus.pumpStatusType = podStateManager.isSuspended() ? PumpStatusType.Suspended : PumpStatusType.Running;
|
|
||||||
sendEvent(new EventOmnipodPumpValuesChanged());
|
|
||||||
|
|
||||||
if (podStateManager.isSuspended() != PumpStatusType.Suspended.equals(pumpStatus.pumpStatusType)) {
|
|
||||||
sendEvent(new EventRefreshOverview("Omnipod Pump", false));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> translateActiveAlerts(PodStateManager podStateManager) {
|
|
||||||
List<String> translatedAlerts = new ArrayList<>();
|
|
||||||
AlertSet activeAlerts = podStateManager.getActiveAlerts();
|
|
||||||
if (activeAlerts == null) {
|
|
||||||
return translatedAlerts;
|
|
||||||
}
|
|
||||||
for (AlertSlot alertSlot : activeAlerts.getAlertSlots()) {
|
|
||||||
translatedAlerts.add(translateAlertType(podStateManager.getConfiguredAlertType(alertSlot)));
|
|
||||||
}
|
|
||||||
return translatedAlerts;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isReservoirStatusUpToDate(OmnipodPumpStatus pumpStatus, Double unitsRemaining) {
|
|
||||||
double expectedUnitsRemaining = unitsRemaining == null ? 75.0 : unitsRemaining;
|
|
||||||
return Math.abs(expectedUnitsRemaining - pumpStatus.reservoirRemainingUnits) < 0.000001;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PumpEnactResult initPod(PodInitActionType podInitActionType, PodInitReceiver podInitReceiver, Profile profile) {
|
public PumpEnactResult initPod(PodInitActionType podInitActionType, PodInitReceiver podInitReceiver, Profile profile) {
|
||||||
long time = System.currentTimeMillis();
|
long time = System.currentTimeMillis();
|
||||||
|
@ -306,7 +219,6 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
|
||||||
return new PumpEnactResult(injector).success(false).enacted(false).comment(comment);
|
return new PumpEnactResult(injector).success(false).enacted(false).comment(comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return new PumpEnactResult(injector).success(true).enacted(true);
|
return new PumpEnactResult(injector).success(true).enacted(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,11 +268,6 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
|
||||||
|
|
||||||
double unitsDelivered = bolusDeliveryResult.getUnitsDelivered();
|
double unitsDelivered = bolusDeliveryResult.getUnitsDelivered();
|
||||||
|
|
||||||
if (pumpStatus != null && !detailedBolusInfo.isSMB) {
|
|
||||||
lastBolusTime = pumpStatus.lastBolusTime = bolusStarted;
|
|
||||||
lastBolusUnits = pumpStatus.lastBolusAmount = unitsDelivered;
|
|
||||||
}
|
|
||||||
|
|
||||||
long pumpId = addSuccessToHistory(bolusStarted.getTime(), PodHistoryEntryType.SetBolus, unitsDelivered + ";" + detailedBolusInfo.carbs);
|
long pumpId = addSuccessToHistory(bolusStarted.getTime(), PodHistoryEntryType.SetBolus, unitsDelivered + ";" + detailedBolusInfo.carbs);
|
||||||
|
|
||||||
detailedBolusInfo.date = bolusStarted.getTime();
|
detailedBolusInfo.date = bolusStarted.getTime();
|
||||||
|
@ -467,12 +374,6 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
|
||||||
return new PumpEnactResult(injector).success(true).enacted(true);
|
return new PumpEnactResult(injector).success(true).enacted(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPumpStatus(OmnipodPumpStatus pumpStatus) {
|
|
||||||
this.pumpStatus = pumpStatus;
|
|
||||||
updatePumpStatus(podStateManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO should we add this to the OmnipodCommunicationManager interface?
|
// TODO should we add this to the OmnipodCommunicationManager interface?
|
||||||
public PumpEnactResult getPodInfo(PodInfoType podInfoType) {
|
public PumpEnactResult getPodInfo(PodInfoType podInfoType) {
|
||||||
long time = System.currentTimeMillis();
|
long time = System.currentTimeMillis();
|
||||||
|
@ -554,10 +455,6 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
|
||||||
return delegate.isReadyForDelivery();
|
return delegate.isReadyForDelivery();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPodStateAsString() {
|
|
||||||
return podStateManager.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void reportImplicitlyCanceledTbr() {
|
private void reportImplicitlyCanceledTbr() {
|
||||||
//TreatmentsPlugin plugin = TreatmentsPlugin.getPlugin();
|
//TreatmentsPlugin plugin = TreatmentsPlugin.getPlugin();
|
||||||
TreatmentsInterface plugin = activePlugin.getActiveTreatments();
|
TreatmentsInterface plugin = activePlugin.getActiveTreatments();
|
||||||
|
@ -718,28 +615,6 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
|
||||||
sendEvent(new EventNewNotification(notification));
|
sendEvent(new EventNewNotification(notification));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String translateAlertType(AlertType alertType) {
|
|
||||||
if (alertType == null) {
|
|
||||||
return getStringResource(R.string.omnipod_alert_unknown_alert);
|
|
||||||
}
|
|
||||||
switch (alertType) {
|
|
||||||
case FINISH_PAIRING_REMINDER:
|
|
||||||
return getStringResource(R.string.omnipod_alert_finish_pairing_reminder);
|
|
||||||
case FINISH_SETUP_REMINDER:
|
|
||||||
return getStringResource(R.string.omnipod_alert_finish_setup_reminder_reminder);
|
|
||||||
case EXPIRATION_ALERT:
|
|
||||||
return getStringResource(R.string.omnipod_alert_expiration);
|
|
||||||
case EXPIRATION_ADVISORY_ALERT:
|
|
||||||
return getStringResource(R.string.omnipod_alert_expiration_advisory);
|
|
||||||
case SHUTDOWN_IMMINENT_ALARM:
|
|
||||||
return getStringResource(R.string.omnipod_alert_shutdown_imminent);
|
|
||||||
case LOW_RESERVOIR_ALERT:
|
|
||||||
return getStringResource(R.string.omnipod_alert_low_reservoir);
|
|
||||||
default:
|
|
||||||
return alertType.name();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isBolusBeepsEnabled() {
|
private boolean isBolusBeepsEnabled() {
|
||||||
return this.pumpStatus.beepBolusEnabled;
|
return this.pumpStatus.beepBolusEnabled;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,631 +1,182 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.driver.comm;
|
package info.nightscout.androidaps.plugins.pump.omnipod.driver.comm;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.joda.time.DateTime;
|
|
||||||
import org.joda.time.DateTimeZone;
|
|
||||||
import org.joda.time.Duration;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import info.nightscout.androidaps.R;
|
||||||
|
import info.nightscout.androidaps.events.Event;
|
||||||
import dagger.android.HasAndroidInjector;
|
import info.nightscout.androidaps.events.EventRefreshOverview;
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||||
import info.nightscout.androidaps.logging.LTag;
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.StatusResponse;
|
import info.nightscout.androidaps.plugins.pump.common.defs.PumpStatusType;
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.podinfo.PodInfoFaultEvent;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.defs.AlertSet;
|
import info.nightscout.androidaps.plugins.pump.omnipod.defs.AlertSet;
|
||||||
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.DeliveryStatus;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.defs.FirmwareVersion;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.defs.SetupProgress;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.defs.schedule.BasalSchedule;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodStateChangedHandler;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodStateManager;
|
import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodStateManager;
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.util.OmniCRC;
|
import info.nightscout.androidaps.plugins.pump.omnipod.driver.OmnipodPumpStatus;
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.events.EventOmnipodAcknowledgeAlertsChanged;
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.events.EventOmnipodPumpValuesChanged;
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodConst;
|
import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodConst;
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodUtil;
|
import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodUtil;
|
||||||
import info.nightscout.androidaps.utils.DateUtil;
|
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||||
|
|
||||||
public class AapsPodStateManager implements PodStateManager {
|
public class AapsPodStateManager extends PodStateManager {
|
||||||
|
|
||||||
@Inject protected AAPSLogger aapsLogger;
|
private final AAPSLogger aapsLogger;
|
||||||
@Inject protected SP sp;
|
private final SP sp;
|
||||||
@Inject protected OmnipodUtil omnipodUtil;
|
private final OmnipodUtil omnipodUtil;
|
||||||
|
private final OmnipodPumpStatus omnipodPumpStatus;
|
||||||
|
private final RxBusWrapper rxBus;
|
||||||
|
private final ResourceHelper resourceHelper;
|
||||||
|
|
||||||
private PodState podState;
|
public AapsPodStateManager(AAPSLogger aapsLogger, SP sp, OmnipodUtil omnipodUtil,
|
||||||
private PodStateChangedHandler stateChangedHandler;
|
OmnipodPumpStatus omnipodPumpStatus, RxBusWrapper rxBus,
|
||||||
|
ResourceHelper resourceHelper) {
|
||||||
|
super(aapsLogger);
|
||||||
|
|
||||||
public AapsPodStateManager(HasAndroidInjector injector) {
|
if (aapsLogger == null) {
|
||||||
injector.androidInjector().inject(this);
|
throw new IllegalArgumentException("aapsLogger can not be null");
|
||||||
|
}
|
||||||
// TODO is there something like @PostConstruct in Dagger? if so, we should probably move loading the pod state there
|
if (sp == null) {
|
||||||
loadPodState();
|
throw new IllegalArgumentException("sp can not be null");
|
||||||
|
}
|
||||||
|
if (omnipodUtil == null) {
|
||||||
|
throw new IllegalArgumentException("omnipodUtil can not be null");
|
||||||
|
}
|
||||||
|
if (omnipodPumpStatus == null) {
|
||||||
|
throw new IllegalArgumentException("omnipodPumpStatus can not be null");
|
||||||
|
}
|
||||||
|
if (rxBus == null) {
|
||||||
|
throw new IllegalArgumentException("rxBus can not be null");
|
||||||
|
}
|
||||||
|
if (resourceHelper == null) {
|
||||||
|
throw new IllegalArgumentException("resourceHelper can not be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public boolean hasState() {
|
this.aapsLogger = aapsLogger;
|
||||||
return podState != null;
|
this.sp = sp;
|
||||||
}
|
this.omnipodUtil = omnipodUtil;
|
||||||
|
this.omnipodPumpStatus = omnipodPumpStatus;
|
||||||
@Override public void removeState() {
|
this.rxBus = rxBus;
|
||||||
this.podState = null;
|
this.resourceHelper = resourceHelper;
|
||||||
persistPodState();
|
|
||||||
notifyPodStateChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initState(int address) {
|
protected String readPodState() {
|
||||||
if (hasState()) {
|
return sp.getString(OmnipodConst.Prefs.PodState, "");
|
||||||
throw new IllegalStateException("Can not init a new pod state: podState <> null");
|
|
||||||
}
|
|
||||||
podState = new PodState(address);
|
|
||||||
persistPodState();
|
|
||||||
notifyPodStateChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean isPaired() {
|
|
||||||
return hasState() //
|
|
||||||
&& podState.getLot() != null && podState.getTid() != null //
|
|
||||||
&& podState.getPiVersion() != null && podState.getPmVersion() != null //
|
|
||||||
&& podState.getTimeZone() != null //
|
|
||||||
&& podState.getSetupProgress() != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPairingParameters(int lot, int tid, FirmwareVersion piVersion, FirmwareVersion pmVersion, DateTimeZone timeZone) {
|
protected void storePodState(String podState) {
|
||||||
if (!hasState()) {
|
sp.putString(OmnipodConst.Prefs.PodState, podState);
|
||||||
throw new IllegalStateException("Cannot set pairing parameters: podState is null");
|
|
||||||
}
|
|
||||||
if (isPaired()) {
|
|
||||||
throw new IllegalStateException("Cannot set pairing parameters: pairing parameters have already been set");
|
|
||||||
}
|
|
||||||
if (piVersion == null) {
|
|
||||||
throw new IllegalArgumentException("Cannot set pairing parameters: piVersion can not be null");
|
|
||||||
}
|
|
||||||
if (pmVersion == null) {
|
|
||||||
throw new IllegalArgumentException("Cannot set pairing parameters: pmVersion can not be null");
|
|
||||||
}
|
|
||||||
if (timeZone == null) {
|
|
||||||
throw new IllegalArgumentException("Cannot set pairing parameters: timeZone can not be null");
|
|
||||||
}
|
|
||||||
|
|
||||||
setAndStore(() -> {
|
|
||||||
podState.setLot(lot);
|
|
||||||
podState.setTid(tid);
|
|
||||||
podState.setPiVersion(piVersion);
|
|
||||||
podState.setPmVersion(pmVersion);
|
|
||||||
podState.setTimeZone(timeZone);
|
|
||||||
podState.setNonceState(new NonceState(lot, tid));
|
|
||||||
podState.setSetupProgress(SetupProgress.ADDRESS_ASSIGNED);
|
|
||||||
podState.getConfiguredAlerts().put(AlertSlot.SLOT7, AlertType.FINISH_SETUP_REMINDER);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int getAddress() {
|
|
||||||
return getSafe(() -> podState.getAddress());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int getMessageNumber() {
|
|
||||||
return getSafe(() -> podState.getMessageNumber());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void setMessageNumber(int messageNumber) {
|
|
||||||
setAndStore(() -> podState.setMessageNumber(messageNumber));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int getPacketNumber() {
|
|
||||||
return getSafe(() -> podState.getPacketNumber());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void setPacketNumber(int packetNumber) {
|
|
||||||
setAndStore(() -> podState.setPacketNumber(packetNumber));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void increaseMessageNumber() {
|
|
||||||
setAndStore(() -> podState.setMessageNumber((podState.getMessageNumber() + 1) & 0b1111));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void increasePacketNumber() {
|
|
||||||
setAndStore(() -> podState.setPacketNumber((podState.getPacketNumber() + 1) & 0b11111));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public synchronized void resyncNonce(int syncWord, int sentNonce, int sequenceNumber) {
|
|
||||||
if (!isPaired()) {
|
|
||||||
throw new IllegalStateException("Cannot resync nonce: Pod is not paired yet");
|
|
||||||
}
|
|
||||||
|
|
||||||
int sum = (sentNonce & 0xFFFF)
|
|
||||||
+ OmniCRC.crc16lookup[sequenceNumber]
|
|
||||||
+ (podState.getLot() & 0xFFFF)
|
|
||||||
+ (podState.getTid() & 0xFFFF);
|
|
||||||
int seed = ((sum & 0xFFFF) ^ syncWord);
|
|
||||||
NonceState nonceState = new NonceState(podState.getLot(), podState.getTid(), (byte) (seed & 0xFF));
|
|
||||||
|
|
||||||
setAndStore(() -> podState.setNonceState(nonceState));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public synchronized int getCurrentNonce() {
|
|
||||||
if (!isPaired()) {
|
|
||||||
throw new IllegalStateException("Cannot get current nonce: Pod is not paired yet");
|
|
||||||
}
|
|
||||||
return podState.getNonceState().getCurrentNonce();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public synchronized void advanceToNextNonce() {
|
|
||||||
if (!isPaired()) {
|
|
||||||
throw new IllegalStateException("Cannot advance to next nonce: Pod is not paired yet");
|
|
||||||
}
|
|
||||||
setAndStore(() -> podState.getNonceState().advanceToNextNonce());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean hasFaultEvent() {
|
|
||||||
return getSafe(() -> podState.getFaultEvent()) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public PodInfoFaultEvent getFaultEvent() {
|
|
||||||
return getSafe(() -> podState.getFaultEvent());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void setFaultEvent(PodInfoFaultEvent faultEvent) {
|
|
||||||
setAndStore(() -> podState.setFaultEvent(faultEvent));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public AlertType getConfiguredAlertType(AlertSlot alertSlot) {
|
|
||||||
return getSafe(() -> podState.getConfiguredAlerts().get(alertSlot));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void putConfiguredAlert(AlertSlot alertSlot, AlertType alertType) {
|
|
||||||
setAndStore(() -> podState.getConfiguredAlerts().put(alertSlot, alertType));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void removeConfiguredAlert(AlertSlot alertSlot) {
|
|
||||||
setAndStore(() -> podState.getConfiguredAlerts().remove(alertSlot));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean hasActiveAlerts() {
|
|
||||||
AlertSet activeAlerts = podState.getActiveAlerts();
|
|
||||||
return activeAlerts != null && activeAlerts.size() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public AlertSet getActiveAlerts() {
|
|
||||||
return getSafe(() -> podState.getActiveAlerts());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public Integer getLot() {
|
|
||||||
return getSafe(() -> podState.getLot());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public Integer getTid() {
|
|
||||||
return getSafe(() -> podState.getTid());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public FirmwareVersion getPiVersion() {
|
|
||||||
return getSafe(() -> podState.getPiVersion());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public FirmwareVersion getPmVersion() {
|
|
||||||
return getSafe(() -> podState.getPmVersion());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public DateTimeZone getTimeZone() {
|
|
||||||
return getSafe(() -> podState.getTimeZone());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void setTimeZone(DateTimeZone timeZone) {
|
|
||||||
if (timeZone == null) {
|
|
||||||
throw new IllegalArgumentException("Time zone can not be null");
|
|
||||||
}
|
|
||||||
setAndStore(() -> podState.setTimeZone(timeZone));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public DateTime getTime() {
|
|
||||||
DateTime now = DateTime.now();
|
|
||||||
return now.withZone(getSafe(() -> podState.getTimeZone()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateTime getActivatedAt() {
|
|
||||||
DateTime activatedAt = getSafe(() -> podState.getActivatedAt());
|
|
||||||
return activatedAt == null ? null : activatedAt.withZone(getSafe(() -> podState.getTimeZone()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateTime getExpiresAt() {
|
|
||||||
DateTime expiresAt = getSafe(() -> podState.getExpiresAt());
|
|
||||||
return expiresAt == null ? null : expiresAt.withZone(getSafe(() -> podState.getTimeZone()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO doesn't belong here
|
|
||||||
public String getExpiryDateAsString() {
|
|
||||||
DateTime expiresAt = getExpiresAt();
|
|
||||||
return expiresAt == null ? "???" : DateUtil.dateAndTimeString(expiresAt.toDate());
|
|
||||||
}
|
|
||||||
|
|
||||||
public SetupProgress getSetupProgress() {
|
|
||||||
return getSafe(() -> podState.getSetupProgress());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSetupProgress(SetupProgress setupProgress) {
|
|
||||||
if (setupProgress == null) {
|
|
||||||
throw new IllegalArgumentException("Setup progress can not be null");
|
|
||||||
}
|
|
||||||
setAndStore(() -> podState.setSetupProgress(setupProgress));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean isSuspended() {
|
|
||||||
return getSafe(() -> podState.isSuspended());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public Double getReservoirLevel() {
|
|
||||||
return getSafe(() -> podState.getReservoirLevel());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public Duration getScheduleOffset() {
|
|
||||||
DateTime now = getTime();
|
|
||||||
DateTime startOfDay = new DateTime(now.getYear(), now.getMonthOfYear(), now.getDayOfMonth(),
|
|
||||||
0, 0, 0, getSafe(() -> podState.getTimeZone()));
|
|
||||||
return new Duration(startOfDay, now);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public BasalSchedule getBasalSchedule() {
|
|
||||||
return getSafe(() -> podState.getBasalSchedule());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void setBasalSchedule(BasalSchedule basalSchedule) {
|
|
||||||
setAndStore(() -> podState.setBasalSchedule(basalSchedule));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public DeliveryStatus getLastDeliveryStatus() {
|
|
||||||
return getSafe(() -> podState.getLastDeliveryStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void updateFromStatusResponse(StatusResponse statusResponse) {
|
|
||||||
if (!hasState()) {
|
|
||||||
throw new IllegalStateException("Cannot update from status response: podState is null");
|
|
||||||
}
|
|
||||||
setAndStore(() -> {
|
|
||||||
if (podState.getActivatedAt() == null) {
|
|
||||||
DateTime activatedAtCalculated = getTime().minus(statusResponse.getTimeActive());
|
|
||||||
podState.setActivatedAt(activatedAtCalculated);
|
|
||||||
}
|
|
||||||
DateTime expiresAt = podState.getExpiresAt();
|
|
||||||
DateTime expiresAtCalculated = podState.getActivatedAt().plus(OmnipodConst.NOMINAL_POD_LIFE);
|
|
||||||
if (expiresAt == null || expiresAtCalculated.isBefore(expiresAt) || expiresAtCalculated.isAfter(expiresAt.plusMinutes(1))) {
|
|
||||||
podState.setExpiresAt(expiresAtCalculated);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean newSuspendedState = statusResponse.getDeliveryStatus() == DeliveryStatus.SUSPENDED;
|
|
||||||
if (podState.isSuspended() != newSuspendedState) {
|
|
||||||
aapsLogger.info(LTag.PUMPCOMM, "Updating pod suspended state in updateFromStatusResponse. newSuspendedState={}, statusResponse={}", newSuspendedState, statusResponse.toString());
|
|
||||||
podState.setSuspended(newSuspendedState);
|
|
||||||
}
|
|
||||||
podState.setActiveAlerts(statusResponse.getAlerts());
|
|
||||||
podState.setLastDeliveryStatus(statusResponse.getDeliveryStatus());
|
|
||||||
podState.setReservoirLevel(statusResponse.getReservoirLevel());
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setStateChangedHandler(PodStateChangedHandler handler) {
|
protected void notifyPodStateChanged() {
|
||||||
// FIXME this is an ugly workaround for not being able to serialize the PodStateChangedHandler
|
if (omnipodPumpStatus != null) {
|
||||||
if (stateChangedHandler != null) {
|
|
||||||
throw new IllegalStateException("A PodStateChangedHandler has already been already registered");
|
|
||||||
}
|
|
||||||
stateChangedHandler = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setAndStore(Runnable runnable) {
|
|
||||||
if (!hasState()) {
|
if (!hasState()) {
|
||||||
throw new IllegalStateException("Cannot mutate PodState: podState is null");
|
omnipodPumpStatus.ackAlertsText = null;
|
||||||
}
|
omnipodPumpStatus.ackAlertsAvailable = false;
|
||||||
runnable.run();
|
omnipodPumpStatus.lastBolusTime = null;
|
||||||
persistPodState();
|
omnipodPumpStatus.lastBolusAmount = null;
|
||||||
notifyPodStateChanged();
|
omnipodPumpStatus.reservoirRemainingUnits = 0.0;
|
||||||
}
|
omnipodPumpStatus.pumpStatusType = PumpStatusType.Suspended;
|
||||||
|
sendEvent(new EventOmnipodAcknowledgeAlertsChanged());
|
||||||
private void persistPodState() {
|
sendEvent(new EventOmnipodPumpValuesChanged());
|
||||||
Gson gson = omnipodUtil.getGsonInstance();
|
sendEvent(new EventRefreshOverview("Omnipod Pump", false));
|
||||||
String gsonValue = gson.toJson(podState);
|
|
||||||
aapsLogger.info(LTag.PUMPCOMM, "PodState-SP: Saved PodState to SharedPreferences: " + gsonValue);
|
|
||||||
sp.putString(OmnipodConst.Prefs.PodState, gsonValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyPodStateChanged() {
|
|
||||||
if (stateChangedHandler != null) {
|
|
||||||
stateChangedHandler.handle(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not actually "safe" as it throws an Exception, but it prevents NPEs
|
|
||||||
private <T> T getSafe(Supplier<T> supplier) {
|
|
||||||
if (!hasState()) {
|
|
||||||
throw new IllegalStateException("Cannot read from PodState: podState is null");
|
|
||||||
}
|
|
||||||
return supplier.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadPodState() {
|
|
||||||
podState = null;
|
|
||||||
|
|
||||||
String storedPodState = sp.getString(OmnipodConst.Prefs.PodState, "");
|
|
||||||
|
|
||||||
if (StringUtils.isEmpty(storedPodState)) {
|
|
||||||
aapsLogger.info(LTag.PUMP, "PodState-SP: no PodState present in SharedPreferences");
|
|
||||||
} else {
|
} else {
|
||||||
aapsLogger.info(LTag.PUMP, "PodState-SP: loaded PodState from SharedPreferences: " + storedPodState);
|
// Update active alerts
|
||||||
try {
|
if (hasActiveAlerts()) {
|
||||||
podState = omnipodUtil.getGsonInstance().fromJson(storedPodState, PodState.class);
|
List<String> alerts = getTranslatedActiveAlerts();
|
||||||
} catch (Exception ex) {
|
String alertsText = TextUtils.join("\n", alerts);
|
||||||
aapsLogger.error(LTag.PUMPCOMM, "PodState-SP: could not deserialize PodState", ex);
|
|
||||||
|
if (!omnipodPumpStatus.ackAlertsAvailable || !alertsText.equals(omnipodPumpStatus.ackAlertsText)) {
|
||||||
|
omnipodPumpStatus.ackAlertsAvailable = true;
|
||||||
|
omnipodPumpStatus.ackAlertsText = TextUtils.join("\n", alerts);
|
||||||
|
|
||||||
|
sendEvent(new EventOmnipodAcknowledgeAlertsChanged());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (omnipodPumpStatus.ackAlertsAvailable || StringUtils.isNotEmpty(omnipodPumpStatus.ackAlertsText)) {
|
||||||
|
omnipodPumpStatus.ackAlertsText = null;
|
||||||
|
omnipodPumpStatus.ackAlertsAvailable = false;
|
||||||
|
sendEvent(new EventOmnipodAcknowledgeAlertsChanged());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
notifyPodStateChanged();
|
Date lastBolusStartTime = getLastBolusStartTime() == null ? null : getLastBolusStartTime().toDate();
|
||||||
|
Double lastBolusAmount = getLastBolusAmount();
|
||||||
|
|
||||||
|
// Update other info: last bolus, units remaining, suspended
|
||||||
|
if (Objects.equals(lastBolusStartTime, omnipodPumpStatus.lastBolusTime) //
|
||||||
|
|| !Objects.equals(lastBolusAmount, omnipodPumpStatus.lastBolusAmount) //
|
||||||
|
|| !isReservoirStatusUpToDate(omnipodPumpStatus, getReservoirLevel())
|
||||||
|
|| isSuspended() != PumpStatusType.Suspended.equals(omnipodPumpStatus.pumpStatusType)) {
|
||||||
|
omnipodPumpStatus.lastBolusTime = lastBolusStartTime;
|
||||||
|
omnipodPumpStatus.lastBolusAmount = lastBolusAmount;
|
||||||
|
omnipodPumpStatus.reservoirRemainingUnits = getReservoirLevel() == null ? 75.0 : getReservoirLevel();
|
||||||
|
omnipodPumpStatus.pumpStatusType = isSuspended() ? PumpStatusType.Suspended : PumpStatusType.Running;
|
||||||
|
sendEvent(new EventOmnipodPumpValuesChanged());
|
||||||
|
|
||||||
|
if (isSuspended() != PumpStatusType.Suspended.equals(omnipodPumpStatus.pumpStatusType)) {
|
||||||
|
sendEvent(new EventRefreshOverview("Omnipod Pump", false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
omnipodUtil.notifyDeviceStatusChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public String toString() {
|
private List<String> getTranslatedActiveAlerts() {
|
||||||
return "AapsPodStateManager{" +
|
List<String> translatedAlerts = new ArrayList<>();
|
||||||
"podState=" + podState +
|
AlertSet activeAlerts = getActiveAlerts();
|
||||||
'}';
|
|
||||||
|
for (AlertSlot alertSlot : activeAlerts.getAlertSlots()) {
|
||||||
|
translatedAlerts.add(translateAlertType(getConfiguredAlertType(alertSlot)));
|
||||||
|
}
|
||||||
|
return translatedAlerts;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class PodState {
|
|
||||||
private final int address;
|
|
||||||
private Integer lot;
|
|
||||||
private Integer tid;
|
|
||||||
private FirmwareVersion piVersion;
|
|
||||||
private FirmwareVersion pmVersion;
|
|
||||||
private int packetNumber;
|
|
||||||
private int messageNumber;
|
|
||||||
private DateTimeZone timeZone;
|
|
||||||
private DateTime activatedAt;
|
|
||||||
private DateTime expiresAt;
|
|
||||||
private PodInfoFaultEvent faultEvent;
|
|
||||||
private Double reservoirLevel;
|
|
||||||
private boolean suspended;
|
|
||||||
private NonceState nonceState;
|
|
||||||
private SetupProgress setupProgress;
|
|
||||||
private DeliveryStatus lastDeliveryStatus;
|
|
||||||
private AlertSet activeAlerts;
|
|
||||||
private BasalSchedule basalSchedule;
|
|
||||||
private final Map<AlertSlot, AlertType> configuredAlerts = new HashMap<>();
|
|
||||||
|
|
||||||
private PodState(int address) {
|
private String translateAlertType(AlertType alertType) {
|
||||||
this.address = address;
|
if (alertType == null) {
|
||||||
|
return getStringResource(R.string.omnipod_alert_unknown_alert);
|
||||||
}
|
}
|
||||||
|
switch (alertType) {
|
||||||
public int getAddress() {
|
case FINISH_PAIRING_REMINDER:
|
||||||
return address;
|
return getStringResource(R.string.omnipod_alert_finish_pairing_reminder);
|
||||||
}
|
case FINISH_SETUP_REMINDER:
|
||||||
|
return getStringResource(R.string.omnipod_alert_finish_setup_reminder_reminder);
|
||||||
public Integer getLot() {
|
case EXPIRATION_ALERT:
|
||||||
return lot;
|
return getStringResource(R.string.omnipod_alert_expiration);
|
||||||
}
|
case EXPIRATION_ADVISORY_ALERT:
|
||||||
|
return getStringResource(R.string.omnipod_alert_expiration_advisory);
|
||||||
public void setLot(int lot) {
|
case SHUTDOWN_IMMINENT_ALARM:
|
||||||
this.lot = lot;
|
return getStringResource(R.string.omnipod_alert_shutdown_imminent);
|
||||||
}
|
case LOW_RESERVOIR_ALERT:
|
||||||
|
return getStringResource(R.string.omnipod_alert_low_reservoir);
|
||||||
public Integer getTid() {
|
default:
|
||||||
return tid;
|
return alertType.name();
|
||||||
}
|
|
||||||
|
|
||||||
public void setTid(int tid) {
|
|
||||||
this.tid = tid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FirmwareVersion getPiVersion() {
|
|
||||||
return piVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPiVersion(FirmwareVersion piVersion) {
|
|
||||||
if (this.piVersion != null) {
|
|
||||||
throw new IllegalStateException("piVersion has already been set");
|
|
||||||
}
|
|
||||||
if (piVersion == null) {
|
|
||||||
throw new IllegalArgumentException("piVersion can not be null");
|
|
||||||
}
|
|
||||||
this.piVersion = piVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FirmwareVersion getPmVersion() {
|
|
||||||
return pmVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPmVersion(FirmwareVersion pmVersion) {
|
|
||||||
this.pmVersion = pmVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPacketNumber() {
|
|
||||||
return packetNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPacketNumber(int packetNumber) {
|
|
||||||
this.packetNumber = packetNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMessageNumber() {
|
|
||||||
return messageNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMessageNumber(int messageNumber) {
|
|
||||||
this.messageNumber = messageNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateTimeZone getTimeZone() {
|
|
||||||
return timeZone;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTimeZone(DateTimeZone timeZone) {
|
|
||||||
this.timeZone = timeZone;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateTime getActivatedAt() {
|
|
||||||
return activatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setActivatedAt(DateTime activatedAt) {
|
|
||||||
this.activatedAt = activatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateTime getExpiresAt() {
|
|
||||||
return expiresAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExpiresAt(DateTime expiresAt) {
|
|
||||||
this.expiresAt = expiresAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PodInfoFaultEvent getFaultEvent() {
|
|
||||||
return faultEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFaultEvent(PodInfoFaultEvent faultEvent) {
|
|
||||||
this.faultEvent = faultEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Double getReservoirLevel() {
|
|
||||||
return reservoirLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setReservoirLevel(Double reservoirLevel) {
|
|
||||||
this.reservoirLevel = reservoirLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSuspended() {
|
|
||||||
return suspended;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSuspended(boolean suspended) {
|
|
||||||
this.suspended = suspended;
|
|
||||||
}
|
|
||||||
|
|
||||||
public NonceState getNonceState() {
|
|
||||||
return nonceState;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNonceState(NonceState nonceState) {
|
|
||||||
this.nonceState = nonceState;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SetupProgress getSetupProgress() {
|
|
||||||
return setupProgress;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSetupProgress(SetupProgress setupProgress) {
|
|
||||||
this.setupProgress = setupProgress;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DeliveryStatus getLastDeliveryStatus() {
|
|
||||||
return lastDeliveryStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLastDeliveryStatus(DeliveryStatus lastDeliveryStatus) {
|
|
||||||
this.lastDeliveryStatus = lastDeliveryStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AlertSet getActiveAlerts() {
|
|
||||||
return activeAlerts;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setActiveAlerts(AlertSet activeAlerts) {
|
|
||||||
this.activeAlerts = activeAlerts;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BasalSchedule getBasalSchedule() {
|
|
||||||
return basalSchedule;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBasalSchedule(BasalSchedule basalSchedule) {
|
|
||||||
this.basalSchedule = basalSchedule;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<AlertSlot, AlertType> getConfiguredAlerts() {
|
|
||||||
return configuredAlerts;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String toString() {
|
|
||||||
return "PodState{" +
|
|
||||||
"address=" + address +
|
|
||||||
", lot=" + lot +
|
|
||||||
", tid=" + tid +
|
|
||||||
", piVersion=" + piVersion +
|
|
||||||
", pmVersion=" + pmVersion +
|
|
||||||
", packetNumber=" + packetNumber +
|
|
||||||
", messageNumber=" + messageNumber +
|
|
||||||
", timeZone=" + timeZone +
|
|
||||||
", activatedAt=" + activatedAt +
|
|
||||||
", expiresAt=" + expiresAt +
|
|
||||||
", faultEvent=" + faultEvent +
|
|
||||||
", reservoirLevel=" + reservoirLevel +
|
|
||||||
", suspended=" + suspended +
|
|
||||||
", nonceState=" + nonceState +
|
|
||||||
", setupProgress=" + setupProgress +
|
|
||||||
", lastDeliveryStatus=" + lastDeliveryStatus +
|
|
||||||
", activeAlerts=" + activeAlerts +
|
|
||||||
", basalSchedule=" + basalSchedule +
|
|
||||||
", configuredAlerts=" + configuredAlerts +
|
|
||||||
'}';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class NonceState {
|
private String getStringResource(int id, Object... args) {
|
||||||
private final long[] table = new long[21];
|
return resourceHelper.gs(id, args);
|
||||||
private int index;
|
|
||||||
|
|
||||||
private NonceState(int lot, int tid) {
|
|
||||||
initializeTable(lot, tid, (byte) 0x00);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private NonceState(int lot, int tid, byte seed) {
|
private static boolean isReservoirStatusUpToDate(OmnipodPumpStatus pumpStatus, Double unitsRemaining) {
|
||||||
initializeTable(lot, tid, seed);
|
double expectedUnitsRemaining = unitsRemaining == null ? 75.0 : unitsRemaining;
|
||||||
|
return Math.abs(expectedUnitsRemaining - pumpStatus.reservoirRemainingUnits) < 0.000001;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeTable(int lot, int tid, byte seed) {
|
private void sendEvent(Event event) {
|
||||||
table[0] = (long) (lot & 0xFFFF) + 0x55543DC3L + (((long) (lot) & 0xFFFFFFFFL) >> 16);
|
rxBus.send(event);
|
||||||
table[0] = table[0] & 0xFFFFFFFFL;
|
|
||||||
table[1] = (tid & 0xFFFF) + 0xAAAAE44EL + (((long) (tid) & 0xFFFFFFFFL) >> 16);
|
|
||||||
table[1] = table[1] & 0xFFFFFFFFL;
|
|
||||||
index = 0;
|
|
||||||
table[0] += seed;
|
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
table[2 + i] = generateEntry();
|
|
||||||
}
|
|
||||||
index = (int) ((table[0] + table[1]) & 0X0F);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int generateEntry() {
|
|
||||||
table[0] = (((table[0] >> 16) + (table[0] & 0xFFFF) * 0x5D7FL) & 0xFFFFFFFFL);
|
|
||||||
table[1] = (((table[1] >> 16) + (table[1] & 0xFFFF) * 0x8CA0L) & 0xFFFFFFFFL);
|
|
||||||
return (int) ((table[1] + (table[0] << 16)) & 0xFFFFFFFFL);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCurrentNonce() {
|
|
||||||
return (int) table[(2 + index)];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void advanceToNextNonce() {
|
|
||||||
int nonce = getCurrentNonce();
|
|
||||||
table[(2 + index)] = generateEntry();
|
|
||||||
index = (nonce & 0x0F);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "NonceState{" +
|
|
||||||
"table=" + Arrays.toString(table) +
|
|
||||||
", index=" + index +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO replace with java.util.function.Supplier<T> when min API level >= 24
|
|
||||||
@FunctionalInterface
|
|
||||||
private interface Supplier<T> {
|
|
||||||
T get();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,7 @@ public class RileyLinkOmnipodService extends RileyLinkService {
|
||||||
private void initializeErosOmnipodManager() {
|
private void initializeErosOmnipodManager() {
|
||||||
AapsOmnipodManager instance = AapsOmnipodManager.getInstance();
|
AapsOmnipodManager instance = AapsOmnipodManager.getInstance();
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
PodStateManager podStateManager = new AapsPodStateManager(injector);
|
PodStateManager podStateManager = new AapsPodStateManager(aapsLogger, sp, omnipodUtil, omnipodPumpStatus, rxBus, resourceHelper);
|
||||||
omnipodUtil.setPodStateManager(podStateManager);
|
omnipodUtil.setPodStateManager(podStateManager);
|
||||||
|
|
||||||
OmnipodCommunicationManager omnipodCommunicationService = new OmnipodCommunicationManager(injector, rfspy);
|
OmnipodCommunicationManager omnipodCommunicationService = new OmnipodCommunicationManager(injector, rfspy);
|
||||||
|
|
|
@ -44,6 +44,7 @@ public class OmnipodConst {
|
||||||
public static final int DEFAULT_ADDRESS = 0xffffffff;
|
public static final int DEFAULT_ADDRESS = 0xffffffff;
|
||||||
|
|
||||||
public static final Duration AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION = Duration.millis(1500);
|
public static final Duration AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION = Duration.millis(1500);
|
||||||
|
public static final Duration AVERAGE_TEMP_BASAL_COMMAND_COMMUNICATION_DURATION = Duration.millis(1500);
|
||||||
|
|
||||||
public static final Duration SERVICE_DURATION = Duration.standardHours(80);
|
public static final Duration SERVICE_DURATION = Duration.standardHours(80);
|
||||||
public static final Duration EXPIRATION_ADVISORY_WINDOW = Duration.standardHours(9);
|
public static final Duration EXPIRATION_ADVISORY_WINDOW = Duration.standardHours(9);
|
||||||
|
|
|
@ -114,11 +114,6 @@ public class OmnipodDashCommunicationManager implements OmnipodCommunicationMana
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPumpStatus(OmnipodPumpStatus pumpStatusLocal) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PodInfoRecentPulseLog readPulseLog() {
|
public PodInfoRecentPulseLog readPulseLog() {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -26,8 +26,8 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingBottom="5dp"
|
|
||||||
android:paddingTop="2dp"
|
android:paddingTop="2dp"
|
||||||
|
android:paddingBottom="5dp"
|
||||||
android:visibility="gone">
|
android:visibility="gone">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -45,10 +45,10 @@
|
||||||
<View
|
<View
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="2dip"
|
android:layout_height="2dip"
|
||||||
android:layout_marginBottom="5dp"
|
|
||||||
android:layout_marginLeft="20dp"
|
android:layout_marginLeft="20dp"
|
||||||
android:layout_marginRight="20dp"
|
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginRight="20dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
android:background="@color/listdelimiter" />
|
android:background="@color/listdelimiter" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
@ -70,8 +70,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="0"
|
android:layout_weight="0"
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:paddingEnd="2dp"
|
|
||||||
android:paddingStart="2dp"
|
android:paddingStart="2dp"
|
||||||
|
android:paddingEnd="2dp"
|
||||||
android:text=":"
|
android:text=":"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
@ -93,10 +93,10 @@
|
||||||
<View
|
<View
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="2dip"
|
android:layout_height="2dip"
|
||||||
android:layout_marginBottom="5dp"
|
|
||||||
android:layout_marginLeft="20dp"
|
android:layout_marginLeft="20dp"
|
||||||
android:layout_marginRight="20dp"
|
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginRight="20dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
android:background="@color/listdelimiter" />
|
android:background="@color/listdelimiter" />
|
||||||
|
|
||||||
<!-- Pod Address -->
|
<!-- Pod Address -->
|
||||||
|
@ -119,8 +119,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="0"
|
android:layout_weight="0"
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:paddingEnd="2dp"
|
|
||||||
android:paddingStart="2dp"
|
android:paddingStart="2dp"
|
||||||
|
android:paddingEnd="2dp"
|
||||||
android:text=":"
|
android:text=":"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
@ -133,12 +133,118 @@
|
||||||
android:paddingLeft="5dp"
|
android:paddingLeft="5dp"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Pod Lot -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1.5"
|
||||||
|
android:gravity="end"
|
||||||
|
android:paddingRight="5dp"
|
||||||
|
android:text="@string/omnipod_pod_lot"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="5dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingStart="2dp"
|
||||||
|
android:paddingEnd="2dp"
|
||||||
|
android:text=":"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/omnipod_pod_lot"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="start"
|
||||||
|
android:paddingLeft="5dp"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Pod Tid -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1.5"
|
||||||
|
android:gravity="end"
|
||||||
|
android:paddingRight="5dp"
|
||||||
|
android:text="@string/omnipod_pod_tid"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="5dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingStart="2dp"
|
||||||
|
android:paddingEnd="2dp"
|
||||||
|
android:text=":"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/omnipod_pod_tid"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="start"
|
||||||
|
android:paddingLeft="5dp"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Pod fw version -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1.5"
|
||||||
|
android:gravity="end"
|
||||||
|
android:paddingRight="5dp"
|
||||||
|
android:text="@string/omnipod_pod_fw_version"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="5dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingStart="2dp"
|
||||||
|
android:paddingEnd="2dp"
|
||||||
|
android:text=":"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/omnipod_pod_fw_version"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="start"
|
||||||
|
android:paddingLeft="5dp"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="14sp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
<!-- Pod Address -->
|
<!-- Pod Expires -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -158,8 +264,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="0"
|
android:layout_weight="0"
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:paddingEnd="2dp"
|
|
||||||
android:paddingStart="2dp"
|
android:paddingStart="2dp"
|
||||||
|
android:paddingEnd="2dp"
|
||||||
android:text=":"
|
android:text=":"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
@ -175,7 +281,7 @@
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Pod Status -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -195,8 +301,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="0"
|
android:layout_weight="0"
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:paddingEnd="2dp"
|
|
||||||
android:paddingStart="2dp"
|
android:paddingStart="2dp"
|
||||||
|
android:paddingEnd="2dp"
|
||||||
android:text=":"
|
android:text=":"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
@ -212,7 +318,6 @@
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -225,10 +330,10 @@
|
||||||
<View
|
<View
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="2dip"
|
android:layout_height="2dip"
|
||||||
android:layout_marginBottom="5dp"
|
|
||||||
android:layout_marginLeft="20dp"
|
android:layout_marginLeft="20dp"
|
||||||
android:layout_marginRight="20dp"
|
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginRight="20dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
android:background="@color/listdelimiter" />
|
android:background="@color/listdelimiter" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
@ -250,8 +355,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="0"
|
android:layout_weight="0"
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:paddingEnd="2dp"
|
|
||||||
android:paddingStart="2dp"
|
android:paddingStart="2dp"
|
||||||
|
android:paddingEnd="2dp"
|
||||||
android:text=":"
|
android:text=":"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
@ -270,10 +375,10 @@
|
||||||
<View
|
<View
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="2dip"
|
android:layout_height="2dip"
|
||||||
android:layout_marginBottom="5dp"
|
|
||||||
android:layout_marginLeft="20dp"
|
android:layout_marginLeft="20dp"
|
||||||
android:layout_marginRight="20dp"
|
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginRight="20dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
android:background="@color/listdelimiter" />
|
android:background="@color/listdelimiter" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
@ -295,8 +400,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="0"
|
android:layout_weight="0"
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:paddingEnd="2dp"
|
|
||||||
android:paddingStart="2dp"
|
android:paddingStart="2dp"
|
||||||
|
android:paddingEnd="2dp"
|
||||||
android:text=":"
|
android:text=":"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
@ -316,10 +421,10 @@
|
||||||
<View
|
<View
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="2dip"
|
android:layout_height="2dip"
|
||||||
android:layout_marginBottom="5dp"
|
|
||||||
android:layout_marginLeft="20dp"
|
android:layout_marginLeft="20dp"
|
||||||
android:layout_marginRight="20dp"
|
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginRight="20dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
android:background="@color/listdelimiter" />
|
android:background="@color/listdelimiter" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
@ -341,8 +446,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="0"
|
android:layout_weight="0"
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:paddingEnd="2dp"
|
|
||||||
android:paddingStart="2dp"
|
android:paddingStart="2dp"
|
||||||
|
android:paddingEnd="2dp"
|
||||||
android:text=":"
|
android:text=":"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
@ -361,10 +466,10 @@
|
||||||
<View
|
<View
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="2dip"
|
android:layout_height="2dip"
|
||||||
android:layout_marginBottom="5dp"
|
|
||||||
android:layout_marginLeft="20dp"
|
android:layout_marginLeft="20dp"
|
||||||
android:layout_marginRight="20dp"
|
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginRight="20dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
android:background="@color/listdelimiter" />
|
android:background="@color/listdelimiter" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
@ -386,8 +491,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="0"
|
android:layout_weight="0"
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:paddingEnd="2dp"
|
|
||||||
android:paddingStart="2dp"
|
android:paddingStart="2dp"
|
||||||
|
android:paddingEnd="2dp"
|
||||||
android:text=":"
|
android:text=":"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
@ -406,10 +511,10 @@
|
||||||
<View
|
<View
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="2dip"
|
android:layout_height="2dip"
|
||||||
android:layout_marginBottom="5dp"
|
|
||||||
android:layout_marginLeft="20dp"
|
android:layout_marginLeft="20dp"
|
||||||
android:layout_marginRight="20dp"
|
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginRight="20dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
android:background="@color/listdelimiter" />
|
android:background="@color/listdelimiter" />
|
||||||
|
|
||||||
|
|
||||||
|
@ -432,8 +537,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="0"
|
android:layout_weight="0"
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:paddingEnd="2dp"
|
|
||||||
android:paddingStart="2dp"
|
android:paddingStart="2dp"
|
||||||
|
android:paddingEnd="2dp"
|
||||||
android:text=":"
|
android:text=":"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
@ -453,10 +558,10 @@
|
||||||
<View
|
<View
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="2dip"
|
android:layout_height="2dip"
|
||||||
android:layout_marginBottom="5dp"
|
|
||||||
android:layout_marginLeft="20dp"
|
android:layout_marginLeft="20dp"
|
||||||
android:layout_marginRight="20dp"
|
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginRight="20dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
android:background="@color/listdelimiter" />
|
android:background="@color/listdelimiter" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
@ -478,8 +583,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="0"
|
android:layout_weight="0"
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:paddingEnd="2dp"
|
|
||||||
android:paddingStart="2dp"
|
android:paddingStart="2dp"
|
||||||
|
android:paddingEnd="2dp"
|
||||||
android:text=":"
|
android:text=":"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
@ -498,10 +603,10 @@
|
||||||
<View
|
<View
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="2dip"
|
android:layout_height="2dip"
|
||||||
android:layout_marginBottom="5dp"
|
|
||||||
android:layout_marginLeft="20dp"
|
android:layout_marginLeft="20dp"
|
||||||
android:layout_marginRight="20dp"
|
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginRight="20dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
android:background="@color/listdelimiter" />
|
android:background="@color/listdelimiter" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
@ -523,8 +628,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="0"
|
android:layout_weight="0"
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:paddingEnd="2dp"
|
|
||||||
android:paddingStart="2dp"
|
android:paddingStart="2dp"
|
||||||
|
android:paddingEnd="2dp"
|
||||||
android:text=":"
|
android:text=":"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
@ -543,10 +648,10 @@
|
||||||
<View
|
<View
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="2dip"
|
android:layout_height="2dip"
|
||||||
android:layout_marginBottom="5dp"
|
|
||||||
android:layout_marginLeft="20dp"
|
android:layout_marginLeft="20dp"
|
||||||
android:layout_marginRight="20dp"
|
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginRight="20dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
android:background="@color/listdelimiter" />
|
android:background="@color/listdelimiter" />
|
||||||
|
|
||||||
|
|
||||||
|
@ -621,8 +726,7 @@
|
||||||
android:drawableTop="@drawable/icon_cp_bolus_correction"
|
android:drawableTop="@drawable/icon_cp_bolus_correction"
|
||||||
android:paddingLeft="0dp"
|
android:paddingLeft="0dp"
|
||||||
android:paddingRight="0dp"
|
android:paddingRight="0dp"
|
||||||
android:text="@string/omnipod_read_pulse_log_short"
|
android:text="@string/omnipod_read_pulse_log_short" />
|
||||||
/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
|
@ -1982,5 +1982,8 @@
|
||||||
<string name="omnipod_bolus_failed_uncertain">Unable to verify whether the bolus succeeded. Please verify that your Pod is bolusing or cancel the bolus.</string>
|
<string name="omnipod_bolus_failed_uncertain">Unable to verify whether the bolus succeeded. Please verify that your Pod is bolusing or cancel the bolus.</string>
|
||||||
<string name="omnipod_rl_stats">RL Stats</string>
|
<string name="omnipod_rl_stats">RL Stats</string>
|
||||||
<string name="omnipod_read_pulse_log_short">Pulse Log</string>
|
<string name="omnipod_read_pulse_log_short">Pulse Log</string>
|
||||||
|
<string name="omnipod_pod_lot">LOT</string>
|
||||||
|
<string name="omnipod_pod_tid">TID</string>
|
||||||
|
<string name="omnipod_pod_fw_version">PM / PI version</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue